framebuffer.c revision 23524e87339b25be75580a2dd2ea296b1741bffb
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.2 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * Functions for allocating/managing framebuffers and renderbuffers. 28 * Also, routines for reading/writing renderbuffer data as ubytes, 29 * ushorts, uints, etc. 30 */ 31 32 33#include "glheader.h" 34#include "imports.h" 35#include "buffers.h" 36#include "context.h" 37#include "depthstencil.h" 38#include "macros.h" 39#include "mtypes.h" 40#include "fbobject.h" 41#include "framebuffer.h" 42#include "renderbuffer.h" 43#include "texobj.h" 44 45 46 47/** 48 * Compute/set the _DepthMax field for the given framebuffer. 49 * This value depends on the Z buffer resolution. 50 */ 51static void 52compute_depth_max(struct gl_framebuffer *fb) 53{ 54 if (fb->Visual.depthBits == 0) { 55 /* Special case. Even if we don't have a depth buffer we need 56 * good values for DepthMax for Z vertex transformation purposes 57 * and for per-fragment fog computation. 58 */ 59 fb->_DepthMax = (1 << 16) - 1; 60 } 61 else if (fb->Visual.depthBits < 32) { 62 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 63 } 64 else { 65 /* Special case since shift values greater than or equal to the 66 * number of bits in the left hand expression's type are undefined. 67 */ 68 fb->_DepthMax = 0xffffffff; 69 } 70 fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 71 72 /* Minimum resolvable depth value, for polygon offset */ 73 fb->_MRD = (GLfloat)1.0 / fb->_DepthMaxF; 74} 75 76 77/** 78 * Create and initialize a gl_framebuffer object. 79 * This is intended for creating _window_system_ framebuffers, not generic 80 * framebuffer objects ala GL_EXT_framebuffer_object. 81 * 82 * \sa _mesa_new_framebuffer 83 */ 84struct gl_framebuffer * 85_mesa_create_framebuffer(const GLvisual *visual) 86{ 87 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 88 assert(visual); 89 if (fb) { 90 _mesa_initialize_framebuffer(fb, visual); 91 } 92 return fb; 93} 94 95 96/** 97 * Allocate a new gl_framebuffer object. 98 * This is the default function for ctx->Driver.NewFramebuffer(). 99 * This is for allocating user-created framebuffers, not window-system 100 * framebuffers! 101 * \sa _mesa_create_framebuffer 102 */ 103struct gl_framebuffer * 104_mesa_new_framebuffer(GLcontext *ctx, GLuint name) 105{ 106 struct gl_framebuffer *fb; 107 (void) ctx; 108 assert(name != 0); 109 fb = CALLOC_STRUCT(gl_framebuffer); 110 if (fb) { 111 fb->Name = name; 112 fb->RefCount = 1; 113 fb->_NumColorDrawBuffers = 1; 114 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 115 fb->_ColorDrawBufferIndexes[0] = BUFFER_COLOR0; 116 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 117 fb->_ColorReadBufferIndex = BUFFER_COLOR0; 118 fb->Delete = _mesa_destroy_framebuffer; 119 } 120 return fb; 121} 122 123 124/** 125 * Initialize a gl_framebuffer object. Typically used to initialize 126 * window system-created framebuffers, not user-created framebuffers. 127 * \sa _mesa_create_framebuffer 128 */ 129void 130_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) 131{ 132 assert(fb); 133 assert(visual); 134 135 _mesa_bzero(fb, sizeof(struct gl_framebuffer)); 136 137 _glthread_INIT_MUTEX(fb->Mutex); 138 139 fb->RefCount = 1; 140 141 /* save the visual */ 142 fb->Visual = *visual; 143 144 /* Init read/draw renderbuffer state */ 145 if (visual->doubleBufferMode) { 146 fb->_NumColorDrawBuffers = 1; 147 fb->ColorDrawBuffer[0] = GL_BACK; 148 fb->_ColorDrawBufferIndexes[0] = BUFFER_BACK_LEFT; 149 fb->ColorReadBuffer = GL_BACK; 150 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 151 } 152 else { 153 fb->_NumColorDrawBuffers = 1; 154 fb->ColorDrawBuffer[0] = GL_FRONT; 155 fb->_ColorDrawBufferIndexes[0] = BUFFER_FRONT_LEFT; 156 fb->ColorReadBuffer = GL_FRONT; 157 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 158 } 159 160 fb->Delete = _mesa_destroy_framebuffer; 161 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 162 163 compute_depth_max(fb); 164} 165 166 167/** 168 * Deallocate buffer and everything attached to it. 169 * Typically called via the gl_framebuffer->Delete() method. 170 */ 171void 172_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 173{ 174 if (fb) { 175 _mesa_free_framebuffer_data(fb); 176 _mesa_free(fb); 177 } 178} 179 180 181/** 182 * Free all the data hanging off the given gl_framebuffer, but don't free 183 * the gl_framebuffer object itself. 184 */ 185void 186_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 187{ 188 GLuint i; 189 190 assert(fb); 191 assert(fb->RefCount == 0); 192 193 _glthread_DESTROY_MUTEX(fb->Mutex); 194 195 for (i = 0; i < BUFFER_COUNT; i++) { 196 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 197 if (att->Renderbuffer) { 198 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); 199 } 200 if (att->Texture) { 201 _mesa_reference_texobj(&att->Texture, NULL); 202 } 203 ASSERT(!att->Renderbuffer); 204 ASSERT(!att->Texture); 205 att->Type = GL_NONE; 206 } 207 208 /* unbind _Depth/_StencilBuffer to decr ref counts */ 209 _mesa_reference_renderbuffer(&fb->_DepthBuffer, NULL); 210 _mesa_reference_renderbuffer(&fb->_StencilBuffer, NULL); 211} 212 213 214/** 215 * Set *ptr to point to fb, with refcounting and locking. 216 */ 217void 218_mesa_reference_framebuffer(struct gl_framebuffer **ptr, 219 struct gl_framebuffer *fb) 220{ 221 assert(ptr); 222 if (*ptr == fb) { 223 /* no change */ 224 return; 225 } 226 if (*ptr) { 227 _mesa_unreference_framebuffer(ptr); 228 } 229 assert(!*ptr); 230 assert(fb); 231 _glthread_LOCK_MUTEX(fb->Mutex); 232 fb->RefCount++; 233 _glthread_UNLOCK_MUTEX(fb->Mutex); 234 *ptr = fb; 235} 236 237 238/** 239 * Undo/remove a reference to a framebuffer object. 240 * Decrement the framebuffer object's reference count and delete it when 241 * the refcount hits zero. 242 * Note: we pass the address of a pointer and set it to NULL. 243 */ 244void 245_mesa_unreference_framebuffer(struct gl_framebuffer **fb) 246{ 247 assert(fb); 248 if (*fb) { 249 GLboolean deleteFlag = GL_FALSE; 250 251 _glthread_LOCK_MUTEX((*fb)->Mutex); 252 ASSERT((*fb)->RefCount > 0); 253 (*fb)->RefCount--; 254 deleteFlag = ((*fb)->RefCount == 0); 255 _glthread_UNLOCK_MUTEX((*fb)->Mutex); 256 257 if (deleteFlag) 258 (*fb)->Delete(*fb); 259 260 *fb = NULL; 261 } 262} 263 264 265 266 267/** 268 * Resize the given framebuffer's renderbuffers to the new width and height. 269 * This should only be used for window-system framebuffers, not 270 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 271 * This will typically be called via ctx->Driver.ResizeBuffers() or directly 272 * from a device driver. 273 * 274 * \note it's possible for ctx to be null since a window can be resized 275 * without a currently bound rendering context. 276 */ 277void 278_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, 279 GLuint width, GLuint height) 280{ 281 GLuint i; 282 283 /* XXX I think we could check if the size is not changing 284 * and return early. 285 */ 286 287 /* For window system framebuffers, Name is zero */ 288 assert(fb->Name == 0); 289 290 for (i = 0; i < BUFFER_COUNT; i++) { 291 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 292 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 293 struct gl_renderbuffer *rb = att->Renderbuffer; 294 /* only resize if size is changing */ 295 if (rb->Width != width || rb->Height != height) { 296 /* could just as well pass rb->_ActualFormat here */ 297 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 298 ASSERT(rb->Width == width); 299 ASSERT(rb->Height == height); 300 } 301 else { 302 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 303 /* no return */ 304 } 305 } 306 } 307 } 308 309 if (fb->_DepthBuffer) { 310 struct gl_renderbuffer *rb = fb->_DepthBuffer; 311 if (rb->Width != width || rb->Height != height) { 312 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 313 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 314 } 315 } 316 } 317 318 if (fb->_StencilBuffer) { 319 struct gl_renderbuffer *rb = fb->_StencilBuffer; 320 if (rb->Width != width || rb->Height != height) { 321 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 322 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 323 } 324 } 325 } 326 327 fb->Width = width; 328 fb->Height = height; 329 330 if (ctx) { 331 /* update scissor / window bounds */ 332 _mesa_update_draw_buffer_bounds(ctx); 333 /* Signal new buffer state so that swrast will update its clipping 334 * info (the CLIP_BIT flag). 335 */ 336 ctx->NewState |= _NEW_BUFFERS; 337 } 338} 339 340 341 342/** 343 * XXX THIS IS OBSOLETE - drivers should take care of detecting window 344 * size changes and act accordingly, likely calling _mesa_resize_framebuffer(). 345 * 346 * GL_MESA_resize_buffers extension. 347 * 348 * When this function is called, we'll ask the window system how large 349 * the current window is. If it's a new size, we'll call the driver's 350 * ResizeBuffers function. The driver will then resize its color buffers 351 * as needed, and maybe call the swrast's routine for reallocating 352 * swrast-managed depth/stencil/accum/etc buffers. 353 * \note This function should only be called through the GL API, not 354 * from device drivers (as was done in the past). 355 */ 356void 357_mesa_resizebuffers( GLcontext *ctx ) 358{ 359 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH( ctx ); 360 361 if (MESA_VERBOSE & VERBOSE_API) 362 _mesa_debug(ctx, "glResizeBuffersMESA\n"); 363 364 if (!ctx->Driver.GetBufferSize) { 365 return; 366 } 367 368 if (ctx->WinSysDrawBuffer) { 369 GLuint newWidth, newHeight; 370 GLframebuffer *buffer = ctx->WinSysDrawBuffer; 371 372 assert(buffer->Name == 0); 373 374 /* ask device driver for size of output buffer */ 375 ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); 376 377 /* see if size of device driver's color buffer (window) has changed */ 378 if (buffer->Width != newWidth || buffer->Height != newHeight) { 379 if (ctx->Driver.ResizeBuffers) 380 ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); 381 } 382 } 383 384 if (ctx->WinSysReadBuffer 385 && ctx->WinSysReadBuffer != ctx->WinSysDrawBuffer) { 386 GLuint newWidth, newHeight; 387 GLframebuffer *buffer = ctx->WinSysReadBuffer; 388 389 assert(buffer->Name == 0); 390 391 /* ask device driver for size of read buffer */ 392 ctx->Driver.GetBufferSize( buffer, &newWidth, &newHeight ); 393 394 /* see if size of device driver's color buffer (window) has changed */ 395 if (buffer->Width != newWidth || buffer->Height != newHeight) { 396 if (ctx->Driver.ResizeBuffers) 397 ctx->Driver.ResizeBuffers(ctx, buffer, newWidth, newHeight ); 398 } 399 } 400 401 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ 402} 403 404 405/* 406 * XXX THIS IS OBSOLETE 407 */ 408void GLAPIENTRY 409_mesa_ResizeBuffersMESA( void ) 410{ 411 GET_CURRENT_CONTEXT(ctx); 412 413 if (ctx->Extensions.MESA_resize_buffers) 414 _mesa_resizebuffers( ctx ); 415} 416 417 418 419/** 420 * Examine all the framebuffer's renderbuffers to update the Width/Height 421 * fields of the framebuffer. If we have renderbuffers with different 422 * sizes, set the framebuffer's width and height to the min size. 423 * Note: this is only intended for user-created framebuffers, not 424 * window-system framebuffes. 425 */ 426static void 427update_framebuffer_size(GLcontext *ctx, struct gl_framebuffer *fb) 428{ 429 GLuint minWidth = ~0, minHeight = ~0; 430 GLuint i; 431 432 /* user-created framebuffers only */ 433 assert(fb->Name); 434 435 for (i = 0; i < BUFFER_COUNT; i++) { 436 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 437 const struct gl_renderbuffer *rb = att->Renderbuffer; 438 if (rb) { 439 minWidth = MIN2(minWidth, rb->Width); 440 minHeight = MIN2(minHeight, rb->Height); 441 } 442 } 443 444 if (minWidth != ~0) { 445 fb->Width = minWidth; 446 fb->Height = minHeight; 447 } 448 else { 449 fb->Width = 0; 450 fb->Height = 0; 451 } 452} 453 454 455/** 456 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 457 * These values are computed from the buffer's width and height and 458 * the scissor box, if it's enabled. 459 * \param ctx the GL context. 460 */ 461void 462_mesa_update_draw_buffer_bounds(GLcontext *ctx) 463{ 464 struct gl_framebuffer *buffer = ctx->DrawBuffer; 465 466 if (!buffer) 467 return; 468 469 if (buffer->Name) { 470 /* user-created framebuffer size depends on the renderbuffers */ 471 update_framebuffer_size(ctx, buffer); 472 } 473 474 buffer->_Xmin = 0; 475 buffer->_Ymin = 0; 476 buffer->_Xmax = buffer->Width; 477 buffer->_Ymax = buffer->Height; 478 479 if (ctx->Scissor.Enabled) { 480 if (ctx->Scissor.X > buffer->_Xmin) { 481 buffer->_Xmin = ctx->Scissor.X; 482 } 483 if (ctx->Scissor.Y > buffer->_Ymin) { 484 buffer->_Ymin = ctx->Scissor.Y; 485 } 486 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { 487 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; 488 } 489 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { 490 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; 491 } 492 /* finally, check for empty region */ 493 if (buffer->_Xmin > buffer->_Xmax) { 494 buffer->_Xmin = buffer->_Xmax; 495 } 496 if (buffer->_Ymin > buffer->_Ymax) { 497 buffer->_Ymin = buffer->_Ymax; 498 } 499 } 500 501 ASSERT(buffer->_Xmin <= buffer->_Xmax); 502 ASSERT(buffer->_Ymin <= buffer->_Ymax); 503} 504 505 506/** 507 * The glGet queries of the framebuffer red/green/blue size, stencil size, 508 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 509 * change depending on the renderbuffer bindings. This function updates 510 * the given framebuffer's Visual from the current renderbuffer bindings. 511 * 512 * This may apply to user-created framebuffers or window system framebuffers. 513 * 514 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 515 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 516 * The former one is used to convert floating point depth values into 517 * integer Z values. 518 */ 519void 520_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) 521{ 522 GLuint i; 523 524 _mesa_bzero(&fb->Visual, sizeof(fb->Visual)); 525 fb->Visual.rgbMode = GL_TRUE; /* assume this */ 526 527#if 0 /* this _might_ be needed */ 528 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 529 /* leave visual fields zero'd */ 530 return; 531 } 532#endif 533 534 /* find first RGB or CI renderbuffer */ 535 for (i = 0; i < BUFFER_COUNT; i++) { 536 if (fb->Attachment[i].Renderbuffer) { 537 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 538 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) { 539 fb->Visual.redBits = rb->RedBits; 540 fb->Visual.greenBits = rb->GreenBits; 541 fb->Visual.blueBits = rb->BlueBits; 542 fb->Visual.alphaBits = rb->AlphaBits; 543 fb->Visual.rgbBits = fb->Visual.redBits 544 + fb->Visual.greenBits + fb->Visual.blueBits; 545 fb->Visual.floatMode = GL_FALSE; 546 fb->Visual.samples = rb->NumSamples; 547 break; 548 } 549 else if (rb->_BaseFormat == GL_COLOR_INDEX) { 550 fb->Visual.indexBits = rb->IndexBits; 551 fb->Visual.rgbMode = GL_FALSE; 552 break; 553 } 554 } 555 } 556 557 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 558 fb->Visual.haveDepthBuffer = GL_TRUE; 559 fb->Visual.depthBits 560 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits; 561 } 562 563 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 564 fb->Visual.haveStencilBuffer = GL_TRUE; 565 fb->Visual.stencilBits 566 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits; 567 } 568 569 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 570 fb->Visual.haveAccumBuffer = GL_TRUE; 571 fb->Visual.accumRedBits 572 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->RedBits; 573 fb->Visual.accumGreenBits 574 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->GreenBits; 575 fb->Visual.accumBlueBits 576 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->BlueBits; 577 fb->Visual.accumAlphaBits 578 = fb->Attachment[BUFFER_ACCUM].Renderbuffer->AlphaBits; 579 } 580 581 compute_depth_max(fb); 582} 583 584 585/** 586 * Update the framebuffer's _DepthBuffer field using the renderbuffer 587 * found at the given attachment index. 588 * 589 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 590 * create and install a depth wrapper/adaptor. 591 * 592 * \param fb the framebuffer whose _DepthBuffer field to update 593 * \param attIndex indicates the renderbuffer to possibly wrap 594 */ 595void 596_mesa_update_depth_buffer(GLcontext *ctx, 597 struct gl_framebuffer *fb, 598 GLuint attIndex) 599{ 600 struct gl_renderbuffer *depthRb; 601 602 /* only one possiblity for now */ 603 ASSERT(attIndex == BUFFER_DEPTH); 604 605 depthRb = fb->Attachment[attIndex].Renderbuffer; 606 607 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { 608 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */ 609 if (!fb->_DepthBuffer 610 || fb->_DepthBuffer->Wrapped != depthRb 611 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) { 612 /* need to update wrapper */ 613 struct gl_renderbuffer *wrapper 614 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); 615 _mesa_reference_renderbuffer(&fb->_DepthBuffer, wrapper); 616 ASSERT(fb->_DepthBuffer->Wrapped == depthRb); 617 } 618 } 619 else { 620 /* depthRb may be null */ 621 _mesa_reference_renderbuffer(&fb->_DepthBuffer, depthRb); 622 } 623} 624 625 626/** 627 * Update the framebuffer's _StencilBuffer field using the renderbuffer 628 * found at the given attachment index. 629 * 630 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 631 * create and install a stencil wrapper/adaptor. 632 * 633 * \param fb the framebuffer whose _StencilBuffer field to update 634 * \param attIndex indicates the renderbuffer to possibly wrap 635 */ 636void 637_mesa_update_stencil_buffer(GLcontext *ctx, 638 struct gl_framebuffer *fb, 639 GLuint attIndex) 640{ 641 struct gl_renderbuffer *stencilRb; 642 643 ASSERT(attIndex == BUFFER_DEPTH || 644 attIndex == BUFFER_STENCIL); 645 646 stencilRb = fb->Attachment[attIndex].Renderbuffer; 647 648 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { 649 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */ 650 if (!fb->_StencilBuffer 651 || fb->_StencilBuffer->Wrapped != stencilRb 652 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) { 653 /* need to update wrapper */ 654 struct gl_renderbuffer *wrapper 655 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); 656 _mesa_reference_renderbuffer(&fb->_StencilBuffer, wrapper); 657 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb); 658 } 659 } 660 else { 661 /* stencilRb may be null */ 662 _mesa_reference_renderbuffer(&fb->_StencilBuffer, stencilRb); 663 } 664} 665 666 667/* 668 * Example DrawBuffers scenarios: 669 * 670 * 1. glDrawBuffer(GL_FRONT_AND_BACK), fixed-func or shader writes to 671 * "gl_FragColor" or program writes to the "result.color" register: 672 * 673 * fragment color output renderbuffer 674 * --------------------- --------------- 675 * color[0] Front, Back 676 * 677 * 678 * 2. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]), shader writes to 679 * gl_FragData[i] or program writes to result.color[i] registers: 680 * 681 * fragment color output renderbuffer 682 * --------------------- --------------- 683 * color[0] Front 684 * color[1] Aux0 685 * color[3] Aux1 686 * 687 * 688 * 3. glDrawBuffers(3, [GL_FRONT, GL_AUX0, GL_AUX1]) and shader writes to 689 * gl_FragColor, or fixed function: 690 * 691 * fragment color output renderbuffer 692 * --------------------- --------------- 693 * color[0] Front, Aux0, Aux1 694 * 695 * 696 * In either case, the list of renderbuffers is stored in the 697 * framebuffer->_ColorDrawBuffers[] array and 698 * framebuffer->_NumColorDrawBuffers indicates the number of buffers. 699 * The renderer (like swrast) has to look at the current fragment shader 700 * to see if it writes to gl_FragColor vs. gl_FragData[i] to determine 701 * how to map color outputs to renderbuffers. 702 * 703 * Note that these two calls are equivalent (for fixed function fragment 704 * shading anyway): 705 * a) glDrawBuffer(GL_FRONT_AND_BACK); (assuming non-stereo framebuffer) 706 * b) glDrawBuffers(2, [GL_FRONT_LEFT, GL_BACK_LEFT]); 707 */ 708 709 710 711 712/** 713 * Update the (derived) list of color drawing renderbuffer pointers. 714 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 715 * writing colors. 716 */ 717static void 718update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb) 719{ 720 GLuint output; 721 722 /* set 0th buffer to NULL now in case _NumColorDrawBuffers is zero */ 723 fb->_ColorDrawBuffers[0] = NULL; 724 725 for (output = 0; output < fb->_NumColorDrawBuffers; output++) { 726 GLint buf = fb->_ColorDrawBufferIndexes[output]; 727 if (buf >= 0) { 728 fb->_ColorDrawBuffers[output] = fb->Attachment[buf].Renderbuffer; 729 } 730 else { 731 fb->_ColorDrawBuffers[output] = NULL; 732 } 733 } 734} 735 736 737/** 738 * Update the (derived) color read renderbuffer pointer. 739 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 740 */ 741static void 742update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb) 743{ 744 (void) ctx; 745 if (fb->_ColorReadBufferIndex == -1 || 746 fb->DeletePending || 747 fb->Width == 0 || 748 fb->Height == 0) { 749 fb->_ColorReadBuffer = NULL; /* legal! */ 750 } 751 else { 752 ASSERT(fb->_ColorReadBufferIndex >= 0); 753 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 754 fb->_ColorReadBuffer 755 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 756 } 757} 758 759 760/** 761 * Update a gl_framebuffer's derived state. 762 * 763 * Specifically, update these framebuffer fields: 764 * _ColorDrawBuffers 765 * _NumColorDrawBuffers 766 * _ColorReadBuffer 767 * _DepthBuffer 768 * _StencilBuffer 769 * 770 * If the framebuffer is user-created, make sure it's complete. 771 * 772 * The following functions (at least) can effect framebuffer state: 773 * glReadBuffer, glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 774 * glRenderbufferStorageEXT. 775 */ 776static void 777update_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) 778{ 779 if (fb->Name == 0) { 780 /* This is a window-system framebuffer */ 781 /* Need to update the FB's GL_DRAW_BUFFER state to match the 782 * context state (GL_READ_BUFFER too). 783 */ 784 if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { 785 _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, 786 ctx->Color.DrawBuffer, NULL); 787 } 788 if (fb->ColorReadBuffer != ctx->Pixel.ReadBuffer) { 789 790 } 791 } 792 else { 793 /* This is a user-created framebuffer. 794 * Completeness only matters for user-created framebuffers. 795 */ 796 _mesa_test_framebuffer_completeness(ctx, fb); 797 _mesa_update_framebuffer_visual(fb); 798 } 799 800 /* Strictly speaking, we don't need to update the draw-state 801 * if this FB is bound as ctx->ReadBuffer (and conversely, the 802 * read-state if this FB is bound as ctx->DrawBuffer), but no 803 * harm. 804 */ 805 update_color_draw_buffers(ctx, fb); 806 update_color_read_buffer(ctx, fb); 807 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); 808 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); 809 810 compute_depth_max(fb); 811} 812 813 814/** 815 * Update state related to the current draw/read framebuffers. 816 */ 817void 818_mesa_update_framebuffer(GLcontext *ctx) 819{ 820 struct gl_framebuffer *drawFb = ctx->DrawBuffer; 821 struct gl_framebuffer *readFb = ctx->ReadBuffer; 822 823 update_framebuffer(ctx, drawFb); 824 if (readFb != drawFb) 825 update_framebuffer(ctx, readFb); 826} 827 828 829/** 830 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 831 * glCopyTex[Sub]Image, etc. exists. 832 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 833 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 834 * \return GL_TRUE if buffer exists, GL_FALSE otherwise 835 */ 836GLboolean 837_mesa_source_buffer_exists(GLcontext *ctx, GLenum format) 838{ 839 const struct gl_renderbuffer_attachment *att 840 = ctx->ReadBuffer->Attachment; 841 842 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 843 return GL_FALSE; 844 } 845 846 switch (format) { 847 case GL_COLOR: 848 case GL_RED: 849 case GL_GREEN: 850 case GL_BLUE: 851 case GL_ALPHA: 852 case GL_LUMINANCE: 853 case GL_LUMINANCE_ALPHA: 854 case GL_INTENSITY: 855 case GL_RGB: 856 case GL_BGR: 857 case GL_RGBA: 858 case GL_BGRA: 859 case GL_ABGR_EXT: 860 case GL_COLOR_INDEX: 861 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) { 862 return GL_FALSE; 863 } 864 /* XXX enable this post 6.5 release: 865 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 || 866 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0); 867 */ 868 break; 869 case GL_DEPTH: 870 case GL_DEPTH_COMPONENT: 871 if (!att[BUFFER_DEPTH].Renderbuffer) { 872 return GL_FALSE; 873 } 874 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 875 break; 876 case GL_STENCIL: 877 case GL_STENCIL_INDEX: 878 if (!att[BUFFER_STENCIL].Renderbuffer) { 879 return GL_FALSE; 880 } 881 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 882 break; 883 case GL_DEPTH_STENCIL_EXT: 884 if (!att[BUFFER_DEPTH].Renderbuffer || 885 !att[BUFFER_STENCIL].Renderbuffer) { 886 return GL_FALSE; 887 } 888 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 889 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 890 break; 891 default: 892 _mesa_problem(ctx, 893 "Unexpected format 0x%x in _mesa_source_buffer_exists", 894 format); 895 return GL_FALSE; 896 } 897 898 /* OK */ 899 return GL_TRUE; 900} 901 902 903/** 904 * As above, but for drawing operations. 905 * XXX code do some code merging w/ above function. 906 */ 907GLboolean 908_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) 909{ 910 const struct gl_renderbuffer_attachment *att 911 = ctx->ReadBuffer->Attachment; 912 913 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 914 return GL_FALSE; 915 } 916 917 switch (format) { 918 case GL_COLOR: 919 case GL_RED: 920 case GL_GREEN: 921 case GL_BLUE: 922 case GL_ALPHA: 923 case GL_LUMINANCE: 924 case GL_LUMINANCE_ALPHA: 925 case GL_INTENSITY: 926 case GL_RGB: 927 case GL_BGR: 928 case GL_RGBA: 929 case GL_BGRA: 930 case GL_ABGR_EXT: 931 case GL_COLOR_INDEX: 932 /* nothing special */ 933 /* Could assert that colorbuffer has RedBits > 0 */ 934 break; 935 case GL_DEPTH: 936 case GL_DEPTH_COMPONENT: 937 if (!att[BUFFER_DEPTH].Renderbuffer) { 938 return GL_FALSE; 939 } 940 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 941 break; 942 case GL_STENCIL: 943 case GL_STENCIL_INDEX: 944 if (!att[BUFFER_STENCIL].Renderbuffer) { 945 return GL_FALSE; 946 } 947 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 948 break; 949 case GL_DEPTH_STENCIL_EXT: 950 if (!att[BUFFER_DEPTH].Renderbuffer || 951 !att[BUFFER_STENCIL].Renderbuffer) { 952 return GL_FALSE; 953 } 954 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 955 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 956 break; 957 default: 958 _mesa_problem(ctx, 959 "Unexpected format 0x%x in _mesa_source_buffer_exists", 960 format); 961 return GL_FALSE; 962 } 963 964 /* OK */ 965 return GL_TRUE; 966} 967