X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_gen_mipmap.c;h=e656908bedec0cb6a2cd47cdf29d974cc88339b0;hb=1975208919a273018a2cda87e765870c5f86d01f;hp=453be425bcb02fb34554a633bc918ddba801d915;hpb=394ff065f33bdf4f9b5bac11e85d18e3ce4eb42f;p=mesa.git diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c index 453be425bcb..e656908bede 100644 --- a/src/mesa/state_tracker/st_gen_mipmap.c +++ b/src/mesa/state_tracker/st_gen_mipmap.c @@ -39,9 +39,9 @@ #include "st_debug.h" #include "st_context.h" +#include "st_texture.h" #include "st_gen_mipmap.h" #include "st_cb_texture.h" -#include "st_inlines.h" /** @@ -79,6 +79,7 @@ st_render_mipmap(struct st_context *st, struct pipe_sampler_view *psv = st_get_texture_sampler_view(stObj, pipe); const uint face = _mesa_tex_target_to_face(target); + assert(psv->texture == stObj->pt); assert(target != GL_TEXTURE_3D); /* not done yet */ /* check if we can render in the texture's format */ @@ -94,6 +95,62 @@ st_render_mipmap(struct st_context *st, } +/** + * Helper function to decompress an image. The result is a 32-bpp RGBA + * image with stride==width. + */ +static void +decompress_image(enum pipe_format format, + const uint8_t *src, uint8_t *dst, + unsigned width, unsigned height) +{ + const struct util_format_description *desc = util_format_description(format); + const uint bw = util_format_get_blockwidth(format); + const uint bh = util_format_get_blockheight(format); + const uint dst_stride = 4 * MAX2(width, bw); + const uint src_stride = util_format_get_stride(format, width); + + desc->unpack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); + + if (width < bw || height < bh) { + /* We're decompressing an image smaller than the compression + * block size. We don't want garbage pixel values in the region + * outside (width x height) so replicate pixels from the (width + * x height) region to fill out the (bw x bh) block size. + */ + uint x, y; + for (y = 0; y < bh; y++) { + for (x = 0; x < bw; x++) { + if (x >= width || y >= height) { + uint p = (y * bw + x) * 4; + dst[p + 0] = dst[0]; + dst[p + 1] = dst[1]; + dst[p + 2] = dst[2]; + dst[p + 3] = dst[3]; + } + } + } + } +} + + +/** + * Helper function to compress an image. The source is a 32-bpp RGBA image + * with stride==width. + */ +static void +compress_image(enum pipe_format format, + const uint8_t *src, uint8_t *dst, + unsigned width, unsigned height) +{ + const struct util_format_description *desc = util_format_description(format); + const uint dst_stride = util_format_get_stride(format, width); + const uint src_stride = 4 * width; + + desc->pack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); +} + + /** * Software fallback for generate mipmap levels. */ @@ -109,14 +166,25 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, uint dstLevel; GLenum datatype; GLuint comps; + GLboolean compressed; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); assert(target != GL_TEXTURE_3D); /* not done yet */ - _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, - &datatype, &comps); + compressed = + _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat); + + if (compressed) { + datatype = GL_UNSIGNED_BYTE; + comps = 4; + } + else { + _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, + &datatype, &comps); + assert(comps > 0 && "bad texture format in fallback_generate_mipmap()"); + } for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; @@ -131,13 +199,13 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, ubyte *dstData; int srcStride, dstStride; - srcTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face, + srcTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, face, srcLevel, zslice, PIPE_TRANSFER_READ, 0, 0, srcWidth, srcHeight); - dstTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face, + dstTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, face, dstLevel, zslice, PIPE_TRANSFER_WRITE, 0, 0, dstWidth, dstHeight); @@ -148,14 +216,49 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format); dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format); - _mesa_generate_mipmap_level(target, datatype, comps, - 0 /*border*/, - srcWidth, srcHeight, srcDepth, - srcData, - srcStride, /* stride in texels */ - dstWidth, dstHeight, dstDepth, - dstData, - dstStride); /* stride in texels */ + if (compressed) { + const enum pipe_format format = pt->format; + const uint bw = util_format_get_blockwidth(format); + const uint bh = util_format_get_blockheight(format); + const uint srcWidth2 = align(srcWidth, bw); + const uint srcHeight2 = align(srcHeight, bh); + const uint dstWidth2 = align(dstWidth, bw); + const uint dstHeight2 = align(dstHeight, bh); + uint8_t *srcTemp, *dstTemp; + + assert(comps == 4); + + srcTemp = malloc(srcWidth2 * srcHeight2 * comps + 000); + dstTemp = malloc(dstWidth2 * dstHeight2 * comps + 000); + + /* decompress the src image: srcData -> srcTemp */ + decompress_image(format, srcData, srcTemp, srcWidth, srcHeight); + + _mesa_generate_mipmap_level(target, datatype, comps, + 0 /*border*/, + srcWidth2, srcHeight2, srcDepth, + srcTemp, + srcWidth2, /* stride in texels */ + dstWidth2, dstHeight2, dstDepth, + dstTemp, + dstWidth2); /* stride in texels */ + + /* compress the new image: dstTemp -> dstData */ + compress_image(format, dstTemp, dstData, dstWidth, dstHeight); + + free(srcTemp); + free(dstTemp); + } + else { + _mesa_generate_mipmap_level(target, datatype, comps, + 0 /*border*/, + srcWidth, srcHeight, srcDepth, + srcData, + srcStride, /* stride in texels */ + dstWidth, dstHeight, dstDepth, + dstData, + dstStride); /* stride in texels */ + } pipe_transfer_unmap(pipe, srcTrans); pipe_transfer_unmap(pipe, dstTrans); @@ -181,7 +284,6 @@ compute_num_levels(GLcontext *ctx, return 1; } else { - const GLuint maxLevels = texObj->MaxLevel - texObj->BaseLevel + 1; const struct gl_texture_image *baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); GLuint size, numLevels; @@ -189,14 +291,16 @@ compute_num_levels(GLcontext *ctx, size = MAX2(baseImage->Width2, baseImage->Height2); size = MAX2(size, baseImage->Depth2); - numLevels = 0; + numLevels = texObj->BaseLevel; while (size > 0) { numLevels++; size >>= 1; } - numLevels = MIN2(numLevels, maxLevels); + numLevels = MIN2(numLevels, texObj->MaxLevel + 1); + + assert(numLevels >= 1); return numLevels; } @@ -220,7 +324,7 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, if (!pt) return; - /* find expected last mipmap level */ + /* find expected last mipmap level to generate */ lastLevel = compute_num_levels(ctx, texObj, target) - 1; if (lastLevel == 0) @@ -231,7 +335,6 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, * mipmap levels we need to generate. So allocate a new texture. */ struct pipe_resource *oldTex = stObj->pt; - GLboolean needFlush; /* create new texture with space for more levels */ stObj->pt = st_texture_create(st, @@ -251,7 +354,7 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, /* This will copy the old texture's base image into the new texture * which we just allocated. */ - st_finalize_texture(ctx, st->pipe, texObj, &needFlush); + st_finalize_texture(ctx, st->pipe, texObj); /* release the old tex (will likely be freed too) */ pipe_resource_reference(&oldTex, NULL); @@ -260,12 +363,12 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, pt = stObj->pt; } - assert(lastLevel <= pt->last_level); + assert(pt->last_level >= lastLevel); - /* Recall that the Mesa BaseLevel image is stored in the gallium - * texture's level[0] position. So pass baseLevel=0 here. + /* Try to generate the mipmap by rendering/texturing. If that fails, + * use the software fallback. */ - if (!st_render_mipmap(st, target, stObj, 0, lastLevel)) { + if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) { fallback_generate_mipmap(ctx, target, texObj); } @@ -297,7 +400,9 @@ st_generate_mipmap(GLcontext *ctx, GLenum target, dstImage->TexFormat = srcImage->TexFormat; - stImage = (struct st_texture_image *) dstImage; + stImage = st_texture_image(dstImage); + stImage->level = dstLevel; + pipe_resource_reference(&stImage->pt, pt); } }