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