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