dri2.c revision 39c81dada01585a6030f03d215842a1a2ae87d86
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.9
4 *
5 * Copyright 2009, VMware, Inc.
6 * All Rights Reserved.
7 * Copyright (C) 2010 LunarG Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 *    Keith Whitwell <keithw@vmware.com>
28 *    Jakob Bornecrantz <wallbraker@gmail.com>
29 *    Chia-I Wu <olv@lunarg.com>
30 */
31
32#include "util/u_memory.h"
33#include "util/u_inlines.h"
34#include "util/u_format.h"
35#include "util/u_debug.h"
36#include "state_tracker/drm_api.h"
37
38#include "dri_screen.h"
39#include "dri_context.h"
40#include "dri_drawable.h"
41#include "dri_st_api.h"
42#include "dri2.h"
43
44/**
45 * DRI2 flush extension.
46 */
47static void
48dri2_flush_drawable(__DRIdrawable *draw)
49{
50}
51
52static void
53dri2_invalidate_drawable(__DRIdrawable *dPriv)
54{
55   struct dri_drawable *drawable = dri_drawable(dPriv);
56   struct dri_context *ctx = dri_context(dPriv->driContextPriv);
57
58   dri2InvalidateDrawable(dPriv);
59   drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
60
61   if (ctx)
62      ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
63}
64
65static const __DRI2flushExtension dri2FlushExtension = {
66    { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
67    dri2_flush_drawable,
68    dri2_invalidate_drawable,
69};
70
71/**
72 * These are used for GLX_EXT_texture_from_pixmap
73 */
74static void
75dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
76                     GLint format, __DRIdrawable *dPriv)
77{
78   struct dri_context *ctx = dri_context(pDRICtx);
79   struct dri_drawable *drawable = dri_drawable(dPriv);
80   struct pipe_resource *pt;
81
82   dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT);
83
84   pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
85
86   if (pt) {
87      enum pipe_format internal_format = pt->format;
88
89      if (format == __DRI_TEXTURE_FORMAT_RGB)  {
90         /* only need to cover the formats recognized by dri_fill_st_visual */
91         switch (internal_format) {
92         case PIPE_FORMAT_B8G8R8A8_UNORM:
93            internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
94            break;
95         case PIPE_FORMAT_A8R8G8B8_UNORM:
96            internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
97            break;
98         default:
99            break;
100         }
101      }
102
103      ctx->st->teximage(ctx->st,
104            (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
105            0, internal_format, pt, FALSE);
106   }
107}
108
109static void
110dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
111                    __DRIdrawable *dPriv)
112{
113   dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
114}
115
116static const __DRItexBufferExtension dri2TexBufferExtension = {
117    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
118   dri2_set_tex_buffer,
119   dri2_set_tex_buffer2,
120};
121
122/**
123 * Get the format of an attachment.
124 */
125static INLINE enum pipe_format
126dri2_drawable_get_format(struct dri_drawable *drawable,
127                         enum st_attachment_type statt)
128{
129   enum pipe_format format;
130
131   switch (statt) {
132   case ST_ATTACHMENT_FRONT_LEFT:
133   case ST_ATTACHMENT_BACK_LEFT:
134   case ST_ATTACHMENT_FRONT_RIGHT:
135   case ST_ATTACHMENT_BACK_RIGHT:
136      format = drawable->stvis.color_format;
137      break;
138   case ST_ATTACHMENT_DEPTH_STENCIL:
139      format = drawable->stvis.depth_stencil_format;
140      break;
141   default:
142      format = PIPE_FORMAT_NONE;
143      break;
144   }
145
146   return format;
147}
148
149
150/**
151 * Retrieve __DRIbuffer from the DRI loader.
152 */
153static __DRIbuffer *
154dri2_drawable_get_buffers(struct dri_drawable *drawable,
155                          const enum st_attachment_type *statts,
156                          unsigned *count)
157{
158   __DRIdrawable *dri_drawable = drawable->dPriv;
159   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
160   boolean with_format;
161   __DRIbuffer *buffers;
162   int num_buffers;
163   unsigned attachments[10];
164   unsigned num_attachments, i;
165
166   assert(loader);
167   with_format = dri_with_format(drawable->sPriv);
168
169   num_attachments = 0;
170
171   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
172   if (!with_format)
173      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
174
175   for (i = 0; i < *count; i++) {
176      enum pipe_format format;
177      int att, bpp;
178
179      format = dri2_drawable_get_format(drawable, statts[i]);
180      if (format == PIPE_FORMAT_NONE)
181         continue;
182
183      switch (statts[i]) {
184      case ST_ATTACHMENT_FRONT_LEFT:
185         /* already added */
186         if (!with_format)
187            continue;
188         att = __DRI_BUFFER_FRONT_LEFT;
189         break;
190      case ST_ATTACHMENT_BACK_LEFT:
191         att = __DRI_BUFFER_BACK_LEFT;
192         break;
193      case ST_ATTACHMENT_FRONT_RIGHT:
194         att = __DRI_BUFFER_FRONT_RIGHT;
195         break;
196      case ST_ATTACHMENT_BACK_RIGHT:
197         att = __DRI_BUFFER_BACK_RIGHT;
198         break;
199      case ST_ATTACHMENT_DEPTH_STENCIL:
200         att = __DRI_BUFFER_DEPTH_STENCIL;
201         break;
202      default:
203         att = -1;
204         break;
205      }
206
207      bpp = util_format_get_blocksizebits(format);
208
209      if (att >= 0) {
210         attachments[num_attachments++] = att;
211         if (with_format) {
212            attachments[num_attachments++] = bpp;
213         }
214      }
215   }
216
217   if (with_format) {
218      num_attachments /= 2;
219      buffers = loader->getBuffersWithFormat(dri_drawable,
220            &dri_drawable->w, &dri_drawable->h,
221            attachments, num_attachments,
222            &num_buffers, dri_drawable->loaderPrivate);
223   }
224   else {
225      buffers = loader->getBuffers(dri_drawable,
226            &dri_drawable->w, &dri_drawable->h,
227            attachments, num_attachments,
228            &num_buffers, dri_drawable->loaderPrivate);
229   }
230
231   if (buffers) {
232      /* set one cliprect to cover the whole dri_drawable */
233      dri_drawable->x = 0;
234      dri_drawable->y = 0;
235      dri_drawable->backX = 0;
236      dri_drawable->backY = 0;
237      dri_drawable->numClipRects = 1;
238      dri_drawable->pClipRects[0].x1 = 0;
239      dri_drawable->pClipRects[0].y1 = 0;
240      dri_drawable->pClipRects[0].x2 = dri_drawable->w;
241      dri_drawable->pClipRects[0].y2 = dri_drawable->h;
242      dri_drawable->numBackClipRects = 1;
243      dri_drawable->pBackClipRects[0].x1 = 0;
244      dri_drawable->pBackClipRects[0].y1 = 0;
245      dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
246      dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
247
248      *count = num_buffers;
249   }
250
251   return buffers;
252}
253
254/**
255 * Process __DRIbuffer and convert them into pipe_resources.
256 */
257static void
258dri2_drawable_process_buffers(struct dri_drawable *drawable,
259                              __DRIbuffer *buffers, unsigned count)
260{
261   struct dri_screen *screen = dri_screen(drawable->sPriv);
262   __DRIdrawable *dri_drawable = drawable->dPriv;
263   struct pipe_resource templ;
264   struct winsys_handle whandle;
265   boolean have_depth = FALSE;
266   unsigned i;
267
268   if (drawable->old_num == count &&
269       drawable->old_w == dri_drawable->w &&
270       drawable->old_h == dri_drawable->h &&
271       memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
272      return;
273
274   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
275      pipe_resource_reference(&drawable->textures[i], NULL);
276
277   memset(&templ, 0, sizeof(templ));
278   templ.bind = PIPE_BIND_RENDER_TARGET;
279   templ.target = PIPE_TEXTURE_2D;
280   templ.last_level = 0;
281   templ.width0 = dri_drawable->w;
282   templ.height0 = dri_drawable->h;
283   templ.depth0 = 1;
284
285   memset(&whandle, 0, sizeof(whandle));
286
287   for (i = 0; i < count; i++) {
288      __DRIbuffer *buf = &buffers[i];
289      enum st_attachment_type statt;
290      enum pipe_format format;
291
292      switch (buf->attachment) {
293      case __DRI_BUFFER_FRONT_LEFT:
294         if (!screen->auto_fake_front) {
295            statt = ST_ATTACHMENT_INVALID;
296            break;
297         }
298         /* fallthrough */
299      case __DRI_BUFFER_FAKE_FRONT_LEFT:
300         statt = ST_ATTACHMENT_FRONT_LEFT;
301         break;
302      case __DRI_BUFFER_BACK_LEFT:
303         statt = ST_ATTACHMENT_BACK_LEFT;
304         break;
305      case __DRI_BUFFER_DEPTH:
306      case __DRI_BUFFER_DEPTH_STENCIL:
307      case __DRI_BUFFER_STENCIL:
308         /* use only the first depth/stencil buffer */
309         if (!have_depth) {
310            have_depth = TRUE;
311            statt = ST_ATTACHMENT_DEPTH_STENCIL;
312         }
313         else {
314            statt = ST_ATTACHMENT_INVALID;
315         }
316         break;
317      default:
318         statt = ST_ATTACHMENT_INVALID;
319         break;
320      }
321
322      format = dri2_drawable_get_format(drawable, statt);
323      if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
324         continue;
325
326      templ.format = format;
327      whandle.handle = buf->name;
328      whandle.stride = buf->pitch;
329
330      drawable->textures[statt] =
331         screen->pipe_screen->resource_from_handle(screen->pipe_screen,
332               &templ, &whandle);
333   }
334
335   drawable->old_num = count;
336   drawable->old_w = dri_drawable->w;
337   drawable->old_h = dri_drawable->h;
338   memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
339}
340
341/*
342 * Backend functions for st_framebuffer interface.
343 */
344
345void
346dri2_allocate_textures(struct dri_drawable *drawable,
347                       const enum st_attachment_type *statts,
348                       unsigned count)
349{
350   __DRIbuffer *buffers;
351   unsigned num_buffers = count;
352
353   buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
354   dri2_drawable_process_buffers(drawable, buffers, num_buffers);
355}
356
357void
358dri2_flush_frontbuffer(struct dri_drawable *drawable,
359                       enum st_attachment_type statt)
360{
361   __DRIdrawable *dri_drawable = drawable->dPriv;
362   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
363
364   if (loader->flushFrontBuffer == NULL)
365      return;
366
367   if (statt == ST_ATTACHMENT_FRONT_LEFT) {
368      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
369   }
370}
371
372__DRIimage *
373dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
374{
375   __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
376   __DRIimage *img;
377
378   if (!loader->lookupEGLImage)
379      return NULL;
380
381   img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
382
383   return img;
384}
385
386static __DRIimage *
387dri2_create_image_from_name(__DRIcontext *context,
388                            int width, int height, int format,
389                            int name, int pitch, void *loaderPrivate)
390{
391   struct dri_screen *screen = dri_screen(context->driScreenPriv);
392   __DRIimage *img;
393   struct pipe_resource templ;
394   struct winsys_handle whandle;
395   unsigned tex_usage;
396   enum pipe_format pf;
397
398   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
399
400   switch (format) {
401   case __DRI_IMAGE_FORMAT_RGB565:
402      pf = PIPE_FORMAT_B5G6R5_UNORM;
403      break;
404   case __DRI_IMAGE_FORMAT_XRGB8888:
405      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
406      break;
407   case __DRI_IMAGE_FORMAT_ARGB8888:
408      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
409      break;
410   default:
411      pf = PIPE_FORMAT_NONE;
412      break;
413   }
414   if (pf == PIPE_FORMAT_NONE)
415      return NULL;
416
417   img = CALLOC_STRUCT(__DRIimageRec);
418   if (!img)
419      return NULL;
420
421   memset(&templ, 0, sizeof(templ));
422   templ.bind = tex_usage;
423   templ.format = pf;
424   templ.target = PIPE_TEXTURE_2D;
425   templ.last_level = 0;
426   templ.width0 = width;
427   templ.height0 = height;
428   templ.depth0 = 1;
429
430   memset(&whandle, 0, sizeof(whandle));
431   whandle.handle = name;
432   whandle.stride = pitch * util_format_get_blocksize(pf);
433
434   img->texture = screen->pipe_screen->resource_from_handle(screen->pipe_screen,
435         &templ, &whandle);
436   if (!img->texture) {
437      FREE(img);
438      return NULL;
439   }
440
441   img->face = 0;
442   img->level = 0;
443   img->zslice = 0;
444   img->loader_private = loaderPrivate;
445
446   return img;
447}
448
449static __DRIimage *
450dri2_create_image_from_renderbuffer(__DRIcontext *context,
451				    int renderbuffer, void *loaderPrivate)
452{
453   struct dri_context *ctx = dri_context(context->driverPrivate);
454
455   if (!ctx->st->get_resource_for_egl_image)
456      return NULL;
457
458   /* TODO */
459   return NULL;
460}
461
462static void
463dri2_destroy_image(__DRIimage *img)
464{
465   pipe_resource_reference(&img->texture, NULL);
466   FREE(img);
467}
468
469static struct __DRIimageExtensionRec dri2ImageExtension = {
470    { __DRI_IMAGE, __DRI_IMAGE_VERSION },
471    dri2_create_image_from_name,
472    dri2_create_image_from_renderbuffer,
473    dri2_destroy_image,
474};
475
476/*
477 * Backend function init_screen.
478 */
479
480static const __DRIextension *dri_screen_extensions[] = {
481   &driReadDrawableExtension,
482   &driCopySubBufferExtension.base,
483   &driSwapControlExtension.base,
484   &driFrameTrackingExtension.base,
485   &driMediaStreamCounterExtension.base,
486   &dri2TexBufferExtension.base,
487   &dri2FlushExtension.base,
488   &dri2ImageExtension.base,
489   NULL
490};
491
492/**
493 * This is the driver specific part of the createNewScreen entry point.
494 *
495 * Returns the __GLcontextModes supported by this driver.
496 */
497const __DRIconfig **
498dri2_init_screen(__DRIscreen * sPriv)
499{
500   const __DRIconfig **configs;
501   struct dri_screen *screen;
502   struct pipe_screen *pscreen;
503
504   screen = CALLOC_STRUCT(dri_screen);
505   if (!screen)
506      return NULL;
507
508   screen->api = drm_api_create();
509   screen->sPriv = sPriv;
510   screen->fd = sPriv->fd;
511
512   sPriv->private = (void *)screen;
513   sPriv->extensions = dri_screen_extensions;
514
515   pscreen = screen->api->create_screen(screen->api, screen->fd, NULL);
516   /* dri_init_screen_helper checks pscreen for us */
517
518   configs = dri_init_screen_helper(screen, pscreen, 32);
519   if (!configs)
520      goto fail;
521
522   screen->auto_fake_front = dri_with_format(sPriv);
523
524   return configs;
525fail:
526   dri_destroy_screen_helper(screen);
527   FREE(screen);
528   return NULL;
529}
530
531/* This is the table of extensions that the loader will dlsym() for. */
532PUBLIC const __DRIextension *__driDriverExtensions[] = {
533    &driCoreExtension.base,
534    &driLegacyExtension.base,
535    &driDRI2Extension.base,
536    NULL
537};
538
539/* vim: set sw=3 ts=8 sts=3 expandtab: */
540