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