swrast.c revision f4e561ce127cf484d7c76c29b8cd026c9ad5cebc
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 INLINE int 210bytes_per_line(unsigned pitch_bits, unsigned mul) 211{ 212 unsigned mask = mul - 1; 213 214 return ((pitch_bits + mask) & ~mask) / 8; 215} 216 217static GLboolean 218swrast_alloc_front_storage(GLcontext *ctx, struct gl_renderbuffer *rb, 219 GLenum internalFormat, GLuint width, GLuint height) 220{ 221 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb); 222 223 TRACE; 224 225 rb->Data = NULL; 226 rb->Width = width; 227 rb->Height = height; 228 229 xrb->pitch = bytes_per_line(width * xrb->bpp, 32); 230 231 return GL_TRUE; 232} 233 234static GLboolean 235swrast_alloc_back_storage(GLcontext *ctx, struct gl_renderbuffer *rb, 236 GLenum internalFormat, GLuint width, GLuint height) 237{ 238 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb); 239 240 TRACE; 241 242 free(rb->Data); 243 244 swrast_alloc_front_storage(ctx, rb, internalFormat, width, height); 245 246 rb->Data = malloc(height * xrb->pitch); 247 248 return GL_TRUE; 249} 250 251static struct swrast_renderbuffer * 252swrast_new_renderbuffer(const GLvisual *visual, GLboolean front) 253{ 254 struct swrast_renderbuffer *xrb = calloc(1, sizeof *xrb); 255 GLuint pixel_format; 256 257 TRACE; 258 259 if (!xrb) 260 return NULL; 261 262 _mesa_init_renderbuffer(&xrb->Base, 0); 263 264 pixel_format = choose_pixel_format(visual); 265 266 xrb->Base.Delete = swrast_delete_renderbuffer; 267 if (front) { 268 xrb->Base.AllocStorage = swrast_alloc_front_storage; 269 swrast_set_span_funcs_front(xrb, pixel_format); 270 } 271 else { 272 xrb->Base.AllocStorage = swrast_alloc_back_storage; 273 swrast_set_span_funcs_back(xrb, pixel_format); 274 } 275 276 switch (pixel_format) { 277 case PF_A8R8G8B8: 278 xrb->Base.Format = MESA_FORMAT_ARGB8888; 279 xrb->Base.InternalFormat = GL_RGBA; 280 xrb->Base._BaseFormat = GL_RGBA; 281 xrb->Base.DataType = GL_UNSIGNED_BYTE; 282 xrb->bpp = 32; 283 break; 284 case PF_X8R8G8B8: 285 xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */ 286 xrb->Base.InternalFormat = GL_RGB; 287 xrb->Base._BaseFormat = GL_RGB; 288 xrb->Base.DataType = GL_UNSIGNED_BYTE; 289 xrb->bpp = 32; 290 break; 291 case PF_R5G6B5: 292 xrb->Base.Format = MESA_FORMAT_RGB565; 293 xrb->Base.InternalFormat = GL_RGB; 294 xrb->Base._BaseFormat = GL_RGB; 295 xrb->Base.DataType = GL_UNSIGNED_BYTE; 296 xrb->bpp = 16; 297 break; 298 case PF_R3G3B2: 299 xrb->Base.Format = MESA_FORMAT_RGB332; 300 xrb->Base.InternalFormat = GL_RGB; 301 xrb->Base._BaseFormat = GL_RGB; 302 xrb->Base.DataType = GL_UNSIGNED_BYTE; 303 xrb->bpp = 8; 304 break; 305 default: 306 return NULL; 307 } 308 309 return xrb; 310} 311 312static GLboolean 313dri_create_buffer(__DRIscreen * sPriv, 314 __DRIdrawable * dPriv, 315 const __GLcontextModes * visual, GLboolean isPixmap) 316{ 317 struct dri_drawable *drawable = NULL; 318 GLframebuffer *fb; 319 struct swrast_renderbuffer *frontrb, *backrb; 320 321 TRACE; 322 323 drawable = CALLOC_STRUCT(dri_drawable); 324 if (drawable == NULL) 325 goto drawable_fail; 326 327 dPriv->driverPrivate = drawable; 328 drawable->dPriv = dPriv; 329 330 drawable->row = malloc(MAX_WIDTH * 4); 331 if (drawable->row == NULL) 332 goto drawable_fail; 333 334 fb = &drawable->Base; 335 336 /* basic framebuffer setup */ 337 _mesa_initialize_window_framebuffer(fb, visual); 338 339 /* add front renderbuffer */ 340 frontrb = swrast_new_renderbuffer(visual, GL_TRUE); 341 _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontrb->Base); 342 343 /* add back renderbuffer */ 344 if (visual->doubleBufferMode) { 345 backrb = swrast_new_renderbuffer(visual, GL_FALSE); 346 _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backrb->Base); 347 } 348 349 /* add software renderbuffers */ 350 _mesa_add_soft_renderbuffers(fb, 351 GL_FALSE, /* color */ 352 visual->haveDepthBuffer, 353 visual->haveStencilBuffer, 354 visual->haveAccumBuffer, 355 GL_FALSE, /* alpha */ 356 GL_FALSE /* aux bufs */); 357 358 return GL_TRUE; 359 360drawable_fail: 361 362 if (drawable) 363 free(drawable->row); 364 365 FREE(drawable); 366 367 return GL_FALSE; 368} 369 370static void 371dri_destroy_buffer(__DRIdrawable * dPriv) 372{ 373 TRACE; 374 375 if (dPriv) { 376 struct dri_drawable *drawable = dri_drawable(dPriv); 377 GLframebuffer *fb; 378 379 free(drawable->row); 380 381 fb = &drawable->Base; 382 383 fb->DeletePending = GL_TRUE; 384 _mesa_reference_framebuffer(&fb, NULL); 385 } 386} 387 388static void 389dri_swap_buffers(__DRIdrawable * dPriv) 390{ 391 __DRIscreen *sPriv = dPriv->driScreenPriv; 392 393 GET_CURRENT_CONTEXT(ctx); 394 395 struct dri_drawable *drawable = dri_drawable(dPriv); 396 GLframebuffer *fb; 397 struct swrast_renderbuffer *frontrb, *backrb; 398 399 TRACE; 400 401 fb = &drawable->Base; 402 403 frontrb = 404 swrast_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer); 405 backrb = 406 swrast_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer); 407 408 /* check for signle-buffered */ 409 if (backrb == NULL) 410 return; 411 412 /* check if swapping currently bound buffer */ 413 if (ctx && ctx->DrawBuffer == fb) { 414 /* flush pending rendering */ 415 _mesa_notifySwapBuffers(ctx); 416 } 417 418 sPriv->swrast_loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP, 419 0, 0, 420 frontrb->Base.Width, 421 frontrb->Base.Height, 422 backrb->Base.Data, 423 dPriv->loaderPrivate); 424} 425 426 427/** 428 * General device driver functions. 429 */ 430 431static void 432get_window_size( GLframebuffer *fb, GLsizei *w, GLsizei *h ) 433{ 434 __DRIdrawable *dPriv = swrast_drawable(fb)->dPriv; 435 __DRIscreen *sPriv = dPriv->driScreenPriv; 436 int x, y; 437 438 sPriv->swrast_loader->getDrawableInfo(dPriv, 439 &x, &y, w, h, 440 dPriv->loaderPrivate); 441} 442 443static void 444swrast_check_and_update_window_size( GLcontext *ctx, GLframebuffer *fb ) 445{ 446 GLsizei width, height; 447 448 get_window_size(fb, &width, &height); 449 if (fb->Width != width || fb->Height != height) { 450 _mesa_resize_framebuffer(ctx, fb, width, height); 451 } 452} 453 454static const GLubyte * 455get_string(GLcontext *ctx, GLenum pname) 456{ 457 (void) ctx; 458 switch (pname) { 459 case GL_VENDOR: 460 return (const GLubyte *) "Mesa Project"; 461 case GL_RENDERER: 462 return (const GLubyte *) "Software Rasterizer"; 463 default: 464 return NULL; 465 } 466} 467 468static void 469update_state( GLcontext *ctx, GLuint new_state ) 470{ 471 /* not much to do here - pass it on */ 472 _swrast_InvalidateState( ctx, new_state ); 473 _swsetup_InvalidateState( ctx, new_state ); 474 _vbo_InvalidateState( ctx, new_state ); 475 _tnl_InvalidateState( ctx, new_state ); 476} 477 478static void 479viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h) 480{ 481 GLframebuffer *draw = ctx->WinSysDrawBuffer; 482 GLframebuffer *read = ctx->WinSysReadBuffer; 483 484 swrast_check_and_update_window_size(ctx, draw); 485 swrast_check_and_update_window_size(ctx, read); 486} 487 488static void 489swrast_init_driver_functions(struct dd_function_table *driver) 490{ 491 driver->GetString = get_string; 492 driver->UpdateState = update_state; 493 driver->GetBufferSize = NULL; 494 driver->Viewport = viewport; 495} 496 497 498/** 499 * Context-related functions. 500 */ 501 502static GLboolean 503dri_create_context(const __GLcontextModes * visual, 504 __DRIcontext * cPriv, void *sharedContextPrivate) 505{ 506 struct dri_context *ctx = NULL; 507 struct dri_context *share = (struct dri_context *)sharedContextPrivate; 508 GLcontext *mesaCtx = NULL; 509 GLcontext *sharedCtx = NULL; 510 struct dd_function_table functions; 511 512 TRACE; 513 514 ctx = CALLOC_STRUCT(dri_context); 515 if (ctx == NULL) 516 goto context_fail; 517 518 cPriv->driverPrivate = ctx; 519 ctx->cPriv = cPriv; 520 521 /* build table of device driver functions */ 522 _mesa_init_driver_functions(&functions); 523 swrast_init_driver_functions(&functions); 524 525 if (share) { 526 sharedCtx = &share->Base; 527 } 528 529 mesaCtx = &ctx->Base; 530 531 /* basic context setup */ 532 if (!_mesa_initialize_context(mesaCtx, visual, sharedCtx, &functions, (void *) cPriv)) { 533 goto context_fail; 534 } 535 536 /* do bounds checking to prevent segfaults and server crashes! */ 537 mesaCtx->Const.CheckArrayBounds = GL_TRUE; 538 539 /* create module contexts */ 540 _swrast_CreateContext( mesaCtx ); 541 _vbo_CreateContext( mesaCtx ); 542 _tnl_CreateContext( mesaCtx ); 543 _swsetup_CreateContext( mesaCtx ); 544 _swsetup_Wakeup( mesaCtx ); 545 546 /* use default TCL pipeline */ 547 { 548 TNLcontext *tnl = TNL_CONTEXT(mesaCtx); 549 tnl->Driver.RunPipeline = _tnl_run_pipeline; 550 } 551 552 _mesa_enable_sw_extensions(mesaCtx); 553 _mesa_enable_1_3_extensions(mesaCtx); 554 _mesa_enable_1_4_extensions(mesaCtx); 555 _mesa_enable_1_5_extensions(mesaCtx); 556 _mesa_enable_2_0_extensions(mesaCtx); 557 _mesa_enable_2_1_extensions(mesaCtx); 558 559 _mesa_meta_init(mesaCtx); 560 561 driInitExtensions( mesaCtx, NULL, GL_FALSE ); 562 563 return GL_TRUE; 564 565context_fail: 566 567 FREE(ctx); 568 569 return GL_FALSE; 570} 571 572static void 573dri_destroy_context(__DRIcontext * cPriv) 574{ 575 TRACE; 576 577 if (cPriv) { 578 struct dri_context *ctx = dri_context(cPriv); 579 GLcontext *mesaCtx; 580 581 mesaCtx = &ctx->Base; 582 583 _mesa_meta_free(mesaCtx); 584 _swsetup_DestroyContext( mesaCtx ); 585 _swrast_DestroyContext( mesaCtx ); 586 _tnl_DestroyContext( mesaCtx ); 587 _vbo_DestroyContext( mesaCtx ); 588 _mesa_destroy_context( mesaCtx ); 589 } 590} 591 592static GLboolean 593dri_make_current(__DRIcontext * cPriv, 594 __DRIdrawable * driDrawPriv, 595 __DRIdrawable * driReadPriv) 596{ 597 GLcontext *mesaCtx; 598 GLframebuffer *mesaDraw; 599 GLframebuffer *mesaRead; 600 TRACE; 601 602 if (cPriv) { 603 struct dri_context *ctx = dri_context(cPriv); 604 struct dri_drawable *draw = dri_drawable(driDrawPriv); 605 struct dri_drawable *read = dri_drawable(driReadPriv); 606 607 if (!driDrawPriv || !driReadPriv) 608 return GL_FALSE; 609 610 mesaCtx = &ctx->Base; 611 mesaDraw = &draw->Base; 612 mesaRead = &read->Base; 613 614 /* check for same context and buffer */ 615 if (mesaCtx == _mesa_get_current_context() 616 && mesaCtx->DrawBuffer == mesaDraw 617 && mesaCtx->ReadBuffer == mesaRead) { 618 return GL_TRUE; 619 } 620 621 _glapi_check_multithread(); 622 623 swrast_check_and_update_window_size(mesaCtx, mesaDraw); 624 if (mesaRead != mesaDraw) 625 swrast_check_and_update_window_size(mesaCtx, mesaRead); 626 627 _mesa_make_current( mesaCtx, 628 mesaDraw, 629 mesaRead ); 630 } 631 else { 632 /* unbind */ 633 _mesa_make_current( NULL, NULL, NULL ); 634 } 635 636 return GL_TRUE; 637} 638 639static GLboolean 640dri_unbind_context(__DRIcontext * cPriv) 641{ 642 TRACE; 643 (void) cPriv; 644 return GL_TRUE; 645} 646 647 648const struct __DriverAPIRec driDriverAPI = { 649 .InitScreen = dri_init_screen, 650 .DestroyScreen = dri_destroy_screen, 651 .CreateContext = dri_create_context, 652 .DestroyContext = dri_destroy_context, 653 .CreateBuffer = dri_create_buffer, 654 .DestroyBuffer = dri_destroy_buffer, 655 .SwapBuffers = dri_swap_buffers, 656 .MakeCurrent = dri_make_current, 657 .UnbindContext = dri_unbind_context, 658}; 659 660/* This is the table of extensions that the loader will dlsym() for. */ 661PUBLIC const __DRIextension *__driDriverExtensions[] = { 662 &driCoreExtension.base, 663 &driSWRastExtension.base, 664 NULL 665}; 666