dri2.c revision 968bf9634ec03e61441834603f13f0c914bbb0ce
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_texture *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 * 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      int att, bpp;
177
178      format = dri2_drawable_get_format(drawable, statts[i]);
179      if (format == PIPE_FORMAT_NONE)
180         continue;
181
182      switch (statts[i]) {
183      case ST_ATTACHMENT_FRONT_LEFT:
184         /* already added */
185         if (!with_format)
186            continue;
187         att = __DRI_BUFFER_FRONT_LEFT;
188         break;
189      case ST_ATTACHMENT_BACK_LEFT:
190         att = __DRI_BUFFER_BACK_LEFT;
191         break;
192      case ST_ATTACHMENT_FRONT_RIGHT:
193         att = __DRI_BUFFER_FRONT_RIGHT;
194         break;
195      case ST_ATTACHMENT_BACK_RIGHT:
196         att = __DRI_BUFFER_BACK_RIGHT;
197         break;
198      case ST_ATTACHMENT_DEPTH_STENCIL:
199         att = __DRI_BUFFER_DEPTH_STENCIL;
200         break;
201      default:
202         att = -1;
203         break;
204      }
205
206      bpp = util_format_get_blocksizebits(format);
207
208      if (att >= 0) {
209         attachments[num_attachments++] = att;
210         if (with_format) {
211            attachments[num_attachments++] = bpp;
212         }
213      }
214   }
215
216   if (with_format) {
217      num_attachments /= 2;
218      buffers = loader->getBuffersWithFormat(dri_drawable,
219            &dri_drawable->w, &dri_drawable->h,
220            attachments, num_attachments,
221            &num_buffers, dri_drawable->loaderPrivate);
222   }
223   else {
224      buffers = loader->getBuffers(dri_drawable,
225            &dri_drawable->w, &dri_drawable->h,
226            attachments, num_attachments,
227            &num_buffers, dri_drawable->loaderPrivate);
228   }
229
230   if (buffers) {
231      /* set one cliprect to cover the whole dri_drawable */
232      dri_drawable->x = 0;
233      dri_drawable->y = 0;
234      dri_drawable->backX = 0;
235      dri_drawable->backY = 0;
236      dri_drawable->numClipRects = 1;
237      dri_drawable->pClipRects[0].x1 = 0;
238      dri_drawable->pClipRects[0].y1 = 0;
239      dri_drawable->pClipRects[0].x2 = dri_drawable->w;
240      dri_drawable->pClipRects[0].y2 = dri_drawable->h;
241      dri_drawable->numBackClipRects = 1;
242      dri_drawable->pBackClipRects[0].x1 = 0;
243      dri_drawable->pBackClipRects[0].y1 = 0;
244      dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
245      dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
246
247      *count = num_buffers;
248   }
249
250   return buffers;
251}
252
253/**
254 * Process __DRIbuffer and convert them into pipe_textures.
255 */
256static void
257dri2_drawable_process_buffers(struct dri_drawable *drawable,
258                              __DRIbuffer *buffers, unsigned count)
259{
260   struct dri_screen *screen = dri_screen(drawable->sPriv);
261   __DRIdrawable *dri_drawable = drawable->dPriv;
262   struct pipe_texture templ;
263   struct winsys_handle whandle;
264   boolean have_depth = FALSE;
265   unsigned i;
266
267   if (drawable->old_num == count &&
268       drawable->old_w == dri_drawable->w &&
269       drawable->old_h == dri_drawable->h &&
270       memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
271      return;
272
273   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
274      pipe_texture_reference(&drawable->textures[i], NULL);
275
276   memset(&templ, 0, sizeof(templ));
277   templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
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      format = dri2_drawable_get_format(drawable, statt);
322      if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
323         continue;
324
325      templ.format = format;
326      whandle.handle = buf->name;
327      whandle.stride = buf->pitch;
328
329      drawable->textures[statt] =
330         screen->pipe_screen->texture_from_handle(screen->pipe_screen,
331               &templ, &whandle);
332   }
333
334   drawable->old_num = count;
335   drawable->old_w = dri_drawable->w;
336   drawable->old_h = dri_drawable->h;
337   memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
338}
339
340/*
341 * Backend functions for st_framebuffer interface.
342 */
343
344void
345dri2_allocate_textures(struct dri_drawable *drawable,
346                       const enum st_attachment_type *statts,
347                       unsigned count)
348{
349   __DRIbuffer *buffers;
350   unsigned num_buffers = count;
351
352   buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
353   dri2_drawable_process_buffers(drawable, buffers, num_buffers);
354}
355
356void
357dri2_flush_frontbuffer(struct dri_drawable *drawable,
358                       enum st_attachment_type statt)
359{
360   __DRIdrawable *dri_drawable = drawable->dPriv;
361   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
362
363   if (loader->flushFrontBuffer == NULL)
364      return;
365
366   if (statt == ST_ATTACHMENT_FRONT_LEFT) {
367      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
368   }
369}
370
371__DRIimage *
372dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
373{
374   __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
375   __DRIimage *img;
376
377   if (!loader->lookupEGLImage)
378      return NULL;
379
380   img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
381
382   return img;
383}
384
385static __DRIimage *
386dri2_create_image_from_name(__DRIcontext *context,
387                            int width, int height, int format,
388                            int name, int pitch, void *loaderPrivate)
389{
390   struct dri_screen *screen = dri_screen(context->driScreenPriv);
391   __DRIimage *img;
392   struct pipe_texture templ;
393   struct winsys_handle whandle;
394   unsigned tex_usage;
395   enum pipe_format pf;
396
397   tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | PIPE_TEXTURE_USAGE_SAMPLER;
398
399   switch (format) {
400   case __DRI_IMAGE_FORMAT_RGB565:
401      pf = PIPE_FORMAT_B5G6R5_UNORM;
402      break;
403   case __DRI_IMAGE_FORMAT_XRGB8888:
404      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
405      break;
406   case __DRI_IMAGE_FORMAT_ARGB8888:
407      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
408      break;
409   default:
410      pf = PIPE_FORMAT_NONE;
411      break;
412   }
413   if (pf == PIPE_FORMAT_NONE)
414      return NULL;
415
416   img = CALLOC_STRUCT(__DRIimageRec);
417   if (!img)
418      return NULL;
419
420   memset(&templ, 0, sizeof(templ));
421   templ.tex_usage = tex_usage;
422   templ.format = pf;
423   templ.target = PIPE_TEXTURE_2D;
424   templ.last_level = 0;
425   templ.width0 = width;
426   templ.height0 = height;
427   templ.depth0 = 1;
428
429   memset(&whandle, 0, sizeof(whandle));
430   whandle.handle = name;
431   whandle.stride = pitch * util_format_get_blocksize(pf);
432
433   img->texture = screen->pipe_screen->texture_from_handle(screen->pipe_screen,
434         &templ, &whandle);
435   if (!img->texture) {
436      FREE(img);
437      return NULL;
438   }
439
440   img->face = 0;
441   img->level = 0;
442   img->zslice = 0;
443   img->loader_private = loaderPrivate;
444
445   return img;
446}
447
448static __DRIimage *
449dri2_create_image_from_renderbuffer(__DRIcontext *context,
450				    int renderbuffer, void *loaderPrivate)
451{
452   struct dri_context *ctx = dri_context(context->driverPrivate);
453
454   if (!ctx->st->get_resource_for_egl_image)
455      return NULL;
456
457   /* TODO */
458   return NULL;
459}
460
461static void
462dri2_destroy_image(__DRIimage *img)
463{
464   pipe_texture_reference(&img->texture, NULL);
465   FREE(img);
466}
467
468static struct __DRIimageExtensionRec dri2ImageExtension = {
469    { __DRI_IMAGE, __DRI_IMAGE_VERSION },
470    dri2_create_image_from_name,
471    dri2_create_image_from_renderbuffer,
472    dri2_destroy_image,
473};
474
475/*
476 * Backend function init_screen.
477 */
478
479static const __DRIextension *dri_screen_extensions[] = {
480   &driReadDrawableExtension,
481   &driCopySubBufferExtension.base,
482   &driSwapControlExtension.base,
483   &driFrameTrackingExtension.base,
484   &driMediaStreamCounterExtension.base,
485   &dri2TexBufferExtension.base,
486   &dri2FlushExtension.base,
487   &dri2ImageExtension.base,
488   NULL
489};
490
491/**
492 * This is the driver specific part of the createNewScreen entry point.
493 *
494 * Returns the __GLcontextModes supported by this driver.
495 */
496const __DRIconfig **
497dri2_init_screen(__DRIscreen * sPriv)
498{
499   const __DRIconfig **configs;
500   struct dri_screen *screen;
501   struct drm_create_screen_arg arg;
502
503   screen = CALLOC_STRUCT(dri_screen);
504   if (!screen)
505      return NULL;
506
507   screen->api = drm_api_create();
508   screen->sPriv = sPriv;
509   screen->fd = sPriv->fd;
510
511   sPriv->private = (void *)screen;
512   sPriv->extensions = dri_screen_extensions;
513
514   arg.mode = DRM_CREATE_NORMAL;
515
516   configs = dri_init_screen_helper(screen, &arg, 32);
517   if (!configs)
518      goto fail;
519
520   screen->auto_fake_front = dri_with_format(sPriv);
521
522   return configs;
523fail:
524   dri_destroy_screen_helper(screen);
525   FREE(screen);
526   return NULL;
527}
528
529/* This is the table of extensions that the loader will dlsym() for. */
530PUBLIC const __DRIextension *__driDriverExtensions[] = {
531    &driCoreExtension.base,
532    &driLegacyExtension.base,
533    &driDRI2Extension.base,
534    NULL
535};
536
537/* vim: set sw=3 ts=8 sts=3 expandtab: */
538