fbobject.c revision 536e3c9168c315651210ca853eb8cb4423f9f71c
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/* 28 * GL_EXT/ARB_framebuffer_object extensions 29 * 30 * Authors: 31 * Brian Paul 32 */ 33 34 35#include "buffers.h" 36#include "context.h" 37#include "enums.h" 38#include "fbobject.h" 39#include "formats.h" 40#include "framebuffer.h" 41#include "hash.h" 42#include "macros.h" 43#include "renderbuffer.h" 44#include "state.h" 45#include "teximage.h" 46#include "texobj.h" 47 48 49/** Set this to 1 to help debug FBO incompleteness problems */ 50#define DEBUG_FBO 0 51 52/** Set this to 1 to debug/log glBlitFramebuffer() calls */ 53#define DEBUG_BLIT 0 54 55 56/** 57 * Notes: 58 * 59 * None of the GL_EXT_framebuffer_object functions are compiled into 60 * display lists. 61 */ 62 63 64 65/* 66 * When glGenRender/FramebuffersEXT() is called we insert pointers to 67 * these placeholder objects into the hash table. 68 * Later, when the object ID is first bound, we replace the placeholder 69 * with the real frame/renderbuffer. 70 */ 71static struct gl_framebuffer DummyFramebuffer; 72static struct gl_renderbuffer DummyRenderbuffer; 73 74 75#define IS_CUBE_FACE(TARGET) \ 76 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 77 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 78 79 80static void 81delete_dummy_renderbuffer(struct gl_renderbuffer *rb) 82{ 83 /* no op */ 84} 85 86static void 87delete_dummy_framebuffer(struct gl_framebuffer *fb) 88{ 89 /* no op */ 90} 91 92 93void 94_mesa_init_fbobjects(GLcontext *ctx) 95{ 96 DummyFramebuffer.Delete = delete_dummy_framebuffer; 97 DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 98} 99 100 101/** 102 * Helper routine for getting a gl_renderbuffer. 103 */ 104struct gl_renderbuffer * 105_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) 106{ 107 struct gl_renderbuffer *rb; 108 109 if (id == 0) 110 return NULL; 111 112 rb = (struct gl_renderbuffer *) 113 _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 114 return rb; 115} 116 117 118/** 119 * Helper routine for getting a gl_framebuffer. 120 */ 121struct gl_framebuffer * 122_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) 123{ 124 struct gl_framebuffer *fb; 125 126 if (id == 0) 127 return NULL; 128 129 fb = (struct gl_framebuffer *) 130 _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 131 return fb; 132} 133 134 135/** 136 * Mark the given framebuffer as invalid. This will force the 137 * test for framebuffer completeness to be done before the framebuffer 138 * is used. 139 */ 140static void 141invalidate_framebuffer(struct gl_framebuffer *fb) 142{ 143 fb->_Status = 0; /* "indeterminate" */ 144} 145 146 147/** 148 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 149 * gl_renderbuffer_attachment object. 150 * 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 (fb == ctx->DrawBuffer) { 1354 /* bind default */ 1355 ASSERT(fb->RefCount >= 2); 1356 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 1357 } 1358 if (fb == ctx->ReadBuffer) { 1359 /* bind default */ 1360 ASSERT(fb->RefCount >= 2); 1361 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 1362 } 1363 1364 /* remove from hash table immediately, to free the ID */ 1365 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 1366 1367 if (fb != &DummyFramebuffer) { 1368 /* But the object will not be freed until it's no longer 1369 * bound in any context. 1370 */ 1371 _mesa_reference_framebuffer(&fb, NULL); 1372 } 1373 } 1374 } 1375 } 1376} 1377 1378 1379void GLAPIENTRY 1380_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 1381{ 1382 GET_CURRENT_CONTEXT(ctx); 1383 GLuint first; 1384 GLint i; 1385 1386 ASSERT_OUTSIDE_BEGIN_END(ctx); 1387 1388 if (n < 0) { 1389 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 1390 return; 1391 } 1392 1393 if (!framebuffers) 1394 return; 1395 1396 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 1397 1398 for (i = 0; i < n; i++) { 1399 GLuint name = first + i; 1400 framebuffers[i] = name; 1401 /* insert dummy placeholder into hash table */ 1402 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1403 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 1404 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1405 } 1406} 1407 1408 1409 1410GLenum GLAPIENTRY 1411_mesa_CheckFramebufferStatusEXT(GLenum target) 1412{ 1413 struct gl_framebuffer *buffer; 1414 GET_CURRENT_CONTEXT(ctx); 1415 1416 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1417 1418 switch (target) { 1419#if FEATURE_EXT_framebuffer_blit 1420 case GL_DRAW_FRAMEBUFFER_EXT: 1421 if (!ctx->Extensions.EXT_framebuffer_blit) { 1422 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1423 return 0; 1424 } 1425 buffer = ctx->DrawBuffer; 1426 break; 1427 case GL_READ_FRAMEBUFFER_EXT: 1428 if (!ctx->Extensions.EXT_framebuffer_blit) { 1429 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1430 return 0; 1431 } 1432 buffer = ctx->ReadBuffer; 1433 break; 1434#endif 1435 case GL_FRAMEBUFFER_EXT: 1436 buffer = ctx->DrawBuffer; 1437 break; 1438 default: 1439 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1440 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1441 } 1442 1443 if (buffer->Name == 0) { 1444 /* The window system / default framebuffer is always complete */ 1445 return GL_FRAMEBUFFER_COMPLETE_EXT; 1446 } 1447 1448 /* No need to flush here */ 1449 1450 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 1451 _mesa_test_framebuffer_completeness(ctx, buffer); 1452 } 1453 1454 return buffer->_Status; 1455} 1456 1457 1458 1459/** 1460 * Common code called by glFramebufferTexture1D/2D/3DEXT(). 1461 */ 1462static void 1463framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 1464 GLenum attachment, GLenum textarget, GLuint texture, 1465 GLint level, GLint zoffset) 1466{ 1467 struct gl_renderbuffer_attachment *att; 1468 struct gl_texture_object *texObj = NULL; 1469 struct gl_framebuffer *fb; 1470 GLboolean error = GL_FALSE; 1471 1472 ASSERT_OUTSIDE_BEGIN_END(ctx); 1473 1474 switch (target) { 1475 case GL_READ_FRAMEBUFFER_EXT: 1476 error = !ctx->Extensions.EXT_framebuffer_blit; 1477 fb = ctx->ReadBuffer; 1478 break; 1479 case GL_DRAW_FRAMEBUFFER_EXT: 1480 error = !ctx->Extensions.EXT_framebuffer_blit; 1481 /* fall-through */ 1482 case GL_FRAMEBUFFER_EXT: 1483 fb = ctx->DrawBuffer; 1484 break; 1485 default: 1486 error = GL_TRUE; 1487 } 1488 1489 if (error) { 1490 _mesa_error(ctx, GL_INVALID_ENUM, 1491 "glFramebufferTexture%sEXT(target=0x%x)", caller, target); 1492 return; 1493 } 1494 1495 ASSERT(fb); 1496 1497 /* check framebuffer binding */ 1498 if (fb->Name == 0) { 1499 _mesa_error(ctx, GL_INVALID_OPERATION, 1500 "glFramebufferTexture%sEXT", caller); 1501 return; 1502 } 1503 1504 1505 /* The textarget, level, and zoffset parameters are only validated if 1506 * texture is non-zero. 1507 */ 1508 if (texture) { 1509 GLboolean err = GL_TRUE; 1510 1511 texObj = _mesa_lookup_texture(ctx, texture); 1512 if (texObj != NULL) { 1513 if (textarget == 0) { 1514 err = (texObj->Target != GL_TEXTURE_3D) && 1515 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 1516 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 1517 } 1518 else { 1519 err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 1520 ? !IS_CUBE_FACE(textarget) 1521 : (texObj->Target != textarget); 1522 } 1523 } 1524 1525 if (err) { 1526 _mesa_error(ctx, GL_INVALID_OPERATION, 1527 "glFramebufferTexture%sEXT(texture target mismatch)", 1528 caller); 1529 return; 1530 } 1531 1532 if (texObj->Target == GL_TEXTURE_3D) { 1533 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1534 if (zoffset < 0 || zoffset >= maxSize) { 1535 _mesa_error(ctx, GL_INVALID_VALUE, 1536 "glFramebufferTexture%sEXT(zoffset)", caller); 1537 return; 1538 } 1539 } 1540 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 1541 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 1542 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 1543 _mesa_error(ctx, GL_INVALID_VALUE, 1544 "glFramebufferTexture%sEXT(layer)", caller); 1545 return; 1546 } 1547 } 1548 1549 if ((level < 0) || 1550 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 1551 _mesa_error(ctx, GL_INVALID_VALUE, 1552 "glFramebufferTexture%sEXT(level)", caller); 1553 return; 1554 } 1555 } 1556 1557 att = _mesa_get_attachment(ctx, fb, attachment); 1558 if (att == NULL) { 1559 _mesa_error(ctx, GL_INVALID_ENUM, 1560 "glFramebufferTexture%sEXT(attachment)", caller); 1561 return; 1562 } 1563 1564 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1565 1566 _glthread_LOCK_MUTEX(fb->Mutex); 1567 if (texObj) { 1568 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 1569 level, zoffset); 1570 /* Set the render-to-texture flag. We'll check this flag in 1571 * glTexImage() and friends to determine if we need to revalidate 1572 * any FBOs that might be rendering into this texture. 1573 * This flag never gets cleared since it's non-trivial to determine 1574 * when all FBOs might be done rendering to this texture. That's OK 1575 * though since it's uncommon to render to a texture then repeatedly 1576 * call glTexImage() to change images in the texture. 1577 */ 1578 texObj->_RenderToTexture = GL_TRUE; 1579 } 1580 else { 1581 _mesa_remove_attachment(ctx, att); 1582 } 1583 1584 invalidate_framebuffer(fb); 1585 1586 _glthread_UNLOCK_MUTEX(fb->Mutex); 1587} 1588 1589 1590 1591void GLAPIENTRY 1592_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1593 GLenum textarget, GLuint texture, GLint level) 1594{ 1595 GET_CURRENT_CONTEXT(ctx); 1596 1597 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 1598 _mesa_error(ctx, GL_INVALID_ENUM, 1599 "glFramebufferTexture1DEXT(textarget)"); 1600 return; 1601 } 1602 1603 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 1604 level, 0); 1605} 1606 1607 1608void GLAPIENTRY 1609_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1610 GLenum textarget, GLuint texture, GLint level) 1611{ 1612 GET_CURRENT_CONTEXT(ctx); 1613 1614 if ((texture != 0) && 1615 (textarget != GL_TEXTURE_2D) && 1616 (textarget != GL_TEXTURE_RECTANGLE_ARB) && 1617 (!IS_CUBE_FACE(textarget))) { 1618 _mesa_error(ctx, GL_INVALID_OPERATION, 1619 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); 1620 return; 1621 } 1622 1623 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 1624 level, 0); 1625} 1626 1627 1628void GLAPIENTRY 1629_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1630 GLenum textarget, GLuint texture, 1631 GLint level, GLint zoffset) 1632{ 1633 GET_CURRENT_CONTEXT(ctx); 1634 1635 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 1636 _mesa_error(ctx, GL_INVALID_ENUM, 1637 "glFramebufferTexture3DEXT(textarget)"); 1638 return; 1639 } 1640 1641 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 1642 level, zoffset); 1643} 1644 1645 1646void GLAPIENTRY 1647_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 1648 GLuint texture, GLint level, GLint layer) 1649{ 1650 GET_CURRENT_CONTEXT(ctx); 1651 1652 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 1653 level, layer); 1654} 1655 1656 1657void GLAPIENTRY 1658_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1659 GLenum renderbufferTarget, 1660 GLuint renderbuffer) 1661{ 1662 struct gl_renderbuffer_attachment *att; 1663 struct gl_framebuffer *fb; 1664 struct gl_renderbuffer *rb; 1665 GET_CURRENT_CONTEXT(ctx); 1666 1667 ASSERT_OUTSIDE_BEGIN_END(ctx); 1668 1669 switch (target) { 1670#if FEATURE_EXT_framebuffer_blit 1671 case GL_DRAW_FRAMEBUFFER_EXT: 1672 if (!ctx->Extensions.EXT_framebuffer_blit) { 1673 _mesa_error(ctx, GL_INVALID_ENUM, 1674 "glFramebufferRenderbufferEXT(target)"); 1675 return; 1676 } 1677 fb = ctx->DrawBuffer; 1678 break; 1679 case GL_READ_FRAMEBUFFER_EXT: 1680 if (!ctx->Extensions.EXT_framebuffer_blit) { 1681 _mesa_error(ctx, GL_INVALID_ENUM, 1682 "glFramebufferRenderbufferEXT(target)"); 1683 return; 1684 } 1685 fb = ctx->ReadBuffer; 1686 break; 1687#endif 1688 case GL_FRAMEBUFFER_EXT: 1689 fb = ctx->DrawBuffer; 1690 break; 1691 default: 1692 _mesa_error(ctx, GL_INVALID_ENUM, 1693 "glFramebufferRenderbufferEXT(target)"); 1694 return; 1695 } 1696 1697 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1698 _mesa_error(ctx, GL_INVALID_ENUM, 1699 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1700 return; 1701 } 1702 1703 if (fb->Name == 0) { 1704 /* Can't attach new renderbuffers to a window system framebuffer */ 1705 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1706 return; 1707 } 1708 1709 att = _mesa_get_attachment(ctx, fb, attachment); 1710 if (att == NULL) { 1711 _mesa_error(ctx, GL_INVALID_ENUM, 1712 "glFramebufferRenderbufferEXT(invalid attachment %s)", 1713 _mesa_lookup_enum_by_nr(attachment)); 1714 return; 1715 } 1716 1717 if (renderbuffer) { 1718 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 1719 if (!rb) { 1720 _mesa_error(ctx, GL_INVALID_OPERATION, 1721 "glFramebufferRenderbufferEXT(non-existant" 1722 " renderbuffer %u)", renderbuffer); 1723 return; 1724 } 1725 } 1726 else { 1727 /* remove renderbuffer attachment */ 1728 rb = NULL; 1729 } 1730 1731 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1732 /* make sure the renderbuffer is a depth/stencil format */ 1733 const GLenum baseFormat = 1734 _mesa_get_format_base_format(att->Renderbuffer->Format); 1735 if (baseFormat != GL_DEPTH_STENCIL) { 1736 _mesa_error(ctx, GL_INVALID_OPERATION, 1737 "glFramebufferRenderbufferEXT(renderbuffer" 1738 " is not DEPTH_STENCIL format)"); 1739 return; 1740 } 1741 } 1742 1743 1744 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1745 1746 assert(ctx->Driver.FramebufferRenderbuffer); 1747 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 1748 1749 /* Some subsequent GL commands may depend on the framebuffer's visual 1750 * after the binding is updated. Update visual info now. 1751 */ 1752 _mesa_update_framebuffer_visual(fb); 1753} 1754 1755 1756void GLAPIENTRY 1757_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1758 GLenum pname, GLint *params) 1759{ 1760 const struct gl_renderbuffer_attachment *att; 1761 struct gl_framebuffer *buffer; 1762 GET_CURRENT_CONTEXT(ctx); 1763 1764 ASSERT_OUTSIDE_BEGIN_END(ctx); 1765 1766 switch (target) { 1767#if FEATURE_EXT_framebuffer_blit 1768 case GL_DRAW_FRAMEBUFFER_EXT: 1769 if (!ctx->Extensions.EXT_framebuffer_blit) { 1770 _mesa_error(ctx, GL_INVALID_ENUM, 1771 "glGetFramebufferAttachmentParameterivEXT(target)"); 1772 return; 1773 } 1774 buffer = ctx->DrawBuffer; 1775 break; 1776 case GL_READ_FRAMEBUFFER_EXT: 1777 if (!ctx->Extensions.EXT_framebuffer_blit) { 1778 _mesa_error(ctx, GL_INVALID_ENUM, 1779 "glGetFramebufferAttachmentParameterivEXT(target)"); 1780 return; 1781 } 1782 buffer = ctx->ReadBuffer; 1783 break; 1784#endif 1785 case GL_FRAMEBUFFER_EXT: 1786 buffer = ctx->DrawBuffer; 1787 break; 1788 default: 1789 _mesa_error(ctx, GL_INVALID_ENUM, 1790 "glGetFramebufferAttachmentParameterivEXT(target)"); 1791 return; 1792 } 1793 1794 if (buffer->Name == 0) { 1795 _mesa_error(ctx, GL_INVALID_OPERATION, 1796 "glGetFramebufferAttachmentParameterivEXT"); 1797 return; 1798 } 1799 1800 att = _mesa_get_attachment(ctx, buffer, attachment); 1801 if (att == NULL) { 1802 _mesa_error(ctx, GL_INVALID_ENUM, 1803 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1804 return; 1805 } 1806 1807 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1808 /* the depth and stencil attachments must point to the same buffer */ 1809 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 1810 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); 1811 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); 1812 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 1813 _mesa_error(ctx, GL_INVALID_OPERATION, 1814 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" 1815 " attachments differ)"); 1816 return; 1817 } 1818 } 1819 1820 /* No need to flush here */ 1821 1822 switch (pname) { 1823 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1824 *params = att->Type; 1825 return; 1826 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1827 if (att->Type == GL_RENDERBUFFER_EXT) { 1828 *params = att->Renderbuffer->Name; 1829 } 1830 else if (att->Type == GL_TEXTURE) { 1831 *params = att->Texture->Name; 1832 } 1833 else { 1834 _mesa_error(ctx, GL_INVALID_ENUM, 1835 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1836 } 1837 return; 1838 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1839 if (att->Type == GL_TEXTURE) { 1840 *params = att->TextureLevel; 1841 } 1842 else { 1843 _mesa_error(ctx, GL_INVALID_ENUM, 1844 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1845 } 1846 return; 1847 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1848 if (att->Type == GL_TEXTURE) { 1849 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 1850 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1851 } 1852 else { 1853 *params = 0; 1854 } 1855 } 1856 else { 1857 _mesa_error(ctx, GL_INVALID_ENUM, 1858 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1859 } 1860 return; 1861 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1862 if (att->Type == GL_TEXTURE) { 1863 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 1864 *params = att->Zoffset; 1865 } 1866 else { 1867 *params = 0; 1868 } 1869 } 1870 else { 1871 _mesa_error(ctx, GL_INVALID_ENUM, 1872 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1873 } 1874 return; 1875 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 1876 if (!ctx->Extensions.ARB_framebuffer_object) { 1877 _mesa_error(ctx, GL_INVALID_ENUM, 1878 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1879 } 1880 else { 1881 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); 1882 } 1883 return; 1884 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 1885 if (!ctx->Extensions.ARB_framebuffer_object) { 1886 _mesa_error(ctx, GL_INVALID_ENUM, 1887 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1888 return; 1889 } 1890 else { 1891 gl_format format = att->Renderbuffer->Format; 1892 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { 1893 /* special cases */ 1894 *params = GL_INDEX; 1895 } 1896 else { 1897 *params = _mesa_get_format_datatype(format); 1898 } 1899 } 1900 return; 1901 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 1902 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 1903 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 1904 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 1905 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 1906 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 1907 if (!ctx->Extensions.ARB_framebuffer_object) { 1908 _mesa_error(ctx, GL_INVALID_ENUM, 1909 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1910 } 1911 else if (att->Texture) { 1912 const struct gl_texture_image *texImage = 1913 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, 1914 att->TextureLevel); 1915 if (texImage) { 1916 *params = get_component_bits(pname, texImage->_BaseFormat, 1917 texImage->TexFormat); 1918 } 1919 else { 1920 *params = 0; 1921 } 1922 } 1923 else if (att->Renderbuffer) { 1924 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 1925 att->Renderbuffer->Format); 1926 } 1927 else { 1928 *params = 0; 1929 } 1930 return; 1931 default: 1932 _mesa_error(ctx, GL_INVALID_ENUM, 1933 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1934 return; 1935 } 1936} 1937 1938 1939void GLAPIENTRY 1940_mesa_GenerateMipmapEXT(GLenum target) 1941{ 1942 struct gl_texture_object *texObj; 1943 GET_CURRENT_CONTEXT(ctx); 1944 1945 ASSERT_OUTSIDE_BEGIN_END(ctx); 1946 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1947 1948 switch (target) { 1949 case GL_TEXTURE_1D: 1950 case GL_TEXTURE_2D: 1951 case GL_TEXTURE_3D: 1952 case GL_TEXTURE_CUBE_MAP: 1953 /* OK, legal value */ 1954 break; 1955 default: 1956 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1957 return; 1958 } 1959 1960 texObj = _mesa_get_current_tex_object(ctx, target); 1961 1962 if (texObj->BaseLevel >= texObj->MaxLevel) { 1963 /* nothing to do */ 1964 return; 1965 } 1966 1967 _mesa_lock_texture(ctx, texObj); 1968 if (target == GL_TEXTURE_CUBE_MAP) { 1969 GLuint face; 1970 for (face = 0; face < 6; face++) 1971 ctx->Driver.GenerateMipmap(ctx, 1972 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 1973 texObj); 1974 } 1975 else { 1976 ctx->Driver.GenerateMipmap(ctx, target, texObj); 1977 } 1978 _mesa_unlock_texture(ctx, texObj); 1979} 1980 1981 1982#if FEATURE_EXT_framebuffer_blit 1983 1984static const struct gl_renderbuffer_attachment * 1985find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb) 1986{ 1987 GLuint i; 1988 for (i = 0; i < Elements(fb->Attachment); i++) { 1989 if (fb->Attachment[i].Renderbuffer == rb) 1990 return &fb->Attachment[i]; 1991 } 1992 return NULL; 1993} 1994 1995 1996 1997/** 1998 * Blit rectangular region, optionally from one framebuffer to another. 1999 * 2000 * Note, if the src buffer is multisampled and the dest is not, this is 2001 * when the samples must be resolved to a single color. 2002 */ 2003void GLAPIENTRY 2004_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 2005 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 2006 GLbitfield mask, GLenum filter) 2007{ 2008 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | 2009 GL_DEPTH_BUFFER_BIT | 2010 GL_STENCIL_BUFFER_BIT); 2011 const struct gl_framebuffer *readFb, *drawFb; 2012 const struct gl_renderbuffer *colorReadRb, *colorDrawRb; 2013 GET_CURRENT_CONTEXT(ctx); 2014 2015 ASSERT_OUTSIDE_BEGIN_END(ctx); 2016 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 2017 2018 if (ctx->NewState) { 2019 _mesa_update_state(ctx); 2020 } 2021 2022 readFb = ctx->ReadBuffer; 2023 drawFb = ctx->DrawBuffer; 2024 2025 if (!readFb || !drawFb) { 2026 /* This will normally never happen but someday we may want to 2027 * support MakeCurrent() with no drawables. 2028 */ 2029 return; 2030 } 2031 2032 /* check for complete framebuffers */ 2033 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 2034 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 2035 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 2036 "glBlitFramebufferEXT(incomplete draw/read buffers)"); 2037 return; 2038 } 2039 2040 if (filter != GL_NEAREST && filter != GL_LINEAR) { 2041 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 2042 return; 2043 } 2044 2045 if (mask & ~legalMaskBits) { 2046 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 2047 return; 2048 } 2049 2050 /* depth/stencil must be blitted with nearest filtering */ 2051 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 2052 && filter != GL_NEAREST) { 2053 _mesa_error(ctx, GL_INVALID_OPERATION, 2054 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 2055 return; 2056 } 2057 2058 /* get color read/draw renderbuffers */ 2059 if (mask & GL_COLOR_BUFFER_BIT) { 2060 colorReadRb = readFb->_ColorReadBuffer; 2061 colorDrawRb = drawFb->_ColorDrawBuffers[0]; 2062 } 2063 else { 2064 colorReadRb = colorDrawRb = NULL; 2065 } 2066 2067 if (mask & GL_STENCIL_BUFFER_BIT) { 2068 struct gl_renderbuffer *readRb = readFb->_StencilBuffer; 2069 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; 2070 if (!readRb || 2071 !drawRb || 2072 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != 2073 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { 2074 _mesa_error(ctx, GL_INVALID_OPERATION, 2075 "glBlitFramebufferEXT(stencil buffer size mismatch"); 2076 return; 2077 } 2078 } 2079 2080 if (mask & GL_DEPTH_BUFFER_BIT) { 2081 struct gl_renderbuffer *readRb = readFb->_DepthBuffer; 2082 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; 2083 if (!readRb || 2084 !drawRb || 2085 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != 2086 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { 2087 _mesa_error(ctx, GL_INVALID_OPERATION, 2088 "glBlitFramebufferEXT(depth buffer size mismatch"); 2089 return; 2090 } 2091 } 2092 2093 if (readFb->Visual.samples > 0 && 2094 drawFb->Visual.samples > 0 && 2095 readFb->Visual.samples != drawFb->Visual.samples) { 2096 _mesa_error(ctx, GL_INVALID_OPERATION, 2097 "glBlitFramebufferEXT(mismatched samples"); 2098 return; 2099 } 2100 2101 /* extra checks for multisample copies... */ 2102 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { 2103 /* src and dest region sizes must be the same */ 2104 if (srcX1 - srcX0 != dstX1 - dstX0 || 2105 srcY1 - srcY0 != dstY1 - dstY0) { 2106 _mesa_error(ctx, GL_INVALID_OPERATION, 2107 "glBlitFramebufferEXT(bad src/dst multisample region sizes"); 2108 return; 2109 } 2110 2111 /* color formats must match */ 2112 if (colorReadRb && 2113 colorDrawRb && 2114 colorReadRb->Format != colorDrawRb->Format) { 2115 _mesa_error(ctx, GL_INVALID_OPERATION, 2116 "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); 2117 return; 2118 } 2119 } 2120 2121 if (!ctx->Extensions.EXT_framebuffer_blit) { 2122 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 2123 return; 2124 } 2125 2126 /* Debug code */ 2127 if (DEBUG_BLIT) { 2128 _mesa_printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," 2129 " 0x%x, 0x%x)\n", 2130 srcX0, srcY0, srcX1, srcY1, 2131 dstX0, dstY0, dstX1, dstY1, 2132 mask, filter); 2133 if (colorReadRb) { 2134 const struct gl_renderbuffer_attachment *att; 2135 2136 att = find_attachment(readFb, colorReadRb); 2137 _mesa_printf(" Src FBO %u RB %u (%dx%d) ", 2138 readFb->Name, colorReadRb->Name, 2139 colorReadRb->Width, colorReadRb->Height); 2140 if (att && att->Texture) { 2141 _mesa_printf("Tex %u tgt 0x%x level %u face %u", 2142 att->Texture->Name, 2143 att->Texture->Target, 2144 att->TextureLevel, 2145 att->CubeMapFace); 2146 } 2147 _mesa_printf("\n"); 2148 2149 att = find_attachment(drawFb, colorDrawRb); 2150 _mesa_printf(" Dst FBO %u RB %u (%dx%d) ", 2151 drawFb->Name, colorDrawRb->Name, 2152 colorDrawRb->Width, colorDrawRb->Height); 2153 if (att && att->Texture) { 2154 _mesa_printf("Tex %u tgt 0x%x level %u face %u", 2155 att->Texture->Name, 2156 att->Texture->Target, 2157 att->TextureLevel, 2158 att->CubeMapFace); 2159 } 2160 _mesa_printf("\n"); 2161 } 2162 } 2163 2164 ASSERT(ctx->Driver.BlitFramebuffer); 2165 ctx->Driver.BlitFramebuffer(ctx, 2166 srcX0, srcY0, srcX1, srcY1, 2167 dstX0, dstY0, dstX1, dstY1, 2168 mask, filter); 2169} 2170#endif /* FEATURE_EXT_framebuffer_blit */ 2171