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