meta: added _mesa_meta_GetTexImage()
authorBrian Paul <brianp@vmware.com>
Fri, 9 Sep 2011 02:16:18 +0000 (20:16 -0600)
committerBrian Paul <brianp@vmware.com>
Fri, 9 Sep 2011 02:16:18 +0000 (20:16 -0600)
If the texture is compressed, call the meta decompress_texture_image()
function.  Otherwise, call the core _mesa_get_teximage() function.

src/mesa/drivers/common/driverfuncs.c
src/mesa/drivers/common/meta.c
src/mesa/drivers/common/meta.h

index 6484d284d7d60242ae1f0e4b39ab09d8573e0cd1..36ed4f89216c17a108fdcd62f4426653e7f5a858 100644 (file)
@@ -94,7 +94,7 @@ _mesa_init_driver_functions(struct dd_function_table *driver)
    driver->TexSubImage1D = _mesa_store_texsubimage1d;
    driver->TexSubImage2D = _mesa_store_texsubimage2d;
    driver->TexSubImage3D = _mesa_store_texsubimage3d;
-   driver->GetTexImage = _mesa_get_teximage;
+   driver->GetTexImage = _mesa_meta_GetTexImage;
    driver->CopyTexSubImage1D = _mesa_meta_CopyTexSubImage1D;
    driver->CopyTexSubImage2D = _mesa_meta_CopyTexSubImage2D;
    driver->CopyTexSubImage3D = _mesa_meta_CopyTexSubImage3D;
index a0e9316884af379d97c2ed37832817f668d2d6db..2ebcd35bd116f5579cb32ede7fe9401aa9380b9e 100644 (file)
@@ -59,6 +59,7 @@
 #include "main/stencil.h"
 #include "main/texobj.h"
 #include "main/texenv.h"
+#include "main/texgetimage.h"
 #include "main/teximage.h"
 #include "main/texparam.h"
 #include "main/texstate.h"
@@ -259,6 +260,18 @@ struct gen_mipmap_state
    GLuint FBO;
 };
 
+
+/**
+ * State for texture decompression
+ */
+struct decompress_state
+{
+   GLuint ArrayObj;
+   GLuint VBO, FBO, RBO;
+   GLint Width, Height;
+};
+
+
 #define MAX_META_OPS_DEPTH      2
 /**
  * All per-context meta state.
@@ -278,6 +291,7 @@ struct gl_meta_state
    struct drawpix_state DrawPix;  /**< For _mesa_meta_DrawPixels() */
    struct bitmap_state Bitmap;    /**< For _mesa_meta_Bitmap() */
    struct gen_mipmap_state Mipmap;    /**< For _mesa_meta_GenerateMipmap() */
+   struct decompress_state Decompress;  /**< For texture decompression */
 };
 
 
@@ -3023,3 +3037,213 @@ _mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
    copy_tex_sub_image(ctx, 3, target, level, xoffset, yoffset, zoffset,
                       x, y, width, height);
 }
+
+
+/**
+ * Decompress a texture image by drawing a quad with the compressed
+ * texture and reading the pixels out of the color buffer.
+ * \param slice  which slice of a 3D texture or layer of a 1D/2D texture
+ * \param destFormat  format, ala glReadPixels
+ * \param destType  type, ala glReadPixels
+ * \param dest  destination buffer
+ * \param destRowLength  dest image rowLength (ala GL_PACK_ROW_LENGTH)
+ */
+static void
+decompress_texture_image(struct gl_context *ctx,
+                         struct gl_texture_image *texImage,
+                         GLuint slice,
+                         GLenum destFormat, GLenum destType,
+                         GLvoid *dest, GLint destRowLength)
+{
+   struct decompress_state *decompress = &ctx->Meta->Decompress;
+   struct gl_texture_object *texObj = texImage->TexObject;
+   const GLint width = texImage->Width;
+   const GLint height = texImage->Height;
+   const GLenum target = texObj->Target;
+   GLenum faceTarget;
+   struct vertex {
+      GLfloat x, y, tex[3];
+   };
+   struct vertex verts[4];
+   GLuint fboDrawSave, fboReadSave;
+
+   if (slice > 0) {
+      assert(target == GL_TEXTURE_3D ||
+             target == GL_TEXTURE_2D_ARRAY);
+   }
+
+   if (target == GL_TEXTURE_CUBE_MAP) {
+      faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
+   }
+   else {
+      faceTarget = target;
+   }
+
+   /* save fbo bindings (not saved by _mesa_meta_begin()) */
+   fboDrawSave = ctx->DrawBuffer->Name;
+   fboReadSave = ctx->ReadBuffer->Name;
+
+   _mesa_meta_begin(ctx, MESA_META_ALL);
+
+   /* Create/bind FBO/renderbuffer */
+   if (decompress->FBO == 0) {
+      _mesa_GenFramebuffersEXT(1, &decompress->FBO);
+      _mesa_GenRenderbuffersEXT(1, &decompress->RBO);
+      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO);
+      _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, decompress->RBO);
+      _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+                                       GL_COLOR_ATTACHMENT0_EXT,
+                                       GL_RENDERBUFFER_EXT,
+                                       decompress->RBO);
+   }
+   else {
+      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO);
+   }
+
+   /* alloc dest surface */
+   if (width != decompress->Width || height != decompress->Height) {
+      _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA,
+                                   width, height);
+      decompress->Width = width;
+      decompress->Height = height;
+   }
+
+   /* setup VBO data */
+   if (decompress->ArrayObj == 0) {
+      /* create vertex array object */
+      _mesa_GenVertexArrays(1, &decompress->ArrayObj);
+      _mesa_BindVertexArray(decompress->ArrayObj);
+
+      /* create vertex array buffer */
+      _mesa_GenBuffersARB(1, &decompress->VBO);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO);
+      _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts),
+                          NULL, GL_DYNAMIC_DRAW_ARB);
+
+      /* setup vertex arrays */
+      _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x));
+      _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex));
+      _mesa_EnableClientState(GL_VERTEX_ARRAY);
+      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+   }
+   else {
+      _mesa_BindVertexArray(decompress->ArrayObj);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO);
+   }
+
+   setup_texture_coords(faceTarget, slice, width, height,
+                        verts[0].tex,
+                        verts[1].tex,
+                        verts[2].tex,
+                        verts[3].tex);
+
+   /* setup vertex positions */
+   verts[0].x = 0.0F;
+   verts[0].y = 0.0F;
+   verts[1].x = width;
+   verts[1].y = 0.0F;
+   verts[2].x = width;
+   verts[2].y = height;
+   verts[3].x = 0.0F;
+   verts[3].y = height;
+
+   /* upload new vertex data */
+   _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+
+   /* setup texture state */
+   _mesa_BindTexture(target, texObj->Name);
+   _mesa_Enable(target);
+
+   {
+      /* save texture object state */
+      const GLenum minFilterSave = texObj->Sampler.MinFilter;
+      const GLenum magFilterSave = texObj->Sampler.MagFilter;
+      const GLint baseLevelSave = texObj->BaseLevel;
+      const GLint maxLevelSave = texObj->MaxLevel;
+      const GLenum wrapSSave = texObj->Sampler.WrapS;
+      const GLenum wrapTSave = texObj->Sampler.WrapT;
+      const GLenum srgbSave = texObj->Sampler.sRGBDecode;
+
+      /* restrict sampling to the texture level of interest */
+      _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, texImage->Level);
+      _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, texImage->Level);
+      /* nearest filtering */
+      _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+      /* No sRGB decode or encode.*/
+      if (ctx->Extensions.EXT_texture_sRGB_decode) {
+         _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT,
+                             GL_SKIP_DECODE_EXT);
+      }
+      if (ctx->Extensions.EXT_framebuffer_sRGB) {
+         _mesa_Disable(GL_FRAMEBUFFER_SRGB_EXT);
+      }
+
+      /* render quad w/ texture into renderbuffer */
+      _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+      
+      /* Restore texture object state, the texture binding will
+       * be restored by _mesa_meta_end().
+       */
+      _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave);
+      _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave);
+      if (target != GL_TEXTURE_RECTANGLE_ARB) {
+         _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave);
+         _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
+      }
+      _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave);
+      _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave);
+      if (ctx->Extensions.EXT_texture_sRGB_decode) {
+         _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, srgbSave);
+      }
+   }
+
+   /* read pixels from renderbuffer */
+   ctx->Pack.RowLength = destRowLength;
+   _mesa_ReadPixels(0, 0, width, height, destFormat, destType, dest);
+
+   _mesa_meta_end(ctx);
+
+   /* restore fbo bindings */
+   if (fboDrawSave == fboReadSave) {
+      _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboDrawSave);
+   }
+   else {
+      _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave);
+      _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboReadSave);
+   }
+}
+
+
+/**
+ * This is just a wrapper around _mesa_get_tex_image() and
+ * decompress_texture_image().  Meta functions should not be directly called
+ * from core Mesa.
+ */
+void
+_mesa_meta_GetTexImage(struct gl_context *ctx, GLenum target, GLint level,
+                       GLenum format, GLenum type, GLvoid *pixels,
+                       struct gl_texture_object *texObj,
+                       struct gl_texture_image *texImage)
+{
+   /* We can only use the decompress-with-blit method here if the texels are
+    * unsigned, normalized values.  We could handle signed and unnormalized 
+    * with floating point renderbuffers...
+    */
+   if (_mesa_is_format_compressed(texImage->TexFormat) &&
+       _mesa_get_format_datatype(texImage->TexFormat)
+       == GL_UNSIGNED_NORMALIZED) {
+      const GLuint slice = 0; /* only 2D compressed textures for now */
+      /* Need to unlock the texture here to prevent deadlock... */
+      _mesa_unlock_texture(ctx, texObj);
+      decompress_texture_image(ctx, texImage, slice, format, type, pixels,
+                               ctx->Pack.RowLength);
+      /* ... and relock it */
+      _mesa_lock_texture(ctx, texObj);
+   }
+   else {
+      _mesa_get_teximage(ctx, target, level, format, type, pixels,
+                          texObj, texImage);
+   }
+}
index 9a92613c44c4e08743091fe7ded80648a8baed27..9d634ae561faf901a0a13d90cac6b124faf02926 100644 (file)
@@ -121,4 +121,11 @@ _mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
                              GLint x, GLint y,
                              GLsizei width, GLsizei height);
 
+extern void
+_mesa_meta_GetTexImage(struct gl_context *ctx, GLenum target, GLint level,
+                       GLenum format, GLenum type, GLvoid *pixels,
+                       struct gl_texture_object *texObj,
+                       struct gl_texture_image *texImage);
+
+
 #endif /* META_H */