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