swrast.c revision e60693efda7826bf26ffb9993c6dfba3b8c8a812
1/* 2 * Copyright 2008, 2010 George Sapountzis <gsapountzis@gmail.com> 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/* 23 * DRI software rasterizer 24 * 25 * This is the mesa swrast module packaged into a DRI driver structure. 26 * 27 * The front-buffer is allocated by the loader. The loader provides read/write 28 * callbacks for access to the front-buffer. The driver uses a scratch row for 29 * front-buffer rendering to avoid repeated calls to the loader. 30 * 31 * The back-buffer is allocated by the driver and is private. 32 */ 33 34#include "main/context.h" 35#include "main/extensions.h" 36#include "main/formats.h" 37#include "main/framebuffer.h" 38#include "main/imports.h" 39#include "main/renderbuffer.h" 40#include "swrast/swrast.h" 41#include "swrast_setup/swrast_setup.h" 42#include "tnl/tnl.h" 43#include "tnl/t_context.h" 44#include "tnl/t_pipeline.h" 45#include "vbo/vbo.h" 46#include "drivers/common/driverfuncs.h" 47#include "drivers/common/meta.h" 48#include "utils.h" 49 50#include "swrast_priv.h" 51 52 53/** 54 * Screen and config-related functions 55 */ 56 57static const __DRIextension *dri_screen_extensions[] = { 58 NULL 59}; 60 61static __DRIconfig ** 62swrastFillInModes(__DRIscreen *psp, 63 unsigned pixel_bits, unsigned depth_bits, 64 unsigned stencil_bits, GLboolean have_back_buffer) 65{ 66 __DRIconfig **configs; 67 unsigned depth_buffer_factor; 68 unsigned back_buffer_factor; 69 GLenum fb_format; 70 GLenum fb_type; 71 72 /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't 73 * support pageflipping at all. 74 */ 75 static const GLenum back_buffer_modes[] = { 76 GLX_NONE, GLX_SWAP_UNDEFINED_OML 77 }; 78 79 uint8_t depth_bits_array[4]; 80 uint8_t stencil_bits_array[4]; 81 uint8_t msaa_samples_array[1]; 82 83 depth_bits_array[0] = 0; 84 depth_bits_array[1] = 0; 85 depth_bits_array[2] = depth_bits; 86 depth_bits_array[3] = depth_bits; 87 88 /* Just like with the accumulation buffer, always provide some modes 89 * with a stencil buffer. 90 */ 91 stencil_bits_array[0] = 0; 92 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits; 93 stencil_bits_array[2] = 0; 94 stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits; 95 96 msaa_samples_array[0] = 0; 97 98 depth_buffer_factor = 4; 99 back_buffer_factor = 2; 100 101 switch (pixel_bits) { 102 case 8: 103 fb_format = GL_RGB; 104 fb_type = GL_UNSIGNED_BYTE_2_3_3_REV; 105 break; 106 case 16: 107 fb_format = GL_RGB; 108 fb_type = GL_UNSIGNED_SHORT_5_6_5; 109 break; 110 case 24: 111 fb_format = GL_BGR; 112 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV; 113 break; 114 case 32: 115 fb_format = GL_BGRA; 116 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV; 117 break; 118 default: 119 fprintf(stderr, "[%s:%u] bad depth %d\n", __func__, __LINE__, 120 pixel_bits); 121 return NULL; 122 } 123 124 configs = driCreateConfigs(fb_format, fb_type, 125 depth_bits_array, stencil_bits_array, 126 depth_buffer_factor, back_buffer_modes, 127 back_buffer_factor, msaa_samples_array, 1, 128 GL_TRUE); 129 if (configs == NULL) { 130 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, 131 __LINE__); 132 return NULL; 133 } 134 135 return configs; 136} 137 138static const __DRIconfig ** 139dri_init_screen(__DRIscreen * psp) 140{ 141 __DRIconfig **configs8, **configs16, **configs24, **configs32; 142 143 TRACE; 144 145 psp->extensions = dri_screen_extensions; 146 147 configs8 = swrastFillInModes(psp, 8, 8, 0, 1); 148 configs16 = swrastFillInModes(psp, 16, 16, 0, 1); 149 configs24 = swrastFillInModes(psp, 24, 24, 8, 1); 150 configs32 = swrastFillInModes(psp, 32, 24, 8, 1); 151 152 configs16 = driConcatConfigs(configs8, configs16); 153 configs24 = driConcatConfigs(configs16, configs24); 154 configs32 = driConcatConfigs(configs24, configs32); 155 156 return (const __DRIconfig **)configs32; 157} 158 159static void 160dri_destroy_screen(__DRIscreen * sPriv) 161{ 162 TRACE; 163} 164 165 166/** 167 * Framebuffer and renderbuffer-related functions. 168 */ 169 170static GLuint 171choose_pixel_format(const GLvisual *v) 172{ 173 int depth = v->rgbBits; 174 175 if (depth == 32 176 && v->redMask == 0xff0000 177 && v->greenMask == 0x00ff00 178 && v->blueMask == 0x0000ff) 179 return PF_A8R8G8B8; 180 else if (depth == 24 181 && v->redMask == 0xff0000 182 && v->greenMask == 0x00ff00 183 && v->blueMask == 0x0000ff) 184 return PF_X8R8G8B8; 185 else if (depth == 16 186 && v->redMask == 0xf800 187 && v->greenMask == 0x07e0 188 && v->blueMask == 0x001f) 189 return PF_R5G6B5; 190 else if (depth == 8 191 && v->redMask == 0x07 192 && v->greenMask == 0x38 193 && v->blueMask == 0xc0) 194 return PF_R3G3B2; 195 196 _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ ); 197 return 0; 198} 199 200static void 201swrast_delete_renderbuffer(struct gl_renderbuffer *rb) 202{ 203 TRACE; 204 205 free(rb->Data); 206 free(rb); 207} 208 209static GLboolean 210swrast_alloc_front_storage(GLcontext *ctx, struct gl_renderbuffer *rb, 211 GLenum internalFormat, GLuint width, GLuint height) 212{ 213 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb); 214 unsigned mask = PITCH_ALIGN_BITS - 1; 215 216 TRACE; 217 218 rb->Data = NULL; 219 rb->Width = width; 220 rb->Height = height; 221 222 /* always pad to PITCH_ALIGN_BITS */ 223 xrb->pitch = ((width * xrb->bpp + mask) & ~mask) / 8; 224 225 return GL_TRUE; 226} 227 228static GLboolean 229swrast_alloc_back_storage(GLcontext *ctx, struct gl_renderbuffer *rb, 230 GLenum internalFormat, GLuint width, GLuint height) 231{ 232 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb); 233 234 TRACE; 235 236 free(rb->Data); 237 238 swrast_alloc_front_storage(ctx, rb, internalFormat, width, height); 239 240 rb->Data = malloc(height * xrb->pitch); 241 242 return GL_TRUE; 243} 244 245static struct swrast_renderbuffer * 246swrast_new_renderbuffer(const GLvisual *visual, GLboolean front) 247{ 248 struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb); 249 GLuint pixel_format; 250 251 TRACE; 252 253 if (!xrb) 254 return NULL; 255 256 _mesa_init_renderbuffer(&xrb->Base, 0); 257 258 pixel_format = choose_pixel_format(visual); 259 260 xrb->Base.Delete = swrast_delete_renderbuffer; 261 if (front) { 262 xrb->Base.AllocStorage = swrast_alloc_front_storage; 263 swrast_set_span_funcs_front(xrb, pixel_format); 264 } 265 else { 266 xrb->Base.AllocStorage = swrast_alloc_back_storage; 267 swrast_set_span_funcs_back(xrb, pixel_format); 268 } 269 270 switch (pixel_format) { 271 case PF_A8R8G8B8: 272 xrb->Base.Format = MESA_FORMAT_ARGB8888; 273 xrb->Base.InternalFormat = GL_RGBA; 274 xrb->Base._BaseFormat = GL_RGBA; 275 xrb->Base.DataType = GL_UNSIGNED_BYTE; 276 xrb->bpp = 32; 277 break; 278 case PF_X8R8G8B8: 279 xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */ 280 xrb->Base.InternalFormat = GL_RGB; 281 xrb->Base._BaseFormat = GL_RGB; 282 xrb->Base.DataType = GL_UNSIGNED_BYTE; 283 xrb->bpp = 32; 284 break; 285 case PF_R5G6B5: 286 xrb->Base.Format = MESA_FORMAT_RGB565; 287 xrb->Base.InternalFormat = GL_RGB; 288 xrb->Base._BaseFormat = GL_RGB; 289 xrb->Base.DataType = GL_UNSIGNED_BYTE; 290 xrb->bpp = 16; 291 break; 292 case PF_R3G3B2: 293 xrb->Base.Format = MESA_FORMAT_RGB332; 294 xrb->Base.InternalFormat = GL_RGB; 295 xrb->Base._BaseFormat = GL_RGB; 296 xrb->Base.DataType = GL_UNSIGNED_BYTE; 297 xrb->bpp = 8; 298 break; 299 default: 300 return NULL; 301 } 302 303 return xrb; 304} 305 306static GLboolean 307dri_create_buffer(__DRIscreen * sPriv, 308 __DRIdrawable * dPriv, 309 const __GLcontextModes * visual, GLboolean isPixmap) 310{ 311 struct dri_drawable *drawable = NULL; 312 GLframebuffer *fb; 313 struct swrast_renderbuffer *frontrb, *backrb; 314 315 TRACE; 316 317 drawable = CALLOC_STRUCT(dri_drawable); 318 if (drawable == NULL) 319 goto drawable_fail; 320 321 dPriv->driverPrivate = drawable; 322 drawable->dPriv = dPriv; 323 324 drawable->row = malloc(MAX_WIDTH * 4); 325 if (drawable->row == NULL) 326 goto drawable_fail; 327 328 fb = &drawable->Base; 329 330 /* basic framebuffer setup */ 331 _mesa_initialize_window_framebuffer(fb, visual); 332 333 /* add front renderbuffer */ 334 frontrb = swrast_new_renderbuffer(visual, GL_TRUE); 335 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base); 336 337 /* add back renderbuffer */ 338 if (visual->doubleBufferMode) { 339 backrb = swrast_new_renderbuffer(visual, GL_FALSE); 340 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base); 341 } 342 343 /* add software renderbuffers */ 344 _mesa_add_soft_renderbuffers(fb, 345 GL_FALSE, /* color */ 346 visual->haveDepthBuffer, 347 visual->haveStencilBuffer, 348 visual->haveAccumBuffer, 349 GL_FALSE, /* alpha */ 350 GL_FALSE /* aux bufs */); 351 352 return GL_TRUE; 353 354drawable_fail: 355 356 if (drawable) 357 free(drawable->row); 358 359 FREE(drawable); 360 361 return GL_FALSE; 362} 363 364static void 365dri_destroy_buffer(__DRIdrawable * dPriv) 366{ 367 TRACE; 368 369 if (dPriv) { 370 struct dri_drawable *drawable = dri_drawable(dPriv); 371 GLframebuffer *fb; 372 373 free(drawable->row); 374 375 fb = &drawable->Base; 376 377 fb->DeletePending = GL_TRUE; 378 _mesa_reference_framebuffer(&fb, NULL); 379 } 380} 381 382static void 383dri_swap_buffers(__DRIdrawable * dPriv) 384{ 385 __DRIscreen *sPriv = dPriv->driScreenPriv; 386 387 GET_CURRENT_CONTEXT(ctx); 388 389 struct dri_drawable *drawable = dri_drawable(dPriv); 390 GLframebuffer *fb; 391 struct swrast_renderbuffer *frontrb, *backrb; 392 393 TRACE; 394 395 fb = &drawable->Base; 396 397 frontrb = swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); 398 backrb = swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); 399 400 /* check for signle-buffered */ 401 if (backrb == NULL) 402 return; 403 404 /* check if swapping currently bound buffer */ 405 if (ctx && ctx->DrawBuffer == fb) { 406 /* flush pending rendering */ 407 _mesa_notifySwapBuffers(ctx); 408 } 409 410 sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 411 0, 0, 412 frontrb->Base.Width, 413 frontrb->Base.Height, 414 backrb->Base.Data, 415 dPriv->loaderPrivate); 416} 417 418 419/** 420 * General device driver functions. 421 */ 422 423static void 424get_window_size( GLframebuffer *fb, GLsizei *w, GLsizei *h ) 425{ 426 __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv; 427 __DRIscreen *sPriv = dPriv->driScreenPriv; 428 int x, y; 429 430 sPriv->swrast_loader->getDrawableInfo(dPriv, 431 &x, &y, w, h, 432 dPriv->loaderPrivate); 433} 434 435static void 436swrast_check_and_update_window_size( GLcontext *ctx, GLframebuffer *fb ) 437{ 438 GLsizei width, height; 439 440 get_window_size(fb, &width, &height); 441 if (fb->Width != width || fb->Height != height) { 442 _mesa_resize_framebuffer(ctx, fb, width, height); 443 } 444} 445 446static const GLubyte * 447get_string(GLcontext *ctx, GLenum pname) 448{ 449 (void) ctx; 450 switch (pname) { 451 case GL_VENDOR: 452 return (const GLubyte *) "Mesa Project"; 453 case GL_RENDERER: 454 return (const GLubyte *) "Software Rasterizer"; 455 default: 456 return NULL; 457 } 458} 459 460static void 461update_state( GLcontext *ctx, GLuint new_state ) 462{ 463 /* not much to do here - pass it on */ 464 _swrast_InvalidateState( ctx, new_state ); 465 _swsetup_InvalidateState( ctx, new_state ); 466 _vbo_InvalidateState( ctx, new_state ); 467 _tnl_InvalidateState( ctx, new_state ); 468} 469 470static void 471viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) 472{ 473 GLframebuffer *draw = ctx->WinSysDrawBuffer; 474 GLframebuffer *read = ctx->WinSysReadBuffer; 475 476 swrast_check_and_update_window_size(ctx, draw); 477 swrast_check_and_update_window_size(ctx, read); 478} 479 480static void 481swrast_init_driver_functions(struct dd_function_table *driver) 482{ 483 driver->GetString = get_string; 484 driver->UpdateState = update_state; 485 driver->GetBufferSize = NULL; 486 driver->Viewport = viewport; 487} 488 489 490/** 491 * Context-related functions. 492 */ 493 494static GLboolean 495dri_create_context(const __GLcontextModes * visual, 496 __DRIcontext * cPriv, void *sharedContextPrivate) 497{ 498 struct dri_context *ctx = NULL; 499 struct dri_context *share = (struct dri_context *)sharedContextPrivate; 500 GLcontext *mesaCtx = NULL; 501 GLcontext *sharedCtx = NULL; 502 struct dd_function_table functions; 503 504 TRACE; 505 506 ctx = CALLOC_STRUCT(dri_context); 507 if (ctx == NULL) 508 goto context_fail; 509 510 cPriv->driverPrivate = ctx; 511 ctx->cPriv = cPriv; 512 513 /* build table of device driver functions */ 514 _mesa_init_driver_functions(&functions); 515 swrast_init_driver_functions(&functions); 516 517 if (share) { 518 sharedCtx = &share->Base; 519 } 520 521 mesaCtx = &ctx->Base; 522 523 /* basic context setup */ 524 if (!_mesa_initialize_context(mesaCtx, visual, sharedCtx, &functions, (void *) cPriv)) { 525 goto context_fail; 526 } 527 528 /* do bounds checking to prevent segfaults and server crashes! */ 529 mesaCtx->Const.CheckArrayBounds = GL_TRUE; 530 531 /* create module contexts */ 532 _swrast_CreateContext( mesaCtx ); 533 _vbo_CreateContext( mesaCtx ); 534 _tnl_CreateContext( mesaCtx ); 535 _swsetup_CreateContext( mesaCtx ); 536 _swsetup_Wakeup( mesaCtx ); 537 538 /* use default TCL pipeline */ 539 { 540 TNLcontext *tnl = TNL_CONTEXT(mesaCtx); 541 tnl->Driver.RunPipeline = _tnl_run_pipeline; 542 } 543 544 _mesa_enable_sw_extensions(mesaCtx); 545 _mesa_enable_1_3_extensions(mesaCtx); 546 _mesa_enable_1_4_extensions(mesaCtx); 547 _mesa_enable_1_5_extensions(mesaCtx); 548 _mesa_enable_2_0_extensions(mesaCtx); 549 _mesa_enable_2_1_extensions(mesaCtx); 550 551 _mesa_meta_init(mesaCtx); 552 553 driInitExtensions( mesaCtx, NULL, GL_FALSE ); 554 555 return GL_TRUE; 556 557context_fail: 558 559 FREE(ctx); 560 561 return GL_FALSE; 562} 563 564static void 565dri_destroy_context(__DRIcontext * cPriv) 566{ 567 TRACE; 568 569 if (cPriv) { 570 struct dri_context *ctx = dri_context(cPriv); 571 GLcontext *mesaCtx; 572 573 mesaCtx = &ctx->Base; 574 575 _mesa_meta_free(mesaCtx); 576 _swsetup_DestroyContext( mesaCtx ); 577 _swrast_DestroyContext( mesaCtx ); 578 _tnl_DestroyContext( mesaCtx ); 579 _vbo_DestroyContext( mesaCtx ); 580 _mesa_destroy_context( mesaCtx ); 581 } 582} 583 584static GLboolean 585dri_make_current(__DRIcontext * cPriv, 586 __DRIdrawable * driDrawPriv, 587 __DRIdrawable * driReadPriv) 588{ 589 GLcontext *mesaCtx; 590 GLframebuffer *mesaDraw; 591 GLframebuffer *mesaRead; 592 TRACE; 593 594 if (cPriv) { 595 struct dri_context *ctx = dri_context(cPriv); 596 struct dri_drawable *draw = dri_drawable(driDrawPriv); 597 struct dri_drawable *read = dri_drawable(driReadPriv); 598 599 if (!driDrawPriv || !driReadPriv) 600 return GL_FALSE; 601 602 mesaCtx = &ctx->Base; 603 mesaDraw = &draw->Base; 604 mesaRead = &read->Base; 605 606 /* check for same context and buffer */ 607 if (mesaCtx == _mesa_get_current_context() 608 && mesaCtx->DrawBuffer == mesaDraw 609 && mesaCtx->ReadBuffer == mesaRead) { 610 return GL_TRUE; 611 } 612 613 _glapi_check_multithread(); 614 615 swrast_check_and_update_window_size(mesaCtx, mesaDraw); 616 if (mesaRead != mesaDraw) 617 swrast_check_and_update_window_size(mesaCtx, mesaRead); 618 619 _mesa_make_current( mesaCtx, 620 mesaDraw, 621 mesaRead ); 622 } 623 else { 624 /* unbind */ 625 _mesa_make_current( NULL, NULL, NULL ); 626 } 627 628 return GL_TRUE; 629} 630 631static GLboolean 632dri_unbind_context(__DRIcontext * cPriv) 633{ 634 TRACE; 635 (void) cPriv; 636 return GL_TRUE; 637} 638 639 640const struct __DriverAPIRec driDriverAPI = { 641 .InitScreen = dri_init_screen, 642 .DestroyScreen = dri_destroy_screen, 643 .CreateContext = dri_create_context, 644 .DestroyContext = dri_destroy_context, 645 .CreateBuffer = dri_create_buffer, 646 .DestroyBuffer = dri_destroy_buffer, 647 .SwapBuffers = dri_swap_buffers, 648 .MakeCurrent = dri_make_current, 649 .UnbindContext = dri_unbind_context, 650}; 651 652/* This is the table of extensions that the loader will dlsym() for. */ 653PUBLIC const __DRIextension *__driDriverExtensions[] = { 654 &driCoreExtension.base, 655 &driSWRastExtension.base, 656 NULL 657}; 658