dri2.c revision f4515d106cd40351133c89855e3277a70bba8721
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_buffer.h"
42
43/**
44 * DRI2 flush extension.
45 */
46static void
47dri2_flush_drawable(__DRIdrawable *dPriv)
48{
49   struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
50   struct dri_drawable *drawable = dri_drawable(dPriv);
51
52   struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
53
54   if (ctx) {
55      if (ptex && ctx->pp && drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
56         pp_run(ctx->pp, ptex, ptex, drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
57
58      ctx->st->flush(ctx->st, 0, NULL);
59   }
60}
61
62static void
63dri2_invalidate_drawable(__DRIdrawable *dPriv)
64{
65   struct dri_drawable *drawable = dri_drawable(dPriv);
66
67   dri2InvalidateDrawable(dPriv);
68   drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
69
70   p_atomic_inc(&drawable->base.stamp);
71}
72
73static const __DRI2flushExtension dri2FlushExtension = {
74    { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
75    dri2_flush_drawable,
76    dri2_invalidate_drawable,
77};
78
79/**
80 * Retrieve __DRIbuffer from the DRI loader.
81 */
82static __DRIbuffer *
83dri2_drawable_get_buffers(struct dri_drawable *drawable,
84                          const enum st_attachment_type *statts,
85                          unsigned *count)
86{
87   __DRIdrawable *dri_drawable = drawable->dPriv;
88   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
89   boolean with_format;
90   __DRIbuffer *buffers;
91   int num_buffers;
92   unsigned attachments[10];
93   unsigned num_attachments, i;
94
95   assert(loader);
96   with_format = dri_with_format(drawable->sPriv);
97
98   num_attachments = 0;
99
100   /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
101   if (!with_format)
102      attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
103
104   for (i = 0; i < *count; i++) {
105      enum pipe_format format;
106      unsigned bind;
107      int att, bpp;
108
109      dri_drawable_get_format(drawable, statts[i], &format, &bind);
110      if (format == PIPE_FORMAT_NONE)
111         continue;
112
113      switch (statts[i]) {
114      case ST_ATTACHMENT_FRONT_LEFT:
115         /* already added */
116         if (!with_format)
117            continue;
118         att = __DRI_BUFFER_FRONT_LEFT;
119         break;
120      case ST_ATTACHMENT_BACK_LEFT:
121         att = __DRI_BUFFER_BACK_LEFT;
122         break;
123      case ST_ATTACHMENT_FRONT_RIGHT:
124         att = __DRI_BUFFER_FRONT_RIGHT;
125         break;
126      case ST_ATTACHMENT_BACK_RIGHT:
127         att = __DRI_BUFFER_BACK_RIGHT;
128         break;
129      case ST_ATTACHMENT_DEPTH_STENCIL:
130         att = __DRI_BUFFER_DEPTH_STENCIL;
131         break;
132      default:
133         att = -1;
134         break;
135      }
136
137      bpp = util_format_get_blocksizebits(format);
138
139      if (att >= 0) {
140         attachments[num_attachments++] = att;
141         if (with_format) {
142            attachments[num_attachments++] = bpp;
143         }
144      }
145   }
146
147   if (with_format) {
148      num_attachments /= 2;
149      buffers = loader->getBuffersWithFormat(dri_drawable,
150            &dri_drawable->w, &dri_drawable->h,
151            attachments, num_attachments,
152            &num_buffers, dri_drawable->loaderPrivate);
153   }
154   else {
155      buffers = loader->getBuffers(dri_drawable,
156            &dri_drawable->w, &dri_drawable->h,
157            attachments, num_attachments,
158            &num_buffers, dri_drawable->loaderPrivate);
159   }
160
161   if (buffers)
162      *count = num_buffers;
163
164   return buffers;
165}
166
167/**
168 * Process __DRIbuffer and convert them into pipe_resources.
169 */
170static void
171dri2_drawable_process_buffers(struct dri_drawable *drawable,
172                              __DRIbuffer *buffers, unsigned count)
173{
174   struct dri_screen *screen = dri_screen(drawable->sPriv);
175   __DRIdrawable *dri_drawable = drawable->dPriv;
176   struct pipe_resource templ;
177   struct winsys_handle whandle;
178   boolean have_depth = FALSE;
179   unsigned i, bind;
180
181   if (drawable->old_num == count &&
182       drawable->old_w == dri_drawable->w &&
183       drawable->old_h == dri_drawable->h &&
184       memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
185      return;
186
187   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
188      pipe_resource_reference(&drawable->textures[i], NULL);
189
190   memset(&templ, 0, sizeof(templ));
191   templ.target = screen->target;
192   templ.last_level = 0;
193   templ.width0 = dri_drawable->w;
194   templ.height0 = dri_drawable->h;
195   templ.depth0 = 1;
196   templ.array_size = 1;
197
198   memset(&whandle, 0, sizeof(whandle));
199
200   for (i = 0; i < count; i++) {
201      __DRIbuffer *buf = &buffers[i];
202      enum st_attachment_type statt;
203      enum pipe_format format;
204
205      switch (buf->attachment) {
206      case __DRI_BUFFER_FRONT_LEFT:
207         if (!screen->auto_fake_front) {
208            statt = ST_ATTACHMENT_INVALID;
209            break;
210         }
211         /* fallthrough */
212      case __DRI_BUFFER_FAKE_FRONT_LEFT:
213         statt = ST_ATTACHMENT_FRONT_LEFT;
214         break;
215      case __DRI_BUFFER_BACK_LEFT:
216         statt = ST_ATTACHMENT_BACK_LEFT;
217         break;
218      case __DRI_BUFFER_DEPTH:
219      case __DRI_BUFFER_DEPTH_STENCIL:
220      case __DRI_BUFFER_STENCIL:
221         /* use only the first depth/stencil buffer */
222         if (!have_depth) {
223            have_depth = TRUE;
224            statt = ST_ATTACHMENT_DEPTH_STENCIL;
225         }
226         else {
227            statt = ST_ATTACHMENT_INVALID;
228         }
229         break;
230      default:
231         statt = ST_ATTACHMENT_INVALID;
232         break;
233      }
234
235      dri_drawable_get_format(drawable, statt, &format, &bind);
236      if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
237         continue;
238
239      templ.format = format;
240      templ.bind = bind;
241      whandle.handle = buf->name;
242      whandle.stride = buf->pitch;
243
244      drawable->textures[statt] =
245         screen->base.screen->resource_from_handle(screen->base.screen,
246               &templ, &whandle);
247   }
248
249   drawable->old_num = count;
250   drawable->old_w = dri_drawable->w;
251   drawable->old_h = dri_drawable->h;
252   memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
253}
254
255static __DRIbuffer *
256dri2_allocate_buffer(__DRIscreen *sPriv,
257                     unsigned attachment, unsigned format,
258                     int width, int height)
259{
260   struct dri_screen *screen = dri_screen(sPriv);
261   struct dri2_buffer *buffer;
262   struct pipe_resource templ;
263   enum pipe_format pf;
264   unsigned bind = 0;
265   struct winsys_handle whandle;
266
267   switch (attachment) {
268      case __DRI_BUFFER_FRONT_LEFT:
269      case __DRI_BUFFER_FAKE_FRONT_LEFT:
270         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
271         break;
272      case __DRI_BUFFER_BACK_LEFT:
273         bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
274         break;
275      case __DRI_BUFFER_DEPTH:
276      case __DRI_BUFFER_DEPTH_STENCIL:
277      case __DRI_BUFFER_STENCIL:
278            bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
279         break;
280   }
281
282   switch (format) {
283      case 32:
284         pf = PIPE_FORMAT_B8G8R8X8_UNORM;
285         break;
286      case 16:
287         pf = PIPE_FORMAT_Z16_UNORM;
288         break;
289      default:
290         return NULL;
291   }
292
293   buffer = CALLOC_STRUCT(dri2_buffer);
294   if (!buffer)
295      return NULL;
296
297   memset(&templ, 0, sizeof(templ));
298   templ.bind = bind;
299   templ.format = pf;
300   templ.target = PIPE_TEXTURE_2D;
301   templ.last_level = 0;
302   templ.width0 = width;
303   templ.height0 = height;
304   templ.depth0 = 1;
305   templ.array_size = 1;
306
307   buffer->resource =
308      screen->base.screen->resource_create(screen->base.screen, &templ);
309   if (!buffer->resource) {
310      FREE(buffer);
311      return NULL;
312   }
313
314   memset(&whandle, 0, sizeof(whandle));
315   whandle.type = DRM_API_HANDLE_TYPE_SHARED;
316   screen->base.screen->resource_get_handle(screen->base.screen,
317         buffer->resource, &whandle);
318
319   buffer->base.attachment = attachment;
320   buffer->base.name = whandle.handle;
321   buffer->base.cpp = util_format_get_blocksize(pf);
322   buffer->base.pitch = whandle.stride;
323
324   return &buffer->base;
325}
326
327static void
328dri2_release_buffer(__DRIscreen *sPriv, __DRIbuffer *bPriv)
329{
330   struct dri2_buffer *buffer = dri2_buffer(bPriv);
331
332   pipe_resource_reference(&buffer->resource, NULL);
333   FREE(buffer);
334}
335
336/*
337 * Backend functions for st_framebuffer interface.
338 */
339
340static void
341dri2_allocate_textures(struct dri_drawable *drawable,
342                       const enum st_attachment_type *statts,
343                       unsigned count)
344{
345   __DRIbuffer *buffers;
346   unsigned num_buffers = count;
347
348   buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
349   if (buffers)
350      dri2_drawable_process_buffers(drawable, buffers, num_buffers);
351}
352
353static void
354dri2_flush_frontbuffer(struct dri_drawable *drawable,
355                       enum st_attachment_type statt)
356{
357   __DRIdrawable *dri_drawable = drawable->dPriv;
358   struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
359
360   if (loader->flushFrontBuffer == NULL)
361      return;
362
363   if (statt == ST_ATTACHMENT_FRONT_LEFT) {
364      loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
365   }
366}
367
368static void
369dri2_update_tex_buffer(struct dri_drawable *drawable,
370                       struct dri_context *ctx,
371                       struct pipe_resource *res)
372{
373   /* no-op */
374}
375
376static __DRIimage *
377dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
378{
379   __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
380   __DRIimage *img;
381
382   if (!loader->lookupEGLImage)
383      return NULL;
384
385   img = loader->lookupEGLImage(screen->sPriv,
386				handle, screen->sPriv->loaderPrivate);
387
388   return img;
389}
390
391static __DRIimage *
392dri2_create_image_from_name(__DRIscreen *_screen,
393                            int width, int height, int format,
394                            int name, int pitch, void *loaderPrivate)
395{
396   struct dri_screen *screen = dri_screen(_screen);
397   __DRIimage *img;
398   struct pipe_resource templ;
399   struct winsys_handle whandle;
400   unsigned tex_usage;
401   enum pipe_format pf;
402
403   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
404
405   switch (format) {
406   case __DRI_IMAGE_FORMAT_RGB565:
407      pf = PIPE_FORMAT_B5G6R5_UNORM;
408      break;
409   case __DRI_IMAGE_FORMAT_XRGB8888:
410      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
411      break;
412   case __DRI_IMAGE_FORMAT_ARGB8888:
413      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
414      break;
415   case __DRI_IMAGE_FORMAT_ABGR8888:
416      pf = PIPE_FORMAT_R8G8B8A8_UNORM;
417      break;
418   default:
419      pf = PIPE_FORMAT_NONE;
420      break;
421   }
422   if (pf == PIPE_FORMAT_NONE)
423      return NULL;
424
425   img = CALLOC_STRUCT(__DRIimageRec);
426   if (!img)
427      return NULL;
428
429   memset(&templ, 0, sizeof(templ));
430   templ.bind = tex_usage;
431   templ.format = pf;
432   templ.target = screen->target;
433   templ.last_level = 0;
434   templ.width0 = width;
435   templ.height0 = height;
436   templ.depth0 = 1;
437   templ.array_size = 1;
438
439   memset(&whandle, 0, sizeof(whandle));
440   whandle.handle = name;
441   whandle.stride = pitch * util_format_get_blocksize(pf);
442
443   img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
444         &templ, &whandle);
445   if (!img->texture) {
446      FREE(img);
447      return NULL;
448   }
449
450   img->level = 0;
451   img->layer = 0;
452   img->loader_private = loaderPrivate;
453
454   return img;
455}
456
457static __DRIimage *
458dri2_create_image_from_renderbuffer(__DRIcontext *context,
459				    int renderbuffer, void *loaderPrivate)
460{
461   struct dri_context *ctx = dri_context(context);
462
463   if (!ctx->st->get_resource_for_egl_image)
464      return NULL;
465
466   /* TODO */
467   return NULL;
468}
469
470static __DRIimage *
471dri2_create_image(__DRIscreen *_screen,
472                   int width, int height, int format,
473                   unsigned int use, void *loaderPrivate)
474{
475   struct dri_screen *screen = dri_screen(_screen);
476   __DRIimage *img;
477   struct pipe_resource templ;
478   unsigned tex_usage;
479   enum pipe_format pf;
480
481   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
482   if (use & __DRI_IMAGE_USE_SCANOUT)
483      tex_usage |= PIPE_BIND_SCANOUT;
484   if (use & __DRI_IMAGE_USE_SHARE)
485      tex_usage |= PIPE_BIND_SHARED;
486   if (use & __DRI_IMAGE_USE_CURSOR) {
487      if (width != 64 || height != 64)
488         return NULL;
489      tex_usage |= PIPE_BIND_CURSOR;
490   }
491
492   switch (format) {
493   case __DRI_IMAGE_FORMAT_RGB565:
494      pf = PIPE_FORMAT_B5G6R5_UNORM;
495      break;
496   case __DRI_IMAGE_FORMAT_XRGB8888:
497      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
498      break;
499   case __DRI_IMAGE_FORMAT_ARGB8888:
500      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
501      break;
502   case __DRI_IMAGE_FORMAT_ABGR8888:
503      pf = PIPE_FORMAT_R8G8B8A8_UNORM;
504      break;
505   default:
506      pf = PIPE_FORMAT_NONE;
507      break;
508   }
509   if (pf == PIPE_FORMAT_NONE)
510      return NULL;
511
512   img = CALLOC_STRUCT(__DRIimageRec);
513   if (!img)
514      return NULL;
515
516   memset(&templ, 0, sizeof(templ));
517   templ.bind = tex_usage;
518   templ.format = pf;
519   templ.target = PIPE_TEXTURE_2D;
520   templ.last_level = 0;
521   templ.width0 = width;
522   templ.height0 = height;
523   templ.depth0 = 1;
524   templ.array_size = 1;
525
526   img->texture = screen->base.screen->resource_create(screen->base.screen, &templ);
527   if (!img->texture) {
528      FREE(img);
529      return NULL;
530   }
531
532   img->level = 0;
533   img->layer = 0;
534
535   img->loader_private = loaderPrivate;
536   return img;
537}
538
539static GLboolean
540dri2_query_image(__DRIimage *image, int attrib, int *value)
541{
542   struct winsys_handle whandle;
543   memset(&whandle, 0, sizeof(whandle));
544
545   switch (attrib) {
546   case __DRI_IMAGE_ATTRIB_STRIDE:
547      image->texture->screen->resource_get_handle(image->texture->screen,
548            image->texture, &whandle);
549      *value = whandle.stride;
550      return GL_TRUE;
551   case __DRI_IMAGE_ATTRIB_HANDLE:
552      whandle.type = DRM_API_HANDLE_TYPE_KMS;
553      image->texture->screen->resource_get_handle(image->texture->screen,
554         image->texture, &whandle);
555      *value = whandle.handle;
556      return GL_TRUE;
557   case __DRI_IMAGE_ATTRIB_NAME:
558      whandle.type = DRM_API_HANDLE_TYPE_SHARED;
559      image->texture->screen->resource_get_handle(image->texture->screen,
560         image->texture, &whandle);
561      *value = whandle.handle;
562      return GL_TRUE;
563   default:
564      return GL_FALSE;
565   }
566}
567
568static __DRIimage *
569dri2_dup_image(__DRIimage *image, void *loaderPrivate)
570{
571   __DRIimage *img;
572
573   img = CALLOC_STRUCT(__DRIimageRec);
574   if (!img)
575      return NULL;
576
577   img->texture = NULL;
578   pipe_resource_reference(&img->texture, image->texture);
579   img->level = image->level;
580   img->layer = image->layer;
581   img->loader_private = loaderPrivate;
582
583   return img;
584}
585
586static void
587dri2_destroy_image(__DRIimage *img)
588{
589   pipe_resource_reference(&img->texture, NULL);
590   FREE(img);
591}
592
593static struct __DRIimageExtensionRec dri2ImageExtension = {
594    { __DRI_IMAGE, __DRI_IMAGE_VERSION },
595    dri2_create_image_from_name,
596    dri2_create_image_from_renderbuffer,
597    dri2_destroy_image,
598    dri2_create_image,
599    dri2_query_image,
600    dri2_dup_image,
601};
602
603/*
604 * Backend function init_screen.
605 */
606
607static const __DRIextension *dri_screen_extensions[] = {
608   &driTexBufferExtension.base,
609   &dri2FlushExtension.base,
610   &dri2ImageExtension.base,
611   &dri2ConfigQueryExtension.base,
612   NULL
613};
614
615static const __DRIextension *dri_screen_extensions_throttle[] = {
616   &driTexBufferExtension.base,
617   &dri2FlushExtension.base,
618   &dri2ImageExtension.base,
619   &dri2ConfigQueryExtension.base,
620   &dri2ThrottleExtension.base,
621   NULL
622};
623
624/**
625 * This is the driver specific part of the createNewScreen entry point.
626 *
627 * Returns the struct gl_config supported by this driver.
628 */
629static const __DRIconfig **
630dri2_init_screen(__DRIscreen * sPriv)
631{
632   const __DRIconfig **configs;
633   struct dri_screen *screen;
634   struct pipe_screen *pscreen;
635   const struct drm_conf_ret *throttle_ret = NULL;
636
637   screen = CALLOC_STRUCT(dri_screen);
638   if (!screen)
639      return NULL;
640
641   screen->sPriv = sPriv;
642   screen->fd = sPriv->fd;
643
644   sPriv->driverPrivate = (void *)screen;
645
646   pscreen = driver_descriptor.create_screen(screen->fd);
647   if (driver_descriptor.configuration)
648      throttle_ret = driver_descriptor.configuration(DRM_CONF_THROTTLE);
649
650   if (throttle_ret && throttle_ret->val.val_int != -1) {
651      sPriv->extensions = dri_screen_extensions_throttle;
652      screen->default_throttle_frames = throttle_ret->val.val_int;
653   } else
654      sPriv->extensions = dri_screen_extensions;
655
656   /* dri_init_screen_helper checks pscreen for us */
657
658   configs = dri_init_screen_helper(screen, pscreen, 32);
659   if (!configs)
660      goto fail;
661
662   sPriv->api_mask = 0;
663   if (screen->st_api->profile_mask & ST_PROFILE_DEFAULT_MASK)
664      sPriv->api_mask |= 1 << __DRI_API_OPENGL;
665   if (screen->st_api->profile_mask & ST_PROFILE_OPENGL_ES1_MASK)
666      sPriv->api_mask |= 1 << __DRI_API_GLES;
667   if (screen->st_api->profile_mask & ST_PROFILE_OPENGL_ES2_MASK)
668      sPriv->api_mask |= 1 << __DRI_API_GLES2;
669
670   screen->auto_fake_front = dri_with_format(sPriv);
671   screen->broken_invalidate = !sPriv->dri2.useInvalidate;
672   screen->lookup_egl_image = dri2_lookup_egl_image;
673
674   return configs;
675fail:
676   dri_destroy_screen_helper(screen);
677   FREE(screen);
678   return NULL;
679}
680
681static boolean
682dri2_create_buffer(__DRIscreen * sPriv,
683                   __DRIdrawable * dPriv,
684                   const struct gl_config * visual, boolean isPixmap)
685{
686   struct dri_drawable *drawable = NULL;
687
688   if (!dri_create_buffer(sPriv, dPriv, visual, isPixmap))
689      return FALSE;
690
691   drawable = dPriv->driverPrivate;
692
693   drawable->allocate_textures = dri2_allocate_textures;
694   drawable->flush_frontbuffer = dri2_flush_frontbuffer;
695   drawable->update_tex_buffer = dri2_update_tex_buffer;
696
697   return TRUE;
698}
699
700/**
701 * DRI driver virtual function table.
702 *
703 * DRI versions differ in their implementation of init_screen and swap_buffers.
704 */
705const struct __DriverAPIRec driDriverAPI = {
706   .InitScreen = dri2_init_screen,
707   .DestroyScreen = dri_destroy_screen,
708   .CreateContext = dri_create_context,
709   .DestroyContext = dri_destroy_context,
710   .CreateBuffer = dri2_create_buffer,
711   .DestroyBuffer = dri_destroy_buffer,
712   .MakeCurrent = dri_make_current,
713   .UnbindContext = dri_unbind_context,
714
715   .AllocateBuffer = dri2_allocate_buffer,
716   .ReleaseBuffer  = dri2_release_buffer,
717};
718
719/* This is the table of extensions that the loader will dlsym() for. */
720PUBLIC const __DRIextension *__driDriverExtensions[] = {
721    &driCoreExtension.base,
722    &driDRI2Extension.base,
723    NULL
724};
725
726/* vim: set sw=3 ts=8 sts=3 expandtab: */
727