fbobject.c revision c7037ccd
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.1 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/* 27 * Authors: 28 * Brian Paul 29 */ 30 31 32#include "buffers.h" 33#include "context.h" 34#include "fbobject.h" 35#include "framebuffer.h" 36#include "hash.h" 37#include "mipmap.h" 38#include "renderbuffer.h" 39#include "state.h" 40#include "teximage.h" 41#include "texobj.h" 42#include "texstore.h" 43 44 45/** 46 * Notes: 47 * 48 * None of the GL_EXT_framebuffer_object functions are compiled into 49 * display lists. 50 */ 51 52 53 54/* 55 * When glGenRender/FramebuffersEXT() is called we insert pointers to 56 * these placeholder objects into the hash table. 57 * Later, when the object ID is first bound, we replace the placeholder 58 * with the real frame/renderbuffer. 59 */ 60static struct gl_framebuffer DummyFramebuffer; 61static struct gl_renderbuffer DummyRenderbuffer; 62 63 64#define IS_CUBE_FACE(TARGET) \ 65 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 66 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 67 68 69static void 70delete_dummy_renderbuffer(struct gl_renderbuffer *rb) 71{ 72 /* no op */ 73} 74 75static void 76delete_dummy_framebuffer(struct gl_framebuffer *fb) 77{ 78 /* no op */ 79} 80 81 82void 83_mesa_init_fbobjects(GLcontext *ctx) 84{ 85 DummyFramebuffer.Delete = delete_dummy_framebuffer; 86 DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 87} 88 89 90/** 91 * Helper routine for getting a gl_renderbuffer. 92 */ 93struct gl_renderbuffer * 94_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) 95{ 96 struct gl_renderbuffer *rb; 97 98 if (id == 0) 99 return NULL; 100 101 rb = (struct gl_renderbuffer *) 102 _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 103 return rb; 104} 105 106 107/** 108 * Helper routine for getting a gl_framebuffer. 109 */ 110struct gl_framebuffer * 111_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) 112{ 113 struct gl_framebuffer *fb; 114 115 if (id == 0) 116 return NULL; 117 118 fb = (struct gl_framebuffer *) 119 _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 120 return fb; 121} 122 123 124/** 125 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 126 * gl_renderbuffer_attachment object. 127 */ 128struct gl_renderbuffer_attachment * 129_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, 130 GLenum attachment) 131{ 132 GLuint i; 133 134 switch (attachment) { 135 case GL_COLOR_ATTACHMENT0_EXT: 136 case GL_COLOR_ATTACHMENT1_EXT: 137 case GL_COLOR_ATTACHMENT2_EXT: 138 case GL_COLOR_ATTACHMENT3_EXT: 139 case GL_COLOR_ATTACHMENT4_EXT: 140 case GL_COLOR_ATTACHMENT5_EXT: 141 case GL_COLOR_ATTACHMENT6_EXT: 142 case GL_COLOR_ATTACHMENT7_EXT: 143 case GL_COLOR_ATTACHMENT8_EXT: 144 case GL_COLOR_ATTACHMENT9_EXT: 145 case GL_COLOR_ATTACHMENT10_EXT: 146 case GL_COLOR_ATTACHMENT11_EXT: 147 case GL_COLOR_ATTACHMENT12_EXT: 148 case GL_COLOR_ATTACHMENT13_EXT: 149 case GL_COLOR_ATTACHMENT14_EXT: 150 case GL_COLOR_ATTACHMENT15_EXT: 151 i = attachment - GL_COLOR_ATTACHMENT0_EXT; 152 if (i >= ctx->Const.MaxColorAttachments) { 153 return NULL; 154 } 155 return &fb->Attachment[BUFFER_COLOR0 + i]; 156 case GL_DEPTH_ATTACHMENT_EXT: 157 return &fb->Attachment[BUFFER_DEPTH]; 158 case GL_STENCIL_ATTACHMENT_EXT: 159 return &fb->Attachment[BUFFER_STENCIL]; 160 default: 161 return NULL; 162 } 163} 164 165 166/** 167 * Remove any texture or renderbuffer attached to the given attachment 168 * point. Update reference counts, etc. 169 */ 170void 171_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) 172{ 173 if (att->Type == GL_TEXTURE) { 174 ASSERT(att->Texture); 175 if (ctx->Driver.FinishRenderTexture) { 176 /* tell driver we're done rendering to this texobj */ 177 ctx->Driver.FinishRenderTexture(ctx, att); 178 } 179 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 180 ASSERT(!att->Texture); 181 } 182 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 183 ASSERT(!att->Texture); 184 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 185 ASSERT(!att->Renderbuffer); 186 } 187 att->Type = GL_NONE; 188 att->Complete = GL_TRUE; 189} 190 191 192/** 193 * Bind a texture object to an attachment point. 194 * The previous binding, if any, will be removed first. 195 */ 196void 197_mesa_set_texture_attachment(GLcontext *ctx, 198 struct gl_framebuffer *fb, 199 struct gl_renderbuffer_attachment *att, 200 struct gl_texture_object *texObj, 201 GLenum texTarget, GLuint level, GLuint zoffset) 202{ 203 if (att->Texture == texObj) { 204 /* re-attaching same texture */ 205 ASSERT(att->Type == GL_TEXTURE); 206 } 207 else { 208 /* new attachment */ 209 _mesa_remove_attachment(ctx, att); 210 att->Type = GL_TEXTURE; 211 assert(!att->Texture); 212 _mesa_reference_texobj(&att->Texture, texObj); 213 } 214 215 /* always update these fields */ 216 att->TextureLevel = level; 217 if (IS_CUBE_FACE(texTarget)) { 218 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 219 } 220 else { 221 att->CubeMapFace = 0; 222 } 223 att->Zoffset = zoffset; 224 att->Complete = GL_FALSE; 225 226 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 227 ctx->Driver.RenderTexture(ctx, fb, att); 228 } 229} 230 231 232/** 233 * Bind a renderbuffer to an attachment point. 234 * The previous binding, if any, will be removed first. 235 */ 236void 237_mesa_set_renderbuffer_attachment(GLcontext *ctx, 238 struct gl_renderbuffer_attachment *att, 239 struct gl_renderbuffer *rb) 240{ 241 /* XXX check if re-doing same attachment, exit early */ 242 _mesa_remove_attachment(ctx, att); 243 att->Type = GL_RENDERBUFFER_EXT; 244 att->Texture = NULL; /* just to be safe */ 245 att->Complete = GL_FALSE; 246 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 247} 248 249 250/** 251 * Fallback for ctx->Driver.FramebufferRenderbuffer() 252 * Attach a renderbuffer object to a framebuffer object. 253 */ 254void 255_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, 256 GLenum attachment, struct gl_renderbuffer *rb) 257{ 258 struct gl_renderbuffer_attachment *att; 259 260 _glthread_LOCK_MUTEX(fb->Mutex); 261 262 att = _mesa_get_attachment(ctx, fb, attachment); 263 ASSERT(att); 264 if (rb) { 265 _mesa_set_renderbuffer_attachment(ctx, att, rb); 266 } 267 else { 268 _mesa_remove_attachment(ctx, att); 269 } 270 271 _glthread_UNLOCK_MUTEX(fb->Mutex); 272} 273 274 275/** 276 * Test if an attachment point is complete and update its Complete field. 277 * \param format if GL_COLOR, this is a color attachment point, 278 * if GL_DEPTH, this is a depth component attachment point, 279 * if GL_STENCIL, this is a stencil component attachment point. 280 */ 281static void 282test_attachment_completeness(const GLcontext *ctx, GLenum format, 283 struct gl_renderbuffer_attachment *att) 284{ 285 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 286 287 /* assume complete */ 288 att->Complete = GL_TRUE; 289 290 /* Look for reasons why the attachment might be incomplete */ 291 if (att->Type == GL_TEXTURE) { 292 const struct gl_texture_object *texObj = att->Texture; 293 struct gl_texture_image *texImage; 294 295 if (!texObj) { 296 att->Complete = GL_FALSE; 297 return; 298 } 299 300 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 301 if (!texImage) { 302 att->Complete = GL_FALSE; 303 return; 304 } 305 if (texImage->Width < 1 || texImage->Height < 1) { 306 att->Complete = GL_FALSE; 307 return; 308 } 309 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { 310 att->Complete = GL_FALSE; 311 return; 312 } 313 314 if (format == GL_COLOR) { 315 if (texImage->TexFormat->BaseFormat != GL_RGB && 316 texImage->TexFormat->BaseFormat != GL_RGBA) { 317 att->Complete = GL_FALSE; 318 return; 319 } 320 } 321 else if (format == GL_DEPTH) { 322 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { 323 /* OK */ 324 } 325 else if (ctx->Extensions.EXT_packed_depth_stencil && 326 ctx->Extensions.ARB_depth_texture && 327 texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) { 328 /* OK */ 329 } 330 else { 331 att->Complete = GL_FALSE; 332 return; 333 } 334 } 335 else { 336 ASSERT(format == GL_STENCIL); 337 ASSERT(att->Renderbuffer->StencilBits); 338 if (ctx->Extensions.EXT_packed_depth_stencil && 339 ctx->Extensions.ARB_depth_texture && 340 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 341 /* OK */ 342 } 343 else { 344 /* no such thing as stencil-only textures */ 345 att->Complete = GL_FALSE; 346 return; 347 } 348 } 349 } 350 else if (att->Type == GL_RENDERBUFFER_EXT) { 351 ASSERT(att->Renderbuffer); 352 if (!att->Renderbuffer->InternalFormat || 353 att->Renderbuffer->Width < 1 || 354 att->Renderbuffer->Height < 1) { 355 att->Complete = GL_FALSE; 356 return; 357 } 358 if (format == GL_COLOR) { 359 if (att->Renderbuffer->_BaseFormat != GL_RGB && 360 att->Renderbuffer->_BaseFormat != GL_RGBA) { 361 ASSERT(att->Renderbuffer->RedBits); 362 ASSERT(att->Renderbuffer->GreenBits); 363 ASSERT(att->Renderbuffer->BlueBits); 364 att->Complete = GL_FALSE; 365 return; 366 } 367 } 368 else if (format == GL_DEPTH) { 369 ASSERT(att->Renderbuffer->DepthBits); 370 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { 371 /* OK */ 372 } 373 else if (ctx->Extensions.EXT_packed_depth_stencil && 374 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 375 /* OK */ 376 } 377 else { 378 att->Complete = GL_FALSE; 379 return; 380 } 381 } 382 else { 383 assert(format == GL_STENCIL); 384 ASSERT(att->Renderbuffer->StencilBits); 385 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { 386 /* OK */ 387 } 388 else if (ctx->Extensions.EXT_packed_depth_stencil && 389 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 390 /* OK */ 391 } 392 else { 393 att->Complete = GL_FALSE; 394 return; 395 } 396 } 397 } 398 else { 399 ASSERT(att->Type == GL_NONE); 400 /* complete */ 401 return; 402 } 403} 404 405 406/** 407 * Helpful for debugging 408 */ 409static void 410fbo_incomplete(const char *msg, int index) 411{ 412 (void) msg; 413 (void) index; 414 /* 415 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 416 */ 417} 418 419 420/** 421 * Test if the given framebuffer object is complete and update its 422 * Status field with the results. 423 * Also update the framebuffer's Width and Height fields if the 424 * framebuffer is complete. 425 */ 426void 427_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) 428{ 429 GLuint numImages, width = 0, height = 0; 430 GLenum intFormat = GL_NONE; 431 GLuint w = 0, h = 0; 432 GLint i; 433 GLuint j; 434 435 assert(fb->Name != 0); 436 437 numImages = 0; 438 fb->Width = 0; 439 fb->Height = 0; 440 441 /* Start at -2 to more easily loop over all attachment points */ 442 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 443 struct gl_renderbuffer_attachment *att; 444 GLenum f; 445 446 if (i == -2) { 447 att = &fb->Attachment[BUFFER_DEPTH]; 448 test_attachment_completeness(ctx, GL_DEPTH, att); 449 if (!att->Complete) { 450 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 451 fbo_incomplete("depth attachment incomplete", -1); 452 return; 453 } 454 } 455 else if (i == -1) { 456 att = &fb->Attachment[BUFFER_STENCIL]; 457 test_attachment_completeness(ctx, GL_STENCIL, att); 458 if (!att->Complete) { 459 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 460 fbo_incomplete("stencil attachment incomplete", -1); 461 return; 462 } 463 } 464 else { 465 att = &fb->Attachment[BUFFER_COLOR0 + i]; 466 test_attachment_completeness(ctx, GL_COLOR, att); 467 if (!att->Complete) { 468 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 469 fbo_incomplete("color attachment incomplete", i); 470 return; 471 } 472 } 473 474 if (att->Type == GL_TEXTURE) { 475 const struct gl_texture_image *texImg 476 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 477 w = texImg->Width; 478 h = texImg->Height; 479 f = texImg->_BaseFormat; 480 numImages++; 481 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT 482 && f != GL_DEPTH_STENCIL_EXT) { 483 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 484 fbo_incomplete("texture attachment incomplete", -1); 485 return; 486 } 487 } 488 else if (att->Type == GL_RENDERBUFFER_EXT) { 489 w = att->Renderbuffer->Width; 490 h = att->Renderbuffer->Height; 491 f = att->Renderbuffer->InternalFormat; 492 numImages++; 493 } 494 else { 495 assert(att->Type == GL_NONE); 496 continue; 497 } 498 499 if (numImages == 1) { 500 /* set required width, height and format */ 501 width = w; 502 height = h; 503 if (i >= 0) 504 intFormat = f; 505 } 506 else { 507 /* check that width, height, format are same */ 508 if (w != width || h != height) { 509 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 510 fbo_incomplete("width or height mismatch", -1); 511 return; 512 } 513 if (intFormat != GL_NONE && f != intFormat) { 514 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 515 fbo_incomplete("format mismatch", -1); 516 return; 517 } 518 } 519 } 520 521#ifndef FEATURE_OES_framebuffer_object 522 /* Check that all DrawBuffers are present */ 523 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 524 if (fb->ColorDrawBuffer[j] != GL_NONE) { 525 const struct gl_renderbuffer_attachment *att 526 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); 527 assert(att); 528 if (att->Type == GL_NONE) { 529 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 530 fbo_incomplete("missing drawbuffer", j); 531 return; 532 } 533 } 534 } 535 536 /* Check that the ReadBuffer is present */ 537 if (fb->ColorReadBuffer != GL_NONE) { 538 const struct gl_renderbuffer_attachment *att 539 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); 540 assert(att); 541 if (att->Type == GL_NONE) { 542 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 543 fbo_incomplete("missing readbuffer", -1); 544 return; 545 } 546 } 547#endif 548 549 if (numImages == 0) { 550 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 551 fbo_incomplete("no attachments", -1); 552 return; 553 } 554 555 /* 556 * If we get here, the framebuffer is complete! 557 */ 558 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 559 fb->Width = w; 560 fb->Height = h; 561} 562 563 564GLboolean GLAPIENTRY 565_mesa_IsRenderbufferEXT(GLuint renderbuffer) 566{ 567 GET_CURRENT_CONTEXT(ctx); 568 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 569 if (renderbuffer) { 570 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 571 if (rb != NULL && rb != &DummyRenderbuffer) 572 return GL_TRUE; 573 } 574 return GL_FALSE; 575} 576 577 578void GLAPIENTRY 579_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 580{ 581 struct gl_renderbuffer *newRb; 582 GET_CURRENT_CONTEXT(ctx); 583 584 ASSERT_OUTSIDE_BEGIN_END(ctx); 585 586 if (target != GL_RENDERBUFFER_EXT) { 587 _mesa_error(ctx, GL_INVALID_ENUM, 588 "glBindRenderbufferEXT(target)"); 589 return; 590 } 591 592 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 593 /* The above doesn't fully flush the drivers in the way that a 594 * glFlush does, but that is required here: 595 */ 596 if (ctx->Driver.Flush) 597 ctx->Driver.Flush(ctx); 598 599 600 if (renderbuffer) { 601 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 602 if (newRb == &DummyRenderbuffer) { 603 /* ID was reserved, but no real renderbuffer object made yet */ 604 newRb = NULL; 605 } 606 if (!newRb) { 607 /* create new renderbuffer object */ 608 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 609 if (!newRb) { 610 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 611 return; 612 } 613 ASSERT(newRb->AllocStorage); 614 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 615 newRb->RefCount = 1; /* referenced by hash table */ 616 } 617 } 618 else { 619 newRb = NULL; 620 } 621 622 ASSERT(newRb != &DummyRenderbuffer); 623 624 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 625} 626 627 628void GLAPIENTRY 629_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 630{ 631 GLint i; 632 GET_CURRENT_CONTEXT(ctx); 633 634 ASSERT_OUTSIDE_BEGIN_END(ctx); 635 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 636 637 for (i = 0; i < n; i++) { 638 if (renderbuffers[i] > 0) { 639 struct gl_renderbuffer *rb; 640 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 641 if (rb) { 642 /* check if deleting currently bound renderbuffer object */ 643 if (rb == ctx->CurrentRenderbuffer) { 644 /* bind default */ 645 ASSERT(rb->RefCount >= 2); 646 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 647 } 648 649 /* Remove from hash table immediately, to free the ID. 650 * But the object will not be freed until it's no longer 651 * referenced anywhere else. 652 */ 653 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 654 655 if (rb != &DummyRenderbuffer) { 656 /* no longer referenced by hash table */ 657 _mesa_reference_renderbuffer(&rb, NULL); 658 } 659 } 660 } 661 } 662} 663 664 665void GLAPIENTRY 666_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 667{ 668 GET_CURRENT_CONTEXT(ctx); 669 GLuint first; 670 GLint i; 671 672 ASSERT_OUTSIDE_BEGIN_END(ctx); 673 674 if (n < 0) { 675 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 676 return; 677 } 678 679 if (!renderbuffers) 680 return; 681 682 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 683 684 for (i = 0; i < n; i++) { 685 GLuint name = first + i; 686 renderbuffers[i] = name; 687 /* insert dummy placeholder into hash table */ 688 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 689 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 690 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 691 } 692} 693 694 695/** 696 * Given an internal format token for a render buffer, return the 697 * corresponding base format. 698 * This is very similar to _mesa_base_tex_format() but the set of valid 699 * internal formats is somewhat different. 700 * 701 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT 702 * GL_DEPTH_STENCIL_EXT or zero if error. 703 */ 704GLenum 705_mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) 706{ 707 switch (internalFormat) { 708 case GL_RGB: 709 case GL_R3_G3_B2: 710 case GL_RGB4: 711 case GL_RGB5: 712 case GL_RGB8: 713 case GL_RGB10: 714 case GL_RGB12: 715 case GL_RGB16: 716 return GL_RGB; 717 case GL_RGBA: 718 case GL_RGBA2: 719 case GL_RGBA4: 720 case GL_RGB5_A1: 721 case GL_RGBA8: 722 case GL_RGB10_A2: 723 case GL_RGBA12: 724 case GL_RGBA16: 725 return GL_RGBA; 726 case GL_STENCIL_INDEX: 727 case GL_STENCIL_INDEX1_EXT: 728 case GL_STENCIL_INDEX4_EXT: 729 case GL_STENCIL_INDEX8_EXT: 730 case GL_STENCIL_INDEX16_EXT: 731 return GL_STENCIL_INDEX; 732 case GL_DEPTH_COMPONENT: 733 case GL_DEPTH_COMPONENT16: 734 case GL_DEPTH_COMPONENT24: 735 case GL_DEPTH_COMPONENT32: 736 return GL_DEPTH_COMPONENT; 737 case GL_DEPTH_STENCIL_EXT: 738 case GL_DEPTH24_STENCIL8_EXT: 739 if (ctx->Extensions.EXT_packed_depth_stencil) 740 return GL_DEPTH_STENCIL_EXT; 741 else 742 return 0; 743 /* XXX add floating point formats eventually */ 744 default: 745 return 0; 746 } 747} 748 749 750void GLAPIENTRY 751_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 752 GLsizei width, GLsizei height) 753{ 754 struct gl_renderbuffer *rb; 755 GLenum baseFormat; 756 GET_CURRENT_CONTEXT(ctx); 757 758 ASSERT_OUTSIDE_BEGIN_END(ctx); 759 760 if (target != GL_RENDERBUFFER_EXT) { 761 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)"); 762 return; 763 } 764 765 baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 766 if (baseFormat == 0) { 767 _mesa_error(ctx, GL_INVALID_ENUM, 768 "glRenderbufferStorageEXT(internalFormat)"); 769 return; 770 } 771 772 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 773 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); 774 return; 775 } 776 777 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 778 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); 779 return; 780 } 781 782 rb = ctx->CurrentRenderbuffer; 783 784 if (!rb) { 785 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT"); 786 return; 787 } 788 789 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 790 791 if (rb->InternalFormat == internalFormat && 792 rb->Width == (GLuint) width && 793 rb->Height == (GLuint) height) { 794 /* no change in allocation needed */ 795 return; 796 } 797 798 /* These MUST get set by the AllocStorage func */ 799 rb->_ActualFormat = 0; 800 rb->RedBits = 801 rb->GreenBits = 802 rb->BlueBits = 803 rb->AlphaBits = 804 rb->IndexBits = 805 rb->DepthBits = 806 rb->StencilBits = 0; 807 808 /* Now allocate the storage */ 809 ASSERT(rb->AllocStorage); 810 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 811 /* No error - check/set fields now */ 812 assert(rb->_ActualFormat); 813 assert(rb->Width == (GLuint) width); 814 assert(rb->Height == (GLuint) height); 815 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits || 816 rb->DepthBits || rb->StencilBits || rb->IndexBits); 817 rb->InternalFormat = internalFormat; 818 rb->_BaseFormat = baseFormat; 819 } 820 else { 821 /* Probably ran out of memory - clear the fields */ 822 rb->Width = 0; 823 rb->Height = 0; 824 rb->InternalFormat = GL_NONE; 825 rb->_ActualFormat = GL_NONE; 826 rb->_BaseFormat = GL_NONE; 827 rb->RedBits = 828 rb->GreenBits = 829 rb->BlueBits = 830 rb->AlphaBits = 831 rb->IndexBits = 832 rb->DepthBits = 833 rb->StencilBits = 0; 834 } 835 836 /* 837 test_framebuffer_completeness(ctx, fb); 838 */ 839 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 840 * points??? 841 */ 842} 843 844 845void GLAPIENTRY 846_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 847{ 848 GET_CURRENT_CONTEXT(ctx); 849 850 ASSERT_OUTSIDE_BEGIN_END(ctx); 851 852 if (target != GL_RENDERBUFFER_EXT) { 853 _mesa_error(ctx, GL_INVALID_ENUM, 854 "glGetRenderbufferParameterivEXT(target)"); 855 return; 856 } 857 858 if (!ctx->CurrentRenderbuffer) { 859 _mesa_error(ctx, GL_INVALID_OPERATION, 860 "glGetRenderbufferParameterivEXT"); 861 return; 862 } 863 864 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 865 866 switch (pname) { 867 case GL_RENDERBUFFER_WIDTH_EXT: 868 *params = ctx->CurrentRenderbuffer->Width; 869 return; 870 case GL_RENDERBUFFER_HEIGHT_EXT: 871 *params = ctx->CurrentRenderbuffer->Height; 872 return; 873 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 874 *params = ctx->CurrentRenderbuffer->InternalFormat; 875 return; 876 case GL_RENDERBUFFER_RED_SIZE_EXT: 877 *params = ctx->CurrentRenderbuffer->RedBits; 878 break; 879 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 880 *params = ctx->CurrentRenderbuffer->GreenBits; 881 break; 882 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 883 *params = ctx->CurrentRenderbuffer->BlueBits; 884 break; 885 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 886 *params = ctx->CurrentRenderbuffer->AlphaBits; 887 break; 888 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 889 *params = ctx->CurrentRenderbuffer->DepthBits; 890 break; 891 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 892 *params = ctx->CurrentRenderbuffer->StencilBits; 893 break; 894 default: 895 _mesa_error(ctx, GL_INVALID_ENUM, 896 "glGetRenderbufferParameterivEXT(target)"); 897 return; 898 } 899} 900 901 902GLboolean GLAPIENTRY 903_mesa_IsFramebufferEXT(GLuint framebuffer) 904{ 905 GET_CURRENT_CONTEXT(ctx); 906 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 907 if (framebuffer) { 908 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 909 if (rb != NULL && rb != &DummyFramebuffer) 910 return GL_TRUE; 911 } 912 return GL_FALSE; 913} 914 915 916static void 917check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 918{ 919 GLuint i; 920 ASSERT(ctx->Driver.RenderTexture); 921 for (i = 0; i < BUFFER_COUNT; i++) { 922 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 923 struct gl_texture_object *texObj = att->Texture; 924 if (texObj 925 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 926 ctx->Driver.RenderTexture(ctx, fb, att); 927 } 928 } 929} 930 931 932/** 933 * Examine all the framebuffer's attachments to see if any are textures. 934 * If so, call ctx->Driver.FinishRenderTexture() for each texture to 935 * notify the device driver that the texture image may have changed. 936 */ 937static void 938check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 939{ 940 if (ctx->Driver.FinishRenderTexture) { 941 GLuint i; 942 for (i = 0; i < BUFFER_COUNT; i++) { 943 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 944 if (att->Texture && att->Renderbuffer) { 945 ctx->Driver.FinishRenderTexture(ctx, att); 946 } 947 } 948 } 949} 950 951 952void GLAPIENTRY 953_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 954{ 955 struct gl_framebuffer *newFb, *newFbread; 956 GLboolean bindReadBuf, bindDrawBuf; 957 GET_CURRENT_CONTEXT(ctx); 958 959 ASSERT_OUTSIDE_BEGIN_END(ctx); 960 961 if (!ctx->Extensions.EXT_framebuffer_object) { 962 _mesa_error(ctx, GL_INVALID_OPERATION, 963 "glBindFramebufferEXT(unsupported)"); 964 return; 965 } 966 967 switch (target) { 968#if FEATURE_EXT_framebuffer_blit 969 case GL_DRAW_FRAMEBUFFER_EXT: 970 if (!ctx->Extensions.EXT_framebuffer_blit) { 971 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 972 return; 973 } 974 bindDrawBuf = GL_TRUE; 975 bindReadBuf = GL_FALSE; 976 break; 977 case GL_READ_FRAMEBUFFER_EXT: 978 if (!ctx->Extensions.EXT_framebuffer_blit) { 979 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 980 return; 981 } 982 bindDrawBuf = GL_FALSE; 983 bindReadBuf = GL_TRUE; 984 break; 985#endif 986 case GL_FRAMEBUFFER_EXT: 987 bindDrawBuf = GL_TRUE; 988 bindReadBuf = GL_TRUE; 989 break; 990 default: 991 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 992 return; 993 } 994 995 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 996 997 if (ctx->Driver.Flush) { 998 ctx->Driver.Flush(ctx); 999 } 1000 1001 if (framebuffer) { 1002 /* Binding a user-created framebuffer object */ 1003 newFb = _mesa_lookup_framebuffer(ctx, framebuffer); 1004 if (newFb == &DummyFramebuffer) { 1005 /* ID was reserved, but no real framebuffer object made yet */ 1006 newFb = NULL; 1007 } 1008 if (!newFb) { 1009 /* create new framebuffer object */ 1010 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 1011 if (!newFb) { 1012 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 1013 return; 1014 } 1015 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); 1016 } 1017 newFbread = newFb; 1018 } 1019 else { 1020 /* Binding the window system framebuffer (which was originally set 1021 * with MakeCurrent). 1022 */ 1023 newFb = ctx->WinSysDrawBuffer; 1024 newFbread = ctx->WinSysReadBuffer; 1025 } 1026 1027 ASSERT(newFb); 1028 ASSERT(newFb != &DummyFramebuffer); 1029 1030 /* 1031 * XXX check if re-binding same buffer and skip some of this code. 1032 */ 1033 1034 if (bindReadBuf) { 1035 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread); 1036 } 1037 1038 if (bindDrawBuf) { 1039 /* check if old FB had any texture attachments */ 1040 check_end_texture_render(ctx, ctx->DrawBuffer); 1041 1042 /* check if time to delete this framebuffer */ 1043 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb); 1044 1045 if (newFb->Name != 0) { 1046 /* check if newly bound framebuffer has any texture attachments */ 1047 check_begin_texture_render(ctx, newFb); 1048 } 1049 } 1050 1051 if (ctx->Driver.BindFramebuffer) { 1052 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread); 1053 } 1054} 1055 1056 1057void GLAPIENTRY 1058_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 1059{ 1060 GLint i; 1061 GET_CURRENT_CONTEXT(ctx); 1062 1063 ASSERT_OUTSIDE_BEGIN_END(ctx); 1064 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1065 /* The above doesn't fully flush the drivers in the way that a 1066 * glFlush does, but that is required here: 1067 */ 1068 if (ctx->Driver.Flush) 1069 ctx->Driver.Flush(ctx); 1070 1071 for (i = 0; i < n; i++) { 1072 if (framebuffers[i] > 0) { 1073 struct gl_framebuffer *fb; 1074 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 1075 if (fb) { 1076 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 1077 1078 /* check if deleting currently bound framebuffer object */ 1079 if (fb == ctx->DrawBuffer) { 1080 /* bind default */ 1081 ASSERT(fb->RefCount >= 2); 1082 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 1083 } 1084 1085 /* remove from hash table immediately, to free the ID */ 1086 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 1087 1088 if (fb != &DummyFramebuffer) { 1089 /* But the object will not be freed until it's no longer 1090 * bound in any context. 1091 */ 1092 _mesa_unreference_framebuffer(&fb); 1093 } 1094 } 1095 } 1096 } 1097} 1098 1099 1100void GLAPIENTRY 1101_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 1102{ 1103 GET_CURRENT_CONTEXT(ctx); 1104 GLuint first; 1105 GLint i; 1106 1107 ASSERT_OUTSIDE_BEGIN_END(ctx); 1108 1109 if (n < 0) { 1110 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 1111 return; 1112 } 1113 1114 if (!framebuffers) 1115 return; 1116 1117 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 1118 1119 for (i = 0; i < n; i++) { 1120 GLuint name = first + i; 1121 framebuffers[i] = name; 1122 /* insert dummy placeholder into hash table */ 1123 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1124 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 1125 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1126 } 1127} 1128 1129 1130 1131GLenum GLAPIENTRY 1132_mesa_CheckFramebufferStatusEXT(GLenum target) 1133{ 1134 struct gl_framebuffer *buffer; 1135 GET_CURRENT_CONTEXT(ctx); 1136 1137 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1138 1139 switch (target) { 1140#if FEATURE_EXT_framebuffer_blit 1141 case GL_DRAW_FRAMEBUFFER_EXT: 1142 if (!ctx->Extensions.EXT_framebuffer_blit) { 1143 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1144 return 0; 1145 } 1146 buffer = ctx->DrawBuffer; 1147 break; 1148 case GL_READ_FRAMEBUFFER_EXT: 1149 if (!ctx->Extensions.EXT_framebuffer_blit) { 1150 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1151 return 0; 1152 } 1153 buffer = ctx->ReadBuffer; 1154 break; 1155#endif 1156 case GL_FRAMEBUFFER_EXT: 1157 buffer = ctx->DrawBuffer; 1158 break; 1159 default: 1160 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1161 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1162 } 1163 1164 if (buffer->Name == 0) { 1165 /* The window system / default framebuffer is always complete */ 1166 return GL_FRAMEBUFFER_COMPLETE_EXT; 1167 } 1168 1169 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1170 1171 _mesa_test_framebuffer_completeness(ctx, buffer); 1172 return buffer->_Status; 1173} 1174 1175 1176 1177/** 1178 * Common code called by glFramebufferTexture1D/2D/3DEXT(). 1179 */ 1180static void 1181framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 1182 GLenum attachment, GLenum textarget, GLuint texture, 1183 GLint level, GLint zoffset) 1184{ 1185 struct gl_renderbuffer_attachment *att; 1186 struct gl_texture_object *texObj = NULL; 1187 struct gl_framebuffer *fb; 1188 1189 ASSERT_OUTSIDE_BEGIN_END(ctx); 1190 1191 if (target != GL_FRAMEBUFFER_EXT) { 1192 _mesa_error(ctx, GL_INVALID_ENUM, 1193 "glFramebufferTexture%sEXT(target)", caller); 1194 return; 1195 } 1196 1197 fb = ctx->DrawBuffer; 1198 ASSERT(fb); 1199 1200 /* check framebuffer binding */ 1201 if (fb->Name == 0) { 1202 _mesa_error(ctx, GL_INVALID_OPERATION, 1203 "glFramebufferTexture%sEXT", caller); 1204 return; 1205 } 1206 1207 1208 /* The textarget, level, and zoffset parameters are only validated if 1209 * texture is non-zero. 1210 */ 1211 if (texture) { 1212 GLboolean err = GL_TRUE; 1213 1214 texObj = _mesa_lookup_texture(ctx, texture); 1215 if (texObj != NULL) { 1216 if (textarget == 0) { 1217 err = (texObj->Target != GL_TEXTURE_3D) && 1218 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 1219 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 1220 } 1221 else { 1222 err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 1223 ? !IS_CUBE_FACE(textarget) 1224 : (texObj->Target != textarget); 1225 } 1226 } 1227 1228 if (err) { 1229 _mesa_error(ctx, GL_INVALID_OPERATION, 1230 "glFramebufferTexture%sEXT(texture target mismatch)", 1231 caller); 1232 return; 1233 } 1234 1235 if (texObj->Target == GL_TEXTURE_3D) { 1236 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1237 if (zoffset < 0 || zoffset >= maxSize) { 1238 _mesa_error(ctx, GL_INVALID_VALUE, 1239 "glFramebufferTexture%sEXT(zoffset)", caller); 1240 return; 1241 } 1242 } 1243 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 1244 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 1245 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 1246 _mesa_error(ctx, GL_INVALID_VALUE, 1247 "glFramebufferTexture%sEXT(layer)", caller); 1248 return; 1249 } 1250 } 1251 1252 1253 if ((level < 0) || 1254 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 1255 _mesa_error(ctx, GL_INVALID_VALUE, 1256 "glFramebufferTexture%sEXT(level)", caller); 1257 return; 1258 } 1259 } 1260 1261 att = _mesa_get_attachment(ctx, fb, attachment); 1262 if (att == NULL) { 1263 _mesa_error(ctx, GL_INVALID_ENUM, 1264 "glFramebufferTexture%sEXT(attachment)", caller); 1265 return; 1266 } 1267 1268 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1269 /* The above doesn't fully flush the drivers in the way that a 1270 * glFlush does, but that is required here: 1271 */ 1272 if (ctx->Driver.Flush) 1273 ctx->Driver.Flush(ctx); 1274 1275 _glthread_LOCK_MUTEX(fb->Mutex); 1276 if (texObj) { 1277 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 1278 level, zoffset); 1279 } 1280 else { 1281 _mesa_remove_attachment(ctx, att); 1282 } 1283 _glthread_UNLOCK_MUTEX(fb->Mutex); 1284} 1285 1286 1287 1288void GLAPIENTRY 1289_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1290 GLenum textarget, GLuint texture, GLint level) 1291{ 1292 GET_CURRENT_CONTEXT(ctx); 1293 1294 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 1295 _mesa_error(ctx, GL_INVALID_ENUM, 1296 "glFramebufferTexture1DEXT(textarget)"); 1297 return; 1298 } 1299 1300 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 1301 level, 0); 1302} 1303 1304 1305void GLAPIENTRY 1306_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1307 GLenum textarget, GLuint texture, GLint level) 1308{ 1309 GET_CURRENT_CONTEXT(ctx); 1310 1311 if ((texture != 0) && 1312 (textarget != GL_TEXTURE_2D) && 1313 (textarget != GL_TEXTURE_RECTANGLE_ARB) && 1314 (!IS_CUBE_FACE(textarget))) { 1315 _mesa_error(ctx, GL_INVALID_OPERATION, 1316 "glFramebufferTexture2DEXT(textarget)"); 1317 return; 1318 } 1319 1320 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 1321 level, 0); 1322} 1323 1324 1325void GLAPIENTRY 1326_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1327 GLenum textarget, GLuint texture, 1328 GLint level, GLint zoffset) 1329{ 1330 GET_CURRENT_CONTEXT(ctx); 1331 1332 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 1333 _mesa_error(ctx, GL_INVALID_ENUM, 1334 "glFramebufferTexture3DEXT(textarget)"); 1335 return; 1336 } 1337 1338 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 1339 level, zoffset); 1340} 1341 1342 1343void GLAPIENTRY 1344_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 1345 GLuint texture, GLint level, GLint layer) 1346{ 1347 GET_CURRENT_CONTEXT(ctx); 1348 1349 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 1350 level, layer); 1351} 1352 1353 1354void GLAPIENTRY 1355_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1356 GLenum renderbufferTarget, 1357 GLuint renderbuffer) 1358{ 1359 struct gl_renderbuffer_attachment *att; 1360 struct gl_framebuffer *fb; 1361 struct gl_renderbuffer *rb; 1362 GET_CURRENT_CONTEXT(ctx); 1363 1364 ASSERT_OUTSIDE_BEGIN_END(ctx); 1365 1366 switch (target) { 1367#if FEATURE_EXT_framebuffer_blit 1368 case GL_DRAW_FRAMEBUFFER_EXT: 1369 if (!ctx->Extensions.EXT_framebuffer_blit) { 1370 _mesa_error(ctx, GL_INVALID_ENUM, 1371 "glFramebufferRenderbufferEXT(target)"); 1372 return; 1373 } 1374 fb = ctx->DrawBuffer; 1375 break; 1376 case GL_READ_FRAMEBUFFER_EXT: 1377 if (!ctx->Extensions.EXT_framebuffer_blit) { 1378 _mesa_error(ctx, GL_INVALID_ENUM, 1379 "glFramebufferRenderbufferEXT(target)"); 1380 return; 1381 } 1382 fb = ctx->ReadBuffer; 1383 break; 1384#endif 1385 case GL_FRAMEBUFFER_EXT: 1386 fb = ctx->DrawBuffer; 1387 break; 1388 default: 1389 _mesa_error(ctx, GL_INVALID_ENUM, 1390 "glFramebufferRenderbufferEXT(target)"); 1391 return; 1392 } 1393 1394 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1395 _mesa_error(ctx, GL_INVALID_ENUM, 1396 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1397 return; 1398 } 1399 1400 if (fb->Name == 0) { 1401 /* Can't attach new renderbuffers to a window system framebuffer */ 1402 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1403 return; 1404 } 1405 1406 att = _mesa_get_attachment(ctx, fb, attachment); 1407 if (att == NULL) { 1408 _mesa_error(ctx, GL_INVALID_ENUM, 1409 "glFramebufferRenderbufferEXT(attachment)"); 1410 return; 1411 } 1412 1413 if (renderbuffer) { 1414 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 1415 if (!rb) { 1416 _mesa_error(ctx, GL_INVALID_OPERATION, 1417 "glFramebufferRenderbufferEXT(renderbuffer)"); 1418 return; 1419 } 1420 } 1421 else { 1422 /* remove renderbuffer attachment */ 1423 rb = NULL; 1424 } 1425 1426 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1427 /* The above doesn't fully flush the drivers in the way that a 1428 * glFlush does, but that is required here: 1429 */ 1430 if (ctx->Driver.Flush) 1431 ctx->Driver.Flush(ctx); 1432 1433 assert(ctx->Driver.FramebufferRenderbuffer); 1434 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 1435 1436 /* Some subsequent GL commands may depend on the framebuffer's visual 1437 * after the binding is updated. Update visual info now. 1438 */ 1439 _mesa_update_framebuffer_visual(fb); 1440} 1441 1442 1443void GLAPIENTRY 1444_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1445 GLenum pname, GLint *params) 1446{ 1447 const struct gl_renderbuffer_attachment *att; 1448 struct gl_framebuffer *buffer; 1449 GET_CURRENT_CONTEXT(ctx); 1450 1451 ASSERT_OUTSIDE_BEGIN_END(ctx); 1452 1453 switch (target) { 1454#if FEATURE_EXT_framebuffer_blit 1455 case GL_DRAW_FRAMEBUFFER_EXT: 1456 if (!ctx->Extensions.EXT_framebuffer_blit) { 1457 _mesa_error(ctx, GL_INVALID_ENUM, 1458 "glGetFramebufferAttachmentParameterivEXT(target)"); 1459 return; 1460 } 1461 buffer = ctx->DrawBuffer; 1462 break; 1463 case GL_READ_FRAMEBUFFER_EXT: 1464 if (!ctx->Extensions.EXT_framebuffer_blit) { 1465 _mesa_error(ctx, GL_INVALID_ENUM, 1466 "glGetFramebufferAttachmentParameterivEXT(target)"); 1467 return; 1468 } 1469 buffer = ctx->ReadBuffer; 1470 break; 1471#endif 1472 case GL_FRAMEBUFFER_EXT: 1473 buffer = ctx->DrawBuffer; 1474 break; 1475 default: 1476 _mesa_error(ctx, GL_INVALID_ENUM, 1477 "glGetFramebufferAttachmentParameterivEXT(target)"); 1478 return; 1479 } 1480 1481 if (buffer->Name == 0) { 1482 _mesa_error(ctx, GL_INVALID_OPERATION, 1483 "glGetFramebufferAttachmentParameterivEXT"); 1484 return; 1485 } 1486 1487 att = _mesa_get_attachment(ctx, buffer, attachment); 1488 if (att == NULL) { 1489 _mesa_error(ctx, GL_INVALID_ENUM, 1490 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1491 return; 1492 } 1493 1494 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1495 /* The above doesn't fully flush the drivers in the way that a 1496 * glFlush does, but that is required here: 1497 */ 1498 if (ctx->Driver.Flush) 1499 ctx->Driver.Flush(ctx); 1500 1501 switch (pname) { 1502 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1503 *params = att->Type; 1504 return; 1505 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1506 if (att->Type == GL_RENDERBUFFER_EXT) { 1507 *params = att->Renderbuffer->Name; 1508 } 1509 else if (att->Type == GL_TEXTURE) { 1510 *params = att->Texture->Name; 1511 } 1512 else { 1513 _mesa_error(ctx, GL_INVALID_ENUM, 1514 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1515 } 1516 return; 1517 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1518 if (att->Type == GL_TEXTURE) { 1519 *params = att->TextureLevel; 1520 } 1521 else { 1522 _mesa_error(ctx, GL_INVALID_ENUM, 1523 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1524 } 1525 return; 1526 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1527 if (att->Type == GL_TEXTURE) { 1528 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 1529 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1530 } 1531 else { 1532 *params = 0; 1533 } 1534 } 1535 else { 1536 _mesa_error(ctx, GL_INVALID_ENUM, 1537 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1538 } 1539 return; 1540 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1541 if (att->Type == GL_TEXTURE) { 1542 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 1543 *params = att->Zoffset; 1544 } 1545 else { 1546 *params = 0; 1547 } 1548 } 1549 else { 1550 _mesa_error(ctx, GL_INVALID_ENUM, 1551 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1552 } 1553 return; 1554 default: 1555 _mesa_error(ctx, GL_INVALID_ENUM, 1556 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1557 return; 1558 } 1559} 1560 1561 1562void GLAPIENTRY 1563_mesa_GenerateMipmapEXT(GLenum target) 1564{ 1565 struct gl_texture_unit *texUnit; 1566 struct gl_texture_object *texObj; 1567 GET_CURRENT_CONTEXT(ctx); 1568 1569 ASSERT_OUTSIDE_BEGIN_END(ctx); 1570 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1571 1572 switch (target) { 1573 case GL_TEXTURE_1D: 1574 case GL_TEXTURE_2D: 1575 case GL_TEXTURE_3D: 1576 case GL_TEXTURE_CUBE_MAP: 1577 /* OK, legal value */ 1578 break; 1579 default: 1580 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1581 return; 1582 } 1583 1584 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 1585 texObj = _mesa_select_tex_object(ctx, texUnit, target); 1586 1587 _mesa_lock_texture(ctx, texObj); 1588 if (target == GL_TEXTURE_CUBE_MAP) { 1589 int face; 1590 1591 for (face = 0; face < 6; face++) 1592 ctx->Driver.GenerateMipmap(ctx, 1593 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 1594 texObj); 1595 } else { 1596 ctx->Driver.GenerateMipmap(ctx, target, texObj); 1597 } 1598 _mesa_unlock_texture(ctx, texObj); 1599} 1600 1601 1602#if FEATURE_EXT_framebuffer_blit 1603void GLAPIENTRY 1604_mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 1605 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 1606 GLbitfield mask, GLenum filter) 1607{ 1608 GET_CURRENT_CONTEXT(ctx); 1609 1610 ASSERT_OUTSIDE_BEGIN_END(ctx); 1611 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1612 1613 if (ctx->NewState) { 1614 _mesa_update_state(ctx); 1615 } 1616 1617 if (!ctx->ReadBuffer) { 1618 /* XXX */ 1619 } 1620 1621 /* check for complete framebuffers */ 1622 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 1623 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 1624 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 1625 "glBlitFramebufferEXT(incomplete draw/read buffers)"); 1626 return; 1627 } 1628 1629 if (filter != GL_NEAREST && filter != GL_LINEAR) { 1630 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 1631 return; 1632 } 1633 1634 if (mask & ~(GL_COLOR_BUFFER_BIT | 1635 GL_DEPTH_BUFFER_BIT | 1636 GL_STENCIL_BUFFER_BIT)) { 1637 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 1638 return; 1639 } 1640 1641 /* depth/stencil must be blitted with nearest filtering */ 1642 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 1643 && filter != GL_NEAREST) { 1644 _mesa_error(ctx, GL_INVALID_OPERATION, 1645 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 1646 return; 1647 } 1648 1649 if (mask & GL_STENCIL_BUFFER_BIT) { 1650 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer; 1651 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer; 1652 if (readRb->StencilBits != drawRb->StencilBits) { 1653 _mesa_error(ctx, GL_INVALID_OPERATION, 1654 "glBlitFramebufferEXT(stencil buffer size mismatch"); 1655 return; 1656 } 1657 } 1658 1659 if (mask & GL_DEPTH_BUFFER_BIT) { 1660 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer; 1661 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer; 1662 if (readRb->DepthBits != drawRb->DepthBits) { 1663 _mesa_error(ctx, GL_INVALID_OPERATION, 1664 "glBlitFramebufferEXT(depth buffer size mismatch"); 1665 return; 1666 } 1667 } 1668 1669 if (!ctx->Extensions.EXT_framebuffer_blit) { 1670 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 1671 return; 1672 } 1673 1674 ASSERT(ctx->Driver.BlitFramebuffer); 1675 ctx->Driver.BlitFramebuffer(ctx, 1676 srcX0, srcY0, srcX1, srcY1, 1677 dstX0, dstY0, dstX1, dstY1, 1678 mask, filter); 1679} 1680#endif /* FEATURE_EXT_framebuffer_blit */ 1681