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