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