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