#include "context.h"
#include "fbobject.h"
+#include "texformat.h"
#include "texrender.h"
#include "renderbuffer.h"
*/
struct texture_renderbuffer
{
- struct gl_renderbuffer Base; /* Base class object */
+ struct gl_renderbuffer Base; /**< Base class object */
struct gl_texture_image *TexImage;
StoreTexelFunc Store;
- GLint Zoffset;
+ GLint Yoffset; /**< Layer for 1D array textures. */
+ GLint Zoffset; /**< Layer for 2D array textures, or slice
+ * for 3D textures
+ */
};
-
+/**
+ * Get row of values from the renderbuffer that wraps a texture image.
+ */
static void
texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
GLint x, GLint y, void *values)
{
- /* XXX unfinished */
+ const struct texture_renderbuffer *trb
+ = (const struct texture_renderbuffer *) rb;
+ const GLint z = trb->Zoffset;
+ GLuint i;
+
+ ASSERT(trb->TexImage->Width == rb->Width);
+ ASSERT(trb->TexImage->Height == rb->Height);
+
+ y += trb->Yoffset;
+
+ if (rb->DataType == CHAN_TYPE) {
+ GLchan *rgbaOut = (GLchan *) values;
+ for (i = 0; i < count; i++) {
+ trb->TexImage->FetchTexelc(trb->TexImage, x + i, y, z, rgbaOut + 4 * i);
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ GLuint *zValues = (GLuint *) values;
+ /*
+ const GLdouble scale = (GLdouble) 0xffffffff;
+ */
+ for (i = 0; i < count; i++) {
+ GLfloat flt;
+ trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
+#if 0
+ /* this should work, but doesn't (overflow due to low precision) */
+ zValues[i] = (GLuint) (flt * scale);
+#else
+ /* temporary hack */
+ zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
+#endif
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ GLuint *zValues = (GLuint *) values;
+ for (i = 0; i < count; i++) {
+ GLfloat flt;
+ trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
+ zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
+ }
+ }
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_get_row");
+ }
}
+
static void
texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
const GLint x[], const GLint y[], void *values)
{
- /* XXX unfinished */
+ const struct texture_renderbuffer *trb
+ = (const struct texture_renderbuffer *) rb;
+ const GLint z = trb->Zoffset;
+ GLuint i;
+
+ if (rb->DataType == CHAN_TYPE) {
+ GLchan *rgbaOut = (GLchan *) values;
+ for (i = 0; i < count; i++) {
+ trb->TexImage->FetchTexelc(trb->TexImage, x[i], y[i] + trb->Yoffset,
+ z, rgbaOut + 4 * i);
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ GLuint *zValues = (GLuint *) values;
+ for (i = 0; i < count; i++) {
+ GLfloat flt;
+ trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
+ z, &flt);
+#if 0
+ zValues[i] = (GLuint) (flt * 0xffffffff);
+#else
+ zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
+#endif
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ GLuint *zValues = (GLuint *) values;
+ for (i = 0; i < count; i++) {
+ GLfloat flt;
+ trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
+ z, &flt);
+ zValues[i] = ((GLuint) (flt * 0xffffff)) << 8;
+ }
+ }
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_get_values");
+ }
}
+
+/**
+ * Put row of values into a renderbuffer that wraps a texture image.
+ */
static void
texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
GLint x, GLint y, const void *values, const GLubyte *mask)
const struct texture_renderbuffer *trb
= (const struct texture_renderbuffer *) rb;
const GLint z = trb->Zoffset;
- const GLchan *rgba = (const GLchan *) values;
GLuint i;
- for (i = 0; i < count; i++) {
- if (!mask || mask[i]) {
- trb->Store(trb->TexImage, x + i, y, z, rgba);
+
+ y += trb->Yoffset;
+
+ if (rb->DataType == CHAN_TYPE) {
+ const GLchan *rgba = (const GLchan *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x + i, y, z, rgba);
+ }
+ rgba += 4;
}
- rgba += 4;
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ const GLuint *zValues = (const GLuint *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x + i, y, z, zValues + i);
+ }
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ const GLuint *zValues = (const GLuint *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ GLfloat flt = (zValues[i] >> 8) * (1.0 / 0xffffff);
+ trb->Store(trb->TexImage, x + i, y, z, &flt);
+ }
+ }
+ }
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_put_row");
}
}
+
static void
texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
GLint x, GLint y, const void *value, const GLubyte *mask)
const struct texture_renderbuffer *trb
= (const struct texture_renderbuffer *) rb;
const GLint z = trb->Zoffset;
- const GLchan *rgba = (const GLchan *) value;
GLuint i;
- for (i = 0; i < count; i++) {
- if (!mask || mask[i]) {
- trb->Store(trb->TexImage, x + i, y, z, rgba);
+
+ y += trb->Yoffset;
+
+ if (rb->DataType == CHAN_TYPE) {
+ const GLchan *rgba = (const GLchan *) value;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x + i, y, z, rgba);
+ }
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ const GLuint zValue = *((const GLuint *) value);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x + i, y, z, &zValue);
+ }
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ const GLuint zValue = *((const GLuint *) value);
+ const GLfloat flt = (zValue >> 8) * (1.0 / 0xffffff);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x + i, y, z, &flt);
+ }
}
}
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_row");
+ }
}
+
static void
texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
const GLint x[], const GLint y[], const void *values,
const struct texture_renderbuffer *trb
= (const struct texture_renderbuffer *) rb;
const GLint z = trb->Zoffset;
- const GLchan *rgba = (const GLchan *) values;
GLuint i;
- for (i = 0; i < count; i++) {
- if (!mask || mask[i]) {
- trb->Store(trb->TexImage, x[i], y[i], z, rgba);
+
+ if (rb->DataType == CHAN_TYPE) {
+ const GLchan *rgba = (const GLchan *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
+ }
+ rgba += 4;
}
- rgba += 4;
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ const GLuint *zValues = (const GLuint *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z,
+ zValues + i);
+ }
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ const GLuint *zValues = (const GLuint *) values;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ GLfloat flt = (zValues[i] >> 8) * (1.0 / 0xffffff);
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
+ }
+ }
+ }
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_put_values");
}
}
+
static void
texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
const struct texture_renderbuffer *trb
= (const struct texture_renderbuffer *) rb;
const GLint z = trb->Zoffset;
- const GLchan *rgba = (const GLchan *) value;
GLuint i;
- for (i = 0; i < count; i++) {
- if (!mask || mask[i]) {
- trb->Store(trb->TexImage, x[i], y[i], z, rgba);
+
+ if (rb->DataType == CHAN_TYPE) {
+ const GLchan *rgba = (const GLchan *) value;
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, rgba);
+ }
}
}
+ else if (rb->DataType == GL_UNSIGNED_INT) {
+ const GLuint zValue = *((const GLuint *) value);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &zValue);
+ }
+ }
+ }
+ else if (rb->DataType == GL_UNSIGNED_INT_24_8_EXT) {
+ const GLuint zValue = *((const GLuint *) value);
+ const GLfloat flt = (zValue >> 8) * (1.0 / 0xffffff);
+ for (i = 0; i < count; i++) {
+ if (!mask || mask[i]) {
+ trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
+ }
+ }
+ }
+ else {
+ _mesa_problem(ctx, "invalid rb->DataType in texture_put_mono_values");
+ }
}
static void
delete_texture_wrapper(struct gl_renderbuffer *rb)
{
+ ASSERT(rb->RefCount == 0);
_mesa_free(rb);
}
/**
- * If a render buffer attachment specifies a texture image, we'll use
- * this function to make a gl_renderbuffer wrapper around the texture image.
- * This allows other parts of Mesa to access the texture image as if it
- * was a renderbuffer.
+ * 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(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
ASSERT(att->Type == GL_TEXTURE);
ASSERT(att->Renderbuffer == NULL);
- /*
- ASSERT(att->Complete);
- */
trb = CALLOC_STRUCT(texture_renderbuffer);
if (!trb) {
return;
}
+ /* init base gl_renderbuffer fields */
_mesa_init_renderbuffer(&trb->Base, name);
+ /* plug in our texture_renderbuffer-specific functions */
+ trb->Base.Delete = delete_texture_wrapper;
+ trb->Base.AllocStorage = NULL; /* illegal! */
+ trb->Base.GetRow = texture_get_row;
+ trb->Base.GetValues = texture_get_values;
+ trb->Base.PutRow = texture_put_row;
+ trb->Base.PutMonoRow = texture_put_mono_row;
+ trb->Base.PutValues = texture_put_values;
+ trb->Base.PutMonoValues = texture_put_mono_values;
+
+ /* update attachment point */
+ _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
+}
+
+
+
+/**
+ * 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(GLcontext *ctx, const struct gl_renderbuffer_attachment *att)
+{
+ struct texture_renderbuffer *trb
+ = (struct texture_renderbuffer *) att->Renderbuffer;
+
+ (void) ctx;
+ ASSERT(trb);
trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
- assert(trb->TexImage);
+ ASSERT(trb->TexImage);
trb->Store = trb->TexImage->TexFormat->StoreTexel;
- assert(trb->Store);
+ ASSERT(trb->Store);
- trb->Zoffset = att->Zoffset;
+ if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
+ trb->Yoffset = att->Zoffset;
+ trb->Zoffset = 0;
+ }
+ else {
+ trb->Yoffset = 0;
+ trb->Zoffset = att->Zoffset;
+ }
trb->Base.Width = trb->TexImage->Width;
trb->Base.Height = trb->TexImage->Height;
- trb->Base.InternalFormat = trb->TexImage->IntFormat; /* XXX fix? */
+ trb->Base.InternalFormat = trb->TexImage->InternalFormat;
+ /* XXX may need more special cases here */
+ if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z24_S8) {
+ trb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT;
+ trb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT;
+ }
+ else if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z16) {
+ trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
+ trb->Base.DataType = GL_UNSIGNED_SHORT;
+ }
+ else if (trb->TexImage->TexFormat->MesaFormat == MESA_FORMAT_Z32) {
+ trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
+ trb->Base.DataType = GL_UNSIGNED_INT;
+ }
+ else {
+ trb->Base._ActualFormat = trb->TexImage->InternalFormat;
+ trb->Base.DataType = CHAN_TYPE;
+ }
trb->Base._BaseFormat = trb->TexImage->TexFormat->BaseFormat;
#if 0
/* fix/avoid this assertion someday */
- assert(trb->Base._BaseFormat == GL_RGB ||
+ ASSERT(trb->Base._BaseFormat == GL_RGB ||
trb->Base._BaseFormat == GL_RGBA ||
trb->Base._BaseFormat == GL_DEPTH_COMPONENT);
#endif
- trb->Base.DataType = GL_UNSIGNED_BYTE; /* XXX fix! */
trb->Base.Data = trb->TexImage->Data;
- trb->Base.GetRow = texture_get_row;
- trb->Base.GetValues = texture_get_values;
- trb->Base.PutRow = texture_put_row;
- trb->Base.PutMonoRow = texture_put_mono_row;
- trb->Base.PutValues = texture_put_values;
- trb->Base.PutMonoValues = texture_put_mono_values;
-
- trb->Base.Delete = delete_texture_wrapper;
- trb->Base.AllocStorage = NULL; /* illegal! */
-
- att->Renderbuffer = &(trb->Base);
+ trb->Base.RedBits = trb->TexImage->TexFormat->RedBits;
+ trb->Base.GreenBits = trb->TexImage->TexFormat->GreenBits;
+ trb->Base.BlueBits = trb->TexImage->TexFormat->BlueBits;
+ trb->Base.AlphaBits = trb->TexImage->TexFormat->AlphaBits;
+ trb->Base.DepthBits = trb->TexImage->TexFormat->DepthBits;
}
/**
- * Software fallback for ctx->Driver.RenderbufferTexture.
- * This is called via the glRenderbufferTexture1D/2D/3D() functions.
- * If we're unbinding a texture, texObj will be NULL.
- * The framebuffer of interest is ctx->DrawBuffer.
+ * 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
-_mesa_renderbuffer_texture(GLcontext *ctx,
- struct gl_renderbuffer_attachment *att,
- struct gl_texture_object *texObj,
- GLenum texTarget, GLuint level, GLuint zoffset)
+_mesa_render_texture(GLcontext *ctx,
+ struct gl_framebuffer *fb,
+ struct gl_renderbuffer_attachment *att)
{
- if (texObj) {
- _mesa_set_texture_attachment(ctx, att, texObj,
- texTarget, level, zoffset);
+ (void) fb;
+ if (!att->Renderbuffer) {
wrap_texture(ctx, att);
}
- else {
- _mesa_remove_attachment(ctx, att);
- }
+ update_wrapper(ctx, att);
+}
+
+
+void
+_mesa_finish_render_texture(GLcontext *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;
}