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