summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Bornecrantz <[email protected]>2009-04-08 23:29:18 +0200
committerJakob Bornecrantz <[email protected]>2009-04-09 00:13:10 +0200
commit55ed2a73653fb2fb9dee36c729c09177df2d5b4e (patch)
tree4a580324f2d44c13167122c663664d51b34156f4
parentcafea7528052624c8d3e4cd1c5b26a61bf04d1d0 (diff)
st: If the hw supports it do hw conversion of texture uploads
-rw-r--r--src/mesa/state_tracker/st_cb_texture.c164
1 files changed, 160 insertions, 4 deletions
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index 57c0544ba8b..e68c3d87eed 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -110,6 +110,25 @@ compressed_num_bytes(GLuint mesaFormat)
}
+static GLboolean
+is_compressed_mesa_format(const struct gl_texture_format *format)
+{
+ switch (format->MesaFormat) {
+ case MESA_FORMAT_RGB_DXT1:
+ case MESA_FORMAT_RGBA_DXT1:
+ case MESA_FORMAT_RGBA_DXT3:
+ case MESA_FORMAT_RGBA_DXT5:
+ case MESA_FORMAT_SRGB_DXT1:
+ case MESA_FORMAT_SRGBA_DXT1:
+ case MESA_FORMAT_SRGBA_DXT3:
+ case MESA_FORMAT_SRGBA_DXT5:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
/** called via ctx->Driver.NewTextureImage() */
static struct gl_texture_image *
st_NewTextureImage(GLcontext * ctx)
@@ -379,6 +398,110 @@ strip_texture_border(GLint border,
/**
+ * Try to do texture compression via rendering. If the Gallium driver
+ * can render into a compressed surface this will allow us to do texture
+ * compression.
+ * \return GL_TRUE for success, GL_FALSE for failure
+ */
+static GLboolean
+compress_with_blit(GLcontext * ctx,
+ GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint width, GLint height, GLint depth,
+ GLenum format, GLenum type, const void *pixels,
+ const struct gl_pixelstore_attrib *unpack,
+ struct gl_texture_image *texImage)
+{
+ const GLuint dstImageOffsets[1] = {0};
+ struct st_texture_image *stImage = st_texture_image(texImage);
+ struct pipe_screen *screen = ctx->st->pipe->screen;
+ const GLuint face = _mesa_tex_target_to_face(target);
+ const struct gl_texture_format *mesa_format;
+ struct pipe_texture templ;
+ struct pipe_texture *src_tex;
+ struct pipe_surface *dst_surface;
+ struct pipe_transfer *tex_xfer;
+ void *map;
+
+
+ if (!stImage->pt) {
+ /* XXX: Can this happen? Should we assert? */
+ return GL_FALSE;
+ }
+
+ /* get destination surface (in the compressed texture) */
+ dst_surface = screen->get_tex_surface(screen, stImage->pt,
+ stImage->face, stImage->level, 0,
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+ if (!dst_surface) {
+ /* can't render into this format (or other problem) */
+ return GL_FALSE;
+ }
+
+ /* Choose format for the temporary RGBA texture image.
+ */
+ mesa_format = st_ChooseTextureFormat(ctx, GL_RGBA, format, type);
+ assert(mesa_format);
+ if (!mesa_format)
+ return GL_FALSE;
+
+ /* Create the temporary source texture
+ */
+ memset(&templ, 0, sizeof(templ));
+ templ.target = PIPE_TEXTURE_2D;
+ templ.format = st_mesa_format_to_pipe_format(mesa_format->MesaFormat);
+ pf_get_block(templ.format, &templ.block);
+ templ.width[0] = width;
+ templ.height[0] = height;
+ templ.depth[0] = 1;
+ templ.last_level = 0;
+ templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER;
+ src_tex = screen->texture_create(screen, &templ);
+
+ if (!src_tex)
+ return GL_FALSE;
+
+ /* Put user's tex data into the temporary texture
+ */
+ tex_xfer = screen->get_tex_transfer(screen, src_tex,
+ face, level, 0,
+ PIPE_TRANSFER_WRITE,
+ 0, 0, width, height); /* x, y, w, h */
+ map = screen->transfer_map(screen, tex_xfer);
+
+ mesa_format->StoreImage(ctx, 2, GL_RGBA, mesa_format,
+ map, /* dest ptr */
+ 0, 0, 0, /* dest x/y/z offset */
+ tex_xfer->stride, /* dest row stride (bytes) */
+ dstImageOffsets, /* image offsets (for 3D only) */
+ width, height, 1, /* size */
+ format, type, /* source format/type */
+ pixels, /* source data */
+ unpack); /* source data packing */
+
+ screen->transfer_unmap(screen, tex_xfer);
+ screen->tex_transfer_destroy(tex_xfer);
+
+ /* copy / compress image */
+ util_blit_pixels_tex(ctx->st->blit,
+ src_tex, /* pipe_texture (src) */
+ 0, 0, /* src x0, y0 */
+ width, height, /* src x1, y1 */
+ dst_surface, /* pipe_surface (dst) */
+ xoffset, yoffset, /* dst x0, y0 */
+ xoffset + width, /* dst x1 */
+ yoffset + height, /* dst y1 */
+ 0.0, /* z */
+ PIPE_TEX_MIPFILTER_NEAREST);
+
+ pipe_surface_reference(&dst_surface, NULL);
+ pipe_texture_reference(&src_tex, NULL);
+
+ return GL_TRUE;
+}
+
+
+/**
* Do glTexImage1/2/3D().
*/
static void
@@ -392,8 +515,9 @@ st_TexImage(GLcontext * ctx,
const struct gl_pixelstore_attrib *unpack,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage,
- GLsizei imageSize, GLboolean compressed)
+ GLsizei imageSize, GLboolean compressed_src)
{
+ struct pipe_screen *screen = ctx->st->pipe->screen;
struct st_texture_object *stObj = st_texture_object(texObj);
struct st_texture_image *stImage = st_texture_image(texImage);
GLint postConvWidth, postConvHeight;
@@ -522,7 +646,7 @@ st_TexImage(GLcontext * ctx,
* the expectation that the texture will be set up but nothing
* more will be done. This is where those calls return:
*/
- if (compressed) {
+ if (compressed_src) {
pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
unpack,
"glCompressedTexImage");
@@ -535,6 +659,21 @@ st_TexImage(GLcontext * ctx,
if (!pixels)
return;
+ /* See if we can do texture compression with a blit/render.
+ */
+ if (!compressed_src &&
+ !ctx->Mesa_DXTn &&
+ is_compressed_mesa_format(texImage->TexFormat) &&
+ screen->is_format_supported(screen,
+ stImage->pt->format,
+ stImage->pt->target,
+ PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
+ if (compress_with_blit(ctx, target, level, 0, 0, 0, width, height, depth,
+ format, type, pixels, unpack, texImage)) {
+ return;
+ }
+ }
+
if (stImage->pt) {
texImage->Data = st_texture_image_map(ctx->st, stImage, 0,
PIPE_TRANSFER_WRITE, 0, 0,
@@ -570,7 +709,7 @@ st_TexImage(GLcontext * ctx,
* the blitter to copy. Or, use the hardware to do the format
* conversion and copy:
*/
- if (compressed) {
+ if (compressed_src) {
memcpy(texImage->Data, pixels, imageSize);
}
else {
@@ -607,7 +746,7 @@ st_TexImage(GLcontext * ctx,
_mesa_unmap_teximage_pbo(ctx, unpack);
- if (stImage->pt) {
+ if (stImage->pt && texImage->Data) {
st_texture_image_unmap(ctx->st, stImage);
texImage->Data = NULL;
}
@@ -787,6 +926,7 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
struct gl_texture_object *texObj,
struct gl_texture_image *texImage)
{
+ struct pipe_screen *screen = ctx->st->pipe->screen;
struct st_texture_image *stImage = st_texture_image(texImage);
GLuint dstRowStride;
const GLuint srcImageStride =
@@ -804,6 +944,22 @@ st_TexSubimage(GLcontext *ctx, GLint dims, GLenum target, GLint level,
if (!pixels)
return;
+ /* See if we can do texture compression with a blit/render.
+ */
+ if (!ctx->Mesa_DXTn &&
+ is_compressed_mesa_format(texImage->TexFormat) &&
+ screen->is_format_supported(screen,
+ stImage->pt->format,
+ stImage->pt->target,
+ PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
+ if (compress_with_blit(ctx, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, type, pixels, packing, texImage)) {
+ return;
+ }
+ }
+
/* Map buffer if necessary. Need to lock to prevent other contexts
* from uploading the buffer under us.
*/