fbobject.c revision 5fec84ad0446d4d6d842f5cf740f9787678113be
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/* 28 * GL_EXT/ARB_framebuffer_object extensions 29 * 30 * Authors: 31 * Brian Paul 32 */ 33 34 35#include "buffers.h" 36#include "context.h" 37#include "fbobject.h" 38#include "framebuffer.h" 39#include "hash.h" 40#include "macros.h" 41#include "mipmap.h" 42#include "renderbuffer.h" 43#include "state.h" 44#include "teximage.h" 45#include "texobj.h" 46#include "texstore.h" 47 48 49/** 50 * Notes: 51 * 52 * None of the GL_EXT_framebuffer_object functions are compiled into 53 * display lists. 54 */ 55 56 57 58/* 59 * When glGenRender/FramebuffersEXT() is called we insert pointers to 60 * these placeholder objects into the hash table. 61 * Later, when the object ID is first bound, we replace the placeholder 62 * with the real frame/renderbuffer. 63 */ 64static struct gl_framebuffer DummyFramebuffer; 65static struct gl_renderbuffer DummyRenderbuffer; 66 67 68#define IS_CUBE_FACE(TARGET) \ 69 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 70 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 71 72 73static void 74delete_dummy_renderbuffer(struct gl_renderbuffer *rb) 75{ 76 /* no op */ 77} 78 79static void 80delete_dummy_framebuffer(struct gl_framebuffer *fb) 81{ 82 /* no op */ 83} 84 85 86void 87_mesa_init_fbobjects(GLcontext *ctx) 88{ 89 DummyFramebuffer.Delete = delete_dummy_framebuffer; 90 DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 91} 92 93 94/** 95 * Helper routine for getting a gl_renderbuffer. 96 */ 97struct gl_renderbuffer * 98_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) 99{ 100 struct gl_renderbuffer *rb; 101 102 if (id == 0) 103 return NULL; 104 105 rb = (struct gl_renderbuffer *) 106 _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 107 return rb; 108} 109 110 111/** 112 * Helper routine for getting a gl_framebuffer. 113 */ 114struct gl_framebuffer * 115_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) 116{ 117 struct gl_framebuffer *fb; 118 119 if (id == 0) 120 return NULL; 121 122 fb = (struct gl_framebuffer *) 123 _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 124 return fb; 125} 126 127 128/** 129 * Mark the given framebuffer as invalid. This will force the 130 * test for framebuffer completeness to be done before the framebuffer 131 * is used. 132 */ 133static void 134invalidate_framebuffer(struct gl_framebuffer *fb) 135{ 136 fb->_Status = 0; /* "indeterminate" */ 137} 138 139 140/** 141 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 142 * gl_renderbuffer_attachment object. 143 * If \p attachment is GL_DEPTH_STENCIL_ATTACHMENT, return a pointer to 144 * the depth buffer attachment point. 145 */ 146struct gl_renderbuffer_attachment * 147_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, 148 GLenum attachment) 149{ 150 GLuint i; 151 152 switch (attachment) { 153 case GL_COLOR_ATTACHMENT0_EXT: 154 case GL_COLOR_ATTACHMENT1_EXT: 155 case GL_COLOR_ATTACHMENT2_EXT: 156 case GL_COLOR_ATTACHMENT3_EXT: 157 case GL_COLOR_ATTACHMENT4_EXT: 158 case GL_COLOR_ATTACHMENT5_EXT: 159 case GL_COLOR_ATTACHMENT6_EXT: 160 case GL_COLOR_ATTACHMENT7_EXT: 161 case GL_COLOR_ATTACHMENT8_EXT: 162 case GL_COLOR_ATTACHMENT9_EXT: 163 case GL_COLOR_ATTACHMENT10_EXT: 164 case GL_COLOR_ATTACHMENT11_EXT: 165 case GL_COLOR_ATTACHMENT12_EXT: 166 case GL_COLOR_ATTACHMENT13_EXT: 167 case GL_COLOR_ATTACHMENT14_EXT: 168 case GL_COLOR_ATTACHMENT15_EXT: 169 i = attachment - GL_COLOR_ATTACHMENT0_EXT; 170 if (i >= ctx->Const.MaxColorAttachments) { 171 return NULL; 172 } 173 return &fb->Attachment[BUFFER_COLOR0 + i]; 174 case GL_DEPTH_STENCIL_ATTACHMENT: 175 /* fall-through */ 176 case GL_DEPTH_ATTACHMENT_EXT: 177 return &fb->Attachment[BUFFER_DEPTH]; 178 case GL_STENCIL_ATTACHMENT_EXT: 179 return &fb->Attachment[BUFFER_STENCIL]; 180 default: 181 return NULL; 182 } 183} 184 185 186/** 187 * Remove any texture or renderbuffer attached to the given attachment 188 * point. Update reference counts, etc. 189 */ 190void 191_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) 192{ 193 if (att->Type == GL_TEXTURE) { 194 ASSERT(att->Texture); 195 if (ctx->Driver.FinishRenderTexture) { 196 /* tell driver we're done rendering to this texobj */ 197 ctx->Driver.FinishRenderTexture(ctx, att); 198 } 199 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 200 ASSERT(!att->Texture); 201 } 202 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 203 ASSERT(!att->Texture); 204 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 205 ASSERT(!att->Renderbuffer); 206 } 207 att->Type = GL_NONE; 208 att->Complete = GL_TRUE; 209} 210 211 212/** 213 * Bind a texture object to an attachment point. 214 * The previous binding, if any, will be removed first. 215 */ 216void 217_mesa_set_texture_attachment(GLcontext *ctx, 218 struct gl_framebuffer *fb, 219 struct gl_renderbuffer_attachment *att, 220 struct gl_texture_object *texObj, 221 GLenum texTarget, GLuint level, GLuint zoffset) 222{ 223 if (att->Texture == texObj) { 224 /* re-attaching same texture */ 225 ASSERT(att->Type == GL_TEXTURE); 226 } 227 else { 228 /* new attachment */ 229 _mesa_remove_attachment(ctx, att); 230 att->Type = GL_TEXTURE; 231 assert(!att->Texture); 232 _mesa_reference_texobj(&att->Texture, texObj); 233 } 234 235 /* always update these fields */ 236 att->TextureLevel = level; 237 if (IS_CUBE_FACE(texTarget)) { 238 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 239 } 240 else { 241 att->CubeMapFace = 0; 242 } 243 att->Zoffset = zoffset; 244 att->Complete = GL_FALSE; 245 246 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 247 ctx->Driver.RenderTexture(ctx, fb, att); 248 } 249 250 invalidate_framebuffer(fb); 251} 252 253 254/** 255 * Bind a renderbuffer to an attachment point. 256 * The previous binding, if any, will be removed first. 257 */ 258void 259_mesa_set_renderbuffer_attachment(GLcontext *ctx, 260 struct gl_renderbuffer_attachment *att, 261 struct gl_renderbuffer *rb) 262{ 263 /* XXX check if re-doing same attachment, exit early */ 264 _mesa_remove_attachment(ctx, att); 265 att->Type = GL_RENDERBUFFER_EXT; 266 att->Texture = NULL; /* just to be safe */ 267 att->Complete = GL_FALSE; 268 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 269} 270 271 272/** 273 * Fallback for ctx->Driver.FramebufferRenderbuffer() 274 * Attach a renderbuffer object to a framebuffer object. 275 */ 276void 277_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, 278 GLenum attachment, struct gl_renderbuffer *rb) 279{ 280 struct gl_renderbuffer_attachment *att; 281 282 _glthread_LOCK_MUTEX(fb->Mutex); 283 284 att = _mesa_get_attachment(ctx, fb, attachment); 285 ASSERT(att); 286 if (rb) { 287 _mesa_set_renderbuffer_attachment(ctx, att, rb); 288 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 289 /* do stencil attachment here (depth already done above) */ 290 att = _mesa_get_attachment(ctx, fb, GL_STENCIL_ATTACHMENT_EXT); 291 assert(att); 292 _mesa_set_renderbuffer_attachment(ctx, att, rb); 293 } 294 } 295 else { 296 _mesa_remove_attachment(ctx, att); 297 } 298 299 invalidate_framebuffer(fb); 300 301 _glthread_UNLOCK_MUTEX(fb->Mutex); 302} 303 304 305/** 306 * Test if an attachment point is complete and update its Complete field. 307 * \param format if GL_COLOR, this is a color attachment point, 308 * if GL_DEPTH, this is a depth component attachment point, 309 * if GL_STENCIL, this is a stencil component attachment point. 310 */ 311static void 312test_attachment_completeness(const GLcontext *ctx, GLenum format, 313 struct gl_renderbuffer_attachment *att) 314{ 315 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 316 317 /* assume complete */ 318 att->Complete = GL_TRUE; 319 320 /* Look for reasons why the attachment might be incomplete */ 321 if (att->Type == GL_TEXTURE) { 322 const struct gl_texture_object *texObj = att->Texture; 323 struct gl_texture_image *texImage; 324 325 if (!texObj) { 326 att->Complete = GL_FALSE; 327 return; 328 } 329 330 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 331 if (!texImage) { 332 att->Complete = GL_FALSE; 333 return; 334 } 335 if (texImage->Width < 1 || texImage->Height < 1) { 336 att->Complete = GL_FALSE; 337 return; 338 } 339 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { 340 att->Complete = GL_FALSE; 341 return; 342 } 343 344 if (format == GL_COLOR) { 345 if (texImage->TexFormat->BaseFormat != GL_RGB && 346 texImage->TexFormat->BaseFormat != GL_RGBA) { 347 att->Complete = GL_FALSE; 348 return; 349 } 350 } 351 else if (format == GL_DEPTH) { 352 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { 353 /* OK */ 354 } 355 else if (ctx->Extensions.EXT_packed_depth_stencil && 356 texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) { 357 /* OK */ 358 } 359 else { 360 att->Complete = GL_FALSE; 361 return; 362 } 363 } 364 else { 365 /* no such thing as stencil textures */ 366 att->Complete = GL_FALSE; 367 return; 368 } 369 } 370 else if (att->Type == GL_RENDERBUFFER_EXT) { 371 ASSERT(att->Renderbuffer); 372 if (!att->Renderbuffer->InternalFormat || 373 att->Renderbuffer->Width < 1 || 374 att->Renderbuffer->Height < 1) { 375 att->Complete = GL_FALSE; 376 return; 377 } 378 if (format == GL_COLOR) { 379 if (att->Renderbuffer->_BaseFormat != GL_RGB && 380 att->Renderbuffer->_BaseFormat != GL_RGBA) { 381 ASSERT(att->Renderbuffer->RedBits); 382 ASSERT(att->Renderbuffer->GreenBits); 383 ASSERT(att->Renderbuffer->BlueBits); 384 att->Complete = GL_FALSE; 385 return; 386 } 387 } 388 else if (format == GL_DEPTH) { 389 ASSERT(att->Renderbuffer->DepthBits); 390 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { 391 /* OK */ 392 } 393 else if (ctx->Extensions.EXT_packed_depth_stencil && 394 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 395 /* OK */ 396 } 397 else { 398 att->Complete = GL_FALSE; 399 return; 400 } 401 } 402 else { 403 assert(format == GL_STENCIL); 404 ASSERT(att->Renderbuffer->StencilBits); 405 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { 406 /* OK */ 407 } 408 else if (ctx->Extensions.EXT_packed_depth_stencil && 409 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 410 /* OK */ 411 } 412 else { 413 att->Complete = GL_FALSE; 414 return; 415 } 416 } 417 } 418 else { 419 ASSERT(att->Type == GL_NONE); 420 /* complete */ 421 return; 422 } 423} 424 425 426/** 427 * Helpful for debugging 428 */ 429static void 430fbo_incomplete(const char *msg, int index) 431{ 432 (void) msg; 433 (void) index; 434 /* 435 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 436 */ 437} 438 439 440/** 441 * Test if the given framebuffer object is complete and update its 442 * Status field with the results. 443 * Calls the ctx->Driver.ValidateFramebuffer() function to allow the 444 * driver to make hardware-specific validation/completeness checks. 445 * Also update the framebuffer's Width and Height fields if the 446 * framebuffer is complete. 447 */ 448void 449_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) 450{ 451 GLuint numImages; 452 GLenum intFormat = GL_NONE; /* color buffers' internal format */ 453 GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0; 454 GLint numSamples = -1; 455 GLint i; 456 GLuint j; 457 458 assert(fb->Name != 0); 459 460 numImages = 0; 461 fb->Width = 0; 462 fb->Height = 0; 463 464 /* Start at -2 to more easily loop over all attachment points. 465 * -2: depth buffer 466 * -1: stencil buffer 467 * >=0: color buffer 468 */ 469 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 470 struct gl_renderbuffer_attachment *att; 471 GLenum f; 472 473 /* 474 * XXX for ARB_fbo, only check color buffers that are named by 475 * GL_READ_BUFFER and GL_DRAW_BUFFERi. 476 */ 477 478 /* check for attachment completeness 479 */ 480 if (i == -2) { 481 att = &fb->Attachment[BUFFER_DEPTH]; 482 test_attachment_completeness(ctx, GL_DEPTH, att); 483 if (!att->Complete) { 484 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 485 fbo_incomplete("depth attachment incomplete", -1); 486 return; 487 } 488 } 489 else if (i == -1) { 490 att = &fb->Attachment[BUFFER_STENCIL]; 491 test_attachment_completeness(ctx, GL_STENCIL, att); 492 if (!att->Complete) { 493 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 494 fbo_incomplete("stencil attachment incomplete", -1); 495 return; 496 } 497 } 498 else { 499 att = &fb->Attachment[BUFFER_COLOR0 + i]; 500 test_attachment_completeness(ctx, GL_COLOR, att); 501 if (!att->Complete) { 502 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 503 fbo_incomplete("color attachment incomplete", i); 504 return; 505 } 506 } 507 508 /* get width, height, format of the renderbuffer/texture 509 */ 510 if (att->Type == GL_TEXTURE) { 511 const struct gl_texture_image *texImg 512 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 513 minWidth = MIN2(minWidth, texImg->Width); 514 maxWidth = MAX2(maxWidth, texImg->Width); 515 minHeight = MIN2(minHeight, texImg->Height); 516 maxHeight = MAX2(maxHeight, texImg->Height); 517 f = texImg->_BaseFormat; 518 numImages++; 519 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT 520 && f != GL_DEPTH_STENCIL_EXT) { 521 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 522 fbo_incomplete("texture attachment incomplete", -1); 523 return; 524 } 525 } 526 else if (att->Type == GL_RENDERBUFFER_EXT) { 527 minWidth = MIN2(minWidth, att->Renderbuffer->Width); 528 maxWidth = MAX2(minWidth, att->Renderbuffer->Width); 529 minHeight = MIN2(minHeight, att->Renderbuffer->Height); 530 maxHeight = MAX2(minHeight, att->Renderbuffer->Height); 531 f = att->Renderbuffer->InternalFormat; 532 numImages++; 533 } 534 else { 535 assert(att->Type == GL_NONE); 536 continue; 537 } 538 539 if (numSamples < 0) { 540 /* first buffer */ 541 numSamples = att->Renderbuffer->NumSamples; 542 } 543 544 /* Error-check width, height, format, samples 545 */ 546 if (numImages == 1) { 547 /* save format, num samples */ 548 if (i >= 0) { 549 intFormat = f; 550 } 551 } 552 else { 553 if (!ctx->Extensions.ARB_framebuffer_object) { 554 /* check that width, height, format are same */ 555 if (minWidth != maxWidth || minHeight != maxHeight) { 556 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 557 fbo_incomplete("width or height mismatch", -1); 558 return; 559 } 560 /* check that all color buffer have same format */ 561 if (intFormat != GL_NONE && f != intFormat) { 562 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 563 fbo_incomplete("format mismatch", -1); 564 return; 565 } 566 } 567 if (att->Renderbuffer && 568 att->Renderbuffer->NumSamples != numSamples) { 569 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; 570 fbo_incomplete("inconsistant number of samples", i); 571 return; 572 } 573 574 } 575 } 576 577#ifndef FEATURE_OES_framebuffer_object 578 /* Check that all DrawBuffers are present */ 579 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 580 if (fb->ColorDrawBuffer[j] != GL_NONE) { 581 const struct gl_renderbuffer_attachment *att 582 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); 583 assert(att); 584 if (att->Type == GL_NONE) { 585 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 586 fbo_incomplete("missing drawbuffer", j); 587 return; 588 } 589 } 590 } 591 592 /* Check that the ReadBuffer is present */ 593 if (fb->ColorReadBuffer != GL_NONE) { 594 const struct gl_renderbuffer_attachment *att 595 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); 596 assert(att); 597 if (att->Type == GL_NONE) { 598 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 599 fbo_incomplete("missing readbuffer", -1); 600 return; 601 } 602 } 603#endif 604 605 if (numImages == 0) { 606 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 607 fbo_incomplete("no attachments", -1); 608 return; 609 } 610 611 /* Provisionally set status = COMPLETE ... */ 612 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 613 614 /* ... but the driver may say the FB is incomplete. 615 * Drivers will most likely set the status to GL_FRAMEBUFFER_UNSUPPORTED 616 * if anything. 617 */ 618 if (ctx->Driver.ValidateFramebuffer) { 619 ctx->Driver.ValidateFramebuffer(ctx, fb); 620 if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 621 fbo_incomplete("driver marked FBO as incomplete", -1); 622 } 623 } 624 625 if (fb->_Status == GL_FRAMEBUFFER_COMPLETE_EXT) { 626 /* 627 * Note that if ARB_framebuffer_object is supported and the attached 628 * renderbuffers/textures are different sizes, the framebuffer 629 * width/height will be set to the smallest width/height. 630 */ 631 fb->Width = minWidth; 632 fb->Height = minHeight; 633 634 /* finally, update the visual info for the framebuffer */ 635 _mesa_update_framebuffer_visual(fb); 636 } 637} 638 639 640GLboolean GLAPIENTRY 641_mesa_IsRenderbufferEXT(GLuint renderbuffer) 642{ 643 GET_CURRENT_CONTEXT(ctx); 644 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 645 if (renderbuffer) { 646 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 647 if (rb != NULL && rb != &DummyRenderbuffer) 648 return GL_TRUE; 649 } 650 return GL_FALSE; 651} 652 653 654void GLAPIENTRY 655_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 656{ 657 struct gl_renderbuffer *newRb; 658 GET_CURRENT_CONTEXT(ctx); 659 660 ASSERT_OUTSIDE_BEGIN_END(ctx); 661 662 if (target != GL_RENDERBUFFER_EXT) { 663 _mesa_error(ctx, GL_INVALID_ENUM, 664 "glBindRenderbufferEXT(target)"); 665 return; 666 } 667 668 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 669 /* The above doesn't fully flush the drivers in the way that a 670 * glFlush does, but that is required here: 671 */ 672 if (ctx->Driver.Flush) 673 ctx->Driver.Flush(ctx); 674 675 676 if (renderbuffer) { 677 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 678 if (newRb == &DummyRenderbuffer) { 679 /* ID was reserved, but no real renderbuffer object made yet */ 680 newRb = NULL; 681 } 682 else if (!newRb && ctx->Extensions.ARB_framebuffer_object) { 683 /* All RB IDs must be Gen'd */ 684 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)"); 685 return; 686 } 687 688 if (!newRb) { 689 /* create new renderbuffer object */ 690 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 691 if (!newRb) { 692 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 693 return; 694 } 695 ASSERT(newRb->AllocStorage); 696 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 697 newRb->RefCount = 1; /* referenced by hash table */ 698 } 699 } 700 else { 701 newRb = NULL; 702 } 703 704 ASSERT(newRb != &DummyRenderbuffer); 705 706 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 707} 708 709 710/** 711 * If the given renderbuffer is anywhere attached to the framebuffer, detach 712 * the renderbuffer. 713 * This is used when a renderbuffer object is deleted. 714 * The spec calls for unbinding. 715 */ 716static void 717detach_renderbuffer(GLcontext *ctx, 718 struct gl_framebuffer *fb, 719 struct gl_renderbuffer *rb) 720{ 721 GLuint i; 722 for (i = 0; i < BUFFER_COUNT; i++) { 723 if (fb->Attachment[i].Renderbuffer == rb) { 724 _mesa_remove_attachment(ctx, &fb->Attachment[i]); 725 } 726 } 727 invalidate_framebuffer(fb); 728} 729 730 731void GLAPIENTRY 732_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 733{ 734 GLint i; 735 GET_CURRENT_CONTEXT(ctx); 736 737 ASSERT_OUTSIDE_BEGIN_END(ctx); 738 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 739 740 for (i = 0; i < n; i++) { 741 if (renderbuffers[i] > 0) { 742 struct gl_renderbuffer *rb; 743 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 744 if (rb) { 745 /* check if deleting currently bound renderbuffer object */ 746 if (rb == ctx->CurrentRenderbuffer) { 747 /* bind default */ 748 ASSERT(rb->RefCount >= 2); 749 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 750 } 751 752 if (ctx->DrawBuffer->Name) { 753 detach_renderbuffer(ctx, ctx->DrawBuffer, rb); 754 } 755 if (ctx->ReadBuffer->Name && ctx->ReadBuffer != ctx->DrawBuffer) { 756 detach_renderbuffer(ctx, ctx->ReadBuffer, rb); 757 } 758 759 /* Remove from hash table immediately, to free the ID. 760 * But the object will not be freed until it's no longer 761 * referenced anywhere else. 762 */ 763 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 764 765 if (rb != &DummyRenderbuffer) { 766 /* no longer referenced by hash table */ 767 _mesa_reference_renderbuffer(&rb, NULL); 768 } 769 } 770 } 771 } 772} 773 774 775void GLAPIENTRY 776_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 777{ 778 GET_CURRENT_CONTEXT(ctx); 779 GLuint first; 780 GLint i; 781 782 ASSERT_OUTSIDE_BEGIN_END(ctx); 783 784 if (n < 0) { 785 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 786 return; 787 } 788 789 if (!renderbuffers) 790 return; 791 792 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 793 794 for (i = 0; i < n; i++) { 795 GLuint name = first + i; 796 renderbuffers[i] = name; 797 /* insert dummy placeholder into hash table */ 798 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 799 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 800 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 801 } 802} 803 804 805/** 806 * Given an internal format token for a render buffer, return the 807 * corresponding base format. 808 * This is very similar to _mesa_base_tex_format() but the set of valid 809 * internal formats is somewhat different. 810 * 811 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT 812 * GL_DEPTH_STENCIL_EXT or zero if error. 813 */ 814GLenum 815_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) 816{ 817 switch (internalFormat) { 818 case GL_RGB: 819 case GL_R3_G3_B2: 820 case GL_RGB4: 821 case GL_RGB5: 822 case GL_RGB8: 823 case GL_RGB10: 824 case GL_RGB12: 825 case GL_RGB16: 826 return GL_RGB; 827 case GL_RGBA: 828 case GL_RGBA2: 829 case GL_RGBA4: 830 case GL_RGB5_A1: 831 case GL_RGBA8: 832 case GL_RGB10_A2: 833 case GL_RGBA12: 834 case GL_RGBA16: 835 return GL_RGBA; 836 case GL_STENCIL_INDEX: 837 case GL_STENCIL_INDEX1_EXT: 838 case GL_STENCIL_INDEX4_EXT: 839 case GL_STENCIL_INDEX8_EXT: 840 case GL_STENCIL_INDEX16_EXT: 841 return GL_STENCIL_INDEX; 842 case GL_DEPTH_COMPONENT: 843 case GL_DEPTH_COMPONENT16: 844 case GL_DEPTH_COMPONENT24: 845 case GL_DEPTH_COMPONENT32: 846 return GL_DEPTH_COMPONENT; 847 case GL_DEPTH_STENCIL_EXT: 848 case GL_DEPTH24_STENCIL8_EXT: 849 if (ctx->Extensions.EXT_packed_depth_stencil) 850 return GL_DEPTH_STENCIL_EXT; 851 else 852 return 0; 853 /* XXX add floating point formats eventually */ 854 default: 855 return 0; 856 } 857} 858 859 860/** sentinal value, see below */ 861#define NO_SAMPLES 1000 862 863 864/** 865 * Helper function used by _mesa_RenderbufferStorageEXT() and 866 * _mesa_RenderbufferStorageMultisample(). 867 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). 868 */ 869static void 870renderbuffer_storage(GLenum target, GLenum internalFormat, 871 GLsizei width, GLsizei height, GLsizei samples) 872{ 873 const char *func = samples == NO_SAMPLES ? 874 "glRenderbufferStorage" : "RenderbufferStorageMultisample"; 875 struct gl_renderbuffer *rb; 876 GLenum baseFormat; 877 GET_CURRENT_CONTEXT(ctx); 878 879 ASSERT_OUTSIDE_BEGIN_END(ctx); 880 881 if (target != GL_RENDERBUFFER_EXT) { 882 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 883 return; 884 } 885 886 baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 887 if (baseFormat == 0) { 888 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); 889 return; 890 } 891 892 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 893 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); 894 return; 895 } 896 897 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 898 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); 899 return; 900 } 901 902 if (samples == NO_SAMPLES) { 903 /* NumSamples == 0 indicates non-multisampling */ 904 samples = 0; 905 } 906 else if (samples > ctx->Const.MaxSamples) { 907 /* note: driver may choose to use more samples than what's requested */ 908 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); 909 return; 910 } 911 912 rb = ctx->CurrentRenderbuffer; 913 if (!rb) { 914 _mesa_error(ctx, GL_INVALID_OPERATION, func); 915 return; 916 } 917 918 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 919 920 if (rb->InternalFormat == internalFormat && 921 rb->Width == (GLuint) width && 922 rb->Height == (GLuint) height) { 923 /* no change in allocation needed */ 924 return; 925 } 926 927 /* These MUST get set by the AllocStorage func */ 928 rb->_ActualFormat = 0; 929 rb->RedBits = 930 rb->GreenBits = 931 rb->BlueBits = 932 rb->AlphaBits = 933 rb->IndexBits = 934 rb->DepthBits = 935 rb->StencilBits = 0; 936 rb->NumSamples = samples; 937 938 /* Now allocate the storage */ 939 ASSERT(rb->AllocStorage); 940 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 941 /* No error - check/set fields now */ 942 assert(rb->_ActualFormat); 943 assert(rb->Width == (GLuint) width); 944 assert(rb->Height == (GLuint) height); 945 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits || 946 rb->DepthBits || rb->StencilBits || rb->IndexBits); 947 rb->InternalFormat = internalFormat; 948 rb->_BaseFormat = baseFormat; 949 } 950 else { 951 /* Probably ran out of memory - clear the fields */ 952 rb->Width = 0; 953 rb->Height = 0; 954 rb->InternalFormat = GL_NONE; 955 rb->_ActualFormat = GL_NONE; 956 rb->_BaseFormat = GL_NONE; 957 rb->RedBits = 958 rb->GreenBits = 959 rb->BlueBits = 960 rb->AlphaBits = 961 rb->IndexBits = 962 rb->DepthBits = 963 rb->StencilBits = 964 rb->NumSamples = 0; 965 } 966 967 /* 968 test_framebuffer_completeness(ctx, fb); 969 */ 970 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 971 * points??? 972 */ 973} 974 975 976void GLAPIENTRY 977_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 978 GLsizei width, GLsizei height) 979{ 980 /* GL_ARB_fbo says calling this function is equivalent to calling 981 * glRenderbufferStorageMultisample() with samples=0. We pass in 982 * a token value here just for error reporting purposes. 983 */ 984 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); 985} 986 987 988void GLAPIENTRY 989_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 990 GLenum internalFormat, 991 GLsizei width, GLsizei height) 992{ 993 renderbuffer_storage(target, internalFormat, width, height, samples); 994} 995 996 997 998void GLAPIENTRY 999_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 1000{ 1001 struct gl_renderbuffer *rb; 1002 GET_CURRENT_CONTEXT(ctx); 1003 1004 ASSERT_OUTSIDE_BEGIN_END(ctx); 1005 1006 if (target != GL_RENDERBUFFER_EXT) { 1007 _mesa_error(ctx, GL_INVALID_ENUM, 1008 "glGetRenderbufferParameterivEXT(target)"); 1009 return; 1010 } 1011 1012 rb = ctx->CurrentRenderbuffer; 1013 if (!rb) { 1014 _mesa_error(ctx, GL_INVALID_OPERATION, 1015 "glGetRenderbufferParameterivEXT"); 1016 return; 1017 } 1018 1019 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1020 1021 switch (pname) { 1022 case GL_RENDERBUFFER_WIDTH_EXT: 1023 *params = rb->Width; 1024 return; 1025 case GL_RENDERBUFFER_HEIGHT_EXT: 1026 *params = rb->Height; 1027 return; 1028 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 1029 *params = rb->InternalFormat; 1030 return; 1031 case GL_RENDERBUFFER_RED_SIZE_EXT: 1032 *params = rb->RedBits; 1033 break; 1034 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 1035 *params = rb->GreenBits; 1036 break; 1037 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 1038 *params = rb->BlueBits; 1039 break; 1040 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 1041 *params = rb->AlphaBits; 1042 break; 1043 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 1044 *params = rb->DepthBits; 1045 break; 1046 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 1047 *params = rb->StencilBits; 1048 break; 1049 case GL_RENDERBUFFER_SAMPLES: 1050 if (ctx->Extensions.ARB_framebuffer_object) { 1051 *params = rb->NumSamples; 1052 break; 1053 } 1054 /* fallthrough */ 1055 default: 1056 _mesa_error(ctx, GL_INVALID_ENUM, 1057 "glGetRenderbufferParameterivEXT(target)"); 1058 return; 1059 } 1060} 1061 1062 1063GLboolean GLAPIENTRY 1064_mesa_IsFramebufferEXT(GLuint framebuffer) 1065{ 1066 GET_CURRENT_CONTEXT(ctx); 1067 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1068 if (framebuffer) { 1069 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 1070 if (rb != NULL && rb != &DummyFramebuffer) 1071 return GL_TRUE; 1072 } 1073 return GL_FALSE; 1074} 1075 1076 1077static void 1078check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 1079{ 1080 GLuint i; 1081 ASSERT(ctx->Driver.RenderTexture); 1082 for (i = 0; i < BUFFER_COUNT; i++) { 1083 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 1084 struct gl_texture_object *texObj = att->Texture; 1085 if (texObj 1086 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 1087 ctx->Driver.RenderTexture(ctx, fb, att); 1088 } 1089 } 1090} 1091 1092 1093/** 1094 * Examine all the framebuffer's attachments to see if any are textures. 1095 * If so, call ctx->Driver.FinishRenderTexture() for each texture to 1096 * notify the device driver that the texture image may have changed. 1097 */ 1098static void 1099check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 1100{ 1101 if (ctx->Driver.FinishRenderTexture) { 1102 GLuint i; 1103 for (i = 0; i < BUFFER_COUNT; i++) { 1104 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 1105 if (att->Texture && att->Renderbuffer) { 1106 ctx->Driver.FinishRenderTexture(ctx, att); 1107 } 1108 } 1109 } 1110} 1111 1112 1113void GLAPIENTRY 1114_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 1115{ 1116 struct gl_framebuffer *newFb, *newFbread; 1117 GLboolean bindReadBuf, bindDrawBuf; 1118 GET_CURRENT_CONTEXT(ctx); 1119 1120#ifdef DEBUG 1121 if (ctx->Extensions.ARB_framebuffer_object) { 1122 ASSERT(ctx->Extensions.EXT_framebuffer_object); 1123 ASSERT(ctx->Extensions.EXT_framebuffer_blit); 1124 } 1125#endif 1126 1127 ASSERT_OUTSIDE_BEGIN_END(ctx); 1128 1129 if (!ctx->Extensions.EXT_framebuffer_object) { 1130 _mesa_error(ctx, GL_INVALID_OPERATION, 1131 "glBindFramebufferEXT(unsupported)"); 1132 return; 1133 } 1134 1135 switch (target) { 1136#if FEATURE_EXT_framebuffer_blit 1137 case GL_DRAW_FRAMEBUFFER_EXT: 1138 if (!ctx->Extensions.EXT_framebuffer_blit) { 1139 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1140 return; 1141 } 1142 bindDrawBuf = GL_TRUE; 1143 bindReadBuf = GL_FALSE; 1144 break; 1145 case GL_READ_FRAMEBUFFER_EXT: 1146 if (!ctx->Extensions.EXT_framebuffer_blit) { 1147 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1148 return; 1149 } 1150 bindDrawBuf = GL_FALSE; 1151 bindReadBuf = GL_TRUE; 1152 break; 1153#endif 1154 case GL_FRAMEBUFFER_EXT: 1155 bindDrawBuf = GL_TRUE; 1156 bindReadBuf = GL_TRUE; 1157 break; 1158 default: 1159 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1160 return; 1161 } 1162 1163 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1164 1165 if (ctx->Driver.Flush) { 1166 ctx->Driver.Flush(ctx); 1167 } 1168 1169 if (framebuffer) { 1170 /* Binding a user-created framebuffer object */ 1171 newFb = _mesa_lookup_framebuffer(ctx, framebuffer); 1172 if (newFb == &DummyFramebuffer) { 1173 /* ID was reserved, but no real framebuffer object made yet */ 1174 newFb = NULL; 1175 } 1176 else if (!newFb && ctx->Extensions.ARB_framebuffer_object) { 1177 /* All FBO IDs must be Gen'd */ 1178 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); 1179 return; 1180 } 1181 1182 if (!newFb) { 1183 /* create new framebuffer object */ 1184 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 1185 if (!newFb) { 1186 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 1187 return; 1188 } 1189 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); 1190 } 1191 newFbread = newFb; 1192 } 1193 else { 1194 /* Binding the window system framebuffer (which was originally set 1195 * with MakeCurrent). 1196 */ 1197 newFb = ctx->WinSysDrawBuffer; 1198 newFbread = ctx->WinSysReadBuffer; 1199 } 1200 1201 ASSERT(newFb); 1202 ASSERT(newFb != &DummyFramebuffer); 1203 1204 /* 1205 * XXX check if re-binding same buffer and skip some of this code. 1206 */ 1207 1208 if (bindReadBuf) { 1209 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread); 1210 } 1211 1212 if (bindDrawBuf) { 1213 /* check if old FB had any texture attachments */ 1214 check_end_texture_render(ctx, ctx->DrawBuffer); 1215 1216 /* check if time to delete this framebuffer */ 1217 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb); 1218 1219 if (newFb->Name != 0) { 1220 /* check if newly bound framebuffer has any texture attachments */ 1221 check_begin_texture_render(ctx, newFb); 1222 } 1223 } 1224 1225 if (ctx->Driver.BindFramebuffer) { 1226 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread); 1227 } 1228} 1229 1230 1231void GLAPIENTRY 1232_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 1233{ 1234 GLint i; 1235 GET_CURRENT_CONTEXT(ctx); 1236 1237 ASSERT_OUTSIDE_BEGIN_END(ctx); 1238 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1239 /* The above doesn't fully flush the drivers in the way that a 1240 * glFlush does, but that is required here: 1241 */ 1242 if (ctx->Driver.Flush) 1243 ctx->Driver.Flush(ctx); 1244 1245 for (i = 0; i < n; i++) { 1246 if (framebuffers[i] > 0) { 1247 struct gl_framebuffer *fb; 1248 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 1249 if (fb) { 1250 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 1251 1252 /* check if deleting currently bound framebuffer object */ 1253 if (fb == ctx->DrawBuffer) { 1254 /* bind default */ 1255 ASSERT(fb->RefCount >= 2); 1256 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 1257 } 1258 if (fb == ctx->ReadBuffer) { 1259 /* bind default */ 1260 ASSERT(fb->RefCount >= 2); 1261 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 1262 } 1263 1264 /* remove from hash table immediately, to free the ID */ 1265 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 1266 1267 if (fb != &DummyFramebuffer) { 1268 /* But the object will not be freed until it's no longer 1269 * bound in any context. 1270 */ 1271 _mesa_unreference_framebuffer(&fb); 1272 } 1273 } 1274 } 1275 } 1276} 1277 1278 1279void GLAPIENTRY 1280_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 1281{ 1282 GET_CURRENT_CONTEXT(ctx); 1283 GLuint first; 1284 GLint i; 1285 1286 ASSERT_OUTSIDE_BEGIN_END(ctx); 1287 1288 if (n < 0) { 1289 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 1290 return; 1291 } 1292 1293 if (!framebuffers) 1294 return; 1295 1296 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 1297 1298 for (i = 0; i < n; i++) { 1299 GLuint name = first + i; 1300 framebuffers[i] = name; 1301 /* insert dummy placeholder into hash table */ 1302 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1303 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 1304 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1305 } 1306} 1307 1308 1309 1310GLenum GLAPIENTRY 1311_mesa_CheckFramebufferStatusEXT(GLenum target) 1312{ 1313 struct gl_framebuffer *buffer; 1314 GET_CURRENT_CONTEXT(ctx); 1315 1316 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1317 1318 switch (target) { 1319#if FEATURE_EXT_framebuffer_blit 1320 case GL_DRAW_FRAMEBUFFER_EXT: 1321 if (!ctx->Extensions.EXT_framebuffer_blit) { 1322 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1323 return 0; 1324 } 1325 buffer = ctx->DrawBuffer; 1326 break; 1327 case GL_READ_FRAMEBUFFER_EXT: 1328 if (!ctx->Extensions.EXT_framebuffer_blit) { 1329 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1330 return 0; 1331 } 1332 buffer = ctx->ReadBuffer; 1333 break; 1334#endif 1335 case GL_FRAMEBUFFER_EXT: 1336 buffer = ctx->DrawBuffer; 1337 break; 1338 default: 1339 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1340 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1341 } 1342 1343 if (buffer->Name == 0) { 1344 /* The window system / default framebuffer is always complete */ 1345 return GL_FRAMEBUFFER_COMPLETE_EXT; 1346 } 1347 1348 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1349 1350 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 1351 _mesa_test_framebuffer_completeness(ctx, buffer); 1352 } 1353 1354 return buffer->_Status; 1355} 1356 1357 1358 1359/** 1360 * Common code called by glFramebufferTexture1D/2D/3DEXT(). 1361 */ 1362static void 1363framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 1364 GLenum attachment, GLenum textarget, GLuint texture, 1365 GLint level, GLint zoffset) 1366{ 1367 struct gl_renderbuffer_attachment *att; 1368 struct gl_texture_object *texObj = NULL; 1369 struct gl_framebuffer *fb; 1370 GLboolean error = GL_FALSE; 1371 1372 ASSERT_OUTSIDE_BEGIN_END(ctx); 1373 1374 switch (target) { 1375 case GL_READ_FRAMEBUFFER_EXT: 1376 error = !ctx->Extensions.EXT_framebuffer_blit; 1377 fb = ctx->ReadBuffer; 1378 break; 1379 case GL_DRAW_FRAMEBUFFER_EXT: 1380 error = !ctx->Extensions.EXT_framebuffer_blit; 1381 /* fall-through */ 1382 case GL_FRAMEBUFFER_EXT: 1383 fb = ctx->DrawBuffer; 1384 break; 1385 default: 1386 error = GL_TRUE; 1387 } 1388 1389 if (error) { 1390 _mesa_error(ctx, GL_INVALID_ENUM, 1391 "glFramebufferTexture%sEXT(target=0x%x)", caller, target); 1392 return; 1393 } 1394 1395 ASSERT(fb); 1396 1397 /* check framebuffer binding */ 1398 if (fb->Name == 0) { 1399 _mesa_error(ctx, GL_INVALID_OPERATION, 1400 "glFramebufferTexture%sEXT", caller); 1401 return; 1402 } 1403 1404 1405 /* The textarget, level, and zoffset parameters are only validated if 1406 * texture is non-zero. 1407 */ 1408 if (texture) { 1409 GLboolean err = GL_TRUE; 1410 1411 texObj = _mesa_lookup_texture(ctx, texture); 1412 if (texObj != NULL) { 1413 if (textarget == 0) { 1414 err = (texObj->Target != GL_TEXTURE_3D) && 1415 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 1416 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 1417 } 1418 else { 1419 err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 1420 ? !IS_CUBE_FACE(textarget) 1421 : (texObj->Target != textarget); 1422 } 1423 } 1424 1425 if (err) { 1426 _mesa_error(ctx, GL_INVALID_OPERATION, 1427 "glFramebufferTexture%sEXT(texture target mismatch)", 1428 caller); 1429 return; 1430 } 1431 1432 if (texObj->Target == GL_TEXTURE_3D) { 1433 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1434 if (zoffset < 0 || zoffset >= maxSize) { 1435 _mesa_error(ctx, GL_INVALID_VALUE, 1436 "glFramebufferTexture%sEXT(zoffset)", caller); 1437 return; 1438 } 1439 } 1440 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 1441 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 1442 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 1443 _mesa_error(ctx, GL_INVALID_VALUE, 1444 "glFramebufferTexture%sEXT(layer)", caller); 1445 return; 1446 } 1447 } 1448 1449 if ((level < 0) || 1450 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 1451 _mesa_error(ctx, GL_INVALID_VALUE, 1452 "glFramebufferTexture%sEXT(level)", caller); 1453 return; 1454 } 1455 } 1456 1457 att = _mesa_get_attachment(ctx, fb, attachment); 1458 if (att == NULL) { 1459 _mesa_error(ctx, GL_INVALID_ENUM, 1460 "glFramebufferTexture%sEXT(attachment)", caller); 1461 return; 1462 } 1463 1464 if (texObj && attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1465 /* the texture format must be depth+stencil */ 1466 const struct gl_texture_image *texImg; 1467 texImg = texObj->Image[0][texObj->BaseLevel]; 1468 if (!texImg || texImg->_BaseFormat != GL_DEPTH_STENCIL) { 1469 _mesa_error(ctx, GL_INVALID_OPERATION, 1470 "glFramebufferTexture%sEXT(texture is not" 1471 " DEPTH_STENCIL format)", caller); 1472 return; 1473 } 1474 } 1475 1476 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1477 /* The above doesn't fully flush the drivers in the way that a 1478 * glFlush does, but that is required here: 1479 */ 1480 if (ctx->Driver.Flush) 1481 ctx->Driver.Flush(ctx); 1482 1483 _glthread_LOCK_MUTEX(fb->Mutex); 1484 if (texObj) { 1485 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 1486 level, zoffset); 1487 /* Set the render-to-texture flag. We'll check this flag in 1488 * glTexImage() and friends to determine if we need to revalidate 1489 * any FBOs that might be rendering into this texture. 1490 * This flag never gets cleared since it's non-trivial to determine 1491 * when all FBOs might be done rendering to this texture. That's OK 1492 * though since it's uncommon to render to a texture then repeatedly 1493 * call glTexImage() to change images in the texture. 1494 */ 1495 texObj->_RenderToTexture = GL_TRUE; 1496 } 1497 else { 1498 _mesa_remove_attachment(ctx, att); 1499 } 1500 1501 invalidate_framebuffer(fb); 1502 1503 _glthread_UNLOCK_MUTEX(fb->Mutex); 1504} 1505 1506 1507 1508void GLAPIENTRY 1509_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1510 GLenum textarget, GLuint texture, GLint level) 1511{ 1512 GET_CURRENT_CONTEXT(ctx); 1513 1514 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 1515 _mesa_error(ctx, GL_INVALID_ENUM, 1516 "glFramebufferTexture1DEXT(textarget)"); 1517 return; 1518 } 1519 1520 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 1521 level, 0); 1522} 1523 1524 1525void GLAPIENTRY 1526_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1527 GLenum textarget, GLuint texture, GLint level) 1528{ 1529 GET_CURRENT_CONTEXT(ctx); 1530 1531 if ((texture != 0) && 1532 (textarget != GL_TEXTURE_2D) && 1533 (textarget != GL_TEXTURE_RECTANGLE_ARB) && 1534 (!IS_CUBE_FACE(textarget))) { 1535 _mesa_error(ctx, GL_INVALID_OPERATION, 1536 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); 1537 return; 1538 } 1539 1540 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 1541 level, 0); 1542} 1543 1544 1545void GLAPIENTRY 1546_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1547 GLenum textarget, GLuint texture, 1548 GLint level, GLint zoffset) 1549{ 1550 GET_CURRENT_CONTEXT(ctx); 1551 1552 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 1553 _mesa_error(ctx, GL_INVALID_ENUM, 1554 "glFramebufferTexture3DEXT(textarget)"); 1555 return; 1556 } 1557 1558 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 1559 level, zoffset); 1560} 1561 1562 1563void GLAPIENTRY 1564_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 1565 GLuint texture, GLint level, GLint layer) 1566{ 1567 GET_CURRENT_CONTEXT(ctx); 1568 1569 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 1570 level, layer); 1571} 1572 1573 1574void GLAPIENTRY 1575_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1576 GLenum renderbufferTarget, 1577 GLuint renderbuffer) 1578{ 1579 struct gl_renderbuffer_attachment *att; 1580 struct gl_framebuffer *fb; 1581 struct gl_renderbuffer *rb; 1582 GET_CURRENT_CONTEXT(ctx); 1583 1584 ASSERT_OUTSIDE_BEGIN_END(ctx); 1585 1586 switch (target) { 1587#if FEATURE_EXT_framebuffer_blit 1588 case GL_DRAW_FRAMEBUFFER_EXT: 1589 if (!ctx->Extensions.EXT_framebuffer_blit) { 1590 _mesa_error(ctx, GL_INVALID_ENUM, 1591 "glFramebufferRenderbufferEXT(target)"); 1592 return; 1593 } 1594 fb = ctx->DrawBuffer; 1595 break; 1596 case GL_READ_FRAMEBUFFER_EXT: 1597 if (!ctx->Extensions.EXT_framebuffer_blit) { 1598 _mesa_error(ctx, GL_INVALID_ENUM, 1599 "glFramebufferRenderbufferEXT(target)"); 1600 return; 1601 } 1602 fb = ctx->ReadBuffer; 1603 break; 1604#endif 1605 case GL_FRAMEBUFFER_EXT: 1606 fb = ctx->DrawBuffer; 1607 break; 1608 default: 1609 _mesa_error(ctx, GL_INVALID_ENUM, 1610 "glFramebufferRenderbufferEXT(target)"); 1611 return; 1612 } 1613 1614 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1615 _mesa_error(ctx, GL_INVALID_ENUM, 1616 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1617 return; 1618 } 1619 1620 if (fb->Name == 0) { 1621 /* Can't attach new renderbuffers to a window system framebuffer */ 1622 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1623 return; 1624 } 1625 1626 att = _mesa_get_attachment(ctx, fb, attachment); 1627 if (att == NULL) { 1628 _mesa_error(ctx, GL_INVALID_ENUM, 1629 "glFramebufferRenderbufferEXT(attachment)"); 1630 return; 1631 } 1632 1633 if (renderbuffer) { 1634 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 1635 if (!rb) { 1636 _mesa_error(ctx, GL_INVALID_OPERATION, 1637 "glFramebufferRenderbufferEXT(renderbuffer)"); 1638 return; 1639 } 1640 } 1641 else { 1642 /* remove renderbuffer attachment */ 1643 rb = NULL; 1644 } 1645 1646 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1647 /* make sure the renderbuffer is a depth/stencil format */ 1648 if (rb->_BaseFormat != GL_DEPTH_STENCIL) { 1649 _mesa_error(ctx, GL_INVALID_OPERATION, 1650 "glFramebufferRenderbufferEXT(renderbuffer" 1651 " is not DEPTH_STENCIL format)"); 1652 return; 1653 } 1654 } 1655 1656 1657 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1658 /* The above doesn't fully flush the drivers in the way that a 1659 * glFlush does, but that is required here: 1660 */ 1661 if (ctx->Driver.Flush) 1662 ctx->Driver.Flush(ctx); 1663 1664 assert(ctx->Driver.FramebufferRenderbuffer); 1665 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 1666 1667 /* Some subsequent GL commands may depend on the framebuffer's visual 1668 * after the binding is updated. Update visual info now. 1669 */ 1670 _mesa_update_framebuffer_visual(fb); 1671} 1672 1673 1674void GLAPIENTRY 1675_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1676 GLenum pname, GLint *params) 1677{ 1678 const struct gl_renderbuffer_attachment *att; 1679 struct gl_framebuffer *buffer; 1680 GET_CURRENT_CONTEXT(ctx); 1681 1682 ASSERT_OUTSIDE_BEGIN_END(ctx); 1683 1684 switch (target) { 1685#if FEATURE_EXT_framebuffer_blit 1686 case GL_DRAW_FRAMEBUFFER_EXT: 1687 if (!ctx->Extensions.EXT_framebuffer_blit) { 1688 _mesa_error(ctx, GL_INVALID_ENUM, 1689 "glGetFramebufferAttachmentParameterivEXT(target)"); 1690 return; 1691 } 1692 buffer = ctx->DrawBuffer; 1693 break; 1694 case GL_READ_FRAMEBUFFER_EXT: 1695 if (!ctx->Extensions.EXT_framebuffer_blit) { 1696 _mesa_error(ctx, GL_INVALID_ENUM, 1697 "glGetFramebufferAttachmentParameterivEXT(target)"); 1698 return; 1699 } 1700 buffer = ctx->ReadBuffer; 1701 break; 1702#endif 1703 case GL_FRAMEBUFFER_EXT: 1704 buffer = ctx->DrawBuffer; 1705 break; 1706 default: 1707 _mesa_error(ctx, GL_INVALID_ENUM, 1708 "glGetFramebufferAttachmentParameterivEXT(target)"); 1709 return; 1710 } 1711 1712 if (buffer->Name == 0) { 1713 _mesa_error(ctx, GL_INVALID_OPERATION, 1714 "glGetFramebufferAttachmentParameterivEXT"); 1715 return; 1716 } 1717 1718 att = _mesa_get_attachment(ctx, buffer, attachment); 1719 if (att == NULL) { 1720 _mesa_error(ctx, GL_INVALID_ENUM, 1721 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1722 return; 1723 } 1724 1725 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1726 /* the depth and stencil attachments must point to the same buffer */ 1727 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 1728 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); 1729 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); 1730 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 1731 _mesa_error(ctx, GL_INVALID_OPERATION, 1732 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" 1733 " attachments differ)"); 1734 return; 1735 } 1736 } 1737 1738 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1739 /* The above doesn't fully flush the drivers in the way that a 1740 * glFlush does, but that is required here: 1741 */ 1742 if (ctx->Driver.Flush) 1743 ctx->Driver.Flush(ctx); 1744 1745 switch (pname) { 1746 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1747 *params = att->Type; 1748 return; 1749 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1750 if (att->Type == GL_RENDERBUFFER_EXT) { 1751 *params = att->Renderbuffer->Name; 1752 } 1753 else if (att->Type == GL_TEXTURE) { 1754 *params = att->Texture->Name; 1755 } 1756 else { 1757 _mesa_error(ctx, GL_INVALID_ENUM, 1758 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1759 } 1760 return; 1761 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1762 if (att->Type == GL_TEXTURE) { 1763 *params = att->TextureLevel; 1764 } 1765 else { 1766 _mesa_error(ctx, GL_INVALID_ENUM, 1767 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1768 } 1769 return; 1770 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1771 if (att->Type == GL_TEXTURE) { 1772 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 1773 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1774 } 1775 else { 1776 *params = 0; 1777 } 1778 } 1779 else { 1780 _mesa_error(ctx, GL_INVALID_ENUM, 1781 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1782 } 1783 return; 1784 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1785 if (att->Type == GL_TEXTURE) { 1786 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 1787 *params = att->Zoffset; 1788 } 1789 else { 1790 *params = 0; 1791 } 1792 } 1793 else { 1794 _mesa_error(ctx, GL_INVALID_ENUM, 1795 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1796 } 1797 return; 1798 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 1799 if (!ctx->Extensions.ARB_framebuffer_object) { 1800 _mesa_error(ctx, GL_INVALID_ENUM, 1801 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1802 } 1803 else { 1804 *params = att->Renderbuffer->ColorEncoding; 1805 } 1806 return; 1807 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 1808 if (!ctx->Extensions.ARB_framebuffer_object) { 1809 _mesa_error(ctx, GL_INVALID_ENUM, 1810 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1811 return; 1812 } 1813 else { 1814 *params = att->Renderbuffer->ComponentType; 1815 } 1816 return; 1817 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 1818 if (!ctx->Extensions.ARB_framebuffer_object) { 1819 _mesa_error(ctx, GL_INVALID_ENUM, 1820 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1821 } 1822 else { 1823 *params = att->Renderbuffer->RedBits; 1824 } 1825 return; 1826 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 1827 if (!ctx->Extensions.ARB_framebuffer_object) { 1828 _mesa_error(ctx, GL_INVALID_ENUM, 1829 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1830 } 1831 else { 1832 *params = att->Renderbuffer->GreenBits; 1833 } 1834 return; 1835 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 1836 if (!ctx->Extensions.ARB_framebuffer_object) { 1837 _mesa_error(ctx, GL_INVALID_ENUM, 1838 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1839 } 1840 else { 1841 *params = att->Renderbuffer->BlueBits; 1842 } 1843 return; 1844 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 1845 if (!ctx->Extensions.ARB_framebuffer_object) { 1846 _mesa_error(ctx, GL_INVALID_ENUM, 1847 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1848 } 1849 else { 1850 *params = att->Renderbuffer->AlphaBits; 1851 } 1852 return; 1853 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 1854 if (!ctx->Extensions.ARB_framebuffer_object) { 1855 _mesa_error(ctx, GL_INVALID_ENUM, 1856 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1857 } 1858 else { 1859 *params = att->Renderbuffer->DepthBits; 1860 } 1861 return; 1862 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 1863 if (!ctx->Extensions.ARB_framebuffer_object) { 1864 _mesa_error(ctx, GL_INVALID_ENUM, 1865 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1866 } 1867 else { 1868 *params = att->Renderbuffer->StencilBits; 1869 } 1870 return; 1871 default: 1872 _mesa_error(ctx, GL_INVALID_ENUM, 1873 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1874 return; 1875 } 1876} 1877 1878 1879void GLAPIENTRY 1880_mesa_GenerateMipmapEXT(GLenum target) 1881{ 1882 struct gl_texture_unit *texUnit; 1883 struct gl_texture_object *texObj; 1884 GET_CURRENT_CONTEXT(ctx); 1885 1886 ASSERT_OUTSIDE_BEGIN_END(ctx); 1887 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1888 1889 switch (target) { 1890 case GL_TEXTURE_1D: 1891 case GL_TEXTURE_2D: 1892 case GL_TEXTURE_3D: 1893 case GL_TEXTURE_CUBE_MAP: 1894 /* OK, legal value */ 1895 break; 1896 default: 1897 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1898 return; 1899 } 1900 1901 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 1902 texObj = _mesa_select_tex_object(ctx, texUnit, target); 1903 1904 _mesa_lock_texture(ctx, texObj); 1905 if (target == GL_TEXTURE_CUBE_MAP) { 1906 int face; 1907 1908 for (face = 0; face < 6; face++) 1909 ctx->Driver.GenerateMipmap(ctx, 1910 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 1911 texObj); 1912 } else { 1913 ctx->Driver.GenerateMipmap(ctx, target, texObj); 1914 } 1915 _mesa_unlock_texture(ctx, texObj); 1916} 1917 1918 1919#if FEATURE_EXT_framebuffer_blit 1920/** 1921 * Blit rectangular region, optionally from one framebuffer to another. 1922 * 1923 * Note, if the src buffer is multisampled and the dest is not, this is 1924 * when the samples must be resolved to a single color. 1925 */ 1926void GLAPIENTRY 1927_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 1928 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 1929 GLbitfield mask, GLenum filter) 1930{ 1931 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | 1932 GL_DEPTH_BUFFER_BIT | 1933 GL_STENCIL_BUFFER_BIT); 1934 const struct gl_framebuffer *readFb, *drawFb; 1935 const struct gl_renderbuffer *colorReadRb, *colorDrawRb; 1936 GET_CURRENT_CONTEXT(ctx); 1937 1938 ASSERT_OUTSIDE_BEGIN_END(ctx); 1939 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1940 1941 if (ctx->NewState) { 1942 _mesa_update_state(ctx); 1943 } 1944 1945 readFb = ctx->ReadBuffer; 1946 drawFb = ctx->DrawBuffer; 1947 1948 if (!readFb || !drawFb) { 1949 /* This will normally never happen but someday we may want to 1950 * support MakeCurrent() with no drawables. 1951 */ 1952 return; 1953 } 1954 1955 /* check for complete framebuffers */ 1956 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 1957 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 1958 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 1959 "glBlitFramebufferEXT(incomplete draw/read buffers)"); 1960 return; 1961 } 1962 1963 if (filter != GL_NEAREST && filter != GL_LINEAR) { 1964 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 1965 return; 1966 } 1967 1968 if (mask & ~legalMaskBits) { 1969 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 1970 return; 1971 } 1972 1973 /* depth/stencil must be blitted with nearest filtering */ 1974 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 1975 && filter != GL_NEAREST) { 1976 _mesa_error(ctx, GL_INVALID_OPERATION, 1977 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 1978 return; 1979 } 1980 1981 /* get color read/draw renderbuffers */ 1982 if (mask & GL_COLOR_BUFFER_BIT) { 1983 colorReadRb = readFb->_ColorReadBuffer; 1984 colorDrawRb = drawFb->_ColorDrawBuffers[0]; 1985 } 1986 else { 1987 colorReadRb = colorDrawRb = NULL; 1988 } 1989 1990 if (mask & GL_STENCIL_BUFFER_BIT) { 1991 struct gl_renderbuffer *readRb = readFb->_StencilBuffer; 1992 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; 1993 if (readRb->StencilBits != drawRb->StencilBits) { 1994 _mesa_error(ctx, GL_INVALID_OPERATION, 1995 "glBlitFramebufferEXT(stencil buffer size mismatch"); 1996 return; 1997 } 1998 } 1999 2000 if (mask & GL_DEPTH_BUFFER_BIT) { 2001 struct gl_renderbuffer *readRb = readFb->_DepthBuffer; 2002 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; 2003 if (readRb->DepthBits != drawRb->DepthBits) { 2004 _mesa_error(ctx, GL_INVALID_OPERATION, 2005 "glBlitFramebufferEXT(depth buffer size mismatch"); 2006 return; 2007 } 2008 } 2009 2010 if (readFb->Visual.samples > 0 && 2011 drawFb->Visual.samples > 0 && 2012 readFb->Visual.samples != drawFb->Visual.samples) { 2013 _mesa_error(ctx, GL_INVALID_OPERATION, 2014 "glBlitFramebufferEXT(mismatched samples"); 2015 return; 2016 } 2017 2018 /* extra checks for multisample copies... */ 2019 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { 2020 /* src and dest region sizes must be the same */ 2021 if (srcX1 - srcX0 != dstX1 - dstX0 || 2022 srcY1 - srcY0 != dstY1 - dstY0) { 2023 _mesa_error(ctx, GL_INVALID_OPERATION, 2024 "glBlitFramebufferEXT(bad src/dst multisample region sizes"); 2025 return; 2026 } 2027 2028 /* color formats must match */ 2029 if (colorReadRb && 2030 colorDrawRb && 2031 colorReadRb->_ActualFormat != colorDrawRb->_ActualFormat) { 2032 _mesa_error(ctx, GL_INVALID_OPERATION, 2033 "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); 2034 return; 2035 } 2036 } 2037 2038 if (!ctx->Extensions.EXT_framebuffer_blit) { 2039 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 2040 return; 2041 } 2042 2043 ASSERT(ctx->Driver.BlitFramebuffer); 2044 ctx->Driver.BlitFramebuffer(ctx, 2045 srcX0, srcY0, srcX1, srcY1, 2046 dstX0, dstY0, dstX1, dstY1, 2047 mask, filter); 2048} 2049#endif /* FEATURE_EXT_framebuffer_blit */ 2050