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