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