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