diff options
author | Brian Paul <brianp@vmware.com> | 2011-07-14 20:57:34 -0600 |
---|---|---|
committer | Brian Paul <brianp@vmware.com> | 2011-07-14 20:57:34 -0600 |
commit | 861256c26b66f036a423cbc09df1fef65e8e5e98 (patch) | |
tree | e5265d80781aa1f99e7a992da6971025e924c937 | |
parent | 569727b4a2704a7dd6ff09693844ba478ad66e4c (diff) | |
download | mesa-861256c26b66f036a423cbc09df1fef65e8e5e98.tar.gz |
meta: added _mesa_meta_decompress_texture_image()
Decompress a texture by drawing quad with the texture.
-rw-r--r-- | src/mesa/drivers/common/meta.c | 193 | ||||
-rw-r--r-- | src/mesa/drivers/common/meta.h | 6 |
2 files changed, 198 insertions, 1 deletions
diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 91d9c77a49c..7da4f40f027 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -281,6 +281,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. @@ -300,6 +312,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 */ }; @@ -2812,7 +2825,7 @@ copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, format, type, &ctx->Pack, buf); _mesa_meta_end(ctx); - if (texImage->Data) { + if (ctx->Driver.FreeTexImageData) { ctx->Driver.FreeTexImageData(ctx, texImage); } @@ -3027,3 +3040,181 @@ _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; + 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, 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); + } +} + diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h index b0797d3d91a..d42bd0e29a9 100644 --- a/src/mesa/drivers/common/meta.h +++ b/src/mesa/drivers/common/meta.h @@ -114,5 +114,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 */ |