[Mesa-dev] [PATCH 05/37] meta: added _mesa_meta_decompress_texture_image()
Eric Anholt
eric at anholt.net
Mon Aug 15 11:53:35 PDT 2011
From: Brian Paul <brianp at vmware.com>
Decompress a texture by drawing quad with the texture.
---
src/mesa/drivers/common/meta.c | 200 ++++++++++++++++++++++++++++++++++++++++
src/mesa/drivers/common/meta.h | 6 +
2 files changed, 206 insertions(+), 0 deletions(-)
diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index 19eae42..751f3b6 100644
--- a/src/mesa/drivers/common/meta.c
+++ b/src/mesa/drivers/common/meta.c
@@ -287,6 +287,19 @@ struct gen_mipmap_state
GLuint FBO;
};
+
+/**
+ * State for texture decompression
+ */
+struct decompress_state
+{
+ GLuint ArrayObj;
+ GLuint VBO, FBO, RBO;
+ GLint Width, Height;
+ GLenum RBFormat;
+};
+
+
#define MAX_META_OPS_DEPTH 2
/**
* All per-context meta state.
@@ -306,6 +319,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 */
};
@@ -3094,3 +3108,189 @@ _mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start
free(buf);
}
+
+
+/**
+ * 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)
+ */
+void
+_mesa_meta_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, rbFormat;
+ struct vertex {
+ GLfloat x, y, tex[3];
+ };
+ struct vertex verts[4];
+ GLuint fboDrawSave, fboReadSave;
+ GLenum destDataType = _mesa_get_format_datatype(texImage->TexFormat);
+
+ 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, 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);
+ }
+
+ if (destDataType == GL_SIGNED_NORMALIZED) {
+ rbFormat = GL_RGBA32F;
+ } else {
+ rbFormat = GL_RGBA;
+ }
+
+ /* alloc dest surface */
+ if (width != decompress->Width || height != decompress->Height ||
+ decompress->RBFormat != rbFormat) {
+ _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, rbFormat,
+ width, height);
+ decompress->Width = width;
+ decompress->Height = height;
+ decompress->RBFormat = rbFormat;
+ }
+
+ /* 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);
+
+ /* 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_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
+ GL_DYNAMIC_DRAW_ARB);
+
+ /* 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);
+ }
+}
+
diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
index 95b4b55..50389c9 100644
--- a/src/mesa/drivers/common/meta.h
+++ b/src/mesa/drivers/common/meta.h
@@ -107,5 +107,11 @@ _mesa_meta_CopyConvolutionFilter2D(struct gl_context *ctx, GLenum target,
GLenum internalFormat, GLint x, GLint y,
GLsizei width, GLsizei height);
+void
+_mesa_meta_decompress_texture_image(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLuint slice,
+ GLenum destFormat, GLenum destType,
+ GLvoid *dest, GLint destRowLength);
#endif /* META_H */
--
1.7.5.4
More information about the mesa-dev
mailing list