1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26 /** 27 * Functions for allocating/managing software-based renderbuffers. 28 * Also, routines for reading/writing software-based renderbuffer data as 29 * ubytes, ushorts, uints, etc. 30 */ 31 32 33 #include "main/glheader.h" 34 #include "main/imports.h" 35 #include "main/context.h" 36 #include "main/fbobject.h" 37 #include "main/formats.h" 38 #include "main/mtypes.h" 39 #include "main/renderbuffer.h" 40 #include "swrast/s_context.h" 41 #include "swrast/s_renderbuffer.h" 42 43 44 /** 45 * This is a software fallback for the gl_renderbuffer->AllocStorage 46 * function. 47 * Device drivers will typically override this function for the buffers 48 * which it manages (typically color buffers, Z and stencil). 49 * Other buffers (like software accumulation and aux buffers) which the driver 50 * doesn't manage can be handled with this function. 51 * 52 * This one multi-purpose function can allocate stencil, depth, accum, color 53 * or color-index buffers! 54 */ 55 static GLboolean 56 soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 57 GLenum internalFormat, 58 GLuint width, GLuint height) 59 { 60 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 61 GLuint bpp; 62 63 switch (internalFormat) { 64 case GL_RGB: 65 case GL_R3_G3_B2: 66 case GL_RGB4: 67 case GL_RGB5: 68 case GL_RGB8: 69 case GL_RGB10: 70 case GL_RGB12: 71 case GL_RGB16: 72 rb->Format = MESA_FORMAT_BGR_UNORM8; 73 break; 74 case GL_RGBA: 75 case GL_RGBA2: 76 case GL_RGBA4: 77 case GL_RGB5_A1: 78 case GL_RGBA8: 79 #if 1 80 case GL_RGB10_A2: 81 case GL_RGBA12: 82 #endif 83 if (_mesa_little_endian()) 84 rb->Format = MESA_FORMAT_R8G8B8A8_UNORM; 85 else 86 rb->Format = MESA_FORMAT_A8B8G8R8_UNORM; 87 break; 88 case GL_RGBA16: 89 case GL_RGBA16_SNORM: 90 /* for accum buffer */ 91 rb->Format = MESA_FORMAT_RGBA_SNORM16; 92 break; 93 case GL_STENCIL_INDEX: 94 case GL_STENCIL_INDEX1_EXT: 95 case GL_STENCIL_INDEX4_EXT: 96 case GL_STENCIL_INDEX8_EXT: 97 case GL_STENCIL_INDEX16_EXT: 98 rb->Format = MESA_FORMAT_S_UINT8; 99 break; 100 case GL_DEPTH_COMPONENT: 101 case GL_DEPTH_COMPONENT16: 102 rb->Format = MESA_FORMAT_Z_UNORM16; 103 break; 104 case GL_DEPTH_COMPONENT24: 105 rb->Format = MESA_FORMAT_Z24_UNORM_X8_UINT; 106 break; 107 case GL_DEPTH_COMPONENT32: 108 rb->Format = MESA_FORMAT_Z_UNORM32; 109 break; 110 case GL_DEPTH_STENCIL_EXT: 111 case GL_DEPTH24_STENCIL8_EXT: 112 rb->Format = MESA_FORMAT_S8_UINT_Z24_UNORM; 113 break; 114 default: 115 /* unsupported format */ 116 return GL_FALSE; 117 } 118 119 bpp = _mesa_get_format_bytes(rb->Format); 120 121 /* free old buffer storage */ 122 free(srb->Buffer); 123 srb->Buffer = NULL; 124 125 srb->RowStride = width * bpp; 126 127 if (width > 0 && height > 0) { 128 /* allocate new buffer storage */ 129 srb->Buffer = malloc(srb->RowStride * height); 130 131 if (srb->Buffer == NULL) { 132 rb->Width = 0; 133 rb->Height = 0; 134 _mesa_error(ctx, GL_OUT_OF_MEMORY, 135 "software renderbuffer allocation (%d x %d x %d)", 136 width, height, bpp); 137 return GL_FALSE; 138 } 139 } 140 141 rb->Width = width; 142 rb->Height = height; 143 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 144 145 if (rb->Name == 0 && 146 internalFormat == GL_RGBA16_SNORM && 147 rb->_BaseFormat == 0) { 148 /* NOTE: This is a special case just for accumulation buffers. 149 * This is a very limited use case- there's no snorm texturing or 150 * rendering going on. 151 */ 152 rb->_BaseFormat = GL_RGBA; 153 } 154 else { 155 /* the internalFormat should have been error checked long ago */ 156 assert(rb->_BaseFormat); 157 } 158 159 return GL_TRUE; 160 } 161 162 163 /** 164 * Called via gl_renderbuffer::Delete() 165 */ 166 static void 167 soft_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb) 168 { 169 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 170 171 free(srb->Buffer); 172 srb->Buffer = NULL; 173 _mesa_delete_renderbuffer(ctx, rb); 174 } 175 176 177 void 178 _swrast_map_soft_renderbuffer(struct gl_context *ctx, 179 struct gl_renderbuffer *rb, 180 GLuint x, GLuint y, GLuint w, GLuint h, 181 GLbitfield mode, 182 GLubyte **out_map, 183 GLint *out_stride) 184 { 185 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 186 GLubyte *map = srb->Buffer; 187 int cpp = _mesa_get_format_bytes(rb->Format); 188 int stride = rb->Width * cpp; 189 190 if (!map) { 191 *out_map = NULL; 192 *out_stride = 0; 193 } 194 195 map += y * stride; 196 map += x * cpp; 197 198 *out_map = map; 199 *out_stride = stride; 200 } 201 202 203 void 204 _swrast_unmap_soft_renderbuffer(struct gl_context *ctx, 205 struct gl_renderbuffer *rb) 206 { 207 } 208 209 210 211 /** 212 * Allocate a software-based renderbuffer. This is called via the 213 * ctx->Driver.NewRenderbuffer() function when the user creates a new 214 * renderbuffer. 215 * This would not be used for hardware-based renderbuffers. 216 */ 217 struct gl_renderbuffer * 218 _swrast_new_soft_renderbuffer(struct gl_context *ctx, GLuint name) 219 { 220 struct swrast_renderbuffer *srb = CALLOC_STRUCT(swrast_renderbuffer); 221 if (srb) { 222 _mesa_init_renderbuffer(&srb->Base, name); 223 srb->Base.AllocStorage = soft_renderbuffer_storage; 224 srb->Base.Delete = soft_renderbuffer_delete; 225 } 226 return &srb->Base; 227 } 228 229 230 /** 231 * Add software-based color renderbuffers to the given framebuffer. 232 * This is a helper routine for device drivers when creating a 233 * window system framebuffer (not a user-created render/framebuffer). 234 * Once this function is called, you can basically forget about this 235 * renderbuffer; core Mesa will handle all the buffer management and 236 * rendering! 237 */ 238 static GLboolean 239 add_color_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, 240 GLuint rgbBits, GLuint alphaBits, 241 GLboolean frontLeft, GLboolean backLeft, 242 GLboolean frontRight, GLboolean backRight) 243 { 244 gl_buffer_index b; 245 246 if (rgbBits > 16 || alphaBits > 16) { 247 _mesa_problem(ctx, 248 "Unsupported bit depth in add_color_renderbuffers"); 249 return GL_FALSE; 250 } 251 252 assert(MAX_COLOR_ATTACHMENTS >= 4); 253 254 for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) { 255 struct gl_renderbuffer *rb; 256 257 if (b == BUFFER_FRONT_LEFT && !frontLeft) 258 continue; 259 else if (b == BUFFER_BACK_LEFT && !backLeft) 260 continue; 261 else if (b == BUFFER_FRONT_RIGHT && !frontRight) 262 continue; 263 else if (b == BUFFER_BACK_RIGHT && !backRight) 264 continue; 265 266 assert(fb->Attachment[b].Renderbuffer == NULL); 267 268 rb = ctx->Driver.NewRenderbuffer(ctx, 0); 269 if (!rb) { 270 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer"); 271 return GL_FALSE; 272 } 273 274 rb->InternalFormat = GL_RGBA; 275 276 rb->AllocStorage = soft_renderbuffer_storage; 277 _mesa_add_renderbuffer(fb, b, rb); 278 } 279 280 return GL_TRUE; 281 } 282 283 284 /** 285 * Add a software-based depth renderbuffer to the given framebuffer. 286 * This is a helper routine for device drivers when creating a 287 * window system framebuffer (not a user-created render/framebuffer). 288 * Once this function is called, you can basically forget about this 289 * renderbuffer; core Mesa will handle all the buffer management and 290 * rendering! 291 */ 292 static GLboolean 293 add_depth_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 294 GLuint depthBits) 295 { 296 struct gl_renderbuffer *rb; 297 298 if (depthBits > 32) { 299 _mesa_problem(ctx, 300 "Unsupported depthBits in add_depth_renderbuffer"); 301 return GL_FALSE; 302 } 303 304 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL); 305 306 rb = _swrast_new_soft_renderbuffer(ctx, 0); 307 if (!rb) { 308 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth buffer"); 309 return GL_FALSE; 310 } 311 312 if (depthBits <= 16) { 313 rb->InternalFormat = GL_DEPTH_COMPONENT16; 314 } 315 else if (depthBits <= 24) { 316 rb->InternalFormat = GL_DEPTH_COMPONENT24; 317 } 318 else { 319 rb->InternalFormat = GL_DEPTH_COMPONENT32; 320 } 321 322 rb->AllocStorage = soft_renderbuffer_storage; 323 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb); 324 325 return GL_TRUE; 326 } 327 328 329 /** 330 * Add a software-based stencil renderbuffer to the given framebuffer. 331 * This is a helper routine for device drivers when creating a 332 * window system framebuffer (not a user-created render/framebuffer). 333 * Once this function is called, you can basically forget about this 334 * renderbuffer; core Mesa will handle all the buffer management and 335 * rendering! 336 */ 337 static GLboolean 338 add_stencil_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 339 GLuint stencilBits) 340 { 341 struct gl_renderbuffer *rb; 342 343 if (stencilBits > 16) { 344 _mesa_problem(ctx, 345 "Unsupported stencilBits in add_stencil_renderbuffer"); 346 return GL_FALSE; 347 } 348 349 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL); 350 351 rb = _swrast_new_soft_renderbuffer(ctx, 0); 352 if (!rb) { 353 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating stencil buffer"); 354 return GL_FALSE; 355 } 356 357 assert(stencilBits <= 8); 358 rb->InternalFormat = GL_STENCIL_INDEX8; 359 360 rb->AllocStorage = soft_renderbuffer_storage; 361 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb); 362 363 return GL_TRUE; 364 } 365 366 367 static GLboolean 368 add_depth_stencil_renderbuffer(struct gl_context *ctx, 369 struct gl_framebuffer *fb) 370 { 371 struct gl_renderbuffer *rb; 372 373 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL); 374 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL); 375 376 rb = _swrast_new_soft_renderbuffer(ctx, 0); 377 if (!rb) { 378 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth+stencil buffer"); 379 return GL_FALSE; 380 } 381 382 rb->InternalFormat = GL_DEPTH_STENCIL; 383 384 rb->AllocStorage = soft_renderbuffer_storage; 385 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb); 386 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb); 387 388 return GL_TRUE; 389 } 390 391 392 /** 393 * Add a software-based accumulation renderbuffer to the given framebuffer. 394 * This is a helper routine for device drivers when creating a 395 * window system framebuffer (not a user-created render/framebuffer). 396 * Once this function is called, you can basically forget about this 397 * renderbuffer; core Mesa will handle all the buffer management and 398 * rendering! 399 */ 400 static GLboolean 401 add_accum_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 402 GLuint redBits, GLuint greenBits, 403 GLuint blueBits, GLuint alphaBits) 404 { 405 struct gl_renderbuffer *rb; 406 407 if (redBits > 16 || greenBits > 16 || blueBits > 16 || alphaBits > 16) { 408 _mesa_problem(ctx, 409 "Unsupported accumBits in add_accum_renderbuffer"); 410 return GL_FALSE; 411 } 412 413 assert(fb->Attachment[BUFFER_ACCUM].Renderbuffer == NULL); 414 415 rb = _swrast_new_soft_renderbuffer(ctx, 0); 416 if (!rb) { 417 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer"); 418 return GL_FALSE; 419 } 420 421 rb->InternalFormat = GL_RGBA16_SNORM; 422 rb->AllocStorage = soft_renderbuffer_storage; 423 _mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb); 424 425 return GL_TRUE; 426 } 427 428 429 430 /** 431 * Add a software-based aux renderbuffer to the given framebuffer. 432 * This is a helper routine for device drivers when creating a 433 * window system framebuffer (not a user-created render/framebuffer). 434 * Once this function is called, you can basically forget about this 435 * renderbuffer; core Mesa will handle all the buffer management and 436 * rendering! 437 * 438 * NOTE: color-index aux buffers not supported. 439 */ 440 static GLboolean 441 add_aux_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, 442 GLuint colorBits, GLuint numBuffers) 443 { 444 GLuint i; 445 446 if (colorBits > 16) { 447 _mesa_problem(ctx, 448 "Unsupported colorBits in add_aux_renderbuffers"); 449 return GL_FALSE; 450 } 451 452 assert(numBuffers <= MAX_AUX_BUFFERS); 453 454 for (i = 0; i < numBuffers; i++) { 455 struct gl_renderbuffer *rb = _swrast_new_soft_renderbuffer(ctx, 0); 456 457 assert(fb->Attachment[BUFFER_AUX0 + i].Renderbuffer == NULL); 458 459 if (!rb) { 460 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating aux buffer"); 461 return GL_FALSE; 462 } 463 464 assert (colorBits <= 8); 465 rb->InternalFormat = GL_RGBA; 466 467 rb->AllocStorage = soft_renderbuffer_storage; 468 _mesa_add_renderbuffer(fb, BUFFER_AUX0 + i, rb); 469 } 470 return GL_TRUE; 471 } 472 473 474 /** 475 * Create/attach software-based renderbuffers to the given framebuffer. 476 * This is a helper routine for device drivers. Drivers can just as well 477 * call the individual _mesa_add_*_renderbuffer() routines directly. 478 */ 479 void 480 _swrast_add_soft_renderbuffers(struct gl_framebuffer *fb, 481 GLboolean color, 482 GLboolean depth, 483 GLboolean stencil, 484 GLboolean accum, 485 GLboolean alpha, 486 GLboolean aux) 487 { 488 GLboolean frontLeft = GL_TRUE; 489 GLboolean backLeft = fb->Visual.doubleBufferMode; 490 GLboolean frontRight = fb->Visual.stereoMode; 491 GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode; 492 493 if (color) { 494 assert(fb->Visual.redBits == fb->Visual.greenBits); 495 assert(fb->Visual.redBits == fb->Visual.blueBits); 496 add_color_renderbuffers(NULL, fb, 497 fb->Visual.redBits, 498 fb->Visual.alphaBits, 499 frontLeft, backLeft, 500 frontRight, backRight); 501 } 502 503 #if 0 504 /* This is pretty much for debugging purposes only since there's a perf 505 * hit for using combined depth/stencil in swrast. 506 */ 507 if (depth && fb->Visual.depthBits == 24 && 508 stencil && fb->Visual.stencilBits == 8) { 509 /* use combined depth/stencil buffer */ 510 add_depth_stencil_renderbuffer(NULL, fb); 511 } 512 else 513 #else 514 (void) add_depth_stencil_renderbuffer; 515 #endif 516 { 517 if (depth) { 518 assert(fb->Visual.depthBits > 0); 519 add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits); 520 } 521 522 if (stencil) { 523 assert(fb->Visual.stencilBits > 0); 524 add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits); 525 } 526 } 527 528 if (accum) { 529 assert(fb->Visual.accumRedBits > 0); 530 assert(fb->Visual.accumGreenBits > 0); 531 assert(fb->Visual.accumBlueBits > 0); 532 add_accum_renderbuffer(NULL, fb, 533 fb->Visual.accumRedBits, 534 fb->Visual.accumGreenBits, 535 fb->Visual.accumBlueBits, 536 fb->Visual.accumAlphaBits); 537 } 538 539 if (aux) { 540 assert(fb->Visual.numAuxBuffers > 0); 541 add_aux_renderbuffers(NULL, fb, fb->Visual.redBits, 542 fb->Visual.numAuxBuffers); 543 } 544 545 #if 0 546 if (multisample) { 547 /* maybe someday */ 548 } 549 #endif 550 } 551 552 553 554 static void 555 map_attachment(struct gl_context *ctx, 556 struct gl_framebuffer *fb, 557 gl_buffer_index buffer) 558 { 559 struct gl_texture_object *texObj = fb->Attachment[buffer].Texture; 560 struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer; 561 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 562 563 if (texObj) { 564 /* map texture image (render to texture) */ 565 const GLuint level = fb->Attachment[buffer].TextureLevel; 566 const GLuint face = fb->Attachment[buffer].CubeMapFace; 567 const GLuint slice = fb->Attachment[buffer].Zoffset; 568 struct gl_texture_image *texImage = texObj->Image[face][level]; 569 if (texImage) { 570 ctx->Driver.MapTextureImage(ctx, texImage, slice, 571 0, 0, texImage->Width, texImage->Height, 572 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 573 &srb->Map, &srb->RowStride); 574 } 575 } 576 else if (rb) { 577 /* Map ordinary renderbuffer */ 578 ctx->Driver.MapRenderbuffer(ctx, rb, 579 0, 0, rb->Width, rb->Height, 580 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 581 &srb->Map, &srb->RowStride); 582 } 583 584 assert(srb->Map); 585 } 586 587 588 static void 589 unmap_attachment(struct gl_context *ctx, 590 struct gl_framebuffer *fb, 591 gl_buffer_index buffer) 592 { 593 struct gl_texture_object *texObj = fb->Attachment[buffer].Texture; 594 struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer; 595 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 596 597 if (texObj) { 598 /* unmap texture image (render to texture) */ 599 const GLuint level = fb->Attachment[buffer].TextureLevel; 600 const GLuint face = fb->Attachment[buffer].CubeMapFace; 601 const GLuint slice = fb->Attachment[buffer].Zoffset; 602 struct gl_texture_image *texImage = texObj->Image[face][level]; 603 if (texImage) { 604 ctx->Driver.UnmapTextureImage(ctx, texImage, slice); 605 } 606 } 607 else if (rb) { 608 /* unmap ordinary renderbuffer */ 609 ctx->Driver.UnmapRenderbuffer(ctx, rb); 610 } 611 612 srb->Map = NULL; 613 } 614 615 616 /** 617 * Determine what type to use (ubyte vs. float) for span colors for the 618 * given renderbuffer. 619 * See also _swrast_write_rgba_span(). 620 */ 621 static void 622 find_renderbuffer_colortype(struct gl_renderbuffer *rb) 623 { 624 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 625 GLuint rbMaxBits = _mesa_get_format_max_bits(rb->Format); 626 GLenum rbDatatype = _mesa_get_format_datatype(rb->Format); 627 628 if (rbDatatype == GL_UNSIGNED_NORMALIZED && rbMaxBits <= 8) { 629 /* the buffer's values fit in GLubyte values */ 630 srb->ColorType = GL_UNSIGNED_BYTE; 631 } 632 else { 633 /* use floats otherwise */ 634 srb->ColorType = GL_FLOAT; 635 } 636 } 637 638 639 /** 640 * Map the renderbuffers we'll use for tri/line/point rendering. 641 */ 642 void 643 _swrast_map_renderbuffers(struct gl_context *ctx) 644 { 645 struct gl_framebuffer *fb = ctx->DrawBuffer; 646 struct gl_renderbuffer *depthRb, *stencilRb; 647 GLuint buf; 648 649 depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 650 if (depthRb) { 651 /* map depth buffer */ 652 map_attachment(ctx, fb, BUFFER_DEPTH); 653 } 654 655 stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 656 if (stencilRb && stencilRb != depthRb) { 657 /* map stencil buffer */ 658 map_attachment(ctx, fb, BUFFER_STENCIL); 659 } 660 661 for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { 662 if (fb->_ColorDrawBufferIndexes[buf] >= 0) { 663 map_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]); 664 find_renderbuffer_colortype(fb->_ColorDrawBuffers[buf]); 665 } 666 } 667 } 668 669 670 /** 671 * Unmap renderbuffers after rendering. 672 */ 673 void 674 _swrast_unmap_renderbuffers(struct gl_context *ctx) 675 { 676 struct gl_framebuffer *fb = ctx->DrawBuffer; 677 struct gl_renderbuffer *depthRb, *stencilRb; 678 GLuint buf; 679 680 depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; 681 if (depthRb) { 682 /* map depth buffer */ 683 unmap_attachment(ctx, fb, BUFFER_DEPTH); 684 } 685 686 stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; 687 if (stencilRb && stencilRb != depthRb) { 688 /* map stencil buffer */ 689 unmap_attachment(ctx, fb, BUFFER_STENCIL); 690 } 691 692 for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) { 693 if (fb->_ColorDrawBufferIndexes[buf] >= 0) { 694 unmap_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]); 695 } 696 } 697 } 698