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