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