📄 fbobject.c
字号:
/* * Mesa 3-D graphics library * Version: 6.5 * * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//* * Authors: * Brian Paul */#include "context.h"#include "fbobject.h"#include "framebuffer.h"#include "hash.h"#include "renderbuffer.h"#include "state.h"#include "teximage.h"#include "texobj.h"#include "texstore.h"/** * Notes: * * None of the GL_EXT_framebuffer_object functions are compiled into * display lists. *//* * When glGenRender/FramebuffersEXT() is called we insert pointers to * these placeholder objects into the hash table. * Later, when the object ID is first bound, we replace the placeholder * with the real frame/renderbuffer. */static struct gl_framebuffer DummyFramebuffer;static struct gl_renderbuffer DummyRenderbuffer;#define IS_CUBE_FACE(TARGET) \ ((TARGET) >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && \ (TARGET) <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)/** * Helper routine for getting a gl_renderbuffer. */struct gl_renderbuffer *_mesa_lookup_renderbuffer(GLcontext *ctx, GLuint id){ struct gl_renderbuffer *rb; if (id == 0) return NULL; rb = (struct gl_renderbuffer *) _mesa_HashLookup(ctx->Shared->RenderBuffers, id); return rb;}/** * Helper routine for getting a gl_framebuffer. */struct gl_framebuffer *_mesa_lookup_framebuffer(GLcontext *ctx, GLuint id){ struct gl_framebuffer *fb; if (id == 0) return NULL; fb = (struct gl_framebuffer *) _mesa_HashLookup(ctx->Shared->FrameBuffers, id); return fb;}/** * Given a GL_*_ATTACHMENTn token, return a pointer to the corresponding * gl_renderbuffer_attachment object. */struct gl_renderbuffer_attachment *_mesa_get_attachment(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment){ GLuint i; switch (attachment) { case GL_COLOR_ATTACHMENT0_EXT: case GL_COLOR_ATTACHMENT1_EXT: case GL_COLOR_ATTACHMENT2_EXT: case GL_COLOR_ATTACHMENT3_EXT: case GL_COLOR_ATTACHMENT4_EXT: case GL_COLOR_ATTACHMENT5_EXT: case GL_COLOR_ATTACHMENT6_EXT: case GL_COLOR_ATTACHMENT7_EXT: case GL_COLOR_ATTACHMENT8_EXT: case GL_COLOR_ATTACHMENT9_EXT: case GL_COLOR_ATTACHMENT10_EXT: case GL_COLOR_ATTACHMENT11_EXT: case GL_COLOR_ATTACHMENT12_EXT: case GL_COLOR_ATTACHMENT13_EXT: case GL_COLOR_ATTACHMENT14_EXT: case GL_COLOR_ATTACHMENT15_EXT: i = attachment - GL_COLOR_ATTACHMENT0_EXT; if (i >= ctx->Const.MaxColorAttachments) { return NULL; } return &fb->Attachment[BUFFER_COLOR0 + i]; case GL_DEPTH_ATTACHMENT_EXT: return &fb->Attachment[BUFFER_DEPTH]; case GL_STENCIL_ATTACHMENT_EXT: return &fb->Attachment[BUFFER_STENCIL]; default: return NULL; }}/** * Remove any texture or renderbuffer attached to the given attachment * point. Update reference counts, etc. */void_mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att){ if (att->Type == GL_TEXTURE) { ASSERT(att->Texture); att->Texture->RefCount--; if (att->Texture->RefCount == 0) { ctx->Driver.DeleteTexture(ctx, att->Texture); } else { /* tell driver that we're done rendering to this texture. */ if (ctx->Driver.FinishRenderTexture) { ctx->Driver.FinishRenderTexture(ctx, att); } } att->Texture = NULL; } if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) { ASSERT(att->Renderbuffer); ASSERT(!att->Texture); att->Renderbuffer->RefCount--; if (att->Renderbuffer->RefCount == 0) { att->Renderbuffer->Delete(att->Renderbuffer); } att->Renderbuffer = NULL; } att->Type = GL_NONE; att->Complete = GL_TRUE;}/** * Bind a texture object to an attachment point. * The previous binding, if any, will be removed first. */void_mesa_set_texture_attachment(GLcontext *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att, struct gl_texture_object *texObj, GLenum texTarget, GLuint level, GLuint zoffset){ if (att->Texture == texObj) { /* re-attaching same texture */ ASSERT(att->Type == GL_TEXTURE); } else { /* new attachment */ _mesa_remove_attachment(ctx, att); att->Type = GL_TEXTURE; att->Texture = texObj; texObj->RefCount++; } /* always update these fields */ att->TextureLevel = level; if (IS_CUBE_FACE(texTarget)) { att->CubeMapFace = texTarget - GL_TEXTURE_CUBE_MAP_POSITIVE_X; } else { att->CubeMapFace = 0; } att->Zoffset = zoffset; att->Complete = GL_FALSE; if (att->Texture->Image[att->CubeMapFace][att->TextureLevel]) { ctx->Driver.RenderTexture(ctx, fb, att); }}/** * Bind a renderbuffer to an attachment point. * The previous binding, if any, will be removed first. */void_mesa_set_renderbuffer_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att, struct gl_renderbuffer *rb){ /* XXX check if re-doing same attachment, exit early */ _mesa_remove_attachment(ctx, att); att->Type = GL_RENDERBUFFER_EXT; att->Renderbuffer = rb; att->Texture = NULL; /* just to be safe */ att->Complete = GL_FALSE; rb->RefCount++;}/** * Fallback for ctx->Driver.FramebufferRenderbuffer() * Attach a renderbuffer object to a framebuffer object. */void_mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment, struct gl_renderbuffer *rb){ struct gl_renderbuffer_attachment *att; _glthread_LOCK_MUTEX(fb->Mutex); if (rb) _glthread_LOCK_MUTEX(rb->Mutex); att = _mesa_get_attachment(ctx, fb, attachment); ASSERT(att); if (rb) { _mesa_set_renderbuffer_attachment(ctx, att, rb); } else { _mesa_remove_attachment(ctx, att); } if (rb) _glthread_UNLOCK_MUTEX(rb->Mutex); _glthread_UNLOCK_MUTEX(fb->Mutex);}/** * Test if an attachment point is complete and update its Complete field. * \param format if GL_COLOR, this is a color attachment point, * if GL_DEPTH, this is a depth component attachment point, * if GL_STENCIL, this is a stencil component attachment point. */static voidtest_attachment_completeness(const GLcontext *ctx, GLenum format, struct gl_renderbuffer_attachment *att){ assert(format == GL_COLOR || format == GL_DEPTH || format == GL_STENCIL); /* assume complete */ att->Complete = GL_TRUE; /* Look for reasons why the attachment might be incomplete */ if (att->Type == GL_TEXTURE) { const struct gl_texture_object *texObj = att->Texture; struct gl_texture_image *texImage; if (!texObj) { att->Complete = GL_FALSE; return; } texImage = texObj->Image[att->CubeMapFace][att->TextureLevel]; if (!texImage) { att->Complete = GL_FALSE; return; } if (texImage->Width < 1 || texImage->Height < 1) { att->Complete = GL_FALSE; return; } if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) { att->Complete = GL_FALSE; return; } if (format == GL_COLOR) { if (texImage->TexFormat->BaseFormat != GL_RGB && texImage->TexFormat->BaseFormat != GL_RGBA) { att->Complete = GL_FALSE; return; } } else if (format == GL_DEPTH) { if (texImage->TexFormat->BaseFormat == GL_DEPTH_COMPONENT) { /* OK */ } else if (ctx->Extensions.EXT_packed_depth_stencil && att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* OK */ } else { att->Complete = GL_FALSE; return; } } else { /* no such thing as stencil textures */ att->Complete = GL_FALSE; return; } } else if (att->Type == GL_RENDERBUFFER_EXT) { ASSERT(att->Renderbuffer); if (!att->Renderbuffer->InternalFormat || att->Renderbuffer->Width < 1 || att->Renderbuffer->Height < 1) { att->Complete = GL_FALSE; return; } if (format == GL_COLOR) { if (att->Renderbuffer->_BaseFormat != GL_RGB && att->Renderbuffer->_BaseFormat != GL_RGBA) { ASSERT(att->Renderbuffer->RedBits); ASSERT(att->Renderbuffer->GreenBits); ASSERT(att->Renderbuffer->BlueBits); att->Complete = GL_FALSE; return; } } else if (format == GL_DEPTH) { ASSERT(att->Renderbuffer->DepthBits); if (att->Renderbuffer->_BaseFormat == GL_DEPTH_COMPONENT) { /* OK */ } else if (ctx->Extensions.EXT_packed_depth_stencil && att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* OK */ } else { att->Complete = GL_FALSE; return; } } else { assert(format == GL_STENCIL); ASSERT(att->Renderbuffer->StencilBits); if (att->Renderbuffer->_BaseFormat == GL_STENCIL_INDEX) { /* OK */ } else if (ctx->Extensions.EXT_packed_depth_stencil && att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) { /* OK */ } else { att->Complete = GL_FALSE; return; } } } else { ASSERT(att->Type == GL_NONE); /* complete */ return; }}/** * Helpful for debugging */static voidfbo_incomplete(const char *msg, int index){ /* _mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index); */}/** * Test if the given framebuffer object is complete and update its * Status field with the results. * Also update the framebuffer's Width and Height fields if the * framebuffer is complete. */void_mesa_test_framebuffer_completeness(GLcontext *ctx, struct gl_framebuffer *fb){ GLuint numImages, width = 0, height = 0; GLenum intFormat = GL_NONE; GLuint w = 0, h = 0; GLint i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -