mesa: replace gl_texture_format with gl_format
[mesa.git] / src / mesa / main / texrender.c
index 9c21e03515aeebc0bf5a8bc988cf8979ceb12553..81bb1d40ffdfed49647a1f6fdbb6b2b6fe72ee5d 100644 (file)
@@ -1,6 +1,7 @@
 
 #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)
@@ -30,13 +36,58 @@ texture_get_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
    const struct texture_renderbuffer *trb
       = (const struct texture_renderbuffer *) rb;
    const GLint z = trb->Zoffset;
-   GLchan *rgbaOut = (GLchan *) values;
    GLuint i;
-   for (i = 0; i < count; i++) {
-      trb->TexImage->FetchTexelc(trb->TexImage, x + i, y, z, rgbaOut + 4 * 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_SHORT) {
+      GLushort *zValues = (GLushort *) values;
+      for (i = 0; i < count; i++) {
+         GLfloat flt;
+         trb->TexImage->FetchTexelf(trb->TexImage, x + i, y, z, &flt);
+         zValues[i] = (GLushort) (flt * 0xffff);
+      }
+   }
+   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)
@@ -44,14 +95,55 @@ texture_get_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
    const struct texture_renderbuffer *trb
       = (const struct texture_renderbuffer *) rb;
    const GLint z = trb->Zoffset;
-   GLchan *rgbaOut = (GLchan *) values;
    GLuint i;
-   for (i = 0; i < count; i++) {
-      trb->TexImage->FetchTexelc(trb->TexImage, x[i], y[i], z,
-                                 rgbaOut + 4 * 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_SHORT) {
+      GLushort *zValues = (GLushort *) values;
+      for (i = 0; i < count; i++) {
+         GLfloat flt;
+         trb->TexImage->FetchTexelf(trb->TexImage, x[i], y[i] + trb->Yoffset,
+                                   z, &flt);
+         zValues[i] = (GLushort) (flt * 0xffff);
+      }
+   }
+   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)
@@ -59,16 +151,103 @@ texture_put_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
    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;
+      }
+   }
+   else if (rb->DataType == GL_UNSIGNED_SHORT) {
+      const GLushort *zValues = (const GLushort *) values;
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            trb->Store(trb->TexImage, x + i, y, z, zValues + i);
+         }
       }
-      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 = (GLfloat) ((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");
    }
 }
 
+/**
+ * Put row of RGB values into a renderbuffer that wraps a texture image.
+ */
+static void
+texture_put_row_rgb(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;
+   GLuint i;
+
+   y += trb->Yoffset;
+
+   if (rb->DataType == CHAN_TYPE) {
+      const GLchan *rgb = (const GLchan *) values;
+      for (i = 0; i < count; i++) {
+         if (!mask || mask[i]) {
+            trb->Store(trb->TexImage, x + i, y, z, rgb);
+         }
+         rgb += 3;
+      }
+   }
+   else if (rb->DataType == GL_UNSIGNED_SHORT) {
+      const GLushort *zValues = (const GLushort *) 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) {
+      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 = (GLfloat) ((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)
@@ -76,15 +255,49 @@ texture_put_mono_row(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
    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_SHORT) {
+      const GLushort zValue = *((const GLushort *) 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) {
+      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 = (GLfloat) ((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,
@@ -93,16 +306,48 @@ texture_put_values(GLcontext *ctx, struct gl_renderbuffer *rb, GLuint count,
    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;
+      }
+   }
+   else if (rb->DataType == GL_UNSIGNED_SHORT) {
+      const GLushort *zValues = (const GLushort *) 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) {
+      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 = (GLfloat) ((zValues[i] >> 8) * (1.0 / 0xffffff));
+            trb->Store(trb->TexImage, x[i], y[i] + trb->Yoffset, z, &flt);
+         }
       }
-      rgba += 4;
+   }
+   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[],
@@ -111,28 +356,67 @@ texture_put_mono_values(GLcontext *ctx, struct gl_renderbuffer *rb,
    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_SHORT) {
+      const GLushort zValue = *((const GLushort *) 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 = (GLfloat) ((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
+store_nop(struct gl_texture_image *texImage,
+          GLint col, GLint row, GLint img,
+          const void *texel)
+{
 }
 
 
 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)
@@ -142,9 +426,6 @@ 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) {
@@ -152,71 +433,132 @@ wrap_texture(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
       return;
    }
 
+   /* init base gl_renderbuffer fields */
    _mesa_init_renderbuffer(&trb->Base, name);
-
-   trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
-   assert(trb->TexImage);
-
-   trb->Store = trb->TexImage->TexFormat->StoreTexel;
-   assert(trb->Store);
-
-   trb->Zoffset = att->Zoffset;
-
-   trb->Base.Width = trb->TexImage->Width;
-   trb->Base.Height = trb->TexImage->Height;
-   trb->Base.InternalFormat = trb->TexImage->InternalFormat; /* XXX fix? */
-   trb->Base._BaseFormat = trb->TexImage->TexFormat->BaseFormat;
-#if 0
-   /* fix/avoid this assertion someday */
-   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;
-
+   /* 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.PutRowRGB = texture_put_row_rgb;
    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! */
+   /* update attachment point */
+   _mesa_reference_renderbuffer(&att->Renderbuffer, &(trb->Base));
+}
 
-   /* XXX fix these */
-   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;
 
-   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;
+   gl_format texFormat;
+
+   (void) ctx;
+   ASSERT(trb);
+
+   trb->TexImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+   ASSERT(trb->TexImage);
+
+   trb->Store = _mesa_get_texel_store_func(trb->TexImage->TexFormat);
+   if (!trb->Store) {
+      /* we'll never draw into some textures (compressed formats) */
+      trb->Store = store_nop;
+   }
+
+   if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
+      trb->Yoffset = att->Zoffset;
+      trb->Zoffset = 0;
+   }
+   else {
+      trb->Yoffset = 0;
+      trb->Zoffset = att->Zoffset;
+   }
+
+   texFormat = trb->TexImage->TexFormat;
+
+   trb->Base.Width = trb->TexImage->Width;
+   trb->Base.Height = trb->TexImage->Height;
+   trb->Base.InternalFormat = trb->TexImage->InternalFormat;
+   /* XXX may need more special cases here */
+   if (trb->TexImage->TexFormat == 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 == MESA_FORMAT_Z16) {
+      trb->Base._ActualFormat = GL_DEPTH_COMPONENT;
+      trb->Base.DataType = GL_UNSIGNED_SHORT;
+   }
+   else if (trb->TexImage->TexFormat == 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->_BaseFormat;
+   trb->Base.Data = trb->TexImage->Data;
+
+   trb->Base.RedBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE);
+   trb->Base.GreenBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE);
+   trb->Base.BlueBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE);
+   trb->Base.AlphaBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE);
+   trb->Base.DepthBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE_ARB);
+   trb->Base.StencilBits = _mesa_get_format_bits(texFormat, GL_TEXTURE_STENCIL_SIZE_EXT);
 }
 
 
 
 /**
- * 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;
 }