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