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