Mesa (main): mesa/st: break up st_GetTexSubImage
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Jul 28 17:31:53 UTC 2021
Module: Mesa
Branch: main
Commit: 6276973a9a2061b9dfa3dad7fe87c2d054e42ecb
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=6276973a9a2061b9dfa3dad7fe87c2d054e42ecb
Author: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Date: Mon Apr 19 13:03:06 2021 -0400
mesa/st: break up st_GetTexSubImage
this makes the function more readable and enables a lot of the code
to be reused for other purposes
Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11982>
---
src/mesa/state_tracker/st_cb_texture.c | 503 ++++++++++++++++++---------------
1 file changed, 276 insertions(+), 227 deletions(-)
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index 8bf3603e4ae..6292d526f6a 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -129,6 +129,266 @@ gl_target_to_pipe(GLenum target)
}
}
+static enum pipe_format
+get_src_format(struct pipe_screen *screen, struct st_texture_object *stObj)
+{
+ struct pipe_resource *src = stObj->pt;
+ enum pipe_format src_format;
+ /* Convert the source format to what is expected by GetTexImage
+ * and see if it's supported.
+ *
+ * This only applies to glGetTexImage:
+ * - Luminance must be returned as (L,0,0,1).
+ * - Luminance alpha must be returned as (L,0,0,A).
+ * - Intensity must be returned as (I,0,0,1)
+ */
+ if (stObj->surface_based)
+ src_format = util_format_linear(stObj->surface_format);
+ else
+ src_format = util_format_linear(src->format);
+ src_format = util_format_luminance_to_red(src_format);
+ src_format = util_format_intensity_to_red(src_format);
+
+ if (!src_format ||
+ !screen->is_format_supported(screen, src_format, src->target,
+ src->nr_samples, src->nr_storage_samples,
+ PIPE_BIND_SAMPLER_VIEW)) {
+ return PIPE_FORMAT_NONE;
+ }
+ return src_format;
+}
+
+static struct pipe_resource *
+create_dst_texture(struct gl_context *ctx,
+ enum pipe_format dst_format, enum pipe_texture_target pipe_target,
+ GLsizei width, GLsizei height, GLint depth,
+ GLenum gl_target, unsigned bind)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_screen *screen = st->screen;
+ struct pipe_resource dst_templ;
+
+ /* create the destination texture of size (width X height X depth) */
+ memset(&dst_templ, 0, sizeof(dst_templ));
+ dst_templ.target = pipe_target;
+ dst_templ.format = dst_format;
+ dst_templ.bind = bind;
+ dst_templ.usage = PIPE_USAGE_STAGING;
+
+ st_gl_texture_dims_to_pipe_dims(gl_target, width, height, depth,
+ &dst_templ.width0, &dst_templ.height0,
+ &dst_templ.depth0, &dst_templ.array_size);
+
+ return screen->resource_create(screen, &dst_templ);
+}
+
+static boolean
+copy_to_staging_dest(struct gl_context * ctx, struct pipe_resource *dst,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLint depth,
+ GLenum format, GLenum type, void * pixels,
+ struct gl_texture_image *texImage)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_context *pipe = st->pipe;
+ struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
+ struct pipe_resource *src = stObj->pt;
+ enum pipe_format dst_format = dst->format;
+ mesa_format mesa_format;
+ GLenum gl_target = texImage->TexObject->Target;
+ unsigned dims;
+ struct pipe_transfer *tex_xfer;
+ ubyte *map = NULL;
+ boolean done = FALSE;
+
+ pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
+
+ map = pipe_texture_map_3d(pipe, dst, 0, PIPE_MAP_READ,
+ 0, 0, 0, width, height, depth, &tex_xfer);
+ if (!map) {
+ goto end;
+ }
+
+ mesa_format = st_pipe_format_to_mesa_format(dst_format);
+ dims = _mesa_get_texture_dimensions(gl_target);
+
+ /* copy/pack data into user buffer */
+ if (_mesa_format_matches_format_and_type(mesa_format, format, type,
+ ctx->Pack.SwapBytes, NULL)) {
+ /* memcpy */
+ const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
+ GLuint row, slice;
+
+ for (slice = 0; slice < depth; slice++) {
+ ubyte *slice_map = map;
+
+ for (row = 0; row < height; row++) {
+ void *dest = _mesa_image_address(dims, &ctx->Pack, pixels,
+ width, height, format, type,
+ slice, row, 0);
+
+ memcpy(dest, slice_map, bytesPerRow);
+
+ slice_map += tex_xfer->stride;
+ }
+
+ map += tex_xfer->layer_stride;
+ }
+ }
+ else {
+ /* format translation via floats */
+ GLuint slice;
+ GLfloat *rgba;
+ uint32_t dstMesaFormat;
+ int dstStride, srcStride;
+
+ assert(util_format_is_compressed(src->format));
+
+ rgba = malloc(width * height * 4 * sizeof(GLfloat));
+ if (!rgba) {
+ goto end;
+ }
+
+ if (ST_DEBUG & DEBUG_FALLBACK)
+ debug_printf("%s: fallback format translation\n", __func__);
+
+ dstMesaFormat = _mesa_format_from_format_and_type(format, type);
+ dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
+ srcStride = 4 * width * sizeof(GLfloat);
+ for (slice = 0; slice < depth; slice++) {
+ void *dest = _mesa_image_address(dims, &ctx->Pack, pixels,
+ width, height, format, type,
+ slice, 0, 0);
+
+ /* get float[4] rgba row from surface */
+ pipe_get_tile_rgba(tex_xfer, map, 0, 0, width, height, dst_format,
+ rgba);
+
+ _mesa_format_convert(dest, dstMesaFormat, dstStride,
+ rgba, RGBA32_FLOAT, srcStride,
+ width, height, NULL);
+
+ /* Handle byte swapping if required */
+ if (ctx->Pack.SwapBytes) {
+ _mesa_swap_bytes_2d_image(format, type, &ctx->Pack,
+ width, height, dest, dest);
+ }
+
+ map += tex_xfer->layer_stride;
+ }
+
+ free(rgba);
+ }
+ done = TRUE;
+
+end:
+ if (map)
+ pipe_texture_unmap(pipe, tex_xfer);
+
+ _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
+ return done;
+}
+
+static enum pipe_format
+get_dst_format(struct gl_context *ctx, enum pipe_texture_target target,
+ enum pipe_format src_format, bool is_compressed,
+ GLenum format, GLenum type, unsigned bind)
+{
+ struct st_context *st = st_context(ctx);
+ struct pipe_screen *screen = st->screen;
+ /* Choose the destination format by finding the best match
+ * for the format+type combo. */
+ enum pipe_format dst_format = st_choose_matching_format(st, bind, format, type,
+ ctx->Pack.SwapBytes);
+
+ if (dst_format == PIPE_FORMAT_NONE) {
+ GLenum dst_glformat;
+
+ /* Fall back to _mesa_GetTexImage_sw except for compressed formats,
+ * where decompression with a blit is always preferred. */
+ if (!is_compressed) {
+ return PIPE_FORMAT_NONE;
+ }
+
+ /* Set the appropriate format for the decompressed texture.
+ * Luminance and sRGB formats shouldn't appear here.*/
+ switch (src_format) {
+ case PIPE_FORMAT_DXT1_RGB:
+ case PIPE_FORMAT_DXT1_RGBA:
+ case PIPE_FORMAT_DXT3_RGBA:
+ case PIPE_FORMAT_DXT5_RGBA:
+ case PIPE_FORMAT_RGTC1_UNORM:
+ case PIPE_FORMAT_RGTC2_UNORM:
+ case PIPE_FORMAT_ETC1_RGB8:
+ case PIPE_FORMAT_ETC2_RGB8:
+ case PIPE_FORMAT_ETC2_RGB8A1:
+ case PIPE_FORMAT_ETC2_RGBA8:
+ case PIPE_FORMAT_ASTC_4x4:
+ case PIPE_FORMAT_ASTC_5x4:
+ case PIPE_FORMAT_ASTC_5x5:
+ case PIPE_FORMAT_ASTC_6x5:
+ case PIPE_FORMAT_ASTC_6x6:
+ case PIPE_FORMAT_ASTC_8x5:
+ case PIPE_FORMAT_ASTC_8x6:
+ case PIPE_FORMAT_ASTC_8x8:
+ case PIPE_FORMAT_ASTC_10x5:
+ case PIPE_FORMAT_ASTC_10x6:
+ case PIPE_FORMAT_ASTC_10x8:
+ case PIPE_FORMAT_ASTC_10x10:
+ case PIPE_FORMAT_ASTC_12x10:
+ case PIPE_FORMAT_ASTC_12x12:
+ case PIPE_FORMAT_BPTC_RGBA_UNORM:
+ case PIPE_FORMAT_FXT1_RGB:
+ case PIPE_FORMAT_FXT1_RGBA:
+ dst_glformat = GL_RGBA8;
+ break;
+ case PIPE_FORMAT_RGTC1_SNORM:
+ case PIPE_FORMAT_RGTC2_SNORM:
+ if (!ctx->Extensions.EXT_texture_snorm)
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_RGBA8_SNORM;
+ break;
+ case PIPE_FORMAT_BPTC_RGB_FLOAT:
+ case PIPE_FORMAT_BPTC_RGB_UFLOAT:
+ if (!ctx->Extensions.ARB_texture_float)
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_RGBA32F;
+ break;
+ case PIPE_FORMAT_ETC2_R11_UNORM:
+ if (!screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM,
+ target, 0, 0, bind))
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_R16;
+ break;
+ case PIPE_FORMAT_ETC2_R11_SNORM:
+ if (!screen->is_format_supported(screen, PIPE_FORMAT_R16_SNORM,
+ target, 0, 0, bind))
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_R16_SNORM;
+ break;
+ case PIPE_FORMAT_ETC2_RG11_UNORM:
+ if (!screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM,
+ target, 0, 0, bind))
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_RG16;
+ break;
+ case PIPE_FORMAT_ETC2_RG11_SNORM:
+ if (!screen->is_format_supported(screen, PIPE_FORMAT_R16G16_SNORM,
+ target, 0, 0, bind))
+ return PIPE_FORMAT_NONE;
+ dst_glformat = GL_RG16_SNORM;
+ break;
+ default:
+ assert(0);
+ return PIPE_FORMAT_NONE;
+ }
+
+ dst_format = st_choose_format(st, dst_glformat, format, type,
+ target, 0, 0, bind,
+ false, false);
+ }
+ return dst_format;
+}
/** called via ctx->Driver.NewTextureImage() */
static struct gl_texture_image *
@@ -2028,22 +2288,16 @@ st_GetTexSubImage(struct gl_context * ctx,
struct gl_texture_image *texImage)
{
struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = st->screen;
struct st_texture_image *stImage = st_texture_image(texImage);
struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
struct pipe_resource *src = stObj->pt;
struct pipe_resource *dst = NULL;
- struct pipe_resource dst_templ;
enum pipe_format dst_format, src_format;
- mesa_format mesa_format;
GLenum gl_target = texImage->TexObject->Target;
enum pipe_texture_target pipe_target;
- unsigned dims;
struct pipe_blit_info blit;
unsigned bind;
- struct pipe_transfer *tex_xfer;
- ubyte *map = NULL;
boolean done = FALSE;
assert(!_mesa_is_format_etc2(texImage->TexFormat) &&
@@ -2052,6 +2306,12 @@ st_GetTexSubImage(struct gl_context * ctx,
st_flush_bitmap_cache(st);
+ /* GetTexImage only returns a single face for cubemaps. */
+ if (gl_target == GL_TEXTURE_CUBE_MAP) {
+ gl_target = GL_TEXTURE_2D;
+ }
+ pipe_target = gl_target_to_pipe(gl_target);
+
if (!st->prefer_blit_based_texture_transfer &&
!_mesa_is_format_compressed(texImage->TexFormat)) {
/* Try to avoid the fallback if we're doing texture decompression here */
@@ -2083,151 +2343,23 @@ st_GetTexSubImage(struct gl_context * ctx,
goto fallback;
}
- /* Convert the source format to what is expected by GetTexImage
- * and see if it's supported.
- *
- * This only applies to glGetTexImage:
- * - Luminance must be returned as (L,0,0,1).
- * - Luminance alpha must be returned as (L,0,0,A).
- * - Intensity must be returned as (I,0,0,1)
- */
- if (stObj->surface_based)
- src_format = util_format_linear(stObj->surface_format);
- else
- src_format = util_format_linear(src->format);
- src_format = util_format_luminance_to_red(src_format);
- src_format = util_format_intensity_to_red(src_format);
-
- if (!src_format ||
- !screen->is_format_supported(screen, src_format, src->target,
- src->nr_samples, src->nr_storage_samples,
- PIPE_BIND_SAMPLER_VIEW)) {
+ src_format = get_src_format(screen, stObj);
+ if (src_format == PIPE_FORMAT_NONE)
goto fallback;
- }
if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
bind = PIPE_BIND_DEPTH_STENCIL;
else
bind = PIPE_BIND_RENDER_TARGET;
- /* GetTexImage only returns a single face for cubemaps. */
- if (gl_target == GL_TEXTURE_CUBE_MAP) {
- gl_target = GL_TEXTURE_2D;
- }
- pipe_target = gl_target_to_pipe(gl_target);
-
- /* Choose the destination format by finding the best match
- * for the format+type combo. */
- dst_format = st_choose_matching_format(st, bind, format, type,
- ctx->Pack.SwapBytes);
-
- if (dst_format == PIPE_FORMAT_NONE) {
- GLenum dst_glformat;
-
- /* Fall back to _mesa_GetTexImage_sw except for compressed formats,
- * where decompression with a blit is always preferred. */
- if (!util_format_is_compressed(src->format)) {
- goto fallback;
- }
-
- /* Set the appropriate format for the decompressed texture.
- * Luminance and sRGB formats shouldn't appear here.*/
- switch (src_format) {
- case PIPE_FORMAT_DXT1_RGB:
- case PIPE_FORMAT_DXT1_RGBA:
- case PIPE_FORMAT_DXT3_RGBA:
- case PIPE_FORMAT_DXT5_RGBA:
- case PIPE_FORMAT_RGTC1_UNORM:
- case PIPE_FORMAT_RGTC2_UNORM:
- case PIPE_FORMAT_ETC1_RGB8:
- case PIPE_FORMAT_ETC2_RGB8:
- case PIPE_FORMAT_ETC2_RGB8A1:
- case PIPE_FORMAT_ETC2_RGBA8:
- case PIPE_FORMAT_ASTC_4x4:
- case PIPE_FORMAT_ASTC_5x4:
- case PIPE_FORMAT_ASTC_5x5:
- case PIPE_FORMAT_ASTC_6x5:
- case PIPE_FORMAT_ASTC_6x6:
- case PIPE_FORMAT_ASTC_8x5:
- case PIPE_FORMAT_ASTC_8x6:
- case PIPE_FORMAT_ASTC_8x8:
- case PIPE_FORMAT_ASTC_10x5:
- case PIPE_FORMAT_ASTC_10x6:
- case PIPE_FORMAT_ASTC_10x8:
- case PIPE_FORMAT_ASTC_10x10:
- case PIPE_FORMAT_ASTC_12x10:
- case PIPE_FORMAT_ASTC_12x12:
- case PIPE_FORMAT_BPTC_RGBA_UNORM:
- case PIPE_FORMAT_FXT1_RGB:
- case PIPE_FORMAT_FXT1_RGBA:
- dst_glformat = GL_RGBA8;
- break;
- case PIPE_FORMAT_RGTC1_SNORM:
- case PIPE_FORMAT_RGTC2_SNORM:
- if (!ctx->Extensions.EXT_texture_snorm)
- goto fallback;
- dst_glformat = GL_RGBA8_SNORM;
- break;
- case PIPE_FORMAT_BPTC_RGB_FLOAT:
- case PIPE_FORMAT_BPTC_RGB_UFLOAT:
- if (!ctx->Extensions.ARB_texture_float)
- goto fallback;
- dst_glformat = GL_RGBA32F;
- break;
- case PIPE_FORMAT_ETC2_R11_UNORM:
- if (!screen->is_format_supported(screen, PIPE_FORMAT_R16_UNORM,
- pipe_target, 0, 0, bind))
- goto fallback;
- dst_glformat = GL_R16;
- break;
- case PIPE_FORMAT_ETC2_R11_SNORM:
- if (!screen->is_format_supported(screen, PIPE_FORMAT_R16_SNORM,
- pipe_target, 0, 0, bind))
- goto fallback;
- dst_glformat = GL_R16_SNORM;
- break;
- case PIPE_FORMAT_ETC2_RG11_UNORM:
- if (!screen->is_format_supported(screen, PIPE_FORMAT_R16G16_UNORM,
- pipe_target, 0, 0, bind))
- goto fallback;
- dst_glformat = GL_RG16;
- break;
- case PIPE_FORMAT_ETC2_RG11_SNORM:
- if (!screen->is_format_supported(screen, PIPE_FORMAT_R16G16_SNORM,
- pipe_target, 0, 0, bind))
- goto fallback;
- dst_glformat = GL_RG16_SNORM;
- break;
- default:
- assert(0);
- goto fallback;
- }
-
- dst_format = st_choose_format(st, dst_glformat, format, type,
- pipe_target, 0, 0, bind,
- false, false);
-
- if (dst_format == PIPE_FORMAT_NONE) {
- /* unable to get an rgba format!?! */
- goto fallback;
- }
- }
-
- /* create the destination texture of size (width X height X depth) */
- memset(&dst_templ, 0, sizeof(dst_templ));
- dst_templ.target = pipe_target;
- dst_templ.format = dst_format;
- dst_templ.bind = bind;
- dst_templ.usage = PIPE_USAGE_STAGING;
-
- st_gl_texture_dims_to_pipe_dims(gl_target, width, height, depth,
- &dst_templ.width0, &dst_templ.height0,
- &dst_templ.depth0, &dst_templ.array_size);
+ dst_format = get_dst_format(ctx, pipe_target, src_format, util_format_is_compressed(src->format),
+ format, type, bind);
+ if (dst_format == PIPE_FORMAT_NONE)
+ goto fallback;
- dst = screen->resource_create(screen, &dst_templ);
- if (!dst) {
+ dst = create_dst_texture(ctx, dst_format, pipe_target, width, height, depth, gl_target, bind);
+ if (!dst)
goto fallback;
- }
/* From now on, we need the gallium representation of dimensions. */
if (gl_target == GL_TEXTURE_1D_ARRAY) {
@@ -2264,91 +2396,8 @@ st_GetTexSubImage(struct gl_context * ctx,
/* blit/render/decompress */
st->pipe->blit(st->pipe, &blit);
- pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
-
- map = pipe_texture_map_3d(pipe, dst, 0, PIPE_MAP_READ,
- 0, 0, 0, width, height, depth, &tex_xfer);
- if (!map) {
- goto end;
- }
-
- mesa_format = st_pipe_format_to_mesa_format(dst_format);
- dims = _mesa_get_texture_dimensions(gl_target);
-
- /* copy/pack data into user buffer */
- if (_mesa_format_matches_format_and_type(mesa_format, format, type,
- ctx->Pack.SwapBytes, NULL)) {
- /* memcpy */
- const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
- GLuint row, slice;
-
- for (slice = 0; slice < depth; slice++) {
- ubyte *slice_map = map;
-
- for (row = 0; row < height; row++) {
- void *dest = _mesa_image_address(dims, &ctx->Pack, pixels,
- width, height, format, type,
- slice, row, 0);
-
- memcpy(dest, slice_map, bytesPerRow);
-
- slice_map += tex_xfer->stride;
- }
-
- map += tex_xfer->layer_stride;
- }
- }
- else {
- /* format translation via floats */
- GLuint slice;
- GLfloat *rgba;
- uint32_t dstMesaFormat;
- int dstStride, srcStride;
-
- assert(util_format_is_compressed(src->format));
-
- rgba = malloc(width * height * 4 * sizeof(GLfloat));
- if (!rgba) {
- goto end;
- }
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback format translation\n", __func__);
-
- dstMesaFormat = _mesa_format_from_format_and_type(format, type);
- dstStride = _mesa_image_row_stride(&ctx->Pack, width, format, type);
- srcStride = 4 * width * sizeof(GLfloat);
- for (slice = 0; slice < depth; slice++) {
- void *dest = _mesa_image_address(dims, &ctx->Pack, pixels,
- width, height, format, type,
- slice, 0, 0);
-
- /* get float[4] rgba row from surface */
- pipe_get_tile_rgba(tex_xfer, map, 0, 0, width, height, dst_format,
- rgba);
-
- _mesa_format_convert(dest, dstMesaFormat, dstStride,
- rgba, RGBA32_FLOAT, srcStride,
- width, height, NULL);
-
- /* Handle byte swapping if required */
- if (ctx->Pack.SwapBytes) {
- _mesa_swap_bytes_2d_image(format, type, &ctx->Pack,
- width, height, dest, dest);
- }
-
- map += tex_xfer->layer_stride;
- }
-
- free(rgba);
- }
- done = TRUE;
-
-end:
- if (map)
- pipe_texture_unmap(pipe, tex_xfer);
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
+ done = copy_to_staging_dest(ctx, dst, xoffset, yoffset, zoffset, width, height,
+ depth, format, type, pixels, texImage);
pipe_resource_reference(&dst, NULL);
fallback:
More information about the mesa-commit
mailing list