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