framebuffer.c revision 593802c0b0f451299ac2598c6de61e884fb44830
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.1 4 * 5 * Copyright (C) 1999-2006 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 "context.h" 36#include "depthstencil.h" 37#include "mtypes.h" 38#include "fbobject.h" 39#include "framebuffer.h" 40#include "renderbuffer.h" 41 42 43 44/** 45 * Compute/set the _DepthMax field for the given framebuffer. 46 * This value depends on the Z buffer resolution. 47 */ 48static void 49compute_depth_max(struct gl_framebuffer *fb) 50{ 51 if (fb->Visual.depthBits == 0) { 52 /* Special case. Even if we don't have a depth buffer we need 53 * good values for DepthMax for Z vertex transformation purposes 54 * and for per-fragment fog computation. 55 */ 56 fb->_DepthMax = (1 << 16) - 1; 57 } 58 else if (fb->Visual.depthBits < 32) { 59 fb->_DepthMax = (1 << fb->Visual.depthBits) - 1; 60 } 61 else { 62 /* Special case since shift values greater than or equal to the 63 * number of bits in the left hand expression's type are undefined. 64 */ 65 fb->_DepthMax = 0xffffffff; 66 } 67 fb->_DepthMaxF = (GLfloat) fb->_DepthMax; 68 fb->_MRD = 1.0; /* Minimum resolvable depth value, for polygon offset */ 69} 70 71 72/** 73 * Set the framebuffer's _DepthBuffer field, taking care of 74 * reference counts, etc. 75 */ 76static void 77set_depth_renderbuffer(struct gl_framebuffer *fb, 78 struct gl_renderbuffer *rb) 79{ 80 if (fb->_DepthBuffer) { 81 _mesa_dereference_renderbuffer(&fb->_DepthBuffer); 82 } 83 fb->_DepthBuffer = rb; 84 if (rb) { 85 rb->RefCount++; 86 } 87} 88 89 90/** 91 * Set the framebuffer's _StencilBuffer field, taking care of 92 * reference counts, etc. 93 */ 94static void 95set_stencil_renderbuffer(struct gl_framebuffer *fb, 96 struct gl_renderbuffer *rb) 97{ 98 if (fb->_StencilBuffer) { 99 _mesa_dereference_renderbuffer(&fb->_StencilBuffer); 100 } 101 fb->_StencilBuffer = rb; 102 if (rb) { 103 rb->RefCount++; 104 } 105} 106 107 108/** 109 * Create and initialize a gl_framebuffer object. 110 * This is intended for creating _window_system_ framebuffers, not generic 111 * framebuffer objects ala GL_EXT_framebuffer_object. 112 * 113 * \sa _mesa_new_framebuffer 114 */ 115struct gl_framebuffer * 116_mesa_create_framebuffer(const GLvisual *visual) 117{ 118 struct gl_framebuffer *fb = CALLOC_STRUCT(gl_framebuffer); 119 assert(visual); 120 if (fb) { 121 _mesa_initialize_framebuffer(fb, visual); 122 } 123 return fb; 124} 125 126 127/** 128 * Allocate a new gl_framebuffer object. 129 * This is the default function for ctx->Driver.NewFramebuffer(). 130 * This is for allocating user-created framebuffers, not window-system 131 * framebuffers! 132 * \sa _mesa_create_framebuffer 133 */ 134struct gl_framebuffer * 135_mesa_new_framebuffer(GLcontext *ctx, GLuint name) 136{ 137 struct gl_framebuffer *fb; 138 (void) ctx; 139 assert(name != 0); 140 fb = CALLOC_STRUCT(gl_framebuffer); 141 if (fb) { 142 fb->Name = name; 143 fb->RefCount = 1; 144 fb->ColorDrawBuffer[0] = GL_COLOR_ATTACHMENT0_EXT; 145 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_COLOR0; 146 fb->ColorReadBuffer = GL_COLOR_ATTACHMENT0_EXT; 147 fb->_ColorReadBufferIndex = BUFFER_COLOR0; 148 fb->Delete = _mesa_destroy_framebuffer; 149 } 150 return fb; 151} 152 153 154/** 155 * Initialize a gl_framebuffer object. Typically used to initialize 156 * window system-created framebuffers, not user-created framebuffers. 157 * \sa _mesa_create_framebuffer 158 */ 159void 160_mesa_initialize_framebuffer(struct gl_framebuffer *fb, const GLvisual *visual) 161{ 162 assert(fb); 163 assert(visual); 164 165 _mesa_bzero(fb, sizeof(struct gl_framebuffer)); 166 167 _glthread_INIT_MUTEX(fb->Mutex); 168 169 fb->RefCount = 1; 170 171 /* save the visual */ 172 fb->Visual = *visual; 173 174 /* Init glRead/DrawBuffer state */ 175 if (visual->doubleBufferMode) { 176 fb->ColorDrawBuffer[0] = GL_BACK; 177 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_BACK_LEFT; 178 fb->ColorReadBuffer = GL_BACK; 179 fb->_ColorReadBufferIndex = BUFFER_BACK_LEFT; 180 } 181 else { 182 fb->ColorDrawBuffer[0] = GL_FRONT; 183 fb->_ColorDrawBufferMask[0] = BUFFER_BIT_FRONT_LEFT; 184 fb->ColorReadBuffer = GL_FRONT; 185 fb->_ColorReadBufferIndex = BUFFER_FRONT_LEFT; 186 } 187 188 fb->Delete = _mesa_destroy_framebuffer; 189 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 190 191 compute_depth_max(fb); 192} 193 194 195/** 196 * Deallocate buffer and everything attached to it. 197 * Typically called via the gl_framebuffer->Delete() method. 198 */ 199void 200_mesa_destroy_framebuffer(struct gl_framebuffer *fb) 201{ 202 if (fb) { 203 _mesa_free_framebuffer_data(fb); 204 _mesa_free(fb); 205 } 206} 207 208 209/** 210 * Free all the data hanging off the given gl_framebuffer, but don't free 211 * the gl_framebuffer object itself. 212 */ 213void 214_mesa_free_framebuffer_data(struct gl_framebuffer *fb) 215{ 216 GLuint i; 217 218 assert(fb); 219 assert(fb->RefCount == 0); 220 221 _glthread_DESTROY_MUTEX(fb->Mutex); 222 223 for (i = 0; i < BUFFER_COUNT; i++) { 224 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 225 if (att->Renderbuffer) { 226 _mesa_dereference_renderbuffer(&att->Renderbuffer); 227 } 228 if (att->Texture) { 229 /* render to texture */ 230 att->Texture->RefCount--; 231 if (att->Texture->RefCount == 0) { 232 GET_CURRENT_CONTEXT(ctx); 233 if (ctx) { 234 ctx->Driver.DeleteTexture(ctx, att->Texture); 235 } 236 } 237 } 238 att->Type = GL_NONE; 239 att->Renderbuffer = NULL; 240 att->Texture = NULL; 241 } 242 243 /* unbind depth/stencil to decr ref counts */ 244 set_depth_renderbuffer(fb, NULL); 245 set_stencil_renderbuffer(fb, NULL); 246} 247 248 249/** 250 * Decrement the reference count on a framebuffer and delete it when 251 * the refcount hits zero. 252 * Note: we pass the address of a pointer and set it to NULL if we delete it. 253 */ 254void 255_mesa_dereference_framebuffer(struct gl_framebuffer **fb) 256{ 257 GLboolean deleteFlag = GL_FALSE; 258 259 _glthread_LOCK_MUTEX((*fb)->Mutex); 260 { 261 ASSERT((*fb)->RefCount > 0); 262 (*fb)->RefCount--; 263 deleteFlag = ((*fb)->RefCount == 0); 264 } 265 _glthread_UNLOCK_MUTEX((*fb)->Mutex); 266 267 if (deleteFlag) { 268 (*fb)->Delete(*fb); 269 *fb = NULL; 270 } 271} 272 273 274 275 276/** 277 * Resize the given framebuffer's renderbuffers to the new width and height. 278 * This should only be used for window-system framebuffers, not 279 * user-created renderbuffers (i.e. made with GL_EXT_framebuffer_object). 280 * This will typically be called via ctx->Driver.ResizeBuffers() or directly 281 * from a device driver. 282 * 283 * \note it's possible for ctx to be null since a window can be resized 284 * without a currently bound rendering context. 285 */ 286void 287_mesa_resize_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb, 288 GLuint width, GLuint height) 289{ 290 GLuint i; 291 292 /* XXX I think we could check if the size is not changing 293 * and return early. 294 */ 295 296 /* For window system framebuffers, Name is zero */ 297 assert(fb->Name == 0); 298 299 for (i = 0; i < BUFFER_COUNT; i++) { 300 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 301 if (att->Type == GL_RENDERBUFFER_EXT && att->Renderbuffer) { 302 struct gl_renderbuffer *rb = att->Renderbuffer; 303 /* only resize if size is changing */ 304 if (rb->Width != width || rb->Height != height) { 305 /* could just as well pass rb->_ActualFormat here */ 306 if (rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 307 ASSERT(rb->Width == width); 308 ASSERT(rb->Height == height); 309 } 310 else { 311 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 312 /* no return */ 313 } 314 } 315 } 316 } 317 318 if (fb->_DepthBuffer) { 319 struct gl_renderbuffer *rb = fb->_DepthBuffer; 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 if (fb->_StencilBuffer) { 328 struct gl_renderbuffer *rb = fb->_StencilBuffer; 329 if (rb->Width != width || rb->Height != height) { 330 if (!rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height)) { 331 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Resizing framebuffer"); 332 } 333 } 334 } 335 336 fb->Width = width; 337 fb->Height = height; 338 339 if (ctx) { 340 /* update scissor / window bounds */ 341 _mesa_update_draw_buffer_bounds(ctx); 342 /* Signal new buffer state so that swrast will update its clipping 343 * info (the CLIP_BIT flag). 344 */ 345 ctx->NewState |= _NEW_BUFFERS; 346 } 347} 348 349 350/** 351 * Examine all the framebuffer's renderbuffers to update the Width/Height 352 * fields of the framebuffer. If we have renderbuffers with different 353 * sizes, set the framebuffer's width and height to zero. 354 * Note: this is only intended for user-created framebuffers, not 355 * window-system framebuffes. 356 */ 357static void 358update_framebuffer_size(struct gl_framebuffer *fb) 359{ 360 GLboolean haveSize = GL_FALSE; 361 GLuint i; 362 363 /* user-created framebuffers only */ 364 assert(fb->Name); 365 366 for (i = 0; i < BUFFER_COUNT; i++) { 367 struct gl_renderbuffer_attachment *att = &fb->Attachment[i]; 368 const struct gl_renderbuffer *rb = att->Renderbuffer; 369 if (rb) { 370 if (haveSize) { 371 if (rb->Width != fb->Width && rb->Height != fb->Height) { 372 /* size mismatch! */ 373 fb->Width = 0; 374 fb->Height = 0; 375 return; 376 } 377 } 378 else { 379 fb->Width = rb->Width; 380 fb->Height = rb->Height; 381 haveSize = GL_TRUE; 382 } 383 } 384 } 385} 386 387 388/** 389 * Update the context's current drawing buffer's Xmin, Xmax, Ymin, Ymax fields. 390 * These values are computed from the buffer's width and height and 391 * the scissor box, if it's enabled. 392 * \param ctx the GL context. 393 */ 394void 395_mesa_update_draw_buffer_bounds(GLcontext *ctx) 396{ 397 struct gl_framebuffer *buffer = ctx->DrawBuffer; 398 399 if (!buffer) 400 return; 401 402 if (buffer->Name) { 403 /* user-created framebuffer size depends on the renderbuffers */ 404 update_framebuffer_size(buffer); 405 } 406 407 buffer->_Xmin = 0; 408 buffer->_Ymin = 0; 409 buffer->_Xmax = buffer->Width; 410 buffer->_Ymax = buffer->Height; 411 412 if (ctx->Scissor.Enabled) { 413 if (ctx->Scissor.X > buffer->_Xmin) { 414 buffer->_Xmin = ctx->Scissor.X; 415 } 416 if (ctx->Scissor.Y > buffer->_Ymin) { 417 buffer->_Ymin = ctx->Scissor.Y; 418 } 419 if (ctx->Scissor.X + ctx->Scissor.Width < buffer->_Xmax) { 420 buffer->_Xmax = ctx->Scissor.X + ctx->Scissor.Width; 421 } 422 if (ctx->Scissor.Y + ctx->Scissor.Height < buffer->_Ymax) { 423 buffer->_Ymax = ctx->Scissor.Y + ctx->Scissor.Height; 424 } 425 /* finally, check for empty region */ 426 if (buffer->_Xmin > buffer->_Xmax) { 427 buffer->_Xmin = buffer->_Xmax; 428 } 429 if (buffer->_Ymin > buffer->_Ymax) { 430 buffer->_Ymin = buffer->_Ymax; 431 } 432 } 433 434 ASSERT(buffer->_Xmin <= buffer->_Xmax); 435 ASSERT(buffer->_Ymin <= buffer->_Ymax); 436} 437 438 439/** 440 * The glGet queries of the framebuffer red/green/blue size, stencil size, 441 * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can 442 * change depending on the renderbuffer bindings. This function updates 443 * the given framebuffer's Visual from the current renderbuffer bindings. 444 * 445 * This may apply to user-created framebuffers or window system framebuffers. 446 * 447 * Also note: ctx->DrawBuffer->Visual.depthBits might not equal 448 * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. 449 * The former one is used to convert floating point depth values into 450 * integer Z values. 451 */ 452void 453_mesa_update_framebuffer_visual(struct gl_framebuffer *fb) 454{ 455 GLuint i; 456 457 _mesa_bzero(&fb->Visual, sizeof(fb->Visual)); 458 fb->Visual.rgbMode = GL_TRUE; /* assume this */ 459 460#if 0 /* this _might_ be needed */ 461 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 462 /* leave visual fields zero'd */ 463 return; 464 } 465#endif 466 467 /* find first RGB or CI renderbuffer */ 468 for (i = 0; i < BUFFER_COUNT; i++) { 469 if (fb->Attachment[i].Renderbuffer) { 470 const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 471 if (rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB) { 472 fb->Visual.redBits = rb->RedBits; 473 fb->Visual.greenBits = rb->GreenBits; 474 fb->Visual.blueBits = rb->BlueBits; 475 fb->Visual.alphaBits = rb->AlphaBits; 476 fb->Visual.rgbBits = fb->Visual.redBits 477 + fb->Visual.greenBits + fb->Visual.blueBits; 478 fb->Visual.floatMode = GL_FALSE; 479 break; 480 } 481 else if (rb->_BaseFormat == GL_COLOR_INDEX) { 482 fb->Visual.indexBits = rb->IndexBits; 483 fb->Visual.rgbMode = GL_FALSE; 484 break; 485 } 486 } 487 } 488 489 if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { 490 fb->Visual.haveDepthBuffer = GL_TRUE; 491 fb->Visual.depthBits 492 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->DepthBits; 493 } 494 495 if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { 496 fb->Visual.haveStencilBuffer = GL_TRUE; 497 fb->Visual.stencilBits 498 = fb->Attachment[BUFFER_STENCIL].Renderbuffer->StencilBits; 499 } 500 501 if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { 502 fb->Visual.haveAccumBuffer = GL_TRUE; 503 fb->Visual.accumRedBits 504 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->RedBits; 505 fb->Visual.accumGreenBits 506 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->GreenBits; 507 fb->Visual.accumBlueBits 508 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->BlueBits; 509 fb->Visual.accumAlphaBits 510 = fb->Attachment[BUFFER_DEPTH].Renderbuffer->AlphaBits; 511 } 512 513 compute_depth_max(fb); 514} 515 516 517/** 518 * Update the framebuffer's _DepthBuffer field using the renderbuffer 519 * found at the given attachment index. 520 * 521 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 522 * create and install a depth wrapper/adaptor. 523 * 524 * \param fb the framebuffer whose _DepthBuffer field to update 525 * \param attIndex indicates the renderbuffer to possibly wrap 526 */ 527void 528_mesa_update_depth_buffer(GLcontext *ctx, 529 struct gl_framebuffer *fb, 530 GLuint attIndex) 531{ 532 struct gl_renderbuffer *depthRb; 533 534 /* only one possiblity for now */ 535 ASSERT(attIndex == BUFFER_DEPTH); 536 537 depthRb = fb->Attachment[attIndex].Renderbuffer; 538 539 if (depthRb && depthRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { 540 /* The attached depth buffer is a GL_DEPTH_STENCIL renderbuffer */ 541 if (!fb->_DepthBuffer 542 || fb->_DepthBuffer->Wrapped != depthRb 543 || fb->_DepthBuffer->_BaseFormat != GL_DEPTH_COMPONENT) { 544 /* need to update wrapper */ 545 struct gl_renderbuffer *wrapper 546 = _mesa_new_z24_renderbuffer_wrapper(ctx, depthRb); 547 set_depth_renderbuffer(fb, wrapper); 548 ASSERT(fb->_DepthBuffer->Wrapped == depthRb); 549 } 550 } 551 else { 552 /* depthRb may be null */ 553 set_depth_renderbuffer(fb, depthRb); 554 } 555} 556 557 558/** 559 * Update the framebuffer's _StencilBuffer field using the renderbuffer 560 * found at the given attachment index. 561 * 562 * If that attachment points to a combined GL_DEPTH_STENCIL renderbuffer, 563 * create and install a stencil wrapper/adaptor. 564 * 565 * \param fb the framebuffer whose _StencilBuffer field to update 566 * \param attIndex indicates the renderbuffer to possibly wrap 567 */ 568void 569_mesa_update_stencil_buffer(GLcontext *ctx, 570 struct gl_framebuffer *fb, 571 GLuint attIndex) 572{ 573 struct gl_renderbuffer *stencilRb; 574 575 ASSERT(attIndex == BUFFER_DEPTH || 576 attIndex == BUFFER_STENCIL); 577 578 stencilRb = fb->Attachment[attIndex].Renderbuffer; 579 580 if (stencilRb && stencilRb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { 581 /* The attached stencil buffer is a GL_DEPTH_STENCIL renderbuffer */ 582 if (!fb->_StencilBuffer 583 || fb->_StencilBuffer->Wrapped != stencilRb 584 || fb->_StencilBuffer->_BaseFormat != GL_STENCIL_INDEX) { 585 /* need to update wrapper */ 586 struct gl_renderbuffer *wrapper 587 = _mesa_new_s8_renderbuffer_wrapper(ctx, stencilRb); 588 set_stencil_renderbuffer(fb, wrapper); 589 ASSERT(fb->_StencilBuffer->Wrapped == stencilRb); 590 } 591 } 592 else { 593 /* stencilRb may be null */ 594 set_stencil_renderbuffer(fb, stencilRb); 595 } 596} 597 598 599/** 600 * Update the list of color drawing renderbuffer pointers. 601 * Later, when we're rendering we'll loop from 0 to _NumColorDrawBuffers 602 * writing colors. 603 */ 604static void 605update_color_draw_buffers(GLcontext *ctx, struct gl_framebuffer *fb) 606{ 607 GLuint output; 608 609 /* 610 * Fragment programs can write to multiple colorbuffers with 611 * the GL_ARB_draw_buffers extension. 612 */ 613 for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) { 614 GLbitfield bufferMask = fb->_ColorDrawBufferMask[output]; 615 GLuint count = 0; 616 GLuint i; 617 if (!fb->DeletePending) { 618 /* We need the inner loop here because glDrawBuffer(GL_FRONT_AND_BACK) 619 * can specify writing to two or four color buffers (for example). 620 */ 621 for (i = 0; bufferMask && i < BUFFER_COUNT; i++) { 622 const GLuint bufferBit = 1 << i; 623 if (bufferBit & bufferMask) { 624 struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; 625 if (rb) { 626 fb->_ColorDrawBuffers[output][count] = rb; 627 count++; 628 } 629 else { 630 /* 631 _mesa_warning(ctx, "DrawBuffer names a missing buffer!\n"); 632 */ 633 } 634 bufferMask &= ~bufferBit; 635 } 636 } 637 } 638 fb->_NumColorDrawBuffers[output] = count; 639 } 640} 641 642 643/** 644 * Update the color read renderbuffer pointer. 645 * Unlike the DrawBuffer, we can only read from one (or zero) color buffers. 646 */ 647static void 648update_color_read_buffer(GLcontext *ctx, struct gl_framebuffer *fb) 649{ 650 (void) ctx; 651 if (fb->_ColorReadBufferIndex == -1 || fb->DeletePending) { 652 fb->_ColorReadBuffer = NULL; /* legal! */ 653 } 654 else { 655 ASSERT(fb->_ColorReadBufferIndex >= 0); 656 ASSERT(fb->_ColorReadBufferIndex < BUFFER_COUNT); 657 fb->_ColorReadBuffer 658 = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer; 659 } 660} 661 662 663/** 664 * Update state related to the current draw/read framebuffers. 665 * Specifically, update these framebuffer fields: 666 * _ColorDrawBuffers 667 * _NumColorDrawBuffers 668 * _ColorReadBuffer 669 * _DepthBuffer 670 * _StencilBuffer 671 * If the current framebuffer is user-created, make sure it's complete. 672 * The following functions can effect this state: glReadBuffer, 673 * glDrawBuffer, glDrawBuffersARB, glFramebufferRenderbufferEXT, 674 * glRenderbufferStorageEXT. 675 */ 676void 677_mesa_update_framebuffer(GLcontext *ctx) 678{ 679 struct gl_framebuffer *fb = ctx->DrawBuffer; 680 681 /* Completeness only matters for user-created framebuffers */ 682 if (fb->Name != 0) { 683 _mesa_test_framebuffer_completeness(ctx, fb); 684 _mesa_update_framebuffer_visual(fb); 685 } 686 687 update_color_draw_buffers(ctx, fb); 688 update_color_read_buffer(ctx, fb); 689 _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); 690 _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); 691 692 compute_depth_max(fb); 693} 694 695 696/** 697 * Check if the renderbuffer for a read operation (glReadPixels, glCopyPixels, 698 * glCopyTex[Sub]Image, etc. exists. 699 * \param format a basic image format such as GL_RGB, GL_RGBA, GL_ALPHA, 700 * GL_DEPTH_COMPONENT, etc. or GL_COLOR, GL_DEPTH, GL_STENCIL. 701 * \return GL_TRUE if buffer exists, GL_FALSE otherwise 702 */ 703GLboolean 704_mesa_source_buffer_exists(GLcontext *ctx, GLenum format) 705{ 706 const struct gl_renderbuffer_attachment *att 707 = ctx->ReadBuffer->Attachment; 708 709 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 710 return GL_FALSE; 711 } 712 713 switch (format) { 714 case GL_COLOR: 715 case GL_RED: 716 case GL_GREEN: 717 case GL_BLUE: 718 case GL_ALPHA: 719 case GL_LUMINANCE: 720 case GL_LUMINANCE_ALPHA: 721 case GL_INTENSITY: 722 case GL_RGB: 723 case GL_BGR: 724 case GL_RGBA: 725 case GL_BGRA: 726 case GL_ABGR_EXT: 727 case GL_COLOR_INDEX: 728 if (ctx->ReadBuffer->_ColorReadBuffer == NULL) { 729 return GL_FALSE; 730 } 731 /* XXX enable this post 6.5 release: 732 ASSERT(ctx->ReadBuffer->_ColorReadBuffer->RedBits > 0 || 733 ctx->ReadBuffer->_ColorReadBuffer->IndexBits > 0); 734 */ 735 break; 736 case GL_DEPTH: 737 case GL_DEPTH_COMPONENT: 738 if (!att[BUFFER_DEPTH].Renderbuffer) { 739 return GL_FALSE; 740 } 741 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 742 break; 743 case GL_STENCIL: 744 case GL_STENCIL_INDEX: 745 if (!att[BUFFER_STENCIL].Renderbuffer) { 746 return GL_FALSE; 747 } 748 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 749 break; 750 case GL_DEPTH_STENCIL_EXT: 751 if (!att[BUFFER_DEPTH].Renderbuffer || 752 !att[BUFFER_STENCIL].Renderbuffer) { 753 return GL_FALSE; 754 } 755 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 756 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 757 break; 758 default: 759 _mesa_problem(ctx, 760 "Unexpected format 0x%x in _mesa_source_buffer_exists", 761 format); 762 return GL_FALSE; 763 } 764 765 /* OK */ 766 return GL_TRUE; 767} 768 769 770/** 771 * As above, but for drawing operations. 772 * XXX code do some code merging w/ above function. 773 */ 774GLboolean 775_mesa_dest_buffer_exists(GLcontext *ctx, GLenum format) 776{ 777 const struct gl_renderbuffer_attachment *att 778 = ctx->ReadBuffer->Attachment; 779 780 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 781 return GL_FALSE; 782 } 783 784 switch (format) { 785 case GL_COLOR: 786 case GL_RED: 787 case GL_GREEN: 788 case GL_BLUE: 789 case GL_ALPHA: 790 case GL_LUMINANCE: 791 case GL_LUMINANCE_ALPHA: 792 case GL_INTENSITY: 793 case GL_RGB: 794 case GL_BGR: 795 case GL_RGBA: 796 case GL_BGRA: 797 case GL_ABGR_EXT: 798 case GL_COLOR_INDEX: 799 /* nothing special */ 800 /* Could assert that colorbuffer has RedBits > 0 */ 801 break; 802 case GL_DEPTH: 803 case GL_DEPTH_COMPONENT: 804 if (!att[BUFFER_DEPTH].Renderbuffer) { 805 return GL_FALSE; 806 } 807 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 808 break; 809 case GL_STENCIL: 810 case GL_STENCIL_INDEX: 811 if (!att[BUFFER_STENCIL].Renderbuffer) { 812 return GL_FALSE; 813 } 814 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 815 break; 816 case GL_DEPTH_STENCIL_EXT: 817 if (!att[BUFFER_DEPTH].Renderbuffer || 818 !att[BUFFER_STENCIL].Renderbuffer) { 819 return GL_FALSE; 820 } 821 ASSERT(att[BUFFER_DEPTH].Renderbuffer->DepthBits > 0); 822 ASSERT(att[BUFFER_STENCIL].Renderbuffer->StencilBits > 0); 823 break; 824 default: 825 _mesa_problem(ctx, 826 "Unexpected format 0x%x in _mesa_source_buffer_exists", 827 format); 828 return GL_FALSE; 829 } 830 831 /* OK */ 832 return GL_TRUE; 833} 834