dri2.c revision 2e4ad14a525f4028f0e0a93de2f8db785df33fb7
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_driver.h"
37
38#include "dri_screen.h"
39#include "dri_context.h"
40#include "dri_drawable.h"
41
42/**
43 * DRI2 flush extension.
44 */
45static void
46dri2_flush_drawable(__DRIdrawable *draw)
47{
48}
49
50static void
51dri2_invalidate_drawable(__DRIdrawable *dPriv)
52{
53   struct dri_drawable *drawable = dri_drawable(dPriv);
54   struct dri_context *ctx = dri_context(dPriv->driContextPriv);
55
56   dri2InvalidateDrawable(dPriv);
57   drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
58
59   if (ctx)
60      ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base);
61}
62
63static const __DRI2flushExtension dri2FlushExtension = {
64    { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
65    dri2_flush_drawable,
66    dri2_invalidate_drawable,
67};
68
69/**
70 * These are used for GLX_EXT_texture_from_pixmap
71 */
72static void
73dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
74                     GLint format, __DRIdrawable *dPriv)
75{
76   struct dri_context *ctx = dri_context(pDRICtx);
77   struct dri_drawable *drawable = dri_drawable(dPriv);
78   struct pipe_resource *pt;
79
80   dri_drawable_validate_att(drawable, ST_ATTACHMENT_FRONT_LEFT);
81
82   pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
83
84   if (pt) {
85      enum pipe_format internal_format = pt->format;
86
87      if (format == __DRI_TEXTURE_FORMAT_RGB)  {
88         /* only need to cover the formats recognized by dri_fill_st_visual */
89         switch (internal_format) {
90         case PIPE_FORMAT_B8G8R8A8_UNORM:
91            internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
92            break;
93         case PIPE_FORMAT_A8R8G8B8_UNORM:
94            internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
95            break;
96         default:
97            break;
98         }
99      }
100
101      ctx->st->teximage(ctx->st,
102            (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
103            0, internal_format, pt, FALSE);
104   }
105}
106
107static void
108dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
109                    __DRIdrawable *dPriv)
110{
111   dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
112}
113
114static const __DRItexBufferExtension dri2TexBufferExtension = {
115    { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
116   dri2_set_tex_buffer,
117   dri2_set_tex_buffer2,
118};
119
120/**
121 * Get the format and binding of an attachment.
122 */
123static INLINE void
124dri2_drawable_get_format(struct dri_drawable *drawable,
125                         enum st_attachment_type statt,
126                         enum pipe_format *format,
127                         unsigned *bind)
128{
129   switch (statt) {
130   case ST_ATTACHMENT_FRONT_LEFT:
131   case ST_ATTACHMENT_BACK_LEFT:
132   case ST_ATTACHMENT_FRONT_RIGHT:
133   case ST_ATTACHMENT_BACK_RIGHT:
134      *format = drawable->stvis.color_format;
135      *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
136      break;
137   case ST_ATTACHMENT_DEPTH_STENCIL:
138      *format = drawable->stvis.depth_stencil_format;
139      *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
140      break;
141   default:
142      *format = PIPE_FORMAT_NONE;
143      *bind = 0;
144      break;
145   }
146}
147
148
149/**
150 * Retrieve __DRIbuffer from the DRI loader.
151 */
152static __DRIbuffer *
153dri2_drawable_get_buffers(struct dri_drawable *drawable,
154                          const enum st_attachment_type *statts,
155                          unsigned *count)
156{
157   __DRIdrawable *dri_drawable = drawable->dPriv;
158   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
159   boolean with_format;
160   __DRIbuffer *buffers;
161   int num_buffers;
162   unsigned attachments[10];
163   unsigned num_attachments, i;
164
165   assert(loader);
166   with_format = dri_with_format(drawable->sPriv);
167
168   num_attachments = 0;
169
170   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
171   if (!with_format)
172      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
173
174   for (i = 0; i < *count; i++) {
175      enum pipe_format format;
176      unsigned bind;
177      int att, bpp;
178
179      dri2_drawable_get_format(drawable, statts[i], &format, &bind);
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, bind;
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.target = PIPE_TEXTURE_2D;
279   templ.last_level = 0;
280   templ.width0 = dri_drawable->w;
281   templ.height0 = dri_drawable->h;
282   templ.depth0 = 1;
283
284   memset(&whandle, 0, sizeof(whandle));
285
286   for (i = 0; i < count; i++) {
287      __DRIbuffer *buf = &buffers[i];
288      enum st_attachment_type statt;
289      enum pipe_format format;
290
291      switch (buf->attachment) {
292      case __DRI_BUFFER_FRONT_LEFT:
293         if (!screen->auto_fake_front) {
294            statt = ST_ATTACHMENT_INVALID;
295            break;
296         }
297         /* fallthrough */
298      case __DRI_BUFFER_FAKE_FRONT_LEFT:
299         statt = ST_ATTACHMENT_FRONT_LEFT;
300         break;
301      case __DRI_BUFFER_BACK_LEFT:
302         statt = ST_ATTACHMENT_BACK_LEFT;
303         break;
304      case __DRI_BUFFER_DEPTH:
305      case __DRI_BUFFER_DEPTH_STENCIL:
306      case __DRI_BUFFER_STENCIL:
307         /* use only the first depth/stencil buffer */
308         if (!have_depth) {
309            have_depth = TRUE;
310            statt = ST_ATTACHMENT_DEPTH_STENCIL;
311         }
312         else {
313            statt = ST_ATTACHMENT_INVALID;
314         }
315         break;
316      default:
317         statt = ST_ATTACHMENT_INVALID;
318         break;
319      }
320
321      dri2_drawable_get_format(drawable, statt, &format, &bind);
322      if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
323         continue;
324
325      templ.format = format;
326      templ.bind = bind;
327      whandle.handle = buf->name;
328      whandle.stride = buf->pitch;
329
330      drawable->textures[statt] =
331         screen->base.screen->resource_from_handle(screen->base.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
345static void
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
357static void
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
372static __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->base.screen->resource_from_handle(screen->base.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   &driMediaStreamCounterExtension.base,
485   &dri2TexBufferExtension.base,
486   &dri2FlushExtension.base,
487   &dri2ImageExtension.base,
488   &dri2ConfigQueryExtension.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 */
497static const __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->sPriv = sPriv;
509   screen->fd = sPriv->fd;
510   screen->lookup_egl_image = dri2_lookup_egl_image;
511   screen->allocate_textures = dri2_allocate_textures;
512   screen->flush_frontbuffer = dri2_flush_frontbuffer;
513
514   sPriv->private = (void *)screen;
515   sPriv->extensions = dri_screen_extensions;
516
517   pscreen = driver_descriptor.create_screen(screen->fd);
518   /* dri_init_screen_helper checks pscreen for us */
519
520   configs = dri_init_screen_helper(screen, pscreen, 32);
521   if (!configs)
522      goto fail;
523
524   screen->auto_fake_front = dri_with_format(sPriv);
525   screen->broken_invalidate = !sPriv->dri2.useInvalidate;
526
527   return configs;
528fail:
529   dri_destroy_screen_helper(screen);
530   FREE(screen);
531   return NULL;
532}
533
534/**
535 * DRI driver virtual function table.
536 *
537 * DRI versions differ in their implementation of init_screen and swap_buffers.
538 */
539const struct __DriverAPIRec driDriverAPI = {
540   .DestroyScreen = dri_destroy_screen,
541   .CreateContext = dri_create_context,
542   .DestroyContext = dri_destroy_context,
543   .CreateBuffer = dri_create_buffer,
544   .DestroyBuffer = dri_destroy_buffer,
545   .MakeCurrent = dri_make_current,
546   .UnbindContext = dri_unbind_context,
547
548   .GetSwapInfo = NULL,
549   .GetDrawableMSC = NULL,
550   .WaitForMSC = NULL,
551   .InitScreen2 = dri2_init_screen,
552
553   .InitScreen = NULL,
554   .SwapBuffers = NULL,
555   .CopySubBuffer = NULL,
556};
557
558/* This is the table of extensions that the loader will dlsym() for. */
559PUBLIC const __DRIextension *__driDriverExtensions[] = {
560    &driCoreExtension.base,
561    &driLegacyExtension.base,
562    &driDRI2Extension.base,
563    NULL
564};
565
566/* vim: set sw=3 ts=8 sts=3 expandtab: */
567