Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfbobject.c
Go to the documentation of this file.
00001 /* 00002 * Mesa 3-D graphics library 00003 * Version: 7.1 00004 * 00005 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a 00008 * copy of this software and associated documentation files (the "Software"), 00009 * to deal in the Software without restriction, including without limitation 00010 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 * and/or sell copies of the Software, and to permit persons to whom the 00012 * Software is furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00021 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00022 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 00026 /* 00027 * Authors: 00028 * Brian Paul 00029 */ 00030 00031 00032 #include "buffers.h" 00033 #include "context.h" 00034 #include "fbobject.h" 00035 #include "framebuffer.h" 00036 #include "hash.h" 00037 #include "mipmap.h" 00038 #include "renderbuffer.h" 00039 #include "state.h" 00040 #include "teximage.h" 00041 #include "texobj.h" 00042 #include "texstore.h" 00043 00044 00054 /* 00055 * When glGenRender/FramebuffersEXT() is called we insert pointers to 00056 * these placeholder objects into the hash table. 00057 * Later, when the object ID is first bound, we replace the placeholder 00058 * with the real frame/renderbuffer. 00059 */ 00060 static struct gl_framebuffer DummyFramebuffer; 00061 static struct gl_renderbuffer DummyRenderbuffer; 00062 00063 00064 #define IS_CUBE_FACE(TARGET) \ 00065 ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ 00066 (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) 00067 00068 00069 static void 00070 delete_dummy_renderbuffer(struct gl_renderbuffer *rb) 00071 { 00072 /* no op */ 00073 } 00074 00075 static void 00076 delete_dummy_framebuffer(struct gl_framebuffer *fb) 00077 { 00078 /* no op */ 00079 } 00080 00081 00082 void 00083 _mesa_init_fbobjects(GLcontext *ctx) 00084 { 00085 DummyFramebuffer.Delete = delete_dummy_framebuffer; 00086 DummyRenderbuffer.Delete = delete_dummy_renderbuffer; 00087 } 00088 00089 00093 struct gl_renderbuffer * 00094 _mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id) 00095 { 00096 struct gl_renderbuffer *rb; 00097 00098 if (id == 0) 00099 return NULL; 00100 00101 rb = (struct gl_renderbuffer *) 00102 _mesa_HashLookup(ctx->Shared->RenderBuffers, id); 00103 return rb; 00104 } 00105 00106 00110 struct gl_framebuffer * 00111 _mesa_lookup_framebuffer(GLcontext *ctx, GLuint id) 00112 { 00113 struct gl_framebuffer *fb; 00114 00115 if (id == 0) 00116 return NULL; 00117 00118 fb = (struct gl_framebuffer *) 00119 _mesa_HashLookup(ctx->Shared->FrameBuffers, id); 00120 return fb; 00121 } 00122 00123 00128 struct gl_renderbuffer_attachment * 00129 _mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, 00130 GLenum attachment) 00131 { 00132 GLuint i; 00133 00134 switch (attachment) { 00135 case GL_COLOR_ATTACHMENT0_EXT: 00136 case GL_COLOR_ATTACHMENT1_EXT: 00137 case GL_COLOR_ATTACHMENT2_EXT: 00138 case GL_COLOR_ATTACHMENT3_EXT: 00139 case GL_COLOR_ATTACHMENT4_EXT: 00140 case GL_COLOR_ATTACHMENT5_EXT: 00141 case GL_COLOR_ATTACHMENT6_EXT: 00142 case GL_COLOR_ATTACHMENT7_EXT: 00143 case GL_COLOR_ATTACHMENT8_EXT: 00144 case GL_COLOR_ATTACHMENT9_EXT: 00145 case GL_COLOR_ATTACHMENT10_EXT: 00146 case GL_COLOR_ATTACHMENT11_EXT: 00147 case GL_COLOR_ATTACHMENT12_EXT: 00148 case GL_COLOR_ATTACHMENT13_EXT: 00149 case GL_COLOR_ATTACHMENT14_EXT: 00150 case GL_COLOR_ATTACHMENT15_EXT: 00151 i = attachment - GL_COLOR_ATTACHMENT0_EXT; 00152 if (i >= ctx->Const.MaxColorAttachments) { 00153 return NULL; 00154 } 00155 return &fb->Attachment[BUFFER_COLOR0 + i]; 00156 case GL_DEPTH_ATTACHMENT_EXT: 00157 return &fb->Attachment[BUFFER_DEPTH]; 00158 case GL_STENCIL_ATTACHMENT_EXT: 00159 return &fb->Attachment[BUFFER_STENCIL]; 00160 default: 00161 return NULL; 00162 } 00163 } 00164 00165 00170 void 00171 _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att) 00172 { 00173 if (att->Type == GL_TEXTURE) { 00174 ASSERT(att->Texture); 00175 if (ctx->Driver.FinishRenderTexture) { 00176 /* tell driver we're done rendering to this texobj */ 00177 ctx->Driver.FinishRenderTexture(ctx, att); 00178 } 00179 _mesa_reference_texobj(&att->Texture, NULL); /* unbind */ 00180 ASSERT(!att->Texture); 00181 } 00182 if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { 00183 ASSERT(!att->Texture); 00184 _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */ 00185 ASSERT(!att->Renderbuffer); 00186 } 00187 att->Type = GL_NONE; 00188 att->Complete = GL_TRUE; 00189 } 00190 00191 00196 void 00197 _mesa_set_texture_attachment(GLcontext *ctx, 00198 struct gl_framebuffer *fb, 00199 struct gl_renderbuffer_attachment *att, 00200 struct gl_texture_object *texObj, 00201 GLenum texTarget, GLuint level, GLuint zoffset) 00202 { 00203 if (att->Texture == texObj) { 00204 /* re-attaching same texture */ 00205 ASSERT(att->Type == GL_TEXTURE); 00206 } 00207 else { 00208 /* new attachment */ 00209 _mesa_remove_attachment(ctx, att); 00210 att->Type = GL_TEXTURE; 00211 assert(!att->Texture); 00212 _mesa_reference_texobj(&att->Texture, texObj); 00213 } 00214 00215 /* always update these fields */ 00216 att->TextureLevel = level; 00217 if (IS_CUBE_FACE(texTarget)) { 00218 att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 00219 } 00220 else { 00221 att->CubeMapFace = 0; 00222 } 00223 att->Zoffset = zoffset; 00224 att->Complete = GL_FALSE; 00225 00226 if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 00227 ctx->Driver.RenderTexture(ctx, fb, att); 00228 } 00229 } 00230 00231 00236 void 00237 _mesa_set_renderbuffer_attachment(GLcontext *ctx, 00238 struct gl_renderbuffer_attachment *att, 00239 struct gl_renderbuffer *rb) 00240 { 00241 /* XXX check if re-doing same attachment, exit early */ 00242 _mesa_remove_attachment(ctx, att); 00243 att->Type = GL_RENDERBUFFER_EXT; 00244 att->Texture = NULL; /* just to be safe */ 00245 att->Complete = GL_FALSE; 00246 _mesa_reference_renderbuffer(&att->Renderbuffer, rb); 00247 } 00248 00249 00254 void 00255 _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, 00256 GLenum attachment, struct gl_renderbuffer *rb) 00257 { 00258 struct gl_renderbuffer_attachment *att; 00259 00260 _glthread_LOCK_MUTEX(fb->Mutex); 00261 00262 att = _mesa_get_attachment(ctx, fb, attachment); 00263 ASSERT(att); 00264 if (rb) { 00265 _mesa_set_renderbuffer_attachment(ctx, att, rb); 00266 } 00267 else { 00268 _mesa_remove_attachment(ctx, att); 00269 } 00270 00271 _glthread_UNLOCK_MUTEX(fb->Mutex); 00272 } 00273 00274 00281 static void 00282 test_attachment_completeness(const GLcontext *ctx, GLenum format, 00283 struct gl_renderbuffer_attachment *att) 00284 { 00285 assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); 00286 00287 /* assume complete */ 00288 att->Complete = GL_TRUE; 00289 00290 /* Look for reasons why the attachment might be incomplete */ 00291 if (att->Type == GL_TEXTURE) { 00292 const struct gl_texture_object *texObj = att->Texture; 00293 struct gl_texture_image *texImage; 00294 00295 if (!texObj) { 00296 att->Complete = GL_FALSE; 00297 return; 00298 } 00299 00300 texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; 00301 if (!texImage) { 00302 att->Complete = GL_FALSE; 00303 return; 00304 } 00305 if (texImage->Width < 1 || texImage->Height < 1) { 00306 att->Complete = GL_FALSE; 00307 return; 00308 } 00309 if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { 00310 att->Complete = GL_FALSE; 00311 return; 00312 } 00313 00314 if (format == GL_COLOR) { 00315 if (texImage->TexFormat->BaseFormat != GL_RGB && 00316 texImage->TexFormat->BaseFormat != GL_RGBA) { 00317 att->Complete = GL_FALSE; 00318 return; 00319 } 00320 } 00321 else if (format == GL_DEPTH) { 00322 if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { 00323 /* OK */ 00324 } 00325 else if (ctx->Extensions.EXT_packed_depth_stencil && 00326 texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) { 00327 /* OK */ 00328 } 00329 else { 00330 att->Complete = GL_FALSE; 00331 return; 00332 } 00333 } 00334 else { 00335 /* no such thing as stencil textures */ 00336 att->Complete = GL_FALSE; 00337 return; 00338 } 00339 } 00340 else if (att->Type == GL_RENDERBUFFER_EXT) { 00341 ASSERT(att->Renderbuffer); 00342 if (!att->Renderbuffer->InternalFormat || 00343 att->Renderbuffer->Width < 1 || 00344 att->Renderbuffer->Height < 1) { 00345 att->Complete = GL_FALSE; 00346 return; 00347 } 00348 if (format == GL_COLOR) { 00349 if (att->Renderbuffer->_BaseFormat != GL_RGB && 00350 att->Renderbuffer->_BaseFormat != GL_RGBA) { 00351 ASSERT(att->Renderbuffer->RedBits); 00352 ASSERT(att->Renderbuffer->GreenBits); 00353 ASSERT(att->Renderbuffer->BlueBits); 00354 att->Complete = GL_FALSE; 00355 return; 00356 } 00357 } 00358 else if (format == GL_DEPTH) { 00359 ASSERT(att->Renderbuffer->DepthBits); 00360 if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { 00361 /* OK */ 00362 } 00363 else if (ctx->Extensions.EXT_packed_depth_stencil && 00364 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 00365 /* OK */ 00366 } 00367 else { 00368 att->Complete = GL_FALSE; 00369 return; 00370 } 00371 } 00372 else { 00373 assert(format == GL_STENCIL); 00374 ASSERT(att->Renderbuffer->StencilBits); 00375 if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { 00376 /* OK */ 00377 } 00378 else if (ctx->Extensions.EXT_packed_depth_stencil && 00379 att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { 00380 /* OK */ 00381 } 00382 else { 00383 att->Complete = GL_FALSE; 00384 return; 00385 } 00386 } 00387 } 00388 else { 00389 ASSERT(att->Type == GL_NONE); 00390 /* complete */ 00391 return; 00392 } 00393 } 00394 00395 00399 static void 00400 fbo_incomplete(const char *msg, int index) 00401 { 00402 (void) msg; 00403 (void) index; 00404 /* 00405 _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); 00406 */ 00407 } 00408 00409 00416 void 00417 _mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb) 00418 { 00419 GLuint numImages, width = 0, height = 0; 00420 GLenum intFormat = GL_NONE; 00421 GLuint w = 0, h = 0; 00422 GLint i; 00423 GLuint j; 00424 00425 assert(fb->Name != 0); 00426 00427 numImages = 0; 00428 fb->Width = 0; 00429 fb->Height = 0; 00430 00431 /* Start at -2 to more easily loop over all attachment points */ 00432 for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) { 00433 struct gl_renderbuffer_attachment *att; 00434 GLenum f; 00435 00436 if (i == -2) { 00437 att = &fb->Attachment[BUFFER_DEPTH]; 00438 test_attachment_completeness(ctx, GL_DEPTH, att); 00439 if (!att->Complete) { 00440 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 00441 fbo_incomplete("depth attachment incomplete", -1); 00442 return; 00443 } 00444 } 00445 else if (i == -1) { 00446 att = &fb->Attachment[BUFFER_STENCIL]; 00447 test_attachment_completeness(ctx, GL_STENCIL, att); 00448 if (!att->Complete) { 00449 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 00450 fbo_incomplete("stencil attachment incomplete", -1); 00451 return; 00452 } 00453 } 00454 else { 00455 att = &fb->Attachment[BUFFER_COLOR0 + i]; 00456 test_attachment_completeness(ctx, GL_COLOR, att); 00457 if (!att->Complete) { 00458 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT; 00459 fbo_incomplete("color attachment incomplete", i); 00460 return; 00461 } 00462 } 00463 00464 if (att->Type == GL_TEXTURE) { 00465 const struct gl_texture_image *texImg 00466 = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; 00467 w = texImg->Width; 00468 h = texImg->Height; 00469 f = texImg->_BaseFormat; 00470 numImages++; 00471 if (f != GL_RGB && f != GL_RGBA && f != GL_DEPTH_COMPONENT 00472 && f != GL_DEPTH_STENCIL_EXT) { 00473 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 00474 fbo_incomplete("texture attachment incomplete", -1); 00475 return; 00476 } 00477 } 00478 else if (att->Type == GL_RENDERBUFFER_EXT) { 00479 w = att->Renderbuffer->Width; 00480 h = att->Renderbuffer->Height; 00481 f = att->Renderbuffer->InternalFormat; 00482 numImages++; 00483 } 00484 else { 00485 assert(att->Type == GL_NONE); 00486 continue; 00487 } 00488 00489 if (numImages == 1) { 00490 /* set required width, height and format */ 00491 width = w; 00492 height = h; 00493 if (i >= 0) 00494 intFormat = f; 00495 } 00496 else { 00497 /* check that width, height, format are same */ 00498 if (w != width || h != height) { 00499 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 00500 fbo_incomplete("width or height mismatch", -1); 00501 return; 00502 } 00503 if (intFormat != GL_NONE && f != intFormat) { 00504 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT; 00505 fbo_incomplete("format mismatch", -1); 00506 return; 00507 } 00508 } 00509 } 00510 00511 #ifndef FEATURE_OES_framebuffer_object 00512 /* Check that all DrawBuffers are present */ 00513 for (j = 0; j < ctx->Const.MaxDrawBuffers; j++) { 00514 if (fb->ColorDrawBuffer[j] != GL_NONE) { 00515 const struct gl_renderbuffer_attachment *att 00516 = _mesa_get_attachment(ctx, fb, fb->ColorDrawBuffer[j]); 00517 assert(att); 00518 if (att->Type == GL_NONE) { 00519 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT; 00520 fbo_incomplete("missing drawbuffer", j); 00521 return; 00522 } 00523 } 00524 } 00525 00526 /* Check that the ReadBuffer is present */ 00527 if (fb->ColorReadBuffer != GL_NONE) { 00528 const struct gl_renderbuffer_attachment *att 00529 = _mesa_get_attachment(ctx, fb, fb->ColorReadBuffer); 00530 assert(att); 00531 if (att->Type == GL_NONE) { 00532 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT; 00533 fbo_incomplete("missing readbuffer", -1); 00534 return; 00535 } 00536 } 00537 #endif 00538 00539 if (numImages == 0) { 00540 fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT; 00541 fbo_incomplete("no attachments", -1); 00542 return; 00543 } 00544 00545 /* 00546 * If we get here, the framebuffer is complete! 00547 */ 00548 fb->_Status = GL_FRAMEBUFFER_COMPLETE_EXT; 00549 fb->Width = w; 00550 fb->Height = h; 00551 } 00552 00553 00554 GLboolean GLAPIENTRY 00555 _mesa_IsRenderbufferEXT(GLuint renderbuffer) 00556 { 00557 GET_CURRENT_CONTEXT(ctx); 00558 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 00559 if (renderbuffer) { 00560 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 00561 if (rb != NULL && rb != &DummyRenderbuffer) 00562 return GL_TRUE; 00563 } 00564 return GL_FALSE; 00565 } 00566 00567 00568 void GLAPIENTRY 00569 _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) 00570 { 00571 struct gl_renderbuffer *newRb; 00572 GET_CURRENT_CONTEXT(ctx); 00573 00574 ASSERT_OUTSIDE_BEGIN_END(ctx); 00575 00576 if (target != GL_RENDERBUFFER_EXT) { 00577 _mesa_error(ctx, GL_INVALID_ENUM, 00578 "glBindRenderbufferEXT(target)"); 00579 return; 00580 } 00581 00582 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 00583 /* The above doesn't fully flush the drivers in the way that a 00584 * glFlush does, but that is required here: 00585 */ 00586 if (ctx->Driver.Flush) 00587 ctx->Driver.Flush(ctx); 00588 00589 00590 if (renderbuffer) { 00591 newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 00592 if (newRb == &DummyRenderbuffer) { 00593 /* ID was reserved, but no real renderbuffer object made yet */ 00594 newRb = NULL; 00595 } 00596 if (!newRb) { 00597 /* create new renderbuffer object */ 00598 newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); 00599 if (!newRb) { 00600 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); 00601 return; 00602 } 00603 ASSERT(newRb->AllocStorage); 00604 _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); 00605 newRb->RefCount = 1; /* referenced by hash table */ 00606 } 00607 } 00608 else { 00609 newRb = NULL; 00610 } 00611 00612 ASSERT(newRb != &DummyRenderbuffer); 00613 00614 _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); 00615 } 00616 00617 00618 void GLAPIENTRY 00619 _mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) 00620 { 00621 GLint i; 00622 GET_CURRENT_CONTEXT(ctx); 00623 00624 ASSERT_OUTSIDE_BEGIN_END(ctx); 00625 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 00626 00627 for (i = 0; i < n; i++) { 00628 if (renderbuffers[i] > 0) { 00629 struct gl_renderbuffer *rb; 00630 rb = _mesa_lookup_renderbuffer(ctx, renderbuffers[i]); 00631 if (rb) { 00632 /* check if deleting currently bound renderbuffer object */ 00633 if (rb == ctx->CurrentRenderbuffer) { 00634 /* bind default */ 00635 ASSERT(rb->RefCount >= 2); 00636 _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 00637 } 00638 00639 /* Remove from hash table immediately, to free the ID. 00640 * But the object will not be freed until it's no longer 00641 * referenced anywhere else. 00642 */ 00643 _mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]); 00644 00645 if (rb != &DummyRenderbuffer) { 00646 /* no longer referenced by hash table */ 00647 _mesa_reference_renderbuffer(&rb, NULL); 00648 } 00649 } 00650 } 00651 } 00652 } 00653 00654 00655 void GLAPIENTRY 00656 _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) 00657 { 00658 GET_CURRENT_CONTEXT(ctx); 00659 GLuint first; 00660 GLint i; 00661 00662 ASSERT_OUTSIDE_BEGIN_END(ctx); 00663 00664 if (n < 0) { 00665 _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); 00666 return; 00667 } 00668 00669 if (!renderbuffers) 00670 return; 00671 00672 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); 00673 00674 for (i = 0; i < n; i++) { 00675 GLuint name = first + i; 00676 renderbuffers[i] = name; 00677 /* insert dummy placeholder into hash table */ 00678 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 00679 _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); 00680 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 00681 } 00682 } 00683 00684 00694 GLenum 00695 _mesa_base_fbo_format(GLcontext *ctx, GLenum internalFormat) 00696 { 00697 switch (internalFormat) { 00698 case GL_RGB: 00699 case GL_R3_G3_B2: 00700 case GL_RGB4: 00701 case GL_RGB5: 00702 case GL_RGB8: 00703 case GL_RGB10: 00704 case GL_RGB12: 00705 case GL_RGB16: 00706 return GL_RGB; 00707 case GL_RGBA: 00708 case GL_RGBA2: 00709 case GL_RGBA4: 00710 case GL_RGB5_A1: 00711 case GL_RGBA8: 00712 case GL_RGB10_A2: 00713 case GL_RGBA12: 00714 case GL_RGBA16: 00715 return GL_RGBA; 00716 case GL_STENCIL_INDEX: 00717 case GL_STENCIL_INDEX1_EXT: 00718 case GL_STENCIL_INDEX4_EXT: 00719 case GL_STENCIL_INDEX8_EXT: 00720 case GL_STENCIL_INDEX16_EXT: 00721 return GL_STENCIL_INDEX; 00722 case GL_DEPTH_COMPONENT: 00723 case GL_DEPTH_COMPONENT16: 00724 case GL_DEPTH_COMPONENT24: 00725 case GL_DEPTH_COMPONENT32: 00726 return GL_DEPTH_COMPONENT; 00727 case GL_DEPTH_STENCIL_EXT: 00728 case GL_DEPTH24_STENCIL8_EXT: 00729 if (ctx->Extensions.EXT_packed_depth_stencil) 00730 return GL_DEPTH_STENCIL_EXT; 00731 else 00732 return 0; 00733 /* XXX add floating point formats eventually */ 00734 default: 00735 return 0; 00736 } 00737 } 00738 00739 00740 void GLAPIENTRY 00741 _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, 00742 GLsizei width, GLsizei height) 00743 { 00744 struct gl_renderbuffer *rb; 00745 GLenum baseFormat; 00746 GET_CURRENT_CONTEXT(ctx); 00747 00748 ASSERT_OUTSIDE_BEGIN_END(ctx); 00749 00750 if (target != GL_RENDERBUFFER_EXT) { 00751 _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)"); 00752 return; 00753 } 00754 00755 baseFormat = _mesa_base_fbo_format(ctx, internalFormat); 00756 if (baseFormat == 0) { 00757 _mesa_error(ctx, GL_INVALID_ENUM, 00758 "glRenderbufferStorageEXT(internalFormat)"); 00759 return; 00760 } 00761 00762 if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { 00763 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); 00764 return; 00765 } 00766 00767 if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { 00768 _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); 00769 return; 00770 } 00771 00772 rb = ctx->CurrentRenderbuffer; 00773 00774 if (!rb) { 00775 _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT"); 00776 return; 00777 } 00778 00779 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 00780 00781 if (rb->InternalFormat == internalFormat && 00782 rb->Width == (GLuint) width && 00783 rb->Height == (GLuint) height) { 00784 /* no change in allocation needed */ 00785 return; 00786 } 00787 00788 /* These MUST get set by the AllocStorage func */ 00789 rb->_ActualFormat = 0; 00790 rb->RedBits = 00791 rb->GreenBits = 00792 rb->BlueBits = 00793 rb->AlphaBits = 00794 rb->IndexBits = 00795 rb->DepthBits = 00796 rb->StencilBits = 0; 00797 00798 /* Now allocate the storage */ 00799 ASSERT(rb->AllocStorage); 00800 if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { 00801 /* No error - check/set fields now */ 00802 assert(rb->_ActualFormat); 00803 assert(rb->Width == (GLuint) width); 00804 assert(rb->Height == (GLuint) height); 00805 assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits || 00806 rb->DepthBits || rb->StencilBits || rb->IndexBits); 00807 rb->InternalFormat = internalFormat; 00808 rb->_BaseFormat = baseFormat; 00809 } 00810 else { 00811 /* Probably ran out of memory - clear the fields */ 00812 rb->Width = 0; 00813 rb->Height = 0; 00814 rb->InternalFormat = GL_NONE; 00815 rb->_ActualFormat = GL_NONE; 00816 rb->_BaseFormat = GL_NONE; 00817 rb->RedBits = 00818 rb->GreenBits = 00819 rb->BlueBits = 00820 rb->AlphaBits = 00821 rb->IndexBits = 00822 rb->DepthBits = 00823 rb->StencilBits = 0; 00824 } 00825 00826 /* 00827 test_framebuffer_completeness(ctx, fb); 00828 */ 00829 /* XXX if this renderbuffer is attached anywhere, invalidate attachment 00830 * points??? 00831 */ 00832 } 00833 00834 00835 void GLAPIENTRY 00836 _mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) 00837 { 00838 GET_CURRENT_CONTEXT(ctx); 00839 00840 ASSERT_OUTSIDE_BEGIN_END(ctx); 00841 00842 if (target != GL_RENDERBUFFER_EXT) { 00843 _mesa_error(ctx, GL_INVALID_ENUM, 00844 "glGetRenderbufferParameterivEXT(target)"); 00845 return; 00846 } 00847 00848 if (!ctx->CurrentRenderbuffer) { 00849 _mesa_error(ctx, GL_INVALID_OPERATION, 00850 "glGetRenderbufferParameterivEXT"); 00851 return; 00852 } 00853 00854 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 00855 00856 switch (pname) { 00857 case GL_RENDERBUFFER_WIDTH_EXT: 00858 *params = ctx->CurrentRenderbuffer->Width; 00859 return; 00860 case GL_RENDERBUFFER_HEIGHT_EXT: 00861 *params = ctx->CurrentRenderbuffer->Height; 00862 return; 00863 case GL_RENDERBUFFER_INTERNAL_FORMAT_EXT: 00864 *params = ctx->CurrentRenderbuffer->InternalFormat; 00865 return; 00866 case GL_RENDERBUFFER_RED_SIZE_EXT: 00867 *params = ctx->CurrentRenderbuffer->RedBits; 00868 break; 00869 case GL_RENDERBUFFER_GREEN_SIZE_EXT: 00870 *params = ctx->CurrentRenderbuffer->GreenBits; 00871 break; 00872 case GL_RENDERBUFFER_BLUE_SIZE_EXT: 00873 *params = ctx->CurrentRenderbuffer->BlueBits; 00874 break; 00875 case GL_RENDERBUFFER_ALPHA_SIZE_EXT: 00876 *params = ctx->CurrentRenderbuffer->AlphaBits; 00877 break; 00878 case GL_RENDERBUFFER_DEPTH_SIZE_EXT: 00879 *params = ctx->CurrentRenderbuffer->DepthBits; 00880 break; 00881 case GL_RENDERBUFFER_STENCIL_SIZE_EXT: 00882 *params = ctx->CurrentRenderbuffer->StencilBits; 00883 break; 00884 default: 00885 _mesa_error(ctx, GL_INVALID_ENUM, 00886 "glGetRenderbufferParameterivEXT(target)"); 00887 return; 00888 } 00889 } 00890 00891 00892 GLboolean GLAPIENTRY 00893 _mesa_IsFramebufferEXT(GLuint framebuffer) 00894 { 00895 GET_CURRENT_CONTEXT(ctx); 00896 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 00897 if (framebuffer) { 00898 struct gl_framebuffer *rb = _mesa_lookup_framebuffer(ctx, framebuffer); 00899 if (rb != NULL && rb != &DummyFramebuffer) 00900 return GL_TRUE; 00901 } 00902 return GL_FALSE; 00903 } 00904 00905 00906 static void 00907 check_begin_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 00908 { 00909 GLuint i; 00910 ASSERT(ctx->Driver.RenderTexture); 00911 for (i = 0; i < BUFFER_COUNT; i++) { 00912 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 00913 struct gl_texture_object *texObj = att->Texture; 00914 if (texObj 00915 && att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { 00916 ctx->Driver.RenderTexture(ctx, fb, att); 00917 } 00918 } 00919 } 00920 00921 00927 static void 00928 check_end_texture_render(GLcontext *ctx, struct gl_framebuffer *fb) 00929 { 00930 if (ctx->Driver.FinishRenderTexture) { 00931 GLuint i; 00932 for (i = 0; i < BUFFER_COUNT; i++) { 00933 struct gl_renderbuffer_attachment *att = fb->Attachment + i; 00934 if (att->Texture && att->Renderbuffer) { 00935 ctx->Driver.FinishRenderTexture(ctx, att); 00936 } 00937 } 00938 } 00939 } 00940 00941 00942 void GLAPIENTRY 00943 _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer) 00944 { 00945 struct gl_framebuffer *newFb, *newFbread; 00946 GLboolean bindReadBuf, bindDrawBuf; 00947 GET_CURRENT_CONTEXT(ctx); 00948 00949 ASSERT_OUTSIDE_BEGIN_END(ctx); 00950 00951 if (!ctx->Extensions.EXT_framebuffer_object) { 00952 _mesa_error(ctx, GL_INVALID_OPERATION, 00953 "glBindFramebufferEXT(unsupported)"); 00954 return; 00955 } 00956 00957 switch (target) { 00958 #if FEATURE_EXT_framebuffer_blit 00959 case GL_DRAW_FRAMEBUFFER_EXT: 00960 if (!ctx->Extensions.EXT_framebuffer_blit) { 00961 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 00962 return; 00963 } 00964 bindDrawBuf = GL_TRUE; 00965 bindReadBuf = GL_FALSE; 00966 break; 00967 case GL_READ_FRAMEBUFFER_EXT: 00968 if (!ctx->Extensions.EXT_framebuffer_blit) { 00969 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 00970 return; 00971 } 00972 bindDrawBuf = GL_FALSE; 00973 bindReadBuf = GL_TRUE; 00974 break; 00975 #endif 00976 case GL_FRAMEBUFFER_EXT: 00977 bindDrawBuf = GL_TRUE; 00978 bindReadBuf = GL_TRUE; 00979 break; 00980 default: 00981 _mesa_error(ctx, GL_INVALID_ENUM, "glBindFramebufferEXT(target)"); 00982 return; 00983 } 00984 00985 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 00986 00987 if (ctx->Driver.Flush) { 00988 ctx->Driver.Flush(ctx); 00989 } 00990 00991 if (framebuffer) { 00992 /* Binding a user-created framebuffer object */ 00993 newFb = _mesa_lookup_framebuffer(ctx, framebuffer); 00994 if (newFb == &DummyFramebuffer) { 00995 /* ID was reserved, but no real framebuffer object made yet */ 00996 newFb = NULL; 00997 } 00998 if (!newFb) { 00999 /* create new framebuffer object */ 01000 newFb = ctx->Driver.NewFramebuffer(ctx, framebuffer); 01001 if (!newFb) { 01002 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); 01003 return; 01004 } 01005 _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb); 01006 } 01007 newFbread = newFb; 01008 } 01009 else { 01010 /* Binding the window system framebuffer (which was originally set 01011 * with MakeCurrent). 01012 */ 01013 newFb = ctx->WinSysDrawBuffer; 01014 newFbread = ctx->WinSysReadBuffer; 01015 } 01016 01017 ASSERT(newFb); 01018 ASSERT(newFb != &DummyFramebuffer); 01019 01020 /* 01021 * XXX check if re-binding same buffer and skip some of this code. 01022 */ 01023 01024 if (bindReadBuf) { 01025 _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread); 01026 } 01027 01028 if (bindDrawBuf) { 01029 /* check if old FB had any texture attachments */ 01030 check_end_texture_render(ctx, ctx->DrawBuffer); 01031 01032 /* check if time to delete this framebuffer */ 01033 _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb); 01034 01035 if (newFb->Name != 0) { 01036 /* check if newly bound framebuffer has any texture attachments */ 01037 check_begin_texture_render(ctx, newFb); 01038 } 01039 } 01040 01041 if (ctx->Driver.BindFramebuffer) { 01042 ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread); 01043 } 01044 } 01045 01046 01047 void GLAPIENTRY 01048 _mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) 01049 { 01050 GLint i; 01051 GET_CURRENT_CONTEXT(ctx); 01052 01053 ASSERT_OUTSIDE_BEGIN_END(ctx); 01054 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01055 /* The above doesn't fully flush the drivers in the way that a 01056 * glFlush does, but that is required here: 01057 */ 01058 if (ctx->Driver.Flush) 01059 ctx->Driver.Flush(ctx); 01060 01061 for (i = 0; i < n; i++) { 01062 if (framebuffers[i] > 0) { 01063 struct gl_framebuffer *fb; 01064 fb = _mesa_lookup_framebuffer(ctx, framebuffers[i]); 01065 if (fb) { 01066 ASSERT(fb == &DummyFramebuffer || fb->Name == framebuffers[i]); 01067 01068 /* check if deleting currently bound framebuffer object */ 01069 if (fb == ctx->DrawBuffer) { 01070 /* bind default */ 01071 ASSERT(fb->RefCount >= 2); 01072 _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 01073 } 01074 01075 /* remove from hash table immediately, to free the ID */ 01076 _mesa_HashRemove(ctx->Shared->FrameBuffers, framebuffers[i]); 01077 01078 if (fb != &DummyFramebuffer) { 01079 /* But the object will not be freed until it's no longer 01080 * bound in any context. 01081 */ 01082 _mesa_unreference_framebuffer(&fb); 01083 } 01084 } 01085 } 01086 } 01087 } 01088 01089 01090 void GLAPIENTRY 01091 _mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) 01092 { 01093 GET_CURRENT_CONTEXT(ctx); 01094 GLuint first; 01095 GLint i; 01096 01097 ASSERT_OUTSIDE_BEGIN_END(ctx); 01098 01099 if (n < 0) { 01100 _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); 01101 return; 01102 } 01103 01104 if (!framebuffers) 01105 return; 01106 01107 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->FrameBuffers, n); 01108 01109 for (i = 0; i < n; i++) { 01110 GLuint name = first + i; 01111 framebuffers[i] = name; 01112 /* insert dummy placeholder into hash table */ 01113 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 01114 _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); 01115 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 01116 } 01117 } 01118 01119 01120 01121 GLenum GLAPIENTRY 01122 _mesa_CheckFramebufferStatusEXT(GLenum target) 01123 { 01124 struct gl_framebuffer *buffer; 01125 GET_CURRENT_CONTEXT(ctx); 01126 01127 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 01128 01129 switch (target) { 01130 #if FEATURE_EXT_framebuffer_blit 01131 case GL_DRAW_FRAMEBUFFER_EXT: 01132 if (!ctx->Extensions.EXT_framebuffer_blit) { 01133 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 01134 return 0; 01135 } 01136 buffer = ctx->DrawBuffer; 01137 break; 01138 case GL_READ_FRAMEBUFFER_EXT: 01139 if (!ctx->Extensions.EXT_framebuffer_blit) { 01140 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 01141 return 0; 01142 } 01143 buffer = ctx->ReadBuffer; 01144 break; 01145 #endif 01146 case GL_FRAMEBUFFER_EXT: 01147 buffer = ctx->DrawBuffer; 01148 break; 01149 default: 01150 _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); 01151 return 0; /* formerly GL_FRAMEBUFFER_STATUS_ERROR_EXT */ 01152 } 01153 01154 if (buffer->Name == 0) { 01155 /* The window system / default framebuffer is always complete */ 01156 return GL_FRAMEBUFFER_COMPLETE_EXT; 01157 } 01158 01159 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01160 01161 _mesa_test_framebuffer_completeness(ctx, buffer); 01162 return buffer->_Status; 01163 } 01164 01165 01166 01170 static void 01171 framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 01172 GLenum attachment, GLenum textarget, GLuint texture, 01173 GLint level, GLint zoffset) 01174 { 01175 struct gl_renderbuffer_attachment *att; 01176 struct gl_texture_object *texObj = NULL; 01177 struct gl_framebuffer *fb; 01178 01179 ASSERT_OUTSIDE_BEGIN_END(ctx); 01180 01181 if (target != GL_FRAMEBUFFER_EXT) { 01182 _mesa_error(ctx, GL_INVALID_ENUM, 01183 "glFramebufferTexture%sEXT(target)", caller); 01184 return; 01185 } 01186 01187 fb = ctx->DrawBuffer; 01188 ASSERT(fb); 01189 01190 /* check framebuffer binding */ 01191 if (fb->Name == 0) { 01192 _mesa_error(ctx, GL_INVALID_OPERATION, 01193 "glFramebufferTexture%sEXT", caller); 01194 return; 01195 } 01196 01197 01198 /* The textarget, level, and zoffset parameters are only validated if 01199 * texture is non-zero. 01200 */ 01201 if (texture) { 01202 GLboolean err = GL_TRUE; 01203 01204 texObj = _mesa_lookup_texture(ctx, texture); 01205 if (texObj != NULL) { 01206 if (textarget == 0) { 01207 err = (texObj->Target != GL_TEXTURE_3D) && 01208 (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && 01209 (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); 01210 } 01211 else { 01212 err = (texObj->Target == GL_TEXTURE_CUBE_MAP) 01213 ? !IS_CUBE_FACE(textarget) 01214 : (texObj->Target != textarget); 01215 } 01216 } 01217 01218 if (err) { 01219 _mesa_error(ctx, GL_INVALID_OPERATION, 01220 "glFramebufferTexture%sEXT(texture target mismatch)", 01221 caller); 01222 return; 01223 } 01224 01225 if (texObj->Target == GL_TEXTURE_3D) { 01226 const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); 01227 if (zoffset < 0 || zoffset >= maxSize) { 01228 _mesa_error(ctx, GL_INVALID_VALUE, 01229 "glFramebufferTexture%sEXT(zoffset)", caller); 01230 return; 01231 } 01232 } 01233 else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || 01234 (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { 01235 if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { 01236 _mesa_error(ctx, GL_INVALID_VALUE, 01237 "glFramebufferTexture%sEXT(layer)", caller); 01238 return; 01239 } 01240 } 01241 01242 01243 if ((level < 0) || 01244 (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { 01245 _mesa_error(ctx, GL_INVALID_VALUE, 01246 "glFramebufferTexture%sEXT(level)", caller); 01247 return; 01248 } 01249 } 01250 01251 att = _mesa_get_attachment(ctx, fb, attachment); 01252 if (att == NULL) { 01253 _mesa_error(ctx, GL_INVALID_ENUM, 01254 "glFramebufferTexture%sEXT(attachment)", caller); 01255 return; 01256 } 01257 01258 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01259 /* The above doesn't fully flush the drivers in the way that a 01260 * glFlush does, but that is required here: 01261 */ 01262 if (ctx->Driver.Flush) 01263 ctx->Driver.Flush(ctx); 01264 01265 _glthread_LOCK_MUTEX(fb->Mutex); 01266 if (texObj) { 01267 _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, 01268 level, zoffset); 01269 } 01270 else { 01271 _mesa_remove_attachment(ctx, att); 01272 } 01273 _glthread_UNLOCK_MUTEX(fb->Mutex); 01274 } 01275 01276 01277 01278 void GLAPIENTRY 01279 _mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, 01280 GLenum textarget, GLuint texture, GLint level) 01281 { 01282 GET_CURRENT_CONTEXT(ctx); 01283 01284 if ((texture != 0) && (textarget != GL_TEXTURE_1D)) { 01285 _mesa_error(ctx, GL_INVALID_ENUM, 01286 "glFramebufferTexture1DEXT(textarget)"); 01287 return; 01288 } 01289 01290 framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, 01291 level, 0); 01292 } 01293 01294 01295 void GLAPIENTRY 01296 _mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, 01297 GLenum textarget, GLuint texture, GLint level) 01298 { 01299 GET_CURRENT_CONTEXT(ctx); 01300 01301 if ((texture != 0) && 01302 (textarget != GL_TEXTURE_2D) && 01303 (textarget != GL_TEXTURE_RECTANGLE_ARB) && 01304 (!IS_CUBE_FACE(textarget))) { 01305 _mesa_error(ctx, GL_INVALID_OPERATION, 01306 "glFramebufferTexture2DEXT(textarget)"); 01307 return; 01308 } 01309 01310 framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, 01311 level, 0); 01312 } 01313 01314 01315 void GLAPIENTRY 01316 _mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, 01317 GLenum textarget, GLuint texture, 01318 GLint level, GLint zoffset) 01319 { 01320 GET_CURRENT_CONTEXT(ctx); 01321 01322 if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { 01323 _mesa_error(ctx, GL_INVALID_ENUM, 01324 "glFramebufferTexture3DEXT(textarget)"); 01325 return; 01326 } 01327 01328 framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, 01329 level, zoffset); 01330 } 01331 01332 01333 void GLAPIENTRY 01334 _mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment, 01335 GLuint texture, GLint level, GLint layer) 01336 { 01337 GET_CURRENT_CONTEXT(ctx); 01338 01339 framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, 01340 level, layer); 01341 } 01342 01343 01344 void GLAPIENTRY 01345 _mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, 01346 GLenum renderbufferTarget, 01347 GLuint renderbuffer) 01348 { 01349 struct gl_renderbuffer_attachment *att; 01350 struct gl_framebuffer *fb; 01351 struct gl_renderbuffer *rb; 01352 GET_CURRENT_CONTEXT(ctx); 01353 01354 ASSERT_OUTSIDE_BEGIN_END(ctx); 01355 01356 switch (target) { 01357 #if FEATURE_EXT_framebuffer_blit 01358 case GL_DRAW_FRAMEBUFFER_EXT: 01359 if (!ctx->Extensions.EXT_framebuffer_blit) { 01360 _mesa_error(ctx, GL_INVALID_ENUM, 01361 "glFramebufferRenderbufferEXT(target)"); 01362 return; 01363 } 01364 fb = ctx->DrawBuffer; 01365 break; 01366 case GL_READ_FRAMEBUFFER_EXT: 01367 if (!ctx->Extensions.EXT_framebuffer_blit) { 01368 _mesa_error(ctx, GL_INVALID_ENUM, 01369 "glFramebufferRenderbufferEXT(target)"); 01370 return; 01371 } 01372 fb = ctx->ReadBuffer; 01373 break; 01374 #endif 01375 case GL_FRAMEBUFFER_EXT: 01376 fb = ctx->DrawBuffer; 01377 break; 01378 default: 01379 _mesa_error(ctx, GL_INVALID_ENUM, 01380 "glFramebufferRenderbufferEXT(target)"); 01381 return; 01382 } 01383 01384 if (renderbufferTarget != GL_RENDERBUFFER_EXT) { 01385 _mesa_error(ctx, GL_INVALID_ENUM, 01386 "glFramebufferRenderbufferEXT(renderbufferTarget)"); 01387 return; 01388 } 01389 01390 if (fb->Name == 0) { 01391 /* Can't attach new renderbuffers to a window system framebuffer */ 01392 _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbufferEXT"); 01393 return; 01394 } 01395 01396 att = _mesa_get_attachment(ctx, fb, attachment); 01397 if (att == NULL) { 01398 _mesa_error(ctx, GL_INVALID_ENUM, 01399 "glFramebufferRenderbufferEXT(attachment)"); 01400 return; 01401 } 01402 01403 if (renderbuffer) { 01404 rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); 01405 if (!rb) { 01406 _mesa_error(ctx, GL_INVALID_OPERATION, 01407 "glFramebufferRenderbufferEXT(renderbuffer)"); 01408 return; 01409 } 01410 } 01411 else { 01412 /* remove renderbuffer attachment */ 01413 rb = NULL; 01414 } 01415 01416 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01417 /* The above doesn't fully flush the drivers in the way that a 01418 * glFlush does, but that is required here: 01419 */ 01420 if (ctx->Driver.Flush) 01421 ctx->Driver.Flush(ctx); 01422 01423 assert(ctx->Driver.FramebufferRenderbuffer); 01424 ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb); 01425 01426 /* Some subsequent GL commands may depend on the framebuffer's visual 01427 * after the binding is updated. Update visual info now. 01428 */ 01429 _mesa_update_framebuffer_visual(fb); 01430 } 01431 01432 01433 void GLAPIENTRY 01434 _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, 01435 GLenum pname, GLint *params) 01436 { 01437 const struct gl_renderbuffer_attachment *att; 01438 struct gl_framebuffer *buffer; 01439 GET_CURRENT_CONTEXT(ctx); 01440 01441 ASSERT_OUTSIDE_BEGIN_END(ctx); 01442 01443 switch (target) { 01444 #if FEATURE_EXT_framebuffer_blit 01445 case GL_DRAW_FRAMEBUFFER_EXT: 01446 if (!ctx->Extensions.EXT_framebuffer_blit) { 01447 _mesa_error(ctx, GL_INVALID_ENUM, 01448 "glGetFramebufferAttachmentParameterivEXT(target)"); 01449 return; 01450 } 01451 buffer = ctx->DrawBuffer; 01452 break; 01453 case GL_READ_FRAMEBUFFER_EXT: 01454 if (!ctx->Extensions.EXT_framebuffer_blit) { 01455 _mesa_error(ctx, GL_INVALID_ENUM, 01456 "glGetFramebufferAttachmentParameterivEXT(target)"); 01457 return; 01458 } 01459 buffer = ctx->ReadBuffer; 01460 break; 01461 #endif 01462 case GL_FRAMEBUFFER_EXT: 01463 buffer = ctx->DrawBuffer; 01464 break; 01465 default: 01466 _mesa_error(ctx, GL_INVALID_ENUM, 01467 "glGetFramebufferAttachmentParameterivEXT(target)"); 01468 return; 01469 } 01470 01471 if (buffer->Name == 0) { 01472 _mesa_error(ctx, GL_INVALID_OPERATION, 01473 "glGetFramebufferAttachmentParameterivEXT"); 01474 return; 01475 } 01476 01477 att = _mesa_get_attachment(ctx, buffer, attachment); 01478 if (att == NULL) { 01479 _mesa_error(ctx, GL_INVALID_ENUM, 01480 "glGetFramebufferAttachmentParameterivEXT(attachment)"); 01481 return; 01482 } 01483 01484 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01485 /* The above doesn't fully flush the drivers in the way that a 01486 * glFlush does, but that is required here: 01487 */ 01488 if (ctx->Driver.Flush) 01489 ctx->Driver.Flush(ctx); 01490 01491 switch (pname) { 01492 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: 01493 *params = att->Type; 01494 return; 01495 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: 01496 if (att->Type == GL_RENDERBUFFER_EXT) { 01497 *params = att->Renderbuffer->Name; 01498 } 01499 else if (att->Type == GL_TEXTURE) { 01500 *params = att->Texture->Name; 01501 } 01502 else { 01503 _mesa_error(ctx, GL_INVALID_ENUM, 01504 "glGetFramebufferAttachmentParameterivEXT(pname)"); 01505 } 01506 return; 01507 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: 01508 if (att->Type == GL_TEXTURE) { 01509 *params = att->TextureLevel; 01510 } 01511 else { 01512 _mesa_error(ctx, GL_INVALID_ENUM, 01513 "glGetFramebufferAttachmentParameterivEXT(pname)"); 01514 } 01515 return; 01516 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: 01517 if (att->Type == GL_TEXTURE) { 01518 if (att->Texture && att->Texture->Target == GL_TEXTURE_CUBE_MAP) { 01519 *params = GL_TEXTURE_CUBE_MAP_POSITIVE_X + att->CubeMapFace; 01520 } 01521 else { 01522 *params = 0; 01523 } 01524 } 01525 else { 01526 _mesa_error(ctx, GL_INVALID_ENUM, 01527 "glGetFramebufferAttachmentParameterivEXT(pname)"); 01528 } 01529 return; 01530 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: 01531 if (att->Type == GL_TEXTURE) { 01532 if (att->Texture && att->Texture->Target == GL_TEXTURE_3D) { 01533 *params = att->Zoffset; 01534 } 01535 else { 01536 *params = 0; 01537 } 01538 } 01539 else { 01540 _mesa_error(ctx, GL_INVALID_ENUM, 01541 "glGetFramebufferAttachmentParameterivEXT(pname)"); 01542 } 01543 return; 01544 default: 01545 _mesa_error(ctx, GL_INVALID_ENUM, 01546 "glGetFramebufferAttachmentParameterivEXT(pname)"); 01547 return; 01548 } 01549 } 01550 01551 01552 void GLAPIENTRY 01553 _mesa_GenerateMipmapEXT(GLenum target) 01554 { 01555 struct gl_texture_unit *texUnit; 01556 struct gl_texture_object *texObj; 01557 GET_CURRENT_CONTEXT(ctx); 01558 01559 ASSERT_OUTSIDE_BEGIN_END(ctx); 01560 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01561 01562 switch (target) { 01563 case GL_TEXTURE_1D: 01564 case GL_TEXTURE_2D: 01565 case GL_TEXTURE_3D: 01566 case GL_TEXTURE_CUBE_MAP: 01567 /* OK, legal value */ 01568 break; 01569 default: 01570 _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target)"); 01571 return; 01572 } 01573 01574 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; 01575 texObj = _mesa_select_tex_object(ctx, texUnit, target); 01576 01577 _mesa_lock_texture(ctx, texObj); 01578 if (target == GL_TEXTURE_CUBE_MAP) { 01579 int face; 01580 01581 for (face = 0; face < 6; face++) 01582 ctx->Driver.GenerateMipmap(ctx, 01583 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face, 01584 texObj); 01585 } else { 01586 ctx->Driver.GenerateMipmap(ctx, target, texObj); 01587 } 01588 _mesa_unlock_texture(ctx, texObj); 01589 } 01590 01591 01592 #if FEATURE_EXT_framebuffer_blit 01593 void GLAPIENTRY 01594 _mesa_BlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 01595 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 01596 GLbitfield mask, GLenum filter) 01597 { 01598 GET_CURRENT_CONTEXT(ctx); 01599 01600 ASSERT_OUTSIDE_BEGIN_END(ctx); 01601 FLUSH_VERTICES(ctx, _NEW_BUFFERS); 01602 01603 if (ctx->NewState) { 01604 _mesa_update_state(ctx); 01605 } 01606 01607 if (!ctx->ReadBuffer) { 01608 /* XXX */ 01609 } 01610 01611 /* check for complete framebuffers */ 01612 if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 01613 ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 01614 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 01615 "glBlitFramebufferEXT(incomplete draw/read buffers)"); 01616 return; 01617 } 01618 01619 if (filter != GL_NEAREST && filter != GL_LINEAR) { 01620 _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(filter)"); 01621 return; 01622 } 01623 01624 if (mask & ~(GL_COLOR_BUFFER_BIT | 01625 GL_DEPTH_BUFFER_BIT | 01626 GL_STENCIL_BUFFER_BIT)) { 01627 _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); 01628 return; 01629 } 01630 01631 /* depth/stencil must be blitted with nearest filtering */ 01632 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 01633 && filter != GL_NEAREST) { 01634 _mesa_error(ctx, GL_INVALID_OPERATION, 01635 "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter"); 01636 return; 01637 } 01638 01639 if (mask & GL_STENCIL_BUFFER_BIT) { 01640 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_StencilBuffer; 01641 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_StencilBuffer; 01642 if (readRb->StencilBits != drawRb->StencilBits) { 01643 _mesa_error(ctx, GL_INVALID_OPERATION, 01644 "glBlitFramebufferEXT(stencil buffer size mismatch"); 01645 return; 01646 } 01647 } 01648 01649 if (mask & GL_DEPTH_BUFFER_BIT) { 01650 struct gl_renderbuffer *readRb = ctx->ReadBuffer->_DepthBuffer; 01651 struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_DepthBuffer; 01652 if (readRb->DepthBits != drawRb->DepthBits) { 01653 _mesa_error(ctx, GL_INVALID_OPERATION, 01654 "glBlitFramebufferEXT(depth buffer size mismatch"); 01655 return; 01656 } 01657 } 01658 01659 if (!ctx->Extensions.EXT_framebuffer_blit) { 01660 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT"); 01661 return; 01662 } 01663 01664 ASSERT(ctx->Driver.BlitFramebuffer); 01665 ctx->Driver.BlitFramebuffer(ctx, 01666 srcX0, srcY0, srcX1, srcY1, 01667 dstX0, dstY0, dstX1, dstY1, 01668 mask, filter); 01669 } 01670 #endif /* FEATURE_EXT_framebuffer_blit */ Generated on Mon May 28 2012 04:20:01 for ReactOS by
1.7.6.1
|