fbobject.c revision cdc920a0
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 printf("texobj = %u\n", texObj->Name); 378 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 * 862 * XXX in the future when we support red-only and red-green formats 863 * we'll also return GL_RED and GL_RG. 864 */ 865GLenum 866_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) 867{ 868 switch (internalFormat) { 869 case GL_RGB: 870 case GL_R3_G3_B2: 871 case GL_RGB4: 872 case GL_RGB5: 873 case GL_RGB8: 874 case GL_RGB10: 875 case GL_RGB12: 876 case GL_RGB16: 877 return GL_RGB; 878 case GL_RGBA: 879 case GL_RGBA2: 880 case GL_RGBA4: 881 case GL_RGB5_A1: 882 case GL_RGBA8: 883 case GL_RGB10_A2: 884 case GL_RGBA12: 885 case GL_RGBA16: 886 return GL_RGBA; 887 case GL_STENCIL_INDEX: 888 case GL_STENCIL_INDEX1_EXT: 889 case GL_STENCIL_INDEX4_EXT: 890 case GL_STENCIL_INDEX8_EXT: 891 case GL_STENCIL_INDEX16_EXT: 892 return GL_STENCIL_INDEX; 893 case GL_DEPTH_COMPONENT: 894 case GL_DEPTH_COMPONENT16: 895 case GL_DEPTH_COMPONENT24: 896 case GL_DEPTH_COMPONENT32: 897 return GL_DEPTH_COMPONENT; 898 case GL_DEPTH_STENCIL_EXT: 899 case GL_DEPTH24_STENCIL8_EXT: 900 if (ctx->Extensions.EXT_packed_depth_stencil) 901 return GL_DEPTH_STENCIL_EXT; 902 else 903 return 0; 904 /* XXX add floating point formats eventually */ 905 default: 906 return 0; 907 } 908} 909 910 911/** sentinal value, see below */ 912#define NO_SAMPLES 1000 913 914 915/** 916 * Helper function used by _mesa_RenderbufferStorageEXT() and 917 * _mesa_RenderbufferStorageMultisample(). 918 * samples will be NO_SAMPLES if called by _mesa_RenderbufferStorageEXT(). 919 */ 920static void 921renderbuffer_storage(GLenum target, GLenum internalFormat, 922 GLsizei width, GLsizei height, GLsizei samples) 923{ 924 const char *func = samples == NO_SAMPLES ? 925 "glRenderbufferStorage" : "RenderbufferStorageMultisample"; 926 struct gl_renderbuffer *rb; 927 GLenum baseFormat; 928 GET_CURRENT_CONTEXT(ctx); 929 930 ASSERT_OUTSIDE_BEGIN_END(ctx); 931 932 if (target != GL_RENDERBUFFER_EXT) { 933 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 934 return; 935 } 936 937 baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 938 if (baseFormat == 0) { 939 _mesa_error(ctx, GL_INVALID_ENUM, "%s(internalFormat)", func); 940 return; 941 } 942 943 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 944 _mesa_error(ctx, GL_INVALID_VALUE, "%s(width)", func); 945 return; 946 } 947 948 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 949 _mesa_error(ctx, GL_INVALID_VALUE, "%s(height)", func); 950 return; 951 } 952 953 if (samples == NO_SAMPLES) { 954 /* NumSamples == 0 indicates non-multisampling */ 955 samples = 0; 956 } 957 else if (samples > (GLsizei) ctx->Const.MaxSamples) { 958 /* note: driver may choose to use more samples than what's requested */ 959 _mesa_error(ctx, GL_INVALID_VALUE, "%s(samples)", func); 960 return; 961 } 962 963 rb = ctx->CurrentRenderbuffer; 964 if (!rb) { 965 _mesa_error(ctx, GL_INVALID_OPERATION, func); 966 return; 967 } 968 969 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 970 971 if (rb->InternalFormat == internalFormat && 972 rb->Width == (GLuint) width && 973 rb->Height == (GLuint) height) { 974 /* no change in allocation needed */ 975 return; 976 } 977 978 /* These MUST get set by the AllocStorage func */ 979 rb->Format = MESA_FORMAT_NONE; 980 rb->NumSamples = samples; 981 982 /* Now allocate the storage */ 983 ASSERT(rb->AllocStorage); 984 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 985 /* No error - check/set fields now */ 986 assert(rb->Format != MESA_FORMAT_NONE); 987 assert(rb->Width == (GLuint) width); 988 assert(rb->Height == (GLuint) height); 989 rb->InternalFormat = internalFormat; 990 rb->_BaseFormat = baseFormat; 991 assert(rb->_BaseFormat != 0); 992 } 993 else { 994 /* Probably ran out of memory - clear the fields */ 995 rb->Width = 0; 996 rb->Height = 0; 997 rb->Format = MESA_FORMAT_NONE; 998 rb->InternalFormat = GL_NONE; 999 rb->_BaseFormat = GL_NONE; 1000 rb->NumSamples = 0; 1001 } 1002 1003 /* 1004 test_framebuffer_completeness(ctx, fb); 1005 */ 1006 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 1007 * points??? 1008 */ 1009} 1010 1011#if FEATURE_OES_EGL_image 1012void GLAPIENTRY 1013_mesa_EGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image) 1014{ 1015 struct gl_renderbuffer *rb; 1016 GET_CURRENT_CONTEXT(ctx); 1017 ASSERT_OUTSIDE_BEGIN_END(ctx); 1018 1019 if (target != GL_RENDERBUFFER) { 1020 _mesa_error(ctx, GL_INVALID_ENUM, "EGLImageTargetRenderbufferStorageOES"); 1021 return; 1022 } 1023 1024 rb = ctx->CurrentRenderbuffer; 1025 if (!rb) { 1026 _mesa_error(ctx, GL_INVALID_OPERATION, "EGLImageTargetRenderbufferStorageOES"); 1027 return; 1028 } 1029 1030 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1031 1032 ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); 1033} 1034#endif 1035 1036/** 1037 * Helper function for _mesa_GetRenderbufferParameterivEXT() and 1038 * _mesa_GetFramebufferAttachmentParameterivEXT() 1039 * We have to be careful to respect the base format. For example, if a 1040 * renderbuffer/texture was created with internalFormat=GL_RGB but the 1041 * driver actually chose a GL_RGBA format, when the user queries ALPHA_SIZE 1042 * we need to return zero. 1043 */ 1044static GLint 1045get_component_bits(GLenum pname, GLenum baseFormat, gl_format format) 1046{ 1047 switch (pname) { 1048 case GL_RENDERBUFFER_RED_SIZE_EXT: 1049 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 1050 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 1051 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 1052 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 1053 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 1054 if (baseFormat == GL_RGB || baseFormat == GL_RGBA) 1055 return _mesa_get_format_bits(format, pname); 1056 else 1057 return 0; 1058 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 1059 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 1060 if (baseFormat == GL_RGBA || baseFormat == GL_ALPHA) 1061 return _mesa_get_format_bits(format, pname); 1062 else 1063 return 0; 1064 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 1065 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 1066 if (baseFormat == GL_DEPTH_COMPONENT || baseFormat == GL_DEPTH_STENCIL) 1067 return _mesa_get_format_bits(format, pname); 1068 else 1069 return 0; 1070 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 1071 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 1072 if (baseFormat == GL_STENCIL_INDEX || baseFormat == GL_DEPTH_STENCIL) 1073 return _mesa_get_format_bits(format, pname); 1074 else 1075 return 0; 1076 default: 1077 return 0; 1078 } 1079} 1080 1081 1082 1083void GLAPIENTRY 1084_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 1085 GLsizei width, GLsizei height) 1086{ 1087 /* GL_ARB_fbo says calling this function is equivalent to calling 1088 * glRenderbufferStorageMultisample() with samples=0. We pass in 1089 * a token value here just for error reporting purposes. 1090 */ 1091 renderbuffer_storage(target, internalFormat, width, height, NO_SAMPLES); 1092} 1093 1094 1095void GLAPIENTRY 1096_mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, 1097 GLenum internalFormat, 1098 GLsizei width, GLsizei height) 1099{ 1100 renderbuffer_storage(target, internalFormat, width, height, samples); 1101} 1102 1103 1104 1105void GLAPIENTRY 1106_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 1107{ 1108 struct gl_renderbuffer *rb; 1109 GET_CURRENT_CONTEXT(ctx); 1110 1111 ASSERT_OUTSIDE_BEGIN_END(ctx); 1112 1113 if (target != GL_RENDERBUFFER_EXT) { 1114 _mesa_error(ctx, GL_INVALID_ENUM, 1115 "glGetRenderbufferParameterivEXT(target)"); 1116 return; 1117 } 1118 1119 rb = ctx->CurrentRenderbuffer; 1120 if (!rb) { 1121 _mesa_error(ctx, GL_INVALID_OPERATION, 1122 "glGetRenderbufferParameterivEXT"); 1123 return; 1124 } 1125 1126 /* No need to flush here since we're just quering state which is 1127 * not effected by rendering. 1128 */ 1129 1130 switch (pname) { 1131 case GL_RENDERBUFFER_WIDTH_EXT: 1132 *params = rb->Width; 1133 return; 1134 case GL_RENDERBUFFER_HEIGHT_EXT: 1135 *params = rb->Height; 1136 return; 1137 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 1138 *params = rb->InternalFormat; 1139 return; 1140 case GL_RENDERBUFFER_RED_SIZE_EXT: 1141 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 1142 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 1143 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 1144 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 1145 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 1146 *params = get_component_bits(pname, rb->_BaseFormat, rb->Format); 1147 break; 1148 case GL_RENDERBUFFER_SAMPLES: 1149 if (ctx->Extensions.ARB_framebuffer_object) { 1150 *params = rb->NumSamples; 1151 break; 1152 } 1153 /* fallthrough */ 1154 default: 1155 _mesa_error(ctx, GL_INVALID_ENUM, 1156 "glGetRenderbufferParameterivEXT(target)"); 1157 return; 1158 } 1159} 1160 1161 1162GLboolean GLAPIENTRY 1163_mesa_IsFramebufferEXT(GLuint framebuffer) 1164{ 1165 GET_CURRENT_CONTEXT(ctx); 1166 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1167 if (framebuffer) { 1168 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 1169 if (rb != NULL && rb != &DummyFramebuffer) 1170 return GL_TRUE; 1171 } 1172 return GL_FALSE; 1173} 1174 1175 1176/** 1177 * Check if any of the attachments of the given framebuffer are textures 1178 * (render to texture). Call ctx->Driver.RenderTexture() for such 1179 * attachments. 1180 */ 1181static void 1182check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 1183{ 1184 GLuint i; 1185 ASSERT(ctx->Driver.RenderTexture); 1186 1187 if (fb->Name == 0) 1188 return; /* can't render to texture with winsys framebuffers */ 1189 1190 for (i = 0; i < BUFFER_COUNT; i++) { 1191 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 1192 struct gl_texture_object *texObj = att->Texture; 1193 if (texObj 1194 && texObj->Image[att->CubeMapFace][att->TextureLevel]) { 1195 ctx->Driver.RenderTexture(ctx, fb, att); 1196 } 1197 } 1198} 1199 1200 1201/** 1202 * Examine all the framebuffer's attachments to see if any are textures. 1203 * If so, call ctx->Driver.FinishRenderTexture() for each texture to 1204 * notify the device driver that the texture image may have changed. 1205 */ 1206static void 1207check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 1208{ 1209 if (fb->Name == 0) 1210 return; /* can't render to texture with winsys framebuffers */ 1211 1212 if (ctx->Driver.FinishRenderTexture) { 1213 GLuint i; 1214 for (i = 0; i < BUFFER_COUNT; i++) { 1215 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 1216 if (att->Texture && att->Renderbuffer) { 1217 ctx->Driver.FinishRenderTexture(ctx, att); 1218 } 1219 } 1220 } 1221} 1222 1223 1224void GLAPIENTRY 1225_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 1226{ 1227 struct gl_framebuffer *newDrawFb, *newReadFb; 1228 struct gl_framebuffer *oldDrawFb, *oldReadFb; 1229 GLboolean bindReadBuf, bindDrawBuf; 1230 GET_CURRENT_CONTEXT(ctx); 1231 1232#ifdef DEBUG 1233 if (ctx->Extensions.ARB_framebuffer_object) { 1234 ASSERT(ctx->Extensions.EXT_framebuffer_object); 1235 ASSERT(ctx->Extensions.EXT_framebuffer_blit); 1236 } 1237#endif 1238 1239 ASSERT_OUTSIDE_BEGIN_END(ctx); 1240 1241 if (!ctx->Extensions.EXT_framebuffer_object) { 1242 _mesa_error(ctx, GL_INVALID_OPERATION, 1243 "glBindFramebufferEXT(unsupported)"); 1244 return; 1245 } 1246 1247 switch (target) { 1248#if FEATURE_EXT_framebuffer_blit 1249 case GL_DRAW_FRAMEBUFFER_EXT: 1250 if (!ctx->Extensions.EXT_framebuffer_blit) { 1251 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1252 return; 1253 } 1254 bindDrawBuf = GL_TRUE; 1255 bindReadBuf = GL_FALSE; 1256 break; 1257 case GL_READ_FRAMEBUFFER_EXT: 1258 if (!ctx->Extensions.EXT_framebuffer_blit) { 1259 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1260 return; 1261 } 1262 bindDrawBuf = GL_FALSE; 1263 bindReadBuf = GL_TRUE; 1264 break; 1265#endif 1266 case GL_FRAMEBUFFER_EXT: 1267 bindDrawBuf = GL_TRUE; 1268 bindReadBuf = GL_TRUE; 1269 break; 1270 default: 1271 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 1272 return; 1273 } 1274 1275 if (framebuffer) { 1276 /* Binding a user-created framebuffer object */ 1277 newDrawFb = _mesa_lookup_framebuffer(ctx, framebuffer); 1278 if (newDrawFb == &DummyFramebuffer) { 1279 /* ID was reserved, but no real framebuffer object made yet */ 1280 newDrawFb = NULL; 1281 } 1282 else if (!newDrawFb && ctx->Extensions.ARB_framebuffer_object) { 1283 /* All FBO IDs must be Gen'd */ 1284 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)"); 1285 return; 1286 } 1287 1288 if (!newDrawFb) { 1289 /* create new framebuffer object */ 1290 newDrawFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 1291 if (!newDrawFb) { 1292 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 1293 return; 1294 } 1295 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newDrawFb); 1296 } 1297 newReadFb = newDrawFb; 1298 } 1299 else { 1300 /* Binding the window system framebuffer (which was originally set 1301 * with MakeCurrent). 1302 */ 1303 newDrawFb = ctx->WinSysDrawBuffer; 1304 newReadFb = ctx->WinSysReadBuffer; 1305 } 1306 1307 ASSERT(newDrawFb); 1308 ASSERT(newDrawFb != &DummyFramebuffer); 1309 1310 /* save pointers to current/old framebuffers */ 1311 oldDrawFb = ctx->DrawBuffer; 1312 oldReadFb = ctx->ReadBuffer; 1313 1314 /* check if really changing bindings */ 1315 if (oldDrawFb == newDrawFb) 1316 bindDrawBuf = GL_FALSE; 1317 if (oldReadFb == newReadFb) 1318 bindReadBuf = GL_FALSE; 1319 1320 /* 1321 * OK, now bind the new Draw/Read framebuffers, if they're changing. 1322 * 1323 * We also check if we're beginning and/or ending render-to-texture. 1324 * When a framebuffer with texture attachments is unbound, call 1325 * ctx->Driver.FinishRenderTexture(). 1326 * When a framebuffer with texture attachments is bound, call 1327 * ctx->Driver.RenderTexture(). 1328 * 1329 * Note that if the ReadBuffer has texture attachments we don't consider 1330 * that a render-to-texture case. 1331 */ 1332 if (bindReadBuf) { 1333 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1334 1335 /* check if old readbuffer was render-to-texture */ 1336 check_end_texture_render(ctx, oldReadFb); 1337 1338 _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb); 1339 } 1340 1341 if (bindDrawBuf) { 1342 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1343 1344 /* check if old read/draw buffers were render-to-texture */ 1345 if (!bindReadBuf) 1346 check_end_texture_render(ctx, oldReadFb); 1347 1348 if (oldDrawFb != oldReadFb) 1349 check_end_texture_render(ctx, oldDrawFb); 1350 1351 /* check if newly bound framebuffer has any texture attachments */ 1352 check_begin_texture_render(ctx, newDrawFb); 1353 1354 _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb); 1355 } 1356 1357 if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) { 1358 ctx->Driver.BindFramebuffer(ctx, target, newDrawFb, newReadFb); 1359 } 1360} 1361 1362 1363void GLAPIENTRY 1364_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 1365{ 1366 GLint i; 1367 GET_CURRENT_CONTEXT(ctx); 1368 1369 ASSERT_OUTSIDE_BEGIN_END(ctx); 1370 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1371 1372 for (i = 0; i < n; i++) { 1373 if (framebuffers[i] > 0) { 1374 struct gl_framebuffer *fb; 1375 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 1376 if (fb) { 1377 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 1378 1379 /* check if deleting currently bound framebuffer object */ 1380 if (ctx->Extensions.EXT_framebuffer_blit) { 1381 /* separate draw/read binding points */ 1382 if (fb == ctx->DrawBuffer) { 1383 /* bind default */ 1384 ASSERT(fb->RefCount >= 2); 1385 _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); 1386 } 1387 if (fb == ctx->ReadBuffer) { 1388 /* bind default */ 1389 ASSERT(fb->RefCount >= 2); 1390 _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); 1391 } 1392 } 1393 else { 1394 /* only one binding point for read/draw buffers */ 1395 if (fb == ctx->DrawBuffer || fb == ctx->ReadBuffer) { 1396 /* bind default */ 1397 ASSERT(fb->RefCount >= 2); 1398 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 1399 } 1400 } 1401 1402 /* remove from hash table immediately, to free the ID */ 1403 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 1404 1405 if (fb != &DummyFramebuffer) { 1406 /* But the object will not be freed until it's no longer 1407 * bound in any context. 1408 */ 1409 _mesa_reference_framebuffer(&fb, NULL); 1410 } 1411 } 1412 } 1413 } 1414} 1415 1416 1417void GLAPIENTRY 1418_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 1419{ 1420 GET_CURRENT_CONTEXT(ctx); 1421 GLuint first; 1422 GLint i; 1423 1424 ASSERT_OUTSIDE_BEGIN_END(ctx); 1425 1426 if (n < 0) { 1427 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 1428 return; 1429 } 1430 1431 if (!framebuffers) 1432 return; 1433 1434 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 1435 1436 for (i = 0; i < n; i++) { 1437 GLuint name = first + i; 1438 framebuffers[i] = name; 1439 /* insert dummy placeholder into hash table */ 1440 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1441 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 1442 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1443 } 1444} 1445 1446 1447 1448GLenum GLAPIENTRY 1449_mesa_CheckFramebufferStatusEXT(GLenum target) 1450{ 1451 struct gl_framebuffer *buffer; 1452 GET_CURRENT_CONTEXT(ctx); 1453 1454 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1455 1456 switch (target) { 1457#if FEATURE_EXT_framebuffer_blit 1458 case GL_DRAW_FRAMEBUFFER_EXT: 1459 if (!ctx->Extensions.EXT_framebuffer_blit) { 1460 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1461 return 0; 1462 } 1463 buffer = ctx->DrawBuffer; 1464 break; 1465 case GL_READ_FRAMEBUFFER_EXT: 1466 if (!ctx->Extensions.EXT_framebuffer_blit) { 1467 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1468 return 0; 1469 } 1470 buffer = ctx->ReadBuffer; 1471 break; 1472#endif 1473 case GL_FRAMEBUFFER_EXT: 1474 buffer = ctx->DrawBuffer; 1475 break; 1476 default: 1477 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1478 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1479 } 1480 1481 if (buffer->Name == 0) { 1482 /* The window system / default framebuffer is always complete */ 1483 return GL_FRAMEBUFFER_COMPLETE_EXT; 1484 } 1485 1486 /* No need to flush here */ 1487 1488 if (buffer->_Status != GL_FRAMEBUFFER_COMPLETE) { 1489 _mesa_test_framebuffer_completeness(ctx, buffer); 1490 } 1491 1492 return buffer->_Status; 1493} 1494 1495 1496 1497/** 1498 * Common code called by glFramebufferTexture1D/2D/3DEXT(). 1499 */ 1500static void 1501framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 1502 GLenum attachment, GLenum textarget, GLuint texture, 1503 GLint level, GLint zoffset) 1504{ 1505 struct gl_renderbuffer_attachment *att; 1506 struct gl_texture_object *texObj = NULL; 1507 struct gl_framebuffer *fb; 1508 GLboolean error = GL_FALSE; 1509 1510 ASSERT_OUTSIDE_BEGIN_END(ctx); 1511 1512 switch (target) { 1513 case GL_READ_FRAMEBUFFER_EXT: 1514 error = !ctx->Extensions.EXT_framebuffer_blit; 1515 fb = ctx->ReadBuffer; 1516 break; 1517 case GL_DRAW_FRAMEBUFFER_EXT: 1518 error = !ctx->Extensions.EXT_framebuffer_blit; 1519 /* fall-through */ 1520 case GL_FRAMEBUFFER_EXT: 1521 fb = ctx->DrawBuffer; 1522 break; 1523 default: 1524 error = GL_TRUE; 1525 } 1526 1527 if (error) { 1528 _mesa_error(ctx, GL_INVALID_ENUM, 1529 "glFramebufferTexture%sEXT(target=0x%x)", caller, target); 1530 return; 1531 } 1532 1533 ASSERT(fb); 1534 1535 /* check framebuffer binding */ 1536 if (fb->Name == 0) { 1537 _mesa_error(ctx, GL_INVALID_OPERATION, 1538 "glFramebufferTexture%sEXT", caller); 1539 return; 1540 } 1541 1542 1543 /* The textarget, level, and zoffset parameters are only validated if 1544 * texture is non-zero. 1545 */ 1546 if (texture) { 1547 GLboolean err = GL_TRUE; 1548 1549 texObj = _mesa_lookup_texture(ctx, texture); 1550 if (texObj != NULL) { 1551 if (textarget == 0) { 1552 err = (texObj->Target != GL_TEXTURE_3D) && 1553 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 1554 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 1555 } 1556 else { 1557 err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 1558 ? !IS_CUBE_FACE(textarget) 1559 : (texObj->Target != textarget); 1560 } 1561 } 1562 1563 if (err) { 1564 _mesa_error(ctx, GL_INVALID_OPERATION, 1565 "glFramebufferTexture%sEXT(texture target mismatch)", 1566 caller); 1567 return; 1568 } 1569 1570 if (texObj->Target == GL_TEXTURE_3D) { 1571 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1572 if (zoffset < 0 || zoffset >= maxSize) { 1573 _mesa_error(ctx, GL_INVALID_VALUE, 1574 "glFramebufferTexture%sEXT(zoffset)", caller); 1575 return; 1576 } 1577 } 1578 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 1579 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 1580 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 1581 _mesa_error(ctx, GL_INVALID_VALUE, 1582 "glFramebufferTexture%sEXT(layer)", caller); 1583 return; 1584 } 1585 } 1586 1587 if ((level < 0) || 1588 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 1589 _mesa_error(ctx, GL_INVALID_VALUE, 1590 "glFramebufferTexture%sEXT(level)", caller); 1591 return; 1592 } 1593 } 1594 1595 att = _mesa_get_attachment(ctx, fb, attachment); 1596 if (att == NULL) { 1597 _mesa_error(ctx, GL_INVALID_ENUM, 1598 "glFramebufferTexture%sEXT(attachment)", caller); 1599 return; 1600 } 1601 1602 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1603 1604 _glthread_LOCK_MUTEX(fb->Mutex); 1605 if (texObj) { 1606 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 1607 level, zoffset); 1608 /* Set the render-to-texture flag. We'll check this flag in 1609 * glTexImage() and friends to determine if we need to revalidate 1610 * any FBOs that might be rendering into this texture. 1611 * This flag never gets cleared since it's non-trivial to determine 1612 * when all FBOs might be done rendering to this texture. That's OK 1613 * though since it's uncommon to render to a texture then repeatedly 1614 * call glTexImage() to change images in the texture. 1615 */ 1616 texObj->_RenderToTexture = GL_TRUE; 1617 } 1618 else { 1619 _mesa_remove_attachment(ctx, att); 1620 } 1621 1622 invalidate_framebuffer(fb); 1623 1624 _glthread_UNLOCK_MUTEX(fb->Mutex); 1625} 1626 1627 1628 1629void GLAPIENTRY 1630_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1631 GLenum textarget, GLuint texture, GLint level) 1632{ 1633 GET_CURRENT_CONTEXT(ctx); 1634 1635 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 1636 _mesa_error(ctx, GL_INVALID_ENUM, 1637 "glFramebufferTexture1DEXT(textarget)"); 1638 return; 1639 } 1640 1641 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 1642 level, 0); 1643} 1644 1645 1646void GLAPIENTRY 1647_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1648 GLenum textarget, GLuint texture, GLint level) 1649{ 1650 GET_CURRENT_CONTEXT(ctx); 1651 1652 if ((texture != 0) && 1653 (textarget != GL_TEXTURE_2D) && 1654 (textarget != GL_TEXTURE_RECTANGLE_ARB) && 1655 (!IS_CUBE_FACE(textarget))) { 1656 _mesa_error(ctx, GL_INVALID_OPERATION, 1657 "glFramebufferTexture2DEXT(textarget=0x%x)", textarget); 1658 return; 1659 } 1660 1661 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 1662 level, 0); 1663} 1664 1665 1666void GLAPIENTRY 1667_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1668 GLenum textarget, GLuint texture, 1669 GLint level, GLint zoffset) 1670{ 1671 GET_CURRENT_CONTEXT(ctx); 1672 1673 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 1674 _mesa_error(ctx, GL_INVALID_ENUM, 1675 "glFramebufferTexture3DEXT(textarget)"); 1676 return; 1677 } 1678 1679 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 1680 level, zoffset); 1681} 1682 1683 1684void GLAPIENTRY 1685_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 1686 GLuint texture, GLint level, GLint layer) 1687{ 1688 GET_CURRENT_CONTEXT(ctx); 1689 1690 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 1691 level, layer); 1692} 1693 1694 1695void GLAPIENTRY 1696_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1697 GLenum renderbufferTarget, 1698 GLuint renderbuffer) 1699{ 1700 struct gl_renderbuffer_attachment *att; 1701 struct gl_framebuffer *fb; 1702 struct gl_renderbuffer *rb; 1703 GET_CURRENT_CONTEXT(ctx); 1704 1705 ASSERT_OUTSIDE_BEGIN_END(ctx); 1706 1707 switch (target) { 1708#if FEATURE_EXT_framebuffer_blit 1709 case GL_DRAW_FRAMEBUFFER_EXT: 1710 if (!ctx->Extensions.EXT_framebuffer_blit) { 1711 _mesa_error(ctx, GL_INVALID_ENUM, 1712 "glFramebufferRenderbufferEXT(target)"); 1713 return; 1714 } 1715 fb = ctx->DrawBuffer; 1716 break; 1717 case GL_READ_FRAMEBUFFER_EXT: 1718 if (!ctx->Extensions.EXT_framebuffer_blit) { 1719 _mesa_error(ctx, GL_INVALID_ENUM, 1720 "glFramebufferRenderbufferEXT(target)"); 1721 return; 1722 } 1723 fb = ctx->ReadBuffer; 1724 break; 1725#endif 1726 case GL_FRAMEBUFFER_EXT: 1727 fb = ctx->DrawBuffer; 1728 break; 1729 default: 1730 _mesa_error(ctx, GL_INVALID_ENUM, 1731 "glFramebufferRenderbufferEXT(target)"); 1732 return; 1733 } 1734 1735 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1736 _mesa_error(ctx, GL_INVALID_ENUM, 1737 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1738 return; 1739 } 1740 1741 if (fb->Name == 0) { 1742 /* Can't attach new renderbuffers to a window system framebuffer */ 1743 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1744 return; 1745 } 1746 1747 att = _mesa_get_attachment(ctx, fb, attachment); 1748 if (att == NULL) { 1749 _mesa_error(ctx, GL_INVALID_ENUM, 1750 "glFramebufferRenderbufferEXT(invalid attachment %s)", 1751 _mesa_lookup_enum_by_nr(attachment)); 1752 return; 1753 } 1754 1755 if (renderbuffer) { 1756 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 1757 if (!rb) { 1758 _mesa_error(ctx, GL_INVALID_OPERATION, 1759 "glFramebufferRenderbufferEXT(non-existant" 1760 " renderbuffer %u)", renderbuffer); 1761 return; 1762 } 1763 } 1764 else { 1765 /* remove renderbuffer attachment */ 1766 rb = NULL; 1767 } 1768 1769 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && 1770 rb && rb->Format != MESA_FORMAT_NONE) { 1771 /* make sure the renderbuffer is a depth/stencil format */ 1772 const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); 1773 if (baseFormat != GL_DEPTH_STENCIL) { 1774 _mesa_error(ctx, GL_INVALID_OPERATION, 1775 "glFramebufferRenderbufferEXT(renderbuffer" 1776 " is not DEPTH_STENCIL format)"); 1777 return; 1778 } 1779 } 1780 1781 1782 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1783 1784 assert(ctx->Driver.FramebufferRenderbuffer); 1785 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 1786 1787 /* Some subsequent GL commands may depend on the framebuffer's visual 1788 * after the binding is updated. Update visual info now. 1789 */ 1790 _mesa_update_framebuffer_visual(fb); 1791} 1792 1793 1794void GLAPIENTRY 1795_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1796 GLenum pname, GLint *params) 1797{ 1798 const struct gl_renderbuffer_attachment *att; 1799 struct gl_framebuffer *buffer; 1800 GET_CURRENT_CONTEXT(ctx); 1801 1802 ASSERT_OUTSIDE_BEGIN_END(ctx); 1803 1804 switch (target) { 1805#if FEATURE_EXT_framebuffer_blit 1806 case GL_DRAW_FRAMEBUFFER_EXT: 1807 if (!ctx->Extensions.EXT_framebuffer_blit) { 1808 _mesa_error(ctx, GL_INVALID_ENUM, 1809 "glGetFramebufferAttachmentParameterivEXT(target)"); 1810 return; 1811 } 1812 buffer = ctx->DrawBuffer; 1813 break; 1814 case GL_READ_FRAMEBUFFER_EXT: 1815 if (!ctx->Extensions.EXT_framebuffer_blit) { 1816 _mesa_error(ctx, GL_INVALID_ENUM, 1817 "glGetFramebufferAttachmentParameterivEXT(target)"); 1818 return; 1819 } 1820 buffer = ctx->ReadBuffer; 1821 break; 1822#endif 1823 case GL_FRAMEBUFFER_EXT: 1824 buffer = ctx->DrawBuffer; 1825 break; 1826 default: 1827 _mesa_error(ctx, GL_INVALID_ENUM, 1828 "glGetFramebufferAttachmentParameterivEXT(target)"); 1829 return; 1830 } 1831 1832 if (buffer->Name == 0) { 1833 _mesa_error(ctx, GL_INVALID_OPERATION, 1834 "glGetFramebufferAttachmentParameterivEXT"); 1835 return; 1836 } 1837 1838 att = _mesa_get_attachment(ctx, buffer, attachment); 1839 if (att == NULL) { 1840 _mesa_error(ctx, GL_INVALID_ENUM, 1841 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1842 return; 1843 } 1844 1845 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { 1846 /* the depth and stencil attachments must point to the same buffer */ 1847 const struct gl_renderbuffer_attachment *depthAtt, *stencilAtt; 1848 depthAtt = _mesa_get_attachment(ctx, buffer, GL_DEPTH_ATTACHMENT); 1849 stencilAtt = _mesa_get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); 1850 if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { 1851 _mesa_error(ctx, GL_INVALID_OPERATION, 1852 "glGetFramebufferAttachmentParameterivEXT(DEPTH/STENCIL" 1853 " attachments differ)"); 1854 return; 1855 } 1856 } 1857 1858 /* No need to flush here */ 1859 1860 switch (pname) { 1861 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1862 *params = att->Type; 1863 return; 1864 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1865 if (att->Type == GL_RENDERBUFFER_EXT) { 1866 *params = att->Renderbuffer->Name; 1867 } 1868 else if (att->Type == GL_TEXTURE) { 1869 *params = att->Texture->Name; 1870 } 1871 else { 1872 _mesa_error(ctx, GL_INVALID_ENUM, 1873 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1874 } 1875 return; 1876 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1877 if (att->Type == GL_TEXTURE) { 1878 *params = att->TextureLevel; 1879 } 1880 else { 1881 _mesa_error(ctx, GL_INVALID_ENUM, 1882 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1883 } 1884 return; 1885 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1886 if (att->Type == GL_TEXTURE) { 1887 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 1888 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1889 } 1890 else { 1891 *params = 0; 1892 } 1893 } 1894 else { 1895 _mesa_error(ctx, GL_INVALID_ENUM, 1896 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1897 } 1898 return; 1899 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1900 if (att->Type == GL_TEXTURE) { 1901 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 1902 *params = att->Zoffset; 1903 } 1904 else { 1905 *params = 0; 1906 } 1907 } 1908 else { 1909 _mesa_error(ctx, GL_INVALID_ENUM, 1910 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1911 } 1912 return; 1913 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: 1914 if (!ctx->Extensions.ARB_framebuffer_object) { 1915 _mesa_error(ctx, GL_INVALID_ENUM, 1916 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1917 } 1918 else { 1919 *params = _mesa_get_format_color_encoding(att->Renderbuffer->Format); 1920 } 1921 return; 1922 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: 1923 if (!ctx->Extensions.ARB_framebuffer_object) { 1924 _mesa_error(ctx, GL_INVALID_ENUM, 1925 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1926 return; 1927 } 1928 else { 1929 gl_format format = att->Renderbuffer->Format; 1930 if (format == MESA_FORMAT_CI8 || format == MESA_FORMAT_S8) { 1931 /* special cases */ 1932 *params = GL_INDEX; 1933 } 1934 else { 1935 *params = _mesa_get_format_datatype(format); 1936 } 1937 } 1938 return; 1939 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: 1940 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: 1941 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: 1942 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: 1943 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: 1944 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: 1945 if (!ctx->Extensions.ARB_framebuffer_object) { 1946 _mesa_error(ctx, GL_INVALID_ENUM, 1947 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1948 } 1949 else if (att->Texture) { 1950 const struct gl_texture_image *texImage = 1951 _mesa_select_tex_image(ctx, att->Texture, att->Texture->Target, 1952 att->TextureLevel); 1953 if (texImage) { 1954 *params = get_component_bits(pname, texImage->_BaseFormat, 1955 texImage->TexFormat); 1956 } 1957 else { 1958 *params = 0; 1959 } 1960 } 1961 else if (att->Renderbuffer) { 1962 *params = get_component_bits(pname, att->Renderbuffer->_BaseFormat, 1963 att->Renderbuffer->Format); 1964 } 1965 else { 1966 *params = 0; 1967 } 1968 return; 1969 default: 1970 _mesa_error(ctx, GL_INVALID_ENUM, 1971 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1972 return; 1973 } 1974} 1975 1976 1977void GLAPIENTRY 1978_mesa_GenerateMipmapEXT(GLenum target) 1979{ 1980 struct gl_texture_object *texObj; 1981 GET_CURRENT_CONTEXT(ctx); 1982 1983 ASSERT_OUTSIDE_BEGIN_END(ctx); 1984 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1985 1986 switch (target) { 1987 case GL_TEXTURE_1D: 1988 case GL_TEXTURE_2D: 1989 case GL_TEXTURE_3D: 1990 case GL_TEXTURE_CUBE_MAP: 1991 /* OK, legal value */ 1992 break; 1993 default: 1994 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1995 return; 1996 } 1997 1998 texObj = _mesa_get_current_tex_object(ctx, target); 1999 2000 if (texObj->BaseLevel >= texObj->MaxLevel) { 2001 /* nothing to do */ 2002 return; 2003 } 2004 2005 _mesa_lock_texture(ctx, texObj); 2006 if (target == GL_TEXTURE_CUBE_MAP) { 2007 GLuint face; 2008 for (face = 0; face < 6; face++) 2009 ctx->Driver.GenerateMipmap(ctx, 2010 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 2011 texObj); 2012 } 2013 else { 2014 ctx->Driver.GenerateMipmap(ctx, target, texObj); 2015 } 2016 _mesa_unlock_texture(ctx, texObj); 2017} 2018 2019 2020#if FEATURE_EXT_framebuffer_blit 2021 2022static const struct gl_renderbuffer_attachment * 2023find_attachment(const struct gl_framebuffer *fb, const struct gl_renderbuffer *rb) 2024{ 2025 GLuint i; 2026 for (i = 0; i < Elements(fb->Attachment); i++) { 2027 if (fb->Attachment[i].Renderbuffer == rb) 2028 return &fb->Attachment[i]; 2029 } 2030 return NULL; 2031} 2032 2033 2034 2035/** 2036 * Blit rectangular region, optionally from one framebuffer to another. 2037 * 2038 * Note, if the src buffer is multisampled and the dest is not, this is 2039 * when the samples must be resolved to a single color. 2040 */ 2041void GLAPIENTRY 2042_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 2043 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 2044 GLbitfield mask, GLenum filter) 2045{ 2046 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | 2047 GL_DEPTH_BUFFER_BIT | 2048 GL_STENCIL_BUFFER_BIT); 2049 const struct gl_framebuffer *readFb, *drawFb; 2050 const struct gl_renderbuffer *colorReadRb, *colorDrawRb; 2051 GET_CURRENT_CONTEXT(ctx); 2052 2053 ASSERT_OUTSIDE_BEGIN_END(ctx); 2054 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 2055 2056 if (ctx->NewState) { 2057 _mesa_update_state(ctx); 2058 } 2059 2060 readFb = ctx->ReadBuffer; 2061 drawFb = ctx->DrawBuffer; 2062 2063 if (!readFb || !drawFb) { 2064 /* This will normally never happen but someday we may want to 2065 * support MakeCurrent() with no drawables. 2066 */ 2067 return; 2068 } 2069 2070 /* check for complete framebuffers */ 2071 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 2072 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 2073 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 2074 "glBlitFramebufferEXT(incomplete draw/read buffers)"); 2075 return; 2076 } 2077 2078 if (filter != GL_NEAREST && filter != GL_LINEAR) { 2079 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 2080 return; 2081 } 2082 2083 if (mask & ~legalMaskBits) { 2084 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 2085 return; 2086 } 2087 2088 /* depth/stencil must be blitted with nearest filtering */ 2089 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 2090 && filter != GL_NEAREST) { 2091 _mesa_error(ctx, GL_INVALID_OPERATION, 2092 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 2093 return; 2094 } 2095 2096 /* get color read/draw renderbuffers */ 2097 if (mask & GL_COLOR_BUFFER_BIT) { 2098 colorReadRb = readFb->_ColorReadBuffer; 2099 colorDrawRb = drawFb->_ColorDrawBuffers[0]; 2100 } 2101 else { 2102 colorReadRb = colorDrawRb = NULL; 2103 } 2104 2105 if (mask & GL_STENCIL_BUFFER_BIT) { 2106 struct gl_renderbuffer *readRb = readFb->_StencilBuffer; 2107 struct gl_renderbuffer *drawRb = drawFb->_StencilBuffer; 2108 if (!readRb || 2109 !drawRb || 2110 _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != 2111 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { 2112 _mesa_error(ctx, GL_INVALID_OPERATION, 2113 "glBlitFramebufferEXT(stencil buffer size mismatch"); 2114 return; 2115 } 2116 } 2117 2118 if (mask & GL_DEPTH_BUFFER_BIT) { 2119 struct gl_renderbuffer *readRb = readFb->_DepthBuffer; 2120 struct gl_renderbuffer *drawRb = drawFb->_DepthBuffer; 2121 if (!readRb || 2122 !drawRb || 2123 _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != 2124 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) { 2125 _mesa_error(ctx, GL_INVALID_OPERATION, 2126 "glBlitFramebufferEXT(depth buffer size mismatch"); 2127 return; 2128 } 2129 } 2130 2131 if (readFb->Visual.samples > 0 && 2132 drawFb->Visual.samples > 0 && 2133 readFb->Visual.samples != drawFb->Visual.samples) { 2134 _mesa_error(ctx, GL_INVALID_OPERATION, 2135 "glBlitFramebufferEXT(mismatched samples"); 2136 return; 2137 } 2138 2139 /* extra checks for multisample copies... */ 2140 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { 2141 /* src and dest region sizes must be the same */ 2142 if (srcX1 - srcX0 != dstX1 - dstX0 || 2143 srcY1 - srcY0 != dstY1 - dstY0) { 2144 _mesa_error(ctx, GL_INVALID_OPERATION, 2145 "glBlitFramebufferEXT(bad src/dst multisample region sizes"); 2146 return; 2147 } 2148 2149 /* color formats must match */ 2150 if (colorReadRb && 2151 colorDrawRb && 2152 colorReadRb->Format != colorDrawRb->Format) { 2153 _mesa_error(ctx, GL_INVALID_OPERATION, 2154 "glBlitFramebufferEXT(bad src/dst multisample pixel formats"); 2155 return; 2156 } 2157 } 2158 2159 if (!ctx->Extensions.EXT_framebuffer_blit) { 2160 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 2161 return; 2162 } 2163 2164 /* Debug code */ 2165 if (DEBUG_BLIT) { 2166 printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," 2167 " 0x%x, 0x%x)\n", 2168 srcX0, srcY0, srcX1, srcY1, 2169 dstX0, dstY0, dstX1, dstY1, 2170 mask, filter); 2171 if (colorReadRb) { 2172 const struct gl_renderbuffer_attachment *att; 2173 2174 att = find_attachment(readFb, colorReadRb); 2175 printf(" Src FBO %u RB %u (%dx%d) ", 2176 readFb->Name, colorReadRb->Name, 2177 colorReadRb->Width, colorReadRb->Height); 2178 if (att && att->Texture) { 2179 printf("Tex %u tgt 0x%x level %u face %u", 2180 att->Texture->Name, 2181 att->Texture->Target, 2182 att->TextureLevel, 2183 att->CubeMapFace); 2184 } 2185 printf("\n"); 2186 2187 att = find_attachment(drawFb, colorDrawRb); 2188 printf(" Dst FBO %u RB %u (%dx%d) ", 2189 drawFb->Name, colorDrawRb->Name, 2190 colorDrawRb->Width, colorDrawRb->Height); 2191 if (att && att->Texture) { 2192 printf("Tex %u tgt 0x%x level %u face %u", 2193 att->Texture->Name, 2194 att->Texture->Target, 2195 att->TextureLevel, 2196 att->CubeMapFace); 2197 } 2198 printf("\n"); 2199 } 2200 } 2201 2202 ASSERT(ctx->Driver.BlitFramebuffer); 2203 ctx->Driver.BlitFramebuffer(ctx, 2204 srcX0, srcY0, srcX1, srcY1, 2205 dstX0, dstY0, dstX1, dstY1, 2206 mask, filter); 2207} 2208#endif /* FEATURE_EXT_framebuffer_blit */ 2209