fbobject.c revision 474f28e57ca750ca39d7f684904a3c0e69a03f62
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 const struct gl_texture_image *texImg 410 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 411 w = texImg->Width; 412 h = texImg->Height; 413 f = texImg->_BaseFormat; 414 numImages++; 415 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT) { 416 /* XXX need GL_DEPTH_STENCIL_EXT test? */ 417 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 418 return; 419 } 420 } 421 else if (att->Type == GL_RENDERBUFFER_EXT) { 422 w = att->Renderbuffer->Width; 423 h = att->Renderbuffer->Height; 424 f = att->Renderbuffer->InternalFormat; 425 numImages++; 426 } 427 else { 428 assert(att->Type == GL_NONE); 429 continue; 430 } 431 432 if (numImages == 1) { 433 /* set required width, height and format */ 434 width = w; 435 height = h; 436 if (i >= 0) 437 intFormat = f; 438 } 439 else { 440 /* check that width, height, format are same */ 441 if (w != width || h != height) { 442 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 443 return; 444 } 445 if (intFormat != GL_NONE && f != intFormat) { 446 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 447 return; 448 } 449 } 450 } 451 452 /* Check that all DrawBuffers are present */ 453 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 454 if (fb->ColorDrawBuffer[i] != GL_NONE) { 455 const struct gl_renderbuffer_attachment *att 456 = get_attachment(ctx, fb, fb->ColorDrawBuffer[i]); 457 assert(att); 458 if (att->Type == GL_NONE) { 459 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 460 return; 461 } 462 } 463 } 464 465 /* Check that the ReadBuffer is present */ 466 if (fb->ColorReadBuffer != GL_NONE) { 467 const struct gl_renderbuffer_attachment *att 468 = get_attachment(ctx, fb, fb->ColorReadBuffer); 469 assert(att); 470 if (att->Type == GL_NONE) { 471 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 472 return; 473 } 474 } 475 476 /* Check if any renderbuffer is attached more than once. 477 * Note that there's one exception: a GL_DEPTH_STENCIL renderbuffer can be 478 * bound to both the stencil and depth attachment points at the same time. 479 */ 480 for (i = 0; i < BUFFER_COUNT - 1; i++) { 481 struct gl_renderbuffer *rb_i = fb->Attachment[i].Renderbuffer; 482 if (rb_i) { 483 GLint j; 484 for (j = i + 1; j < BUFFER_COUNT; j++) { 485 struct gl_renderbuffer *rb_j = fb->Attachment[j].Renderbuffer; 486 if (rb_i == rb_j && rb_i->_BaseFormat != GL_DEPTH_STENCIL_EXT) { 487 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT; 488 return; 489 } 490 } 491 } 492 } 493 494 495 if (numImages == 0) { 496 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 497 return; 498 } 499 500 /* 501 * If we get here, the framebuffer is complete! 502 */ 503 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 504 fb->Width = w; 505 fb->Height = h; 506} 507 508 509GLboolean GLAPIENTRY 510_mesa_IsRenderbufferEXT(GLuint renderbuffer) 511{ 512 GET_CURRENT_CONTEXT(ctx); 513 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 514 if (renderbuffer) { 515 struct gl_renderbuffer *rb = lookup_renderbuffer(ctx, renderbuffer); 516 if (rb != NULL && rb != &DummyRenderbuffer) 517 return GL_TRUE; 518 } 519 return GL_FALSE; 520} 521 522 523void GLAPIENTRY 524_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 525{ 526 struct gl_renderbuffer *newRb, *oldRb; 527 GET_CURRENT_CONTEXT(ctx); 528 529 ASSERT_OUTSIDE_BEGIN_END(ctx); 530 531 if (target != GL_RENDERBUFFER_EXT) { 532 _mesa_error(ctx, GL_INVALID_ENUM, 533 "glBindRenderbufferEXT(target)"); 534 return; 535 } 536 537 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 538 539 if (renderbuffer) { 540 newRb = lookup_renderbuffer(ctx, renderbuffer); 541 if (newRb == &DummyRenderbuffer) { 542 /* ID was reserved, but no real renderbuffer object made yet */ 543 newRb = NULL; 544 } 545 if (!newRb) { 546 /* create new renderbuffer object */ 547 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 548 if (!newRb) { 549 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 550 return; 551 } 552 ASSERT(newRb->AllocStorage); 553 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 554 } 555 newRb->RefCount++; 556 } 557 else { 558 newRb = NULL; 559 } 560 561 oldRb = ctx->CurrentRenderbuffer; 562 if (oldRb) { 563 oldRb->RefCount--; 564 if (oldRb->RefCount == 0) { 565 oldRb->Delete(oldRb); 566 } 567 } 568 569 ASSERT(newRb != &DummyRenderbuffer); 570 571 ctx->CurrentRenderbuffer = newRb; 572} 573 574 575void GLAPIENTRY 576_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 577{ 578 GLint i; 579 GET_CURRENT_CONTEXT(ctx); 580 581 ASSERT_OUTSIDE_BEGIN_END(ctx); 582 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 583 584 for (i = 0; i < n; i++) { 585 if (renderbuffers[i] > 0) { 586 struct gl_renderbuffer *rb; 587 rb = lookup_renderbuffer(ctx, renderbuffers[i]); 588 if (rb) { 589 /* check if deleting currently bound renderbuffer object */ 590 if (rb == ctx->CurrentRenderbuffer) { 591 /* bind default */ 592 ASSERT(rb->RefCount >= 2); 593 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 594 } 595 596 /* remove from hash table immediately, to free the ID */ 597 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 598 599 if (rb != &DummyRenderbuffer) { 600 /* But the object will not be freed until it's no longer 601 * bound in any context. 602 */ 603 rb->RefCount--; 604 if (rb->RefCount == 0) { 605 rb->Delete(rb); 606 } 607 } 608 } 609 } 610 } 611} 612 613 614void GLAPIENTRY 615_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 616{ 617 GET_CURRENT_CONTEXT(ctx); 618 GLuint first; 619 GLint i; 620 621 ASSERT_OUTSIDE_BEGIN_END(ctx); 622 623 if (n < 0) { 624 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 625 return; 626 } 627 628 if (!renderbuffers) 629 return; 630 631 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 632 633 for (i = 0; i < n; i++) { 634 GLuint name = first + i; 635 renderbuffers[i] = name; 636 /* insert dummy placeholder into hash table */ 637 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 638 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 639 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 640 } 641} 642 643 644/** 645 * Given an internal format token for a render buffer, return the 646 * corresponding base format. 647 * \return one of GL_RGB, GL_RGBA, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT 648 * GL_DEPTH_STENCIL_EXT or zero if error. 649 */ 650static GLenum 651base_internal_format(GLcontext *ctx, GLenum internalFormat) 652{ 653 switch (internalFormat) { 654 case GL_RGB: 655 case GL_R3_G3_B2: 656 case GL_RGB4: 657 case GL_RGB5: 658 case GL_RGB8: 659 case GL_RGB10: 660 case GL_RGB12: 661 case GL_RGB16: 662 return GL_RGB; 663 case GL_RGBA: 664 case GL_RGBA2: 665 case GL_RGBA4: 666 case GL_RGB5_A1: 667 case GL_RGBA8: 668 case GL_RGB10_A2: 669 case GL_RGBA12: 670 case GL_RGBA16: 671 return GL_RGBA; 672 case GL_STENCIL_INDEX: 673 case GL_STENCIL_INDEX1_EXT: 674 case GL_STENCIL_INDEX4_EXT: 675 case GL_STENCIL_INDEX8_EXT: 676 case GL_STENCIL_INDEX16_EXT: 677 return GL_STENCIL_INDEX; 678 case GL_DEPTH_COMPONENT: 679 case GL_DEPTH_COMPONENT16: 680 case GL_DEPTH_COMPONENT24: 681 case GL_DEPTH_COMPONENT32: 682 return GL_DEPTH_COMPONENT; 683 case GL_DEPTH_STENCIL_EXT: 684 case GL_DEPTH24_STENCIL8_EXT: 685 if (ctx->Extensions.EXT_packed_depth_stencil) 686 return GL_DEPTH_STENCIL_EXT; 687 else 688 return 0; 689 /* XXX add floating point formats eventually */ 690 default: 691 return 0; 692 } 693} 694 695 696void GLAPIENTRY 697_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 698 GLsizei width, GLsizei height) 699{ 700 struct gl_renderbuffer *rb; 701 GLenum baseFormat; 702 GET_CURRENT_CONTEXT(ctx); 703 704 ASSERT_OUTSIDE_BEGIN_END(ctx); 705 706 if (target != GL_RENDERBUFFER_EXT) { 707 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)"); 708 return; 709 } 710 711 baseFormat = base_internal_format(ctx, internalFormat); 712 if (baseFormat == 0) { 713 _mesa_error(ctx, GL_INVALID_ENUM, 714 "glRenderbufferStorageEXT(internalFormat)"); 715 return; 716 } 717 718 if (width < 1 || width > ctx->Const.MaxRenderbufferSize) { 719 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); 720 return; 721 } 722 723 if (height < 1 || height > ctx->Const.MaxRenderbufferSize) { 724 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); 725 return; 726 } 727 728 rb = ctx->CurrentRenderbuffer; 729 730 if (!rb) { 731 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT"); 732 return; 733 } 734 735 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 736 737 /* Now allocate the storage */ 738 ASSERT(rb->AllocStorage); 739 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 740 /* No error - check/set fields now */ 741 assert(rb->Width == width); 742 assert(rb->Height == height); 743 assert(rb->InternalFormat); 744 rb->_BaseFormat = baseFormat; 745 } 746 else { 747 /* Probably ran out of memory - clear the fields */ 748 rb->Width = 0; 749 rb->Height = 0; 750 rb->InternalFormat = GL_NONE; 751 rb->_BaseFormat = GL_NONE; 752 } 753 754 /* 755 test_framebuffer_completeness(ctx, fb); 756 */ 757 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 758 * points??? 759 */ 760} 761 762 763void GLAPIENTRY 764_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 765{ 766 GET_CURRENT_CONTEXT(ctx); 767 768 ASSERT_OUTSIDE_BEGIN_END(ctx); 769 770 if (target != GL_RENDERBUFFER_EXT) { 771 _mesa_error(ctx, GL_INVALID_ENUM, 772 "glGetRenderbufferParameterivEXT(target)"); 773 return; 774 } 775 776 if (!ctx->CurrentRenderbuffer) { 777 _mesa_error(ctx, GL_INVALID_OPERATION, 778 "glGetRenderbufferParameterivEXT"); 779 return; 780 } 781 782 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 783 784 switch (pname) { 785 case GL_RENDERBUFFER_WIDTH_EXT: 786 *params = ctx->CurrentRenderbuffer->Width; 787 return; 788 case GL_RENDERBUFFER_HEIGHT_EXT: 789 *params = ctx->CurrentRenderbuffer->Height; 790 return; 791 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 792 *params = ctx->CurrentRenderbuffer->InternalFormat; 793 return; 794 case GL_RENDERBUFFER_RED_SIZE_EXT: 795 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 796 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 797 *params = ctx->CurrentRenderbuffer->RedBits; 798 } 799 else { 800 *params = 0; 801 } 802 break; 803 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 804 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 805 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 806 *params = ctx->CurrentRenderbuffer->GreenBits; 807 } 808 else { 809 *params = 0; 810 } 811 break; 812 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 813 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 814 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 815 *params = ctx->CurrentRenderbuffer->BlueBits; 816 } 817 else { 818 *params = 0; 819 } 820 break; 821 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 822 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_RGB || 823 ctx->CurrentRenderbuffer->_BaseFormat == GL_RGBA) { 824 *params = ctx->CurrentRenderbuffer->AlphaBits; 825 } 826 else { 827 *params = 0; 828 } 829 break; 830 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 831 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_COMPONENT || 832 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 833 *params = ctx->CurrentRenderbuffer->DepthBits; 834 } 835 else { 836 *params = 0; 837 } 838 break; 839 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 840 if (ctx->CurrentRenderbuffer->_BaseFormat == GL_STENCIL_INDEX || 841 ctx->CurrentRenderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 842 *params = ctx->CurrentRenderbuffer->StencilBits; 843 } 844 else { 845 *params = 0; 846 } 847 break; 848 849 default: 850 _mesa_error(ctx, GL_INVALID_ENUM, 851 "glGetRenderbufferParameterivEXT(target)"); 852 return; 853 } 854} 855 856 857GLboolean GLAPIENTRY 858_mesa_IsFramebufferEXT(GLuint framebuffer) 859{ 860 GET_CURRENT_CONTEXT(ctx); 861 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 862 if (framebuffer) { 863 struct gl_framebuffer *rb = lookup_framebuffer(ctx, framebuffer); 864 if (rb != NULL && rb != &DummyFramebuffer) 865 return GL_TRUE; 866 } 867 return GL_FALSE; 868} 869 870 871void GLAPIENTRY 872_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 873{ 874 struct gl_framebuffer *newFb, *newReadFb, *oldFb; 875 GET_CURRENT_CONTEXT(ctx); 876 877 ASSERT_OUTSIDE_BEGIN_END(ctx); 878 879 if (target != GL_FRAMEBUFFER_EXT) { 880 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 881 return; 882 } 883 884 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 885 886 if (framebuffer) { 887 /* Binding a user-created framebuffer object */ 888 newFb = lookup_framebuffer(ctx, framebuffer); 889 if (newFb == &DummyFramebuffer) { 890 /* ID was reserved, but no real framebuffer object made yet */ 891 newFb = NULL; 892 } 893 if (!newFb) { 894 /* create new framebuffer object */ 895 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 896 if (!newFb) { 897 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 898 return; 899 } 900 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); 901 } 902 newFb->RefCount++; 903 newReadFb = newFb; 904 } 905 else { 906 /* Binding the window system framebuffer (which was originally set 907 * with MakeCurrent). 908 */ 909 newFb = ctx->WinSysDrawBuffer; 910 newReadFb = ctx->WinSysReadBuffer; 911 } 912 913 oldFb = ctx->DrawBuffer; 914 if (oldFb && oldFb->Name != 0) { 915 oldFb->RefCount--; 916 if (oldFb->RefCount == 0) { 917 oldFb->Delete(oldFb); 918 } 919 } 920 921 ASSERT(newFb != &DummyFramebuffer); 922 923 /* Note, we set both the GL_DRAW_BUFFER and GL_READ_BUFFER state: */ 924 ctx->DrawBuffer = newFb; 925 ctx->ReadBuffer = newReadFb; 926} 927 928 929void GLAPIENTRY 930_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 931{ 932 GLint i; 933 GET_CURRENT_CONTEXT(ctx); 934 935 ASSERT_OUTSIDE_BEGIN_END(ctx); 936 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 937 938 for (i = 0; i < n; i++) { 939 if (framebuffers[i] > 0) { 940 struct gl_framebuffer *fb; 941 fb = lookup_framebuffer(ctx, framebuffers[i]); 942 if (fb) { 943 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 944 945 /* check if deleting currently bound framebuffer object */ 946 if (fb == ctx->DrawBuffer) { 947 /* bind default */ 948 ASSERT(fb->RefCount >= 2); 949 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 950 } 951 952 /* remove from hash table immediately, to free the ID */ 953 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 954 955 if (fb != &DummyFramebuffer) { 956 /* But the object will not be freed until it's no longer 957 * bound in any context. 958 */ 959 fb->RefCount--; 960 if (fb->RefCount == 0) { 961 fb->Delete(fb); 962 } 963 } 964 } 965 } 966 } 967} 968 969 970void GLAPIENTRY 971_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 972{ 973 GET_CURRENT_CONTEXT(ctx); 974 GLuint first; 975 GLint i; 976 977 ASSERT_OUTSIDE_BEGIN_END(ctx); 978 979 if (n < 0) { 980 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 981 return; 982 } 983 984 if (!framebuffers) 985 return; 986 987 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 988 989 for (i = 0; i < n; i++) { 990 GLuint name = first + i; 991 framebuffers[i] = name; 992 /* insert dummy placeholder into hash table */ 993 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 994 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 995 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 996 } 997} 998 999 1000 1001GLenum GLAPIENTRY 1002_mesa_CheckFramebufferStatusEXT(GLenum target) 1003{ 1004 GET_CURRENT_CONTEXT(ctx); 1005 1006 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1007 1008 if (target != GL_FRAMEBUFFER_EXT) { 1009 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 1010 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 1011 } 1012 1013 if (ctx->DrawBuffer->Name == 0) { 1014 /* The window system / default framebuffer is always complete */ 1015 return GL_FRAMEBUFFER_COMPLETE_EXT; 1016 } 1017 1018 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1019 1020 _mesa_test_framebuffer_completeness(ctx, ctx->DrawBuffer); 1021 return ctx->DrawBuffer->_Status; 1022} 1023 1024 1025 1026/** 1027 * Do error checking common to glFramebufferTexture1D/2D/3DEXT. 1028 * \return GL_TRUE if any error, GL_FALSE otherwise 1029 */ 1030static GLboolean 1031error_check_framebuffer_texture(GLcontext *ctx, GLuint dims, 1032 GLenum target, GLenum attachment, 1033 GLenum textarget, GLuint texture, GLint level) 1034{ 1035 ASSERT(dims >= 1 && dims <= 3); 1036 1037 if (target != GL_FRAMEBUFFER_EXT) { 1038 _mesa_error(ctx, GL_INVALID_ENUM, 1039 "glFramebufferTexture%dDEXT(target)", dims); 1040 return GL_TRUE; 1041 } 1042 1043 /* check framebuffer binding */ 1044 if (ctx->DrawBuffer->Name == 0) { 1045 _mesa_error(ctx, GL_INVALID_OPERATION, 1046 "glFramebufferTexture%dDEXT", dims); 1047 return GL_TRUE; 1048 } 1049 1050 /* only check textarget, level if texture ID is non-zero */ 1051 if (texture) { 1052 if ((dims == 1 && textarget != GL_TEXTURE_1D) || 1053 (dims == 3 && textarget != GL_TEXTURE_3D) || 1054 (dims == 2 && textarget != GL_TEXTURE_2D && 1055 textarget != GL_TEXTURE_RECTANGLE_ARB && 1056 !IS_CUBE_FACE(textarget))) { 1057 _mesa_error(ctx, GL_INVALID_VALUE, 1058 "glFramebufferTexture%dDEXT(textarget)", dims); 1059 return GL_TRUE; 1060 } 1061 1062 if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) { 1063 _mesa_error(ctx, GL_INVALID_VALUE, 1064 "glFramebufferTexture%dDEXT(level)", dims); 1065 return GL_TRUE; 1066 } 1067 } 1068 1069 return GL_FALSE; 1070} 1071 1072 1073void GLAPIENTRY 1074_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 1075 GLenum textarget, GLuint texture, GLint level) 1076{ 1077 struct gl_renderbuffer_attachment *att; 1078 struct gl_texture_object *texObj; 1079 GET_CURRENT_CONTEXT(ctx); 1080 1081 ASSERT_OUTSIDE_BEGIN_END(ctx); 1082 1083 if (error_check_framebuffer_texture(ctx, 1, target, attachment, 1084 textarget, texture, level)) 1085 return; 1086 1087 ASSERT(textarget == GL_TEXTURE_1D); 1088 1089 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1090 if (att == NULL) { 1091 _mesa_error(ctx, GL_INVALID_ENUM, 1092 "glFramebufferTexture1DEXT(attachment)"); 1093 return; 1094 } 1095 1096 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1097 1098 if (texture) { 1099 texObj = (struct gl_texture_object *) 1100 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1101 if (!texObj) { 1102 _mesa_error(ctx, GL_INVALID_VALUE, 1103 "glFramebufferTexture1DEXT(texture)"); 1104 return; 1105 } 1106 if (texObj->Target != textarget) { 1107 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1108 "glFramebufferTexture1DEXT(texture target)"); 1109 return; 1110 } 1111 } 1112 else { 1113 /* remove texture attachment */ 1114 texObj = NULL; 1115 } 1116 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); 1117} 1118 1119 1120void GLAPIENTRY 1121_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 1122 GLenum textarget, GLuint texture, GLint level) 1123{ 1124 struct gl_renderbuffer_attachment *att; 1125 struct gl_texture_object *texObj; 1126 GET_CURRENT_CONTEXT(ctx); 1127 1128 ASSERT_OUTSIDE_BEGIN_END(ctx); 1129 1130 if (error_check_framebuffer_texture(ctx, 2, target, attachment, 1131 textarget, texture, level)) 1132 return; 1133 1134 ASSERT(textarget == GL_TEXTURE_2D || 1135 textarget == GL_TEXTURE_RECTANGLE_ARB || 1136 IS_CUBE_FACE(textarget)); 1137 1138 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1139 if (att == NULL) { 1140 _mesa_error(ctx, GL_INVALID_ENUM, 1141 "glFramebufferTexture2DEXT(attachment)"); 1142 return; 1143 } 1144 1145 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1146 1147 if (texture) { 1148 texObj = (struct gl_texture_object *) 1149 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1150 if (!texObj) { 1151 _mesa_error(ctx, GL_INVALID_VALUE, 1152 "glFramebufferTexture2DEXT(texture)"); 1153 return; 1154 } 1155 if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) || 1156 (texObj->Target == GL_TEXTURE_RECTANGLE_ARB 1157 && textarget != GL_TEXTURE_RECTANGLE_ARB) || 1158 (texObj->Target == GL_TEXTURE_CUBE_MAP 1159 && !IS_CUBE_FACE(textarget))) { 1160 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1161 "glFramebufferTexture2DEXT(texture target)"); 1162 return; 1163 } 1164 } 1165 else { 1166 /* remove texture attachment */ 1167 texObj = NULL; 1168 } 1169 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, level, 0); 1170} 1171 1172 1173void GLAPIENTRY 1174_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 1175 GLenum textarget, GLuint texture, 1176 GLint level, GLint zoffset) 1177{ 1178 struct gl_renderbuffer_attachment *att; 1179 struct gl_texture_object *texObj; 1180 GET_CURRENT_CONTEXT(ctx); 1181 1182 ASSERT_OUTSIDE_BEGIN_END(ctx); 1183 1184 if (error_check_framebuffer_texture(ctx, 3, target, attachment, 1185 textarget, texture, level)) 1186 return; 1187 1188 ASSERT(textarget == GL_TEXTURE_3D); 1189 1190 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1191 if (att == NULL) { 1192 _mesa_error(ctx, GL_INVALID_ENUM, 1193 "glFramebufferTexture1DEXT(attachment)"); 1194 return; 1195 } 1196 1197 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1198 1199 if (texture) { 1200 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 1201 texObj = (struct gl_texture_object *) 1202 _mesa_HashLookup(ctx->Shared->TexObjects, texture); 1203 if (!texObj) { 1204 _mesa_error(ctx, GL_INVALID_VALUE, 1205 "glFramebufferTexture3DEXT(texture)"); 1206 return; 1207 } 1208 if (texObj->Target != textarget) { 1209 _mesa_error(ctx, GL_INVALID_OPERATION, /* XXX correct error? */ 1210 "glFramebufferTexture3DEXT(texture target)"); 1211 return; 1212 } 1213 if (zoffset < 0 || zoffset >= maxSize) { 1214 _mesa_error(ctx, GL_INVALID_VALUE, 1215 "glFramebufferTexture3DEXT(zoffset)"); 1216 return; 1217 } 1218 } 1219 else { 1220 /* remove texture attachment */ 1221 texObj = NULL; 1222 } 1223 ctx->Driver.RenderbufferTexture(ctx, att, texObj, textarget, 1224 level, zoffset); 1225} 1226 1227 1228void GLAPIENTRY 1229_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 1230 GLenum renderbufferTarget, 1231 GLuint renderbuffer) 1232{ 1233 struct gl_renderbuffer_attachment *att; 1234 struct gl_renderbuffer *rb; 1235 GET_CURRENT_CONTEXT(ctx); 1236 1237 ASSERT_OUTSIDE_BEGIN_END(ctx); 1238 1239 if (target != GL_FRAMEBUFFER_EXT) { 1240 _mesa_error(ctx, GL_INVALID_ENUM, 1241 "glFramebufferRenderbufferEXT(target)"); 1242 return; 1243 } 1244 1245 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 1246 _mesa_error(ctx, GL_INVALID_ENUM, 1247 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 1248 return; 1249 } 1250 1251 if (ctx->DrawBuffer->Name == 0) { 1252 /* Can't attach new renderbuffers to a window system framebuffer */ 1253 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 1254 return; 1255 } 1256 1257 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1258 if (att == NULL) { 1259 _mesa_error(ctx, GL_INVALID_ENUM, 1260 "glFramebufferRenderbufferEXT(attachment)"); 1261 return; 1262 } 1263 1264 if (renderbuffer) { 1265 rb = lookup_renderbuffer(ctx, renderbuffer); 1266 if (!rb) { 1267 _mesa_error(ctx, GL_INVALID_OPERATION, 1268 "glFramebufferRenderbufferEXT(renderbuffer)"); 1269 return; 1270 } 1271 } 1272 else { 1273 /* remove renderbuffer attachment */ 1274 rb = NULL; 1275 } 1276 1277 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1278 1279 assert(ctx->Driver.FramebufferRenderbuffer); 1280 ctx->Driver.FramebufferRenderbuffer(ctx, att, rb); 1281} 1282 1283 1284void GLAPIENTRY 1285_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 1286 GLenum pname, GLint *params) 1287{ 1288 const struct gl_renderbuffer_attachment *att; 1289 GET_CURRENT_CONTEXT(ctx); 1290 1291 ASSERT_OUTSIDE_BEGIN_END(ctx); 1292 1293 if (target != GL_FRAMEBUFFER_EXT) { 1294 _mesa_error(ctx, GL_INVALID_ENUM, 1295 "glGetFramebufferAttachmentParameterivEXT(target)"); 1296 return; 1297 } 1298 1299 if (ctx->DrawBuffer->Name == 0) { 1300 _mesa_error(ctx, GL_INVALID_OPERATION, 1301 "glGetFramebufferAttachmentParameterivEXT"); 1302 return; 1303 } 1304 1305 att = get_attachment(ctx, ctx->DrawBuffer, attachment); 1306 if (att == NULL) { 1307 _mesa_error(ctx, GL_INVALID_ENUM, 1308 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 1309 return; 1310 } 1311 1312 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1313 1314 switch (pname) { 1315 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 1316 *params = att->Type; 1317 return; 1318 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 1319 if (att->Type == GL_RENDERBUFFER_EXT) { 1320 *params = att->Renderbuffer->Name; 1321 } 1322 else if (att->Type == GL_TEXTURE) { 1323 *params = att->Texture->Name; 1324 } 1325 else { 1326 _mesa_error(ctx, GL_INVALID_ENUM, 1327 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1328 } 1329 return; 1330 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 1331 if (att->Type == GL_TEXTURE) { 1332 *params = att->TextureLevel; 1333 } 1334 else { 1335 _mesa_error(ctx, GL_INVALID_ENUM, 1336 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1337 } 1338 return; 1339 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 1340 if (att->Type == GL_TEXTURE) { 1341 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 1342 } 1343 else { 1344 _mesa_error(ctx, GL_INVALID_ENUM, 1345 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1346 } 1347 return; 1348 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 1349 if (att->Type == GL_TEXTURE) { 1350 *params = att->Zoffset; 1351 } 1352 else { 1353 _mesa_error(ctx, GL_INVALID_ENUM, 1354 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1355 } 1356 return; 1357 default: 1358 _mesa_error(ctx, GL_INVALID_ENUM, 1359 "glGetFramebufferAttachmentParameterivEXT(pname)"); 1360 return; 1361 } 1362} 1363 1364 1365void GLAPIENTRY 1366_mesa_GenerateMipmapEXT(GLenum target) 1367{ 1368 struct gl_texture_unit *texUnit; 1369 struct gl_texture_object *texObj; 1370 GET_CURRENT_CONTEXT(ctx); 1371 1372 ASSERT_OUTSIDE_BEGIN_END(ctx); 1373 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 1374 1375 switch (target) { 1376 case GL_TEXTURE_1D: 1377 case GL_TEXTURE_2D: 1378 case GL_TEXTURE_3D: 1379 case GL_TEXTURE_CUBE_MAP: 1380 /* OK, legal value */ 1381 break; 1382 default: 1383 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 1384 return; 1385 } 1386 1387 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 1388 texObj = _mesa_select_tex_object(ctx, texUnit, target); 1389 1390 /* XXX this might not handle cube maps correctly */ 1391 _mesa_generate_mipmap(ctx, target, texUnit, texObj); 1392} 1393