#include "main/context.h" #include "main/colormac.h" #include "main/fbobject.h" #include "main/macros.h" #include "main/teximage.h" #include "main/renderbuffer.h" #include "swrast/swrast.h" #include "swrast/s_context.h" #include "swrast/s_texfetch.h" /* * Render-to-texture code for GL_EXT_framebuffer_object */ static void delete_texture_wrapper(struct gl_renderbuffer *rb) { ASSERT(rb->RefCount == 0); free(rb); } /** * This function creates a renderbuffer object which wraps a texture image. * The new renderbuffer is plugged into the given attachment point. * This allows rendering into the texture as if it were a renderbuffer. */ static void wrap_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) { struct gl_renderbuffer *rb; const GLuint name = 0; ASSERT(att->Type == GL_TEXTURE); ASSERT(att->Renderbuffer == NULL); rb = CALLOC_STRUCT(gl_renderbuffer); if (!rb) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "wrap_texture"); return; } /* init base gl_renderbuffer fields */ _mesa_init_renderbuffer(rb, name); /* plug in our texture_renderbuffer-specific functions */ rb->Delete = delete_texture_wrapper; rb->AllocStorage = NULL; /* illegal! */ /* update attachment point */ _mesa_reference_renderbuffer(&att->Renderbuffer, rb); } /** * Update the renderbuffer wrapper for rendering to a texture. * For example, update the width, height of the RB based on the texture size, * update the internal format info, etc. */ static void update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) { struct gl_renderbuffer *rb = att->Renderbuffer; struct swrast_texture_image *swImage; gl_format format; GLuint zOffset; (void) ctx; swImage = swrast_texture_image(_mesa_get_attachment_teximage(att)); assert(swImage); format = swImage->Base.TexFormat; if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) { zOffset = 0; } else { zOffset = att->Zoffset; } rb->Width = swImage->Base.Width; rb->Height = swImage->Base.Height; rb->InternalFormat = swImage->Base.InternalFormat; rb->_BaseFormat = _mesa_get_format_base_format(format); /* Want to store linear values, not sRGB */ rb->Format = _mesa_get_srgb_format_linear(format); /* Set the gl_renderbuffer::Buffer field so that mapping the buffer * succeeds. */ if (att->Texture->Target == GL_TEXTURE_3D || att->Texture->Target == GL_TEXTURE_2D_ARRAY_EXT) { rb->Buffer = swImage->Buffer + swImage->ImageOffsets[zOffset] * _mesa_get_format_bytes(format); } else { rb->Buffer = swImage->Buffer; } } /** * Called when rendering to a texture image begins, or when changing * the dest mipmap level, cube face, etc. * This is a fallback routine for software render-to-texture. * * Called via the glRenderbufferTexture1D/2D/3D() functions * and elsewhere (such as glTexImage2D). * * The image we're rendering into is * att->Texture->Image[att->CubeMapFace][att->TextureLevel]; * It'll never be NULL. * * \param fb the framebuffer object the texture is being bound to * \param att the fb attachment point of the texture * * \sa _mesa_framebuffer_renderbuffer */ void _swrast_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { (void) fb; if (!att->Renderbuffer) { wrap_texture(ctx, att); } update_wrapper(ctx, att); } void _swrast_finish_render_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) { /* do nothing */ /* The renderbuffer texture wrapper will get deleted by the * normal mechanism for deleting renderbuffers. */ (void) ctx; (void) att; }