swrast.c revision c1d4644f487a3ff4dcb3ef32995fed30cd72eeba
1/*
2 * Copyright (C) 2008 George Sapountzis <gsap7@yahoo.gr>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22#include <GL/gl.h>
23#include <GL/internal/dri_interface.h>
24#include "context.h"
25#include "extensions.h"
26#include "framebuffer.h"
27#include "imports.h"
28#include "renderbuffer.h"
29#include "swrast/swrast.h"
30#include "swrast_setup/swrast_setup.h"
31#include "tnl/tnl.h"
32#include "tnl/t_context.h"
33#include "tnl/t_pipeline.h"
34#include "vbo/vbo.h"
35#include "drivers/common/driverfuncs.h"
36
37#include "swrast_priv.h"
38
39
40#define need_GL_VERSION_1_3
41#define need_GL_VERSION_1_4
42#define need_GL_VERSION_1_5
43#define need_GL_VERSION_2_0
44
45/* sw extensions for imaging */
46#define need_GL_EXT_blend_color
47#define need_GL_EXT_blend_minmax
48#define need_GL_EXT_convolution
49#define need_GL_EXT_histogram
50#define need_GL_SGI_color_table
51
52/* sw extensions not associated with some GL version */
53#define need_GL_ARB_shader_objects
54#define need_GL_ARB_vertex_program
55#define need_GL_APPLE_vertex_array_object
56#define need_GL_ATI_fragment_shader
57#define need_GL_EXT_depth_bounds_test
58#define need_GL_EXT_framebuffer_object
59#define need_GL_EXT_framebuffer_blit
60#define need_GL_EXT_gpu_program_parameters
61#define need_GL_EXT_paletted_texture
62#define need_GL_IBM_multimode_draw_arrays
63#define need_GL_MESA_resize_buffers
64#define need_GL_NV_vertex_program
65#define need_GL_NV_fragment_program
66
67#include "extension_helper.h"
68#include "utils.h"
69
70const struct dri_extension card_extensions[] =
71{
72    { "GL_VERSION_1_3",			GL_VERSION_1_3_functions },
73    { "GL_VERSION_1_4",			GL_VERSION_1_4_functions },
74    { "GL_VERSION_1_5",			GL_VERSION_1_5_functions },
75    { "GL_VERSION_2_0",			GL_VERSION_2_0_functions },
76
77    { "GL_EXT_blend_color",		GL_EXT_blend_color_functions },
78    { "GL_EXT_blend_minmax",		GL_EXT_blend_minmax_functions },
79    { "GL_EXT_convolution",		GL_EXT_convolution_functions },
80    { "GL_EXT_histogram",		GL_EXT_histogram_functions },
81    { "GL_SGI_color_table",		GL_SGI_color_table_functions },
82
83    { "GL_ARB_shader_objects",		GL_ARB_shader_objects_functions },
84    { "GL_ARB_vertex_program",		GL_ARB_vertex_program_functions },
85    { "GL_APPLE_vertex_array_object",	GL_APPLE_vertex_array_object_functions },
86    { "GL_ATI_fragment_shader",		GL_ATI_fragment_shader_functions },
87    { "GL_EXT_depth_bounds_test",	GL_EXT_depth_bounds_test_functions },
88    { "GL_EXT_framebuffer_object",	GL_EXT_framebuffer_object_functions },
89    { "GL_EXT_framebuffer_blit",	GL_EXT_framebuffer_blit_functions },
90    { "GL_EXT_gpu_program_parameters",	GL_EXT_gpu_program_parameters_functions },
91    { "GL_EXT_paletted_texture",	GL_EXT_paletted_texture_functions },
92    { "GL_IBM_multimode_draw_arrays",	GL_IBM_multimode_draw_arrays_functions },
93    { "GL_MESA_resize_buffers",		GL_MESA_resize_buffers_functions },
94    { "GL_NV_vertex_program",		GL_NV_vertex_program_functions },
95    { "GL_NV_fragment_program",		GL_NV_fragment_program_functions },
96    { NULL,				NULL }
97};
98
99static void
100setupLoaderExtensions(__DRIscreen *psp,
101		      const __DRIextension **extensions)
102{
103    int i;
104
105    for (i = 0; extensions[i]; i++) {
106	if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0)
107	    psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i];
108    }
109}
110
111static __DRIconfig **
112swrastFillInModes(__DRIscreen *psp,
113		  unsigned pixel_bits, unsigned depth_bits,
114		  unsigned stencil_bits, GLboolean have_back_buffer)
115{
116    __DRIconfig **configs;
117    unsigned depth_buffer_factor;
118    unsigned back_buffer_factor;
119    GLenum fb_format;
120    GLenum fb_type;
121
122    /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
123     * support pageflipping at all.
124     */
125    static const GLenum back_buffer_modes[] = {
126	GLX_NONE, GLX_SWAP_UNDEFINED_OML
127    };
128
129    u_int8_t depth_bits_array[4];
130    u_int8_t stencil_bits_array[4];
131
132    depth_bits_array[0] = 0;
133    depth_bits_array[1] = 0;
134    depth_bits_array[2] = depth_bits;
135    depth_bits_array[3] = depth_bits;
136
137    /* Just like with the accumulation buffer, always provide some modes
138     * with a stencil buffer.
139     */
140    stencil_bits_array[0] = 0;
141    stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
142    stencil_bits_array[2] = 0;
143    stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
144
145    depth_buffer_factor = 4;
146    back_buffer_factor = 2;
147
148    if (pixel_bits == 8) {
149	fb_format = GL_RGB;
150	fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
151    }
152    else if (pixel_bits == 16) {
153	fb_format = GL_RGB;
154	fb_type = GL_UNSIGNED_SHORT_5_6_5;
155    }
156    else {
157	fb_format = GL_BGRA;
158	fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
159    }
160
161    configs = driCreateConfigs(fb_format, fb_type,
162			       depth_bits_array, stencil_bits_array,
163			       depth_buffer_factor, back_buffer_modes,
164			       back_buffer_factor);
165    if (configs == NULL) {
166	fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__,
167		__LINE__);
168	return NULL;
169    }
170
171    return configs;
172}
173
174static __DRIscreen *
175driCreateNewScreen(int scrn, const __DRIextension **extensions,
176		   const __DRIconfig ***driver_configs, void *data)
177{
178    static const __DRIextension *emptyExtensionList[] = { NULL };
179    __DRIscreen *psp;
180    __DRIconfig **configs8, **configs16, **configs32;
181
182    (void) data;
183
184    TRACE;
185
186    psp = _mesa_calloc(sizeof(*psp));
187    if (!psp)
188	return NULL;
189
190    setupLoaderExtensions(psp, extensions);
191
192    psp->num = scrn;
193    psp->extensions = emptyExtensionList;
194
195    configs8  = swrastFillInModes(psp,  8,  8, 0, 1);
196    configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
197    configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
198
199    configs16 = (__DRIconfig **)driConcatConfigs(configs8, configs16);
200
201    *driver_configs = driConcatConfigs(configs16, configs32);
202
203    driInitExtensions( NULL, card_extensions, GL_FALSE );
204
205    return psp;
206}
207
208static void driDestroyScreen(__DRIscreen *psp)
209{
210    TRACE;
211
212    if (psp) {
213	_mesa_free(psp);
214    }
215}
216
217static const __DRIextension **driGetExtensions(__DRIscreen *psp)
218{
219    TRACE;
220
221    return psp->extensions;
222}
223
224
225/**
226 * swrast_buffer.c
227 */
228
229static GLuint
230choose_pixel_format(const GLvisual *v)
231{
232    if (v->rgbMode) {
233	/* XXX 24bpp packed, 8bpp, xmesa gets bitsPerPixel from xserver */
234	int bpp = v->rgbBits;
235	if (bpp == 24)
236	    bpp = 32;
237
238	if (bpp == 32
239	    && v->redMask   == 0xff0000
240	    && v->greenMask == 0x00ff00
241	    && v->blueMask  == 0x0000ff)
242	    return PF_A8R8G8B8;
243	else if (bpp == 16
244	    && v->redMask   == 0xf800
245	    && v->greenMask == 0x07e0
246	    && v->blueMask  == 0x001f)
247	    return PF_R5G6B5;
248	else if (bpp == 8
249	    && v->redMask   == 0x07
250	    && v->greenMask == 0x38
251	    && v->blueMask  == 0xc0)
252	    return PF_R3G3B2;
253    }
254    else {
255	if (v->indexBits == 8)
256	    return PF_CI8;
257    }
258
259    _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
260    return 0;
261}
262
263static void
264swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
265{
266    TRACE;
267
268    _mesa_free(rb->Data);
269    _mesa_free(rb);
270}
271
272static GLboolean
273swrast_alloc_front_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
274			   GLenum internalFormat, GLuint width, GLuint height)
275{
276    struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
277    int bpp;
278
279    TRACE;
280
281    rb->Data = NULL;
282    rb->Width = width;
283    rb->Height = height;
284
285    switch (internalFormat) {
286    case GL_RGB:
287	bpp = rb->RedBits + rb->GreenBits + rb->BlueBits;
288	break;
289    case GL_RGBA:
290	bpp = rb->RedBits + rb->GreenBits + rb->BlueBits + rb->AlphaBits;
291	break;
292    case GL_COLOR_INDEX8_EXT:
293	bpp = rb->IndexBits;
294	break;
295    default:
296	_mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
297	return GL_FALSE;
298    }
299
300    /* always pad to 32 bits */
301    xrb->pitch = ((width * bpp + 0x1f) & ~0x1f) / 8;
302
303    return GL_TRUE;
304}
305
306static GLboolean
307swrast_alloc_back_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
308			GLenum internalFormat, GLuint width, GLuint height)
309{
310    struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
311
312    TRACE;
313
314    _mesa_free(rb->Data);
315
316    (void) swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
317
318    rb->Data = _mesa_malloc(height * xrb->pitch);
319
320    return GL_TRUE;
321}
322
323static struct swrast_renderbuffer *
324swrast_new_renderbuffer(const GLvisual *visual, GLboolean front)
325{
326    struct swrast_renderbuffer *xrb = _mesa_calloc(sizeof *xrb);
327    GLuint pixel_format;
328
329    TRACE;
330
331    if (xrb) {
332	_mesa_init_renderbuffer(&xrb->Base, 0);
333
334	pixel_format = choose_pixel_format(visual);
335
336	xrb->Base.Delete = swrast_delete_renderbuffer;
337	if (front) {
338	    xrb->Base.AllocStorage = swrast_alloc_front_storage;
339	    swrast_set_span_funcs_pixmap(xrb, pixel_format);
340	}
341	else {
342	    xrb->Base.AllocStorage = swrast_alloc_back_storage;
343	    swrast_set_span_funcs_ximage(xrb, pixel_format);
344	}
345
346	switch (pixel_format) {
347	case PF_A8R8G8B8:
348	    xrb->Base.InternalFormat = GL_RGBA;
349	    xrb->Base._BaseFormat = GL_RGBA;
350	    xrb->Base.DataType = GL_UNSIGNED_BYTE;
351	    xrb->Base.RedBits   = 8 * sizeof(GLubyte);
352	    xrb->Base.GreenBits = 8 * sizeof(GLubyte);
353	    xrb->Base.BlueBits  = 8 * sizeof(GLubyte);
354	    xrb->Base.AlphaBits = 8 * sizeof(GLubyte);
355	    break;
356	case PF_R5G6B5:
357	    xrb->Base.InternalFormat = GL_RGB;
358	    xrb->Base._BaseFormat = GL_RGB;
359	    xrb->Base.DataType = GL_UNSIGNED_BYTE;
360	    xrb->Base.RedBits   = 5 * sizeof(GLubyte);
361	    xrb->Base.GreenBits = 6 * sizeof(GLubyte);
362	    xrb->Base.BlueBits  = 5 * sizeof(GLubyte);
363	    xrb->Base.AlphaBits = 0;
364	    break;
365	case PF_R3G3B2:
366	    xrb->Base.InternalFormat = GL_RGB;
367	    xrb->Base._BaseFormat = GL_RGB;
368	    xrb->Base.DataType = GL_UNSIGNED_BYTE;
369	    xrb->Base.RedBits   = 3 * sizeof(GLubyte);
370	    xrb->Base.GreenBits = 3 * sizeof(GLubyte);
371	    xrb->Base.BlueBits  = 2 * sizeof(GLubyte);
372	    xrb->Base.AlphaBits = 0;
373	    break;
374	case PF_CI8:
375	    xrb->Base.InternalFormat = GL_COLOR_INDEX8_EXT;
376	    xrb->Base._BaseFormat = GL_COLOR_INDEX;
377	    xrb->Base.DataType = GL_UNSIGNED_BYTE;
378	    xrb->Base.IndexBits = 8 * sizeof(GLubyte);
379	    break;
380	default:
381	    return NULL;
382	}
383    }
384    return xrb;
385}
386
387static __DRIdrawable *
388driCreateNewDrawable(__DRIscreen *screen,
389		     const __DRIconfig *config, void *data)
390{
391    __DRIdrawable *buf;
392    struct swrast_renderbuffer *frontrb, *backrb;
393
394    TRACE;
395
396    buf = _mesa_calloc(sizeof *buf);
397    if (!buf)
398	return NULL;
399
400    buf->loaderPrivate = data;
401
402    buf->driScreenPriv = screen;
403
404    buf->row = _mesa_malloc(MAX_WIDTH * 4);
405
406    /* basic framebuffer setup */
407    _mesa_initialize_framebuffer(&buf->Base, &config->modes);
408
409    /* add front renderbuffer */
410    frontrb = swrast_new_renderbuffer(&config->modes, GL_TRUE);
411    _mesa_add_renderbuffer(&buf->Base, BUFFER_FRONT_LEFT, &frontrb->Base);
412
413    /* add back renderbuffer */
414    if (config->modes.doubleBufferMode) {
415	backrb = swrast_new_renderbuffer(&config->modes, GL_FALSE);
416	_mesa_add_renderbuffer(&buf->Base, BUFFER_BACK_LEFT, &backrb->Base);
417    }
418
419    /* add software renderbuffers */
420    _mesa_add_soft_renderbuffers(&buf->Base,
421				 GL_FALSE, /* color */
422				 config->modes.haveDepthBuffer,
423				 config->modes.haveStencilBuffer,
424				 config->modes.haveAccumBuffer,
425				 GL_FALSE, /* alpha */
426				 GL_FALSE /* aux bufs */);
427
428    return buf;
429}
430
431static void
432driDestroyDrawable(__DRIdrawable *buf)
433{
434    TRACE;
435
436    if (buf) {
437	struct gl_framebuffer *fb = &buf->Base;
438
439	_mesa_free(buf->row);
440
441	fb->DeletePending = GL_TRUE;
442	_mesa_unreference_framebuffer(&fb);
443    }
444}
445
446static void driSwapBuffers(__DRIdrawable *buf)
447{
448    GET_CURRENT_CONTEXT(ctx);
449
450    struct swrast_renderbuffer *frontrb =
451	swrast_renderbuffer(buf->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
452    struct swrast_renderbuffer *backrb =
453	swrast_renderbuffer(buf->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
454
455    __DRIscreen *screen = buf->driScreenPriv;
456
457    TRACE;
458
459    /* check for signle-buffered */
460    if (backrb == NULL)
461	return;
462
463    /* check if swapping currently bound buffer */
464    if (ctx && ctx->DrawBuffer == &(buf->Base)) {
465	/* flush pending rendering */
466	_mesa_notifySwapBuffers(ctx);
467    }
468
469    screen->swrast_loader->putImage(buf, __DRI_SWRAST_IMAGE_OP_SWAP,
470				    0, 0,
471				    frontrb->Base.Width,
472				    frontrb->Base.Height,
473				    backrb->Base.Data,
474				    buf->loaderPrivate);
475}
476
477
478/**
479 * swrast_dd.c
480 */
481
482static void
483get_window_size( GLframebuffer *fb, GLsizei *w, GLsizei *h )
484{
485    __DRIdrawable *buf = swrast_drawable(fb);
486    __DRIscreen *screen = buf->driScreenPriv;
487    int x, y;
488
489    screen->swrast_loader->getDrawableInfo(buf,
490					   &x, &y, w, h,
491					   buf->loaderPrivate);
492}
493
494static void
495swrast_check_and_update_window_size( GLcontext *ctx, GLframebuffer *fb )
496{
497    GLsizei width, height;
498
499    get_window_size(fb, &width, &height);
500    if (fb->Width != width || fb->Height != height) {
501	_mesa_resize_framebuffer(ctx, fb, width, height);
502    }
503}
504
505static const GLubyte *
506get_string(GLcontext *ctx, GLenum pname)
507{
508    (void) ctx;
509    switch (pname) {
510	case GL_VENDOR:
511	    return (const GLubyte *) "Mesa Project";
512	case GL_RENDERER:
513	    return (const GLubyte *) "X.Org";
514	default:
515	    return NULL;
516    }
517}
518
519static void
520update_state( GLcontext *ctx, GLuint new_state )
521{
522    /* not much to do here - pass it on */
523    _swrast_InvalidateState( ctx, new_state );
524    _swsetup_InvalidateState( ctx, new_state );
525    _vbo_InvalidateState( ctx, new_state );
526    _tnl_InvalidateState( ctx, new_state );
527}
528
529static void
530viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
531{
532    GLframebuffer *draw = ctx->WinSysDrawBuffer;
533    GLframebuffer *read = ctx->WinSysReadBuffer;
534
535    swrast_check_and_update_window_size(ctx, draw);
536    swrast_check_and_update_window_size(ctx, read);
537}
538
539static void
540swrast_init_driver_functions(struct dd_function_table *driver)
541{
542    driver->GetString = get_string;
543    driver->UpdateState = update_state;
544    driver->GetBufferSize = NULL;
545    driver->Viewport = viewport;
546}
547
548
549/**
550 * swrast_context.c
551 */
552
553static __DRIcontext *
554driCreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
555		    __DRIcontext *shared, void *data)
556{
557    __DRIcontext *ctx;
558    GLcontext *mesaCtx;
559    struct dd_function_table functions;
560
561    TRACE;
562
563    ctx = _mesa_calloc(sizeof *ctx);
564    if (!ctx)
565	return NULL;
566
567    ctx->loaderPrivate = data;
568
569    ctx->driScreenPriv = screen;
570
571    /* build table of device driver functions */
572    _mesa_init_driver_functions(&functions);
573    swrast_init_driver_functions(&functions);
574
575    if (!_mesa_initialize_context(&ctx->Base, &config->modes,
576				  shared ? &shared->Base : NULL,
577				  &functions, (void *) ctx)) {
578      _mesa_free(ctx);
579      return NULL;
580    }
581
582    mesaCtx = &ctx->Base;
583
584    /* do bounds checking to prevent segfaults and server crashes! */
585    mesaCtx->Const.CheckArrayBounds = GL_TRUE;
586
587    /* create module contexts */
588    _swrast_CreateContext( mesaCtx );
589    _vbo_CreateContext( mesaCtx );
590    _tnl_CreateContext( mesaCtx );
591    _swsetup_CreateContext( mesaCtx );
592    _swsetup_Wakeup( mesaCtx );
593
594    /* use default TCL pipeline */
595    {
596       TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
597       tnl->Driver.RunPipeline = _tnl_run_pipeline;
598    }
599
600    _mesa_enable_sw_extensions(mesaCtx);
601    _mesa_enable_1_3_extensions(mesaCtx);
602    _mesa_enable_1_4_extensions(mesaCtx);
603    _mesa_enable_1_5_extensions(mesaCtx);
604    _mesa_enable_2_0_extensions(mesaCtx);
605    _mesa_enable_2_1_extensions(mesaCtx);
606
607    return ctx;
608}
609
610static void
611driDestroyContext(__DRIcontext *ctx)
612{
613    GLcontext *mesaCtx;
614    TRACE;
615
616    if (ctx) {
617	mesaCtx = &ctx->Base;
618	_swsetup_DestroyContext( mesaCtx );
619	_swrast_DestroyContext( mesaCtx );
620	_tnl_DestroyContext( mesaCtx );
621	_vbo_DestroyContext( mesaCtx );
622	_mesa_destroy_context( mesaCtx );
623    }
624}
625
626static int
627driCopyContext(__DRIcontext *dst, __DRIcontext *src, unsigned long mask)
628{
629    TRACE;
630
631    _mesa_copy_context(&src->Base, &dst->Base, mask);
632    return GL_TRUE;
633}
634
635static int driBindContext(__DRIcontext *ctx,
636			  __DRIdrawable *draw,
637			  __DRIdrawable *read)
638{
639    GLcontext *mesaCtx;
640    GLframebuffer *mesaDraw;
641    GLframebuffer *mesaRead;
642    TRACE;
643
644    if (ctx) {
645	if (!draw || !read)
646	    return GL_FALSE;
647
648	/* check for same context and buffer */
649	mesaCtx = &ctx->Base;
650	mesaDraw = &draw->Base;
651	mesaRead = &read->Base;
652	if (mesaCtx == _mesa_get_current_context()
653	    && mesaCtx->DrawBuffer == mesaDraw
654	    && mesaCtx->ReadBuffer == mesaRead) {
655	    return GL_TRUE;
656	}
657
658	_glapi_check_multithread();
659
660	swrast_check_and_update_window_size(mesaCtx, mesaDraw);
661	if (read != draw)
662	    swrast_check_and_update_window_size(mesaCtx, mesaRead);
663
664	_mesa_make_current( mesaCtx,
665			    mesaDraw,
666			    mesaRead );
667    }
668    else {
669	/* unbind */
670	_mesa_make_current( NULL, NULL, NULL );
671    }
672
673    return GL_TRUE;
674}
675
676static int driUnbindContext(__DRIcontext *ctx)
677{
678    TRACE;
679    (void) ctx;
680    _mesa_make_current(NULL, NULL, NULL);
681    return GL_TRUE;
682}
683
684
685static const __DRIcoreExtension driCoreExtension = {
686    { __DRI_CORE, __DRI_CORE_VERSION },
687    NULL,
688    driDestroyScreen,
689    driGetExtensions,
690    driGetConfigAttrib,
691    driIndexConfigAttrib,
692    NULL,
693    driDestroyDrawable,
694    driSwapBuffers,
695    driCreateNewContext,
696    driCopyContext,
697    driDestroyContext,
698    driBindContext,
699    driUnbindContext
700};
701
702static const __DRIswrastExtension driSWRastExtension = {
703    { __DRI_SWRAST, __DRI_SWRAST_VERSION },
704    driCreateNewScreen,
705    driCreateNewDrawable,
706};
707
708/* This is the table of extensions that the loader will dlsym() for. */
709PUBLIC const __DRIextension *__driDriverExtensions[] = {
710    &driCoreExtension.base,
711    &driSWRastExtension.base,
712    NULL
713};
714