#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_context *ctx, 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 = ctx->Driver.NewRenderbuffer(ctx, name);
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_renderbuffer *srb = swrast_renderbuffer(rb);
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) {
srb->Buffer = swImage->Buffer +
swImage->ImageOffsets[zOffset] * _mesa_get_format_bytes(format);
}
else {
srb->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;
}