dri2.c revision d3758feb6b38292d90f4697fa41ea12dce563d5a
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 * Retrieve __DRIbuffer from the DRI loader.
122 */
123static __DRIbuffer *
124dri2_drawable_get_buffers(struct dri_drawable *drawable,
125                          const enum st_attachment_type *statts,
126                          unsigned *count)
127{
128   __DRIdrawable *dri_drawable = drawable->dPriv;
129   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
130   boolean with_format;
131   __DRIbuffer *buffers;
132   int num_buffers;
133   unsigned attachments[10];
134   unsigned num_attachments, i;
135
136   assert(loader);
137   with_format = dri_with_format(drawable->sPriv);
138
139   num_attachments = 0;
140
141   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
142   if (!with_format)
143      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
144
145   for (i = 0; i < *count; i++) {
146      enum pipe_format format;
147      unsigned bind;
148      int att, bpp;
149
150      dri_drawable_get_format(drawable, statts[i], &format, &bind);
151      if (format == PIPE_FORMAT_NONE)
152         continue;
153
154      switch (statts[i]) {
155      case ST_ATTACHMENT_FRONT_LEFT:
156         /* already added */
157         if (!with_format)
158            continue;
159         att = __DRI_BUFFER_FRONT_LEFT;
160         break;
161      case ST_ATTACHMENT_BACK_LEFT:
162         att = __DRI_BUFFER_BACK_LEFT;
163         break;
164      case ST_ATTACHMENT_FRONT_RIGHT:
165         att = __DRI_BUFFER_FRONT_RIGHT;
166         break;
167      case ST_ATTACHMENT_BACK_RIGHT:
168         att = __DRI_BUFFER_BACK_RIGHT;
169         break;
170      case ST_ATTACHMENT_DEPTH_STENCIL:
171         att = __DRI_BUFFER_DEPTH_STENCIL;
172         break;
173      default:
174         att = -1;
175         break;
176      }
177
178      bpp = util_format_get_blocksizebits(format);
179
180      if (att >= 0) {
181         attachments[num_attachments++] = att;
182         if (with_format) {
183            attachments[num_attachments++] = bpp;
184         }
185      }
186   }
187
188   if (with_format) {
189      num_attachments /= 2;
190      buffers = loader->getBuffersWithFormat(dri_drawable,
191            &dri_drawable->w, &dri_drawable->h,
192            attachments, num_attachments,
193            &num_buffers, dri_drawable->loaderPrivate);
194   }
195   else {
196      buffers = loader->getBuffers(dri_drawable,
197            &dri_drawable->w, &dri_drawable->h,
198            attachments, num_attachments,
199            &num_buffers, dri_drawable->loaderPrivate);
200   }
201
202   if (buffers) {
203      /* set one cliprect to cover the whole dri_drawable */
204      dri_drawable->x = 0;
205      dri_drawable->y = 0;
206      dri_drawable->backX = 0;
207      dri_drawable->backY = 0;
208      dri_drawable->numClipRects = 1;
209      dri_drawable->pClipRects[0].x1 = 0;
210      dri_drawable->pClipRects[0].y1 = 0;
211      dri_drawable->pClipRects[0].x2 = dri_drawable->w;
212      dri_drawable->pClipRects[0].y2 = dri_drawable->h;
213      dri_drawable->numBackClipRects = 1;
214      dri_drawable->pBackClipRects[0].x1 = 0;
215      dri_drawable->pBackClipRects[0].y1 = 0;
216      dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
217      dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
218
219      *count = num_buffers;
220   }
221
222   return buffers;
223}
224
225/**
226 * Process __DRIbuffer and convert them into pipe_resources.
227 */
228static void
229dri2_drawable_process_buffers(struct dri_drawable *drawable,
230                              __DRIbuffer *buffers, unsigned count)
231{
232   struct dri_screen *screen = dri_screen(drawable->sPriv);
233   __DRIdrawable *dri_drawable = drawable->dPriv;
234   struct pipe_resource templ;
235   struct winsys_handle whandle;
236   boolean have_depth = FALSE;
237   unsigned i, bind;
238
239   if (drawable->old_num == count &&
240       drawable->old_w == dri_drawable->w &&
241       drawable->old_h == dri_drawable->h &&
242       memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
243      return;
244
245   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
246      pipe_resource_reference(&drawable->textures[i], NULL);
247
248   memset(&templ, 0, sizeof(templ));
249   templ.target = PIPE_TEXTURE_2D;
250   templ.last_level = 0;
251   templ.width0 = dri_drawable->w;
252   templ.height0 = dri_drawable->h;
253   templ.depth0 = 1;
254
255   memset(&whandle, 0, sizeof(whandle));
256
257   for (i = 0; i < count; i++) {
258      __DRIbuffer *buf = &buffers[i];
259      enum st_attachment_type statt;
260      enum pipe_format format;
261
262      switch (buf->attachment) {
263      case __DRI_BUFFER_FRONT_LEFT:
264         if (!screen->auto_fake_front) {
265            statt = ST_ATTACHMENT_INVALID;
266            break;
267         }
268         /* fallthrough */
269      case __DRI_BUFFER_FAKE_FRONT_LEFT:
270         statt = ST_ATTACHMENT_FRONT_LEFT;
271         break;
272      case __DRI_BUFFER_BACK_LEFT:
273         statt = ST_ATTACHMENT_BACK_LEFT;
274         break;
275      case __DRI_BUFFER_DEPTH:
276      case __DRI_BUFFER_DEPTH_STENCIL:
277      case __DRI_BUFFER_STENCIL:
278         /* use only the first depth/stencil buffer */
279         if (!have_depth) {
280            have_depth = TRUE;
281            statt = ST_ATTACHMENT_DEPTH_STENCIL;
282         }
283         else {
284            statt = ST_ATTACHMENT_INVALID;
285         }
286         break;
287      default:
288         statt = ST_ATTACHMENT_INVALID;
289         break;
290      }
291
292      dri_drawable_get_format(drawable, statt, &format, &bind);
293      if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
294         continue;
295
296      templ.format = format;
297      templ.bind = bind;
298      whandle.handle = buf->name;
299      whandle.stride = buf->pitch;
300
301      drawable->textures[statt] =
302         screen->base.screen->resource_from_handle(screen->base.screen,
303               &templ, &whandle);
304   }
305
306   drawable->old_num = count;
307   drawable->old_w = dri_drawable->w;
308   drawable->old_h = dri_drawable->h;
309   memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
310}
311
312/*
313 * Backend functions for st_framebuffer interface.
314 */
315
316static void
317dri2_allocate_textures(struct dri_drawable *drawable,
318                       const enum st_attachment_type *statts,
319                       unsigned count)
320{
321   __DRIbuffer *buffers;
322   unsigned num_buffers = count;
323
324   buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
325   if (buffers)
326      dri2_drawable_process_buffers(drawable, buffers, num_buffers);
327}
328
329static void
330dri2_flush_frontbuffer(struct dri_drawable *drawable,
331                       enum st_attachment_type statt)
332{
333   __DRIdrawable *dri_drawable = drawable->dPriv;
334   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
335
336   if (loader->flushFrontBuffer == NULL)
337      return;
338
339   if (statt == ST_ATTACHMENT_FRONT_LEFT) {
340      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
341   }
342}
343
344static __DRIimage *
345dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
346{
347   __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
348   __DRIimage *img;
349
350   if (!loader->lookupEGLImage)
351      return NULL;
352
353   img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
354
355   return img;
356}
357
358static __DRIimage *
359dri2_create_image_from_name(__DRIcontext *context,
360                            int width, int height, int format,
361                            int name, int pitch, void *loaderPrivate)
362{
363   struct dri_screen *screen = dri_screen(context->driScreenPriv);
364   __DRIimage *img;
365   struct pipe_resource templ;
366   struct winsys_handle whandle;
367   unsigned tex_usage;
368   enum pipe_format pf;
369
370   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
371
372   switch (format) {
373   case __DRI_IMAGE_FORMAT_RGB565:
374      pf = PIPE_FORMAT_B5G6R5_UNORM;
375      break;
376   case __DRI_IMAGE_FORMAT_XRGB8888:
377      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
378      break;
379   case __DRI_IMAGE_FORMAT_ARGB8888:
380      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
381      break;
382   default:
383      pf = PIPE_FORMAT_NONE;
384      break;
385   }
386   if (pf == PIPE_FORMAT_NONE)
387      return NULL;
388
389   img = CALLOC_STRUCT(__DRIimageRec);
390   if (!img)
391      return NULL;
392
393   memset(&templ, 0, sizeof(templ));
394   templ.bind = tex_usage;
395   templ.format = pf;
396   templ.target = PIPE_TEXTURE_2D;
397   templ.last_level = 0;
398   templ.width0 = width;
399   templ.height0 = height;
400   templ.depth0 = 1;
401
402   memset(&whandle, 0, sizeof(whandle));
403   whandle.handle = name;
404   whandle.stride = pitch * util_format_get_blocksize(pf);
405
406   img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
407         &templ, &whandle);
408   if (!img->texture) {
409      FREE(img);
410      return NULL;
411   }
412
413   img->face = 0;
414   img->level = 0;
415   img->zslice = 0;
416   img->loader_private = loaderPrivate;
417
418   return img;
419}
420
421static __DRIimage *
422dri2_create_image_from_renderbuffer(__DRIcontext *context,
423				    int renderbuffer, void *loaderPrivate)
424{
425   struct dri_context *ctx = dri_context(context->driverPrivate);
426
427   if (!ctx->st->get_resource_for_egl_image)
428      return NULL;
429
430   /* TODO */
431   return NULL;
432}
433
434static void
435dri2_destroy_image(__DRIimage *img)
436{
437   pipe_resource_reference(&img->texture, NULL);
438   FREE(img);
439}
440
441static struct __DRIimageExtensionRec dri2ImageExtension = {
442    { __DRI_IMAGE, __DRI_IMAGE_VERSION },
443    dri2_create_image_from_name,
444    dri2_create_image_from_renderbuffer,
445    dri2_destroy_image,
446};
447
448/*
449 * Backend function init_screen.
450 */
451
452static const __DRIextension *dri_screen_extensions[] = {
453   &driReadDrawableExtension,
454   &driCopySubBufferExtension.base,
455   &driSwapControlExtension.base,
456   &driMediaStreamCounterExtension.base,
457   &dri2TexBufferExtension.base,
458   &dri2FlushExtension.base,
459   &dri2ImageExtension.base,
460   &dri2ConfigQueryExtension.base,
461   NULL
462};
463
464/**
465 * This is the driver specific part of the createNewScreen entry point.
466 *
467 * Returns the __GLcontextModes supported by this driver.
468 */
469static const __DRIconfig **
470dri2_init_screen(__DRIscreen * sPriv)
471{
472   const __DRIconfig **configs;
473   struct dri_screen *screen;
474   struct pipe_screen *pscreen;
475
476   screen = CALLOC_STRUCT(dri_screen);
477   if (!screen)
478      return NULL;
479
480   screen->sPriv = sPriv;
481   screen->fd = sPriv->fd;
482
483   sPriv->private = (void *)screen;
484   sPriv->extensions = dri_screen_extensions;
485
486   pscreen = driver_descriptor.create_screen(screen->fd);
487   /* dri_init_screen_helper checks pscreen for us */
488
489   configs = dri_init_screen_helper(screen, pscreen, 32);
490   if (!configs)
491      goto fail;
492
493   screen->auto_fake_front = dri_with_format(sPriv);
494   screen->broken_invalidate = !sPriv->dri2.useInvalidate;
495
496   return configs;
497fail:
498   dri_destroy_screen_helper(screen);
499   FREE(screen);
500   return NULL;
501}
502
503static boolean
504dri2_create_context(gl_api api, const __GLcontextModes * visual,
505                    __DRIcontext * cPriv, void *sharedContextPrivate)
506{
507   struct dri_context *ctx = NULL;
508
509   if (!dri_create_context(api, visual, cPriv, sharedContextPrivate))
510      return FALSE;
511
512   ctx = cPriv->driverPrivate;
513
514   ctx->lookup_egl_image = dri2_lookup_egl_image;
515
516   return TRUE;
517}
518
519static boolean
520dri2_create_buffer(__DRIscreen * sPriv,
521                   __DRIdrawable * dPriv,
522                   const __GLcontextModes * visual, boolean isPixmap)
523{
524   struct dri_drawable *drawable = NULL;
525
526   if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
527      return FALSE;
528
529   drawable = dPriv->driverPrivate;
530
531   drawable->allocate_textures = dri2_allocate_textures;
532   drawable->flush_frontbuffer = dri2_flush_frontbuffer;
533
534   return TRUE;
535}
536
537/**
538 * DRI driver virtual function table.
539 *
540 * DRI versions differ in their implementation of init_screen and swap_buffers.
541 */
542const struct __DriverAPIRec driDriverAPI = {
543   .InitScreen = NULL,
544   .InitScreen2 = dri2_init_screen,
545   .DestroyScreen = dri_destroy_screen,
546   .CreateContext = dri2_create_context,
547   .DestroyContext = dri_destroy_context,
548   .CreateBuffer = dri2_create_buffer,
549   .DestroyBuffer = dri_destroy_buffer,
550   .MakeCurrent = dri_make_current,
551   .UnbindContext = dri_unbind_context,
552
553   .GetSwapInfo = NULL,
554   .GetDrawableMSC = NULL,
555   .WaitForMSC = NULL,
556
557   .SwapBuffers = NULL,
558   .CopySubBuffer = NULL,
559};
560
561/* This is the table of extensions that the loader will dlsym() for. */
562PUBLIC const __DRIextension *__driDriverExtensions[] = {
563    &driCoreExtension.base,
564    &driLegacyExtension.base,
565    &driDRI2Extension.base,
566    NULL
567};
568
569/* vim: set sw=3 ts=8 sts=3 expandtab: */
570