/** * 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; assert(!att->Texture); _mesa_reference_texobj(&att->Texture, texObj); } /* 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->Texture = NULL; /* just to be safe */ att->Complete = GL_FALSE; _mesa_reference_renderbuffer(&att->Renderbuffer, rb); }
/** * 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); att = _mesa_get_attachment(ctx, fb, attachment); ASSERT(att); if (rb) { _mesa_set_renderbuffer_attachment(ctx, att, rb); } else { _mesa_remove_attachment(ctx, att); } _glthread_UNLOCK_MUTEX(fb->Mutex); }
/** * Check if the given texture object is bound to the current draw or * read framebuffer. If so, Unbind it. */ static void unbind_texobj_from_fbo(struct gl_context *ctx, struct gl_texture_object *texObj) { const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2; GLuint i; for (i = 0; i < n; i++) { struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; if (_mesa_is_user_fbo(fb)) { GLuint j; for (j = 0; j < BUFFER_COUNT; j++) { if (fb->Attachment[j].Type == GL_TEXTURE && fb->Attachment[j].Texture == texObj) { /* Vertices are already flushed by _mesa_DeleteTextures */ ctx->NewState |= _NEW_BUFFERS; _mesa_remove_attachment(ctx, fb->Attachment + j); } } } } }
/** * Common code called by glFramebufferTexture1D/2D/3DEXT(). */ static void framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) { struct gl_renderbuffer_attachment *att; struct gl_texture_object *texObj = NULL; struct gl_framebuffer *fb; ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_FRAMEBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture%sEXT(target)", caller); return; } fb = ctx->DrawBuffer; ASSERT(fb); /* check framebuffer binding */ if (fb->Name == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture%sEXT", caller); return; } /* The textarget, level, and zoffset parameters are only validated if * texture is non-zero. */ if (texture) { GLboolean err = GL_TRUE; texObj = _mesa_lookup_texture(ctx, texture); if (texObj != NULL) { if (textarget == 0) { err = (texObj->Target != GL_TEXTURE_3D) && (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT); } else { err = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? !IS_CUBE_FACE(textarget) : (texObj->Target != textarget); } } if (err) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferTexture%sEXT(texture target mismatch)", caller); return; } if (texObj->Target == GL_TEXTURE_3D) { const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); if (zoffset < 0 || zoffset >= maxSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(zoffset)", caller); return; } } else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) { if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(layer)", caller); return; } } if ((level < 0) || (level >= _mesa_max_texture_levels(ctx, texObj->Target))) { _mesa_error(ctx, GL_INVALID_VALUE, "glFramebufferTexture%sEXT(level)", caller); return; } } att = _mesa_get_attachment(ctx, fb, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, "glFramebufferTexture%sEXT(attachment)", caller); return; } FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* The above doesn't fully flush the drivers in the way that a * glFlush does, but that is required here: */ if (ctx->Driver.Flush) ctx->Driver.Flush(ctx); _glthread_LOCK_MUTEX(fb->Mutex); if (texObj) { _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget, level, zoffset); } else { _mesa_remove_attachment(ctx, att); } _glthread_UNLOCK_MUTEX(fb->Mutex); }