fbobject.c revision 91802fdf730451aaa0246f514f6778ffaef92c50
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 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 "teximage.h" 38#include "texstore.h" 39 40 41/** 42 * Notes: 43 * 44 * None of the GL_EXT_framebuffer_object functions are compiled into 45 * display lists. 46 */ 47 48 49 50/* 51 * When glGenRender/FramebuffersEXT() is called we insert pointers to 52 * these placeholder objects into the hash table. 53 * Later, when the object ID is first bound, we replace the placeholder 54 * with the real frame/renderbuffer. 55 */ 56static struct gl_framebuffer DummyFramebuffer; 57static struct gl_renderbuffer DummyRenderbuffer; 58 59 60#define IS_CUBE_FACE(TARGET) \ 61 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 62 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 63 64 65/** 66 * Helper routine for getting a gl_renderbuffer. 67 */ 68static struct gl_renderbuffer * 69lookup_renderbuffer(GLcontext *ctx, GLuint id) 70{ 71 struct gl_renderbuffer *rb; 72 73 if (id == 0) 74 return NULL; 75 76 rb = (struct gl_renderbuffer *) 77 _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 78 return rb; 79} 80 81 82/** 83 * Helper routine for getting a gl_framebuffer. 84 */ 85static struct gl_framebuffer * 86lookup_framebuffer(GLcontext *ctx, GLuint id) 87{ 88 struct gl_framebuffer *fb; 89 90 if (id == 0) 91 return NULL; 92 93 fb = (struct gl_framebuffer *) 94 _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 95 return fb; 96} 97 98 99/** 100 * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding 101 * gl_renderbuffer_attachment object. 102 */ 103static struct gl_renderbuffer_attachment * 104get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment) 105{ 106 GLuint i; 107 108 switch (attachment) { 109 case GL_COLOR_ATTACHMENT0_EXT: 110 case GL_COLOR_ATTACHMENT1_EXT: 111 case GL_COLOR_ATTACHMENT2_EXT: 112 case GL_COLOR_ATTACHMENT3_EXT: 113 case GL_COLOR_ATTACHMENT4_EXT: 114 case GL_COLOR_ATTACHMENT5_EXT: 115 case GL_COLOR_ATTACHMENT6_EXT: 116 case GL_COLOR_ATTACHMENT7_EXT: 117 case GL_COLOR_ATTACHMENT8_EXT: 118 case GL_COLOR_ATTACHMENT9_EXT: 119 case GL_COLOR_ATTACHMENT10_EXT: 120 case GL_COLOR_ATTACHMENT11_EXT: 121 case GL_COLOR_ATTACHMENT12_EXT: 122 case GL_COLOR_ATTACHMENT13_EXT: 123 case GL_COLOR_ATTACHMENT14_EXT: 124 case GL_COLOR_ATTACHMENT15_EXT: 125 i = attachment - GL_COLOR_ATTACHMENT0_EXT; 126 if (i >= ctx->Const.MaxColorAttachments) { 127 return NULL; 128 } 129 return &fb->Attachment[BUFFER_COLOR0 + i]; 130 case GL_DEPTH_ATTACHMENT_EXT: 131 return &fb->Attachment[BUFFER_DEPTH]; 132 case GL_STENCIL_ATTACHMENT_EXT: 133 return &fb->Attachment[BUFFER_STENCIL]; 134 default: 135 return NULL; 136 } 137} 138 139 140/** 141 * Remove any texture or renderbuffer attached to the given attachment 142 * point. Update reference counts, etc. 143 */ 144void 145_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) 146{ 147 if (att->Type == GL_TEXTURE) { 148 ASSERT(att->Texture); 149 if (att->Renderbuffer) { 150 /* delete/remove the 'wrapper' renderbuffer */ 151 /* XXX do we really want to do this??? */ 152 att->Renderbuffer->Delete(att->Renderbuffer); 153 att->Renderbuffer = NULL; 154 } 155 att->Texture->RefCount--; 156 if (att->Texture->RefCount == 0) { 157 ctx->Driver.DeleteTexture(ctx, att->Texture); 158 } 159 att->Texture = NULL; 160 } 161 else if (att->Type == GL_RENDERBUFFER_EXT) { 162 ASSERT(att->Renderbuffer); 163 ASSERT(!att->Texture); 164 att->Renderbuffer->RefCount--; 165 if (att->Renderbuffer->RefCount == 0) { 166 att->Renderbuffer->Delete(att->Renderbuffer); 167 } 168 att->Renderbuffer = NULL; 169 } 170 att->Type = GL_NONE; 171 att->Complete = GL_TRUE; 172} 173 174 175/** 176 * Bind a texture object to an attachment point. 177 * The previous binding, if any, will be removed first. 178 */ 179void 180_mesa_set_texture_attachment(GLcontext *ctx, 181 struct gl_renderbuffer_attachment *att, 182 struct gl_texture_object *texObj, 183 GLenum texTarget, GLuint level, GLuint zoffset) 184{ 185 _mesa_remove_attachment(ctx, att); 186 att->Type = GL_TEXTURE; 187 att->Texture = texObj; 188 att->TextureLevel = level; 189 if (IS_CUBE_FACE(texTarget)) { 190 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 191 } 192 else { 193 att->CubeMapFace = 0; 194 } 195 att->Zoffset = zoffset; 196 att->Complete = GL_FALSE; 197 198 texObj->RefCount++; 199 200 /* XXX when we attach to a texture, we should probably set the 201 * att->Renderbuffer pointer to a "wrapper renderbuffer" which 202 * makes the texture image look like renderbuffer. 203 */ 204} 205 206 207/** 208 * Bind a renderbuffer to an attachment point. 209 * The previous binding, if any, will be removed first. 210 */ 211void 212_mesa_set_renderbuffer_attachment(GLcontext *ctx, 213 struct gl_renderbuffer_attachment *att, 214 struct gl_renderbuffer *rb) 215{ 216 _mesa_remove_attachment(ctx, att); 217 att->Type = GL_RENDERBUFFER_EXT; 218 att->Renderbuffer = rb; 219 att->Texture = NULL; /* just to be safe */ 220 att->Complete = GL_FALSE; 221 rb->RefCount++; 222} 223 224 225/** 226 * Fallback for ctx->Driver.FramebufferRenderbuffer() 227 * Sets a framebuffer attachment to a particular renderbuffer. 228 * The framebuffer in question is ctx->DrawBuffer. 229 * \sa _mesa_renderbuffer_texture 230 */ 231void 232_mesa_framebuffer_renderbuffer(GLcontext *ctx, 233 struct gl_renderbuffer_attachment *att, 234 struct gl_renderbuffer *rb) 235{ 236 if (rb) { 237 _mesa_set_renderbuffer_attachment(ctx, att, rb); 238 } 239 else { 240 _mesa_remove_attachment(ctx, att); 241 } 242} 243 244 245/** 246 * Test if an attachment point is complete and update its Complete field. 247 * \param format if GL_COLOR, this is a color attachment point, 248 * if GL_DEPTH, this is a depth component attachment point, 249 * if GL_STENCIL, this is a stencil component attachment point. 250 */ 251static void 252test_attachment_completeness(const GLcontext *ctx, GLenum format, 253 struct gl_renderbuffer_attachment *att) 254{ 255 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 256 257 /* assume complete */ 258 att->Complete = GL_TRUE; 259 260 /* Look for reasons why the attachment might be incomplete */ 261 if (att->Type == GL_TEXTURE) { 262 const struct gl_texture_object *texObj = att->Texture; 263 struct gl_texture_image *texImage; 264 265 if (!texObj) { 266 att->Complete = GL_FALSE; 267 return; 268 } 269 270 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 271 if (!texImage) { 272 att->Complete = GL_FALSE; 273 return; 274 } 275 if (texImage->Width < 1 || texImage->Height < 1) { 276 att->Complete = GL_FALSE; 277 return; 278 } 279 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { 280 att->Complete = GL_FALSE; 281 return; 282 } 283 284 if (format == GL_COLOR) { 285 if (texImage->TexFormat->BaseFormat != GL_RGB && 286 texImage->TexFormat->BaseFormat != GL_RGBA) { 287 att->Complete = GL_FALSE; 288 return; 289 } 290 } 291 else if (format == GL_DEPTH) { 292 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { 293 /* OK */ 294 } 295 else if (ctx->Extensions.EXT_packed_depth_stencil && 296 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 297 /* OK */ 298 } 299 else { 300 att->Complete = GL_FALSE; 301 return; 302 } 303 } 304 else { 305 /* no such thing as stencil textures */ 306 att->Complete = GL_FALSE; 307 return; 308 } 309 } 310 else if (att->Type == GL_RENDERBUFFER_EXT) { 311 if (att->Renderbuffer->Width < 1 || att->Renderbuffer->Height < 1) { 312 att->Complete = GL_FALSE; 313 return; 314 } 315 if (format == GL_COLOR) { 316 if (att->Renderbuffer->_BaseFormat != GL_RGB && 317 att->Renderbuffer->_BaseFormat != GL_RGBA) { 318 att->Complete = GL_FALSE; 319 return; 320 } 321 } 322 else if (format == GL_DEPTH) { 323 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { 324 /* OK */ 325 } 326 else if (ctx->Extensions.EXT_packed_depth_stencil && 327 att->Renderbuffer->_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 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { 338 /* OK */ 339 } 340 else if (ctx->Extensions.EXT_packed_depth_stencil && 341 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 342 /* OK */ 343 } 344 else { 345 att->Complete = GL_FALSE; 346 return; 347 } 348 } 349 } 350 else { 351 ASSERT(att->Type == GL_NONE); 352 /* complete */ 353 return; 354 } 355} 356 357 358/** 359 * Test if the given framebuffer object is complete and update its 360 * Status field with the results. 361 * Also update the framebuffer's Width and Height fields if the 362 * framebuffer is complete. 363 */ 364void 365_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) 366{ 367 GLuint numImages, width = 0, height = 0; 368 GLenum intFormat = GL_NONE; 369 GLuint w = 0, h = 0; 370 GLint i; 371 372 assert(fb->Name != 0); 373 374 numImages = 0; 375 fb->Width = 0; 376 fb->Height = 0; 377 378 /* Start at -2 to more easily loop over all attachment points */ 379 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 380 struct gl_renderbuffer_attachment *att; 381 GLenum f; 382 383 if (i == -2) { 384 att = &fb->Attachment[BUFFER_DEPTH]; 385 test_attachment_completeness(ctx, GL_DEPTH, att); 386 if (!att->Complete) { 387 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 388 return; 389 } 390 } 391 else if (i == -1) { 392 att = &fb->Attachment[BUFFER_STENCIL]; 393 test_attachment_completeness(ctx, GL_STENCIL, att); 394 if (!att->Complete) { 395 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 396 return; 397 } 398 } 399 else { 400 att = &fb->Attachment[BUFFER_COLOR0 + i]; 401 test_attachment_completeness(ctx, GL_COLOR, att); 402 if (!att->Complete) { 403 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 404 return; 405 } 406 } 407 408 if (att->Type == GL_TEXTURE) { 409 w = att->Texture->Image[att->CubeMapFace][att->TextureLevel]->Width; 410 h = att->Texture->Image[att->CubeMapFace][att->TextureLevel]->Height; 411 f = att->Texture->Image[att->CubeMapFace][att->TextureLevel]->Format; 412 numImages++; 413 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT) { 414 /* XXX need GL_DEPTH_STENCIL_EXT test? */ 415 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 416 return; 417 } 418 } 419 else if (att->Type == GL_RENDERBUFFER_EXT) { 420 w = att->Renderbuffer->Width; 421 h = att->Renderbuffer->Height; 422 f = att->Renderbuffer->InternalFormat; 423 numImages++; 424 } 425 else { 426 assert(att->Type == GL_NONE); 427 continue; 428 } 429 430 if (numImages == 1) { 431 /* set required width, height and format */ 432 width = w; 433 height = h; 434 if (i >= 0) 435 intFormat = f; 436 } 437 else { 438 /* check that width, height, format are same */ 439 if (w != width || h != height) { 440 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 441 return; 442 } 443 if (intFormat != GL_NONE && f != intFormat) { 444 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 445 return; 446 } 447 } 448 } 449 450 /* Check that all DrawBuffers are present */ 451 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 452 if (fb->ColorDrawBuffer[i] != GL_NONE) { 453 const struct gl_renderbuffer_attachment *att 454 = get_attachment(ctx, fb, fb->ColorDrawBuffer[i]); 455 assert(att); 456 if (att->Type == GL_NONE) { 457 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 458 return; 459 } 460 } 461 } 462 463 /* Check that the ReadBuffer is present */ 464 if (fb->ColorReadBuffer != GL_NONE) { 465 const struct gl_renderbuffer_attachment *att 466 = get_attachment(ctx, fb, fb->ColorReadBuffer); 467 assert(att); 468 if (att->Type == GL_NONE) { 469 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 470 return; 471 } 472 } 473 474 /* Check if any renderbuffer is attached more than once. 475 * Note that there's one exception: a GL_DEPTH_STENCIL renderbuffer can be 476 * bound to both the stencil and depth attachment points at the same time. 477 */ 478 for (i = 0; i < BUFFER_COUNT - 1; i++) { 479 struct gl_renderbuffer *rb_i = fb->Attachment[i].Renderbuffer; 480 if (rb_i) { 481 GLint j; 482 for (j = i + 1; j < BUFFER_COUNT; j++) { 483 struct gl_renderbuffer *rb_j = fb->Attachment[j].Renderbuffer; 484 if (rb_i == rb_j && rb_i->_BaseFormat != GL_DEPTH_STENCIL_EXT) { 485 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT; 486 return; 487 } 488 } 489 } 490 } 491 492 493 if (numImages == 0) { 494 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 495 return; 496 } 497 498 /* 499 * If we get here, the framebuffer is complete! 500 */ 501 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 502 fb->Width = w; 503 fb->Height = h; 504} 505 506 507GLboolean GLAPIENTRY 508_mesa_IsRenderbufferEXT(GLuint renderbuffer) 509{ 510 GET_CURRENT_CONTEXT(ctx); 511 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 512 if (renderbuffer) { 513 struct gl_renderbuffer *rb = lookup_renderbuffer(ctx, renderbuffer); 514 if (rb != NULL && rb != &DummyRenderbuffer) 515 return GL_TRUE; 516 } 517 return GL_FALSE; 518} 519 520 521void GLAPIENTRY 522_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 523{ 524 struct gl_renderbuffer *newRb, *oldRb; 525 GET_CURRENT_CONTEXT(ctx); 526 527 ASSERT_OUTSIDE_BEGIN_END(ctx); 528 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 529 530 if (target != GL_RENDERBUFFER_EXT) { 531 _mesa_error(ctx, GL_INVALID_ENUM, 532 "glBindRenderbufferEXT(target)"); 533 return; 534 } 535 536 if (renderbuffer) { 537 newRb = lookup_renderbuffer(ctx, renderbuffer); 538 if (newRb == &DummyRenderbuffer) { 539 /* ID was reserved, but no real renderbuffer object made yet */ 540 newRb = NULL; 541 } 542 if (!newRb) { 543 /* create new renderbuffer object */ 544 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 545 if (!newRb) { 546 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 547 return; 548 } 549 ASSERT(newRb->AllocStorage); 550 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 551 } 552 newRb->RefCount++; 553 } 554 else { 555 newRb = NULL; 556 } 557 558 oldRb = ctx->CurrentRenderbuffer; 559 if (oldRb) { 560 oldRb->RefCount--; 561 if (oldRb->RefCount == 0) { 562 oldRb->Delete(oldRb); 563 } 564 } 565 566 ASSERT(newRb != &DummyRenderbuffer); 567 568 ctx->CurrentRenderbuffer = newRb; 569} 570 571 572void GLAPIENTRY 573_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 574{ 575 GLint i; 576 GET_CURRENT_CONTEXT(ctx); 577 578 ASSERT_OUTSIDE_BEGIN_END(ctx); 579 580 for (i = 0; i < n; i++) { 581 if (renderbuffers[i] > 0) { 582 struct gl_renderbuffer *rb; 583 rb = lookup_renderbuffer(ctx, renderbuffers[i]); 584 if (rb) { 585 /* check if deleting currently bound renderbuffer object */ 586 if (rb == ctx->CurrentRenderbuffer) { 587 /* bind default */ 588 ASSERT(rb->RefCount >= 2); 589 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 590 } 591 592 /* remove from hash table immediately, to free the ID */ 593 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 594 595 if (rb != &DummyRenderbuffer) { 596 /* But the object will not be freed until it's no longer 597 * bound in any context. 598 */ 599 rb->RefCount--; 600 if (rb->RefCount == 0) { 601 rb->Delete(rb); 602 } 603 } 604 } 605 } 606 } 607} 608 609 610void GLAPIENTRY 611_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 612{ 613 GET_CURRENT_CONTEXT(ctx); 614 GLuint first; 615 GLint i; 616 617 ASSERT_OUTSIDE_BEGIN_END(ctx); 618 619 if (n < 0) { 620 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 621 return; 622 } 623 624 if (!renderbuffers) 625 return; 626 627 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 628 629 for (i = 0; i < n; i++) { 630 GLuint name = first + i; 631 renderbuffers[i] = name; 632 /* insert dummy placeholder into hash table */ 633 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 634 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 635 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 636 } 637} 638 639 640/** 641 * Given an internal format token for a render buffer, return the 642 * corresponding base format. 643 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT 644 * GL_DEPTH_STENCIL_EXT or zero if error. 645 */ 646static GLenum 647base_internal_format(GLcontext *ctx, GLenum internalFormat) 648{ 649 switch (internalFormat) { 650 case GL_RGB: 651 case GL_R3_G3_B2: 652 case GL_RGB4: 653 case GL_RGB5: 654 case GL_RGB8: 655 case GL_RGB10: 656 case GL_RGB12: 657 case GL_RGB16: 658 return GL_RGB; 659 case GL_RGBA: 660 case GL_RGBA2: 661 case GL_RGBA4: 662 case GL_RGB5_A1: 663 case GL_RGBA8: 664 case GL_RGB10_A2: 665 case GL_RGBA12: 666 case GL_RGBA16: 667 return GL_RGBA; 668 case GL_STENCIL_INDEX: 669 case GL_STENCIL_INDEX1_EXT: 670 case GL_STENCIL_INDEX4_EXT: 671 case GL_STENCIL_INDEX8_EXT: 672 case GL_STENCIL_INDEX16_EXT: 673 return GL_STENCIL_INDEX; 674 case GL_DEPTH_COMPONENT: 675 case GL_DEPTH_COMPONENT16: 676 case GL_DEPTH_COMPONENT24: 677 case GL_DEPTH_COMPONENT32: 678 return GL_DEPTH_COMPONENT; 679 case GL_DEPTH_STENCIL_EXT: 680 case GL_DEPTH24_STENCIL8_EXT: 681 if (ctx->Extensions.EXT_packed_depth_stencil) 682 return GL_DEPTH_STENCIL_EXT; 683 else 684 return 0; 685 /* XXX add floating point formats eventually */ 686 default: 687 return 0; 688 } 689} 690 691 692void GLAPIENTRY 693_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 694 GLsizei width, GLsizei height) 695{ 696 struct gl_renderbuffer *rb; 697 GLenum baseFormat; 698 GET_CURRENT_CONTEXT(ctx); 699 700 ASSERT_OUTSIDE_BEGIN_END(ctx); 701 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 702 703 if (target != GL_RENDERBUFFER_EXT) { 704 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)"); 705 return; 706 } 707 708 baseFormat = base_internal_format(ctx, internalFormat); 709 if (baseFormat == 0) { 710 _mesa_error(ctx, GL_INVALID_ENUM, 711 "glRenderbufferStorageEXT(internalFormat)"); 712 return; 713 } 714 715 if (width < 1 || width > ctx->Const.MaxRenderbufferSize) { 716 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); 717 return; 718 } 719 720 if (height < 1 || height > ctx->Const.MaxRenderbufferSize) { 721 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); 722 return; 723 } 724 725 rb = ctx->CurrentRenderbuffer; 726 727 if (!rb) { 728 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT"); 729 return; 730 } 731 732 /* Now allocate the storage */ 733 ASSERT(rb->AllocStorage); 734 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 735 /* No error - check/set fields now */ 736 assert(rb->Width == width); 737 assert(rb->Height == height); 738 assert(rb->InternalFormat); 739 rb->_BaseFormat = baseFormat; 740 } 741 else { 742 /* Probably ran out of memory - clear the fields */ 743 rb->Width = 0; 744 rb->Height = 0; 745 rb->InternalFormat = GL_NONE; 746 rb->_BaseFormat = GL_NONE; 747 } 748 749 /* 750 test_framebuffer_completeness(ctx, fb); 751 */ 752 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 753 * points??? 754 */ 755} 756 757 758void GLAPIENTRY 759_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 760{ 761 GET_CURRENT_CONTEXT(ctx); 762 763 ASSERT_OUTSIDE_BEGIN_END(ctx); 764 765 if (target != GL_RENDERBUFFER_EXT) { 766 _mesa_error(ctx, GL_INVALID_ENUM, 767 "glGetRenderbufferParameterivEXT(target)"); 768 return; 769 } 770 771 if (!ctx->CurrentRenderbuffer) { 772 _mesa_error(ctx, GL_INVALID_OPERATION, 773 "glGetRenderbufferParameterivEXT"); 774 return; 775 } 776 777 switch (pname) { 778 case GL_RENDERBUFFER_WIDTH_EXT: 779 *params = ctx->CurrentRenderbuffer->Width; 780 return; 781 case GL_RENDERBUFFER_HEIGHT_EXT: 782 *params = ctx->CurrentRenderbuffer->Height; 783 return; 784 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 785 *params = ctx->CurrentRenderbuffer->InternalFormat; 786 return; 787 case GL_RENDERBUFFER_RED_SIZE_EXT: 788 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 789 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 790 *params = ctx->CurrentRenderbuffer->RedBits; 791 } 792 else { 793 *params = 0; 794 } 795 break; 796 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 797 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 798 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 799 *params = ctx->CurrentRenderbuffer->GreenBits; 800 } 801 else { 802 *params = 0; 803 } 804 break; 805 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 806 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 807 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 808 *params = ctx->CurrentRenderbuffer->BlueBits; 809 } 810 else { 811 *params = 0; 812 } 813 break; 814 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 815 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 816 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 817 *params = ctx->CurrentRenderbuffer->AlphaBits; 818 } 819 else { 820 *params = 0; 821 } 822 break; 823 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 824 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_COMPONENT || 825 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 826 *params = ctx->CurrentRenderbuffer->DepthBits; 827 } 828 else { 829 *params = 0; 830 } 831 break; 832 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 833 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_STENCIL_INDEX || 834 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 835 *params = ctx->CurrentRenderbuffer->StencilBits; 836 } 837 else { 838 *params = 0; 839 } 840 break; 841 842 default: 843 _mesa_error(ctx, GL_INVALID_ENUM, 844 "glGetRenderbufferParameterivEXT(target)"); 845 return; 846 } 847} 848 849 850GLboolean GLAPIENTRY 851_mesa_IsFramebufferEXT(GLuint framebuffer) 852{ 853 GET_CURRENT_CONTEXT(ctx); 854 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 855 if (framebuffer) { 856 struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer); 857 if (rb != NULL && rb != &DummyFramebuffer) 858 return GL_TRUE; 859 } 860 return GL_FALSE; 861} 862 863 864void GLAPIENTRY 865_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 866{ 867 struct gl_framebuffer *newFb, *newReadFb, *oldFb; 868 GET_CURRENT_CONTEXT(ctx); 869 870 ASSERT_OUTSIDE_BEGIN_END(ctx); 871 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 872 873 if (target != GL_FRAMEBUFFER_EXT) { 874 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 875 return; 876 } 877 878 if (framebuffer) { 879 /* Binding a user-created framebuffer object */ 880 newFb = lookup_framebuffer(ctx, framebuffer); 881 if (newFb == &DummyFramebuffer) { 882 /* ID was reserved, but no real framebuffer object made yet */ 883 newFb = NULL; 884 } 885 if (!newFb) { 886 /* create new framebuffer object */ 887 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 888 if (!newFb) { 889 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 890 return; 891 } 892 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); 893 } 894 newFb->RefCount++; 895 newReadFb = newFb; 896 } 897 else { 898 /* Binding the window system framebuffer (which was originally set 899 * with MakeCurrent). 900 */ 901 newFb = ctx->WinSysDrawBuffer; 902 newReadFb = ctx->WinSysReadBuffer; 903 } 904 905 oldFb = ctx->DrawBuffer; 906 if (oldFb && oldFb->Name != 0) { 907 oldFb->RefCount--; 908 if (oldFb->RefCount == 0) { 909 oldFb->Delete(oldFb); 910 } 911 } 912 913 ASSERT(newFb != &DummyFramebuffer); 914 915 /* Note, we set both the GL_DRAW_BUFFER and GL_READ_BUFFER state: */ 916 ctx->DrawBuffer = newFb; 917 ctx->ReadBuffer = newReadFb; 918} 919 920 921void GLAPIENTRY 922_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 923{ 924 GLint i; 925 GET_CURRENT_CONTEXT(ctx); 926 927 ASSERT_OUTSIDE_BEGIN_END(ctx); 928 929 for (i = 0; i < n; i++) { 930 if (framebuffers[i] > 0) { 931 struct gl_framebuffer *fb; 932 fb = lookup_framebuffer(ctx, framebuffers[i]); 933 if (fb) { 934 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 935 936 /* check if deleting currently bound framebuffer object */ 937 if (fb == ctx->DrawBuffer) { 938 /* bind default */ 939 ASSERT(fb->RefCount >= 2); 940 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 941 } 942 943 /* remove from hash table immediately, to free the ID */ 944 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 945 946 if (fb != &DummyFramebuffer) { 947 /* But the object will not be freed until it's no longer 948 * bound in any context. 949 */ 950 fb->RefCount--; 951 if (fb->RefCount == 0) { 952 fb->Delete(fb); 953 } 954 } 955 } 956 } 957 } 958} 959 960 961void GLAPIENTRY 962_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 963{ 964 GET_CURRENT_CONTEXT(ctx); 965 GLuint first; 966 GLint i; 967 968 ASSERT_OUTSIDE_BEGIN_END(ctx); 969 970 if (n < 0) { 971 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 972 return; 973 } 974 975 if (!framebuffers) 976 return; 977 978 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 979 980 for (i = 0; i < n; i++) { 981 GLuint name = first + i; 982 framebuffers[i] = name; 983 /* insert dummy placeholder into hash table */ 984 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 985 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 986 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 987 } 988} 989 990 991 992GLenum GLAPIENTRY 993_mesa_CheckFramebufferStatusEXT(GLenum target) 994{ 995 GET_CURRENT_CONTEXT(ctx); 996 997 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 998 999 if (target != GL_FRAMEBUFFER_EXT) { 1000 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1001 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1002 } 1003 1004 if (ctx->DrawBuffer->Name == 0) { 1005 /* The window system / default framebuffer is always complete */ 1006 return GL_FRAMEBUFFER_COMPLETE_EXT; 1007 } 1008 1009 _mesa_test_framebuffer_completeness(ctx, ctx->DrawBuffer); 1010 return ctx->DrawBuffer->_Status; 1011} 1012 1013 1014 1015/** 1016 * Do error checking common to glFramebufferTexture1D/2D/3DEXT. 1017 * \return GL_TRUE if any error, GL_FALSE otherwise 1018 */ 1019static GLboolean 1020error_check_framebuffer_texture(GLcontext *ctx, GLuint dims, 1021 GLenum target, GLenum attachment, 1022 GLenum textarget, GLuint texture, GLint level) 1023{ 1024 ASSERT(dims >= 1 && dims <= 3); 1025 1026 if (target != GL_FRAMEBUFFER_EXT) { 1027 _mesa_error(ctx, GL_INVALID_ENUM, 1028 "glFramebufferTexture%dDEXT(target)", dims); 1029 return GL_TRUE; 1030 } 1031 1032 /* check framebuffer binding */ 1033 if (ctx->DrawBuffer->Name == 0) { 1034 _mesa_error(ctx, GL_INVALID_OPERATION, 1035 "glFramebufferTexture%dDEXT", dims); 1036 return GL_TRUE; 1037 } 1038 1039 /* only check textarget, level if texture ID is non-zero */ 1040 if (texture) { 1041 if ((dims == 1 && textarget != GL_TEXTURE_1D) || 1042 (dims == 3 && textarget != GL_TEXTURE_3D) || 1043 (dims == 2 && textarget != GL_TEXTURE_2D && 1044 textarget != GL_TEXTURE_RECTANGLE_ARB && 1045 !IS_CUBE_FACE(textarget))) { 1046 _mesa_error(ctx, GL_INVALID_VALUE, 1047 "glFramebufferTexture%dDEXT(textarget)", dims); 1048 return GL_TRUE; 1049 } 1050 1051 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) { 1052 _mesa_error(ctx, GL_INVALID_VALUE, 1053 "glFramebufferTexture%dDEXT(level)", dims); 1054 return GL_TRUE; 1055 } 1056 } 1057 1058 return GL_FALSE; 1059} 1060 1061 1062void GLAPIENTRY 1063_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1064 GLenum textarget, GLuint texture, GLint level) 1065{ 1066 struct gl_renderbuffer_attachment *att; 1067 struct gl_texture_object *texObj; 1068 GET_CURRENT_CONTEXT(ctx); 1069 1070 ASSERT_OUTSIDE_BEGIN_END(ctx); 1071 FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* XXX check */ 1072 1073 if (error_check_framebuffer_texture(ctx, 1, target, attachment, 1074 textarget, texture, level)) 1075 return; 1076 1077 ASSERT(textarget == GL_TEXTURE_1D); 1078 1079 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1080 if (att == NULL) { 1081 _mesa_error(ctx, GL_INVALID_ENUM, 1082 "glFramebufferTexture1DEXT(attachment)"); 1083 return; 1084 } 1085 1086 if (texture) { 1087 texObj = (struct gl_texture_object *) 1088 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1089 if (!texObj) { 1090 _mesa_error(ctx, GL_INVALID_VALUE, 1091 "glFramebufferTexture1DEXT(texture)"); 1092 return; 1093 } 1094 if (texObj->Target != textarget) { 1095 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1096 "glFramebufferTexture1DEXT(texture target)"); 1097 return; 1098 } 1099 } 1100 else { 1101 /* remove texture attachment */ 1102 texObj = NULL; 1103 } 1104 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); 1105 1106 _mesa_update_framebuffer_visual(ctx->DrawBuffer); 1107} 1108 1109 1110void GLAPIENTRY 1111_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1112 GLenum textarget, GLuint texture, GLint level) 1113{ 1114 struct gl_renderbuffer_attachment *att; 1115 struct gl_texture_object *texObj; 1116 GET_CURRENT_CONTEXT(ctx); 1117 1118 ASSERT_OUTSIDE_BEGIN_END(ctx); 1119 FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* XXX check */ 1120 1121 if (error_check_framebuffer_texture(ctx, 2, target, attachment, 1122 textarget, texture, level)) 1123 return; 1124 1125 ASSERT(textarget == GL_TEXTURE_2D || 1126 textarget == GL_TEXTURE_RECTANGLE_ARB || 1127 IS_CUBE_FACE(textarget)); 1128 1129 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1130 if (att == NULL) { 1131 _mesa_error(ctx, GL_INVALID_ENUM, 1132 "glFramebufferTexture2DEXT(attachment)"); 1133 return; 1134 } 1135 1136 if (texture) { 1137 texObj = (struct gl_texture_object *) 1138 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1139 if (!texObj) { 1140 _mesa_error(ctx, GL_INVALID_VALUE, 1141 "glFramebufferTexture2DEXT(texture)"); 1142 return; 1143 } 1144 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) || 1145 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB 1146 && textarget != GL_TEXTURE_RECTANGLE_ARB) || 1147 (texObj->Target == GL_TEXTURE_CUBE_MAP 1148 && !IS_CUBE_FACE(textarget))) { 1149 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1150 "glFramebufferTexture2DEXT(texture target)"); 1151 return; 1152 } 1153 } 1154 else { 1155 /* remove texture attachment */ 1156 texObj = NULL; 1157 } 1158 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); 1159 _mesa_update_framebuffer_visual(ctx->DrawBuffer); 1160} 1161 1162 1163void GLAPIENTRY 1164_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1165 GLenum textarget, GLuint texture, 1166 GLint level, GLint zoffset) 1167{ 1168 struct gl_renderbuffer_attachment *att; 1169 struct gl_texture_object *texObj; 1170 GET_CURRENT_CONTEXT(ctx); 1171 1172 ASSERT_OUTSIDE_BEGIN_END(ctx); 1173 FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* XXX check */ 1174 1175 if (error_check_framebuffer_texture(ctx, 3, target, attachment, 1176 textarget, texture, level)) 1177 return; 1178 1179 ASSERT(textarget == GL_TEXTURE_3D); 1180 1181 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1182 if (att == NULL) { 1183 _mesa_error(ctx, GL_INVALID_ENUM, 1184 "glFramebufferTexture1DEXT(attachment)"); 1185 return; 1186 } 1187 1188 if (texture) { 1189 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1190 texObj = (struct gl_texture_object *) 1191 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1192 if (!texObj) { 1193 _mesa_error(ctx, GL_INVALID_VALUE, 1194 "glFramebufferTexture3DEXT(texture)"); 1195 return; 1196 } 1197 if (texObj->Target != textarget) { 1198 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1199 "glFramebufferTexture3DEXT(texture target)"); 1200 return; 1201 } 1202 if (zoffset < 0 || zoffset >= maxSize) { 1203 _mesa_error(ctx, GL_INVALID_VALUE, 1204 "glFramebufferTexture3DEXT(zoffset)"); 1205 return; 1206 } 1207 } 1208 else { 1209 /* remove texture attachment */ 1210 texObj = NULL; 1211 } 1212 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, 1213 level, zoffset); 1214 _mesa_update_framebuffer_visual(ctx->DrawBuffer); 1215} 1216 1217 1218void GLAPIENTRY 1219_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1220 GLenum renderbufferTarget, 1221 GLuint renderbuffer) 1222{ 1223 struct gl_renderbuffer_attachment *att; 1224 struct gl_renderbuffer *rb; 1225 GET_CURRENT_CONTEXT(ctx); 1226 1227 ASSERT_OUTSIDE_BEGIN_END(ctx); 1228 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1229 1230 if (target != GL_FRAMEBUFFER_EXT) { 1231 _mesa_error(ctx, GL_INVALID_ENUM, 1232 "glFramebufferRenderbufferEXT(target)"); 1233 return; 1234 } 1235 1236 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1237 _mesa_error(ctx, GL_INVALID_ENUM, 1238 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1239 return; 1240 } 1241 1242 if (ctx->DrawBuffer->Name == 0) { 1243 /* Can't attach new renderbuffers to a window system framebuffer */ 1244 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1245 return; 1246 } 1247 1248 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1249 if (att == NULL) { 1250 _mesa_error(ctx, GL_INVALID_ENUM, 1251 "glFramebufferRenderbufferEXT(attachment)"); 1252 return; 1253 } 1254 1255 if (renderbuffer) { 1256 rb = lookup_renderbuffer(ctx, renderbuffer); 1257 if (!rb) { 1258 _mesa_error(ctx, GL_INVALID_OPERATION, 1259 "glFramebufferRenderbufferEXT(renderbuffer)"); 1260 return; 1261 } 1262 } 1263 else { 1264 /* remove renderbuffer attachment */ 1265 rb = NULL; 1266 } 1267 1268 assert(ctx->Driver.FramebufferRenderbuffer); 1269 ctx->Driver.FramebufferRenderbuffer(ctx, att, rb); 1270 1271 _mesa_update_framebuffer_visual(ctx->DrawBuffer); 1272} 1273 1274 1275void GLAPIENTRY 1276_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1277 GLenum pname, GLint *params) 1278{ 1279 const struct gl_renderbuffer_attachment *att; 1280 GET_CURRENT_CONTEXT(ctx); 1281 1282 ASSERT_OUTSIDE_BEGIN_END(ctx); 1283 1284 if (target != GL_FRAMEBUFFER_EXT) { 1285 _mesa_error(ctx, GL_INVALID_ENUM, 1286 "glGetFramebufferAttachmentParameterivEXT(target)"); 1287 return; 1288 } 1289 1290 if (ctx->DrawBuffer->Name == 0) { 1291 _mesa_error(ctx, GL_INVALID_OPERATION, 1292 "glGetFramebufferAttachmentParameterivEXT"); 1293 return; 1294 } 1295 1296 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1297 if (att == NULL) { 1298 _mesa_error(ctx, GL_INVALID_ENUM, 1299 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1300 return; 1301 } 1302 1303 switch (pname) { 1304 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1305 *params = att->Type; 1306 return; 1307 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1308 if (att->Type == GL_RENDERBUFFER_EXT) { 1309 *params = att->Renderbuffer->Name; 1310 } 1311 else if (att->Type == GL_TEXTURE) { 1312 *params = att->Texture->Name; 1313 } 1314 else { 1315 _mesa_error(ctx, GL_INVALID_ENUM, 1316 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1317 } 1318 return; 1319 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1320 if (att->Type == GL_TEXTURE) { 1321 *params = att->TextureLevel; 1322 } 1323 else { 1324 _mesa_error(ctx, GL_INVALID_ENUM, 1325 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1326 } 1327 return; 1328 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1329 if (att->Type == GL_TEXTURE) { 1330 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1331 } 1332 else { 1333 _mesa_error(ctx, GL_INVALID_ENUM, 1334 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1335 } 1336 return; 1337 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1338 if (att->Type == GL_TEXTURE) { 1339 *params = att->Zoffset; 1340 } 1341 else { 1342 _mesa_error(ctx, GL_INVALID_ENUM, 1343 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1344 } 1345 return; 1346 default: 1347 _mesa_error(ctx, GL_INVALID_ENUM, 1348 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1349 return; 1350 } 1351} 1352 1353 1354void GLAPIENTRY 1355_mesa_GenerateMipmapEXT(GLenum target) 1356{ 1357 struct gl_texture_unit *texUnit; 1358 struct gl_texture_object *texObj; 1359 GET_CURRENT_CONTEXT(ctx); 1360 1361 ASSERT_OUTSIDE_BEGIN_END(ctx); 1362 1363 switch (target) { 1364 case GL_TEXTURE_1D: 1365 case GL_TEXTURE_2D: 1366 case GL_TEXTURE_3D: 1367 case GL_TEXTURE_CUBE_MAP: 1368 /* OK, legal value */ 1369 break; 1370 default: 1371 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1372 return; 1373 } 1374 1375 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 1376 texObj = _mesa_select_tex_object(ctx, texUnit, target); 1377 1378 /* XXX this might not handle cube maps correctly */ 1379 _mesa_generate_mipmap(ctx, target, texUnit, texObj); 1380} 1381