From: Iago Toral Quiroga Date: Wed, 26 Nov 2014 08:05:08 +0000 (+0100) Subject: mesa: Add a rebase_swizzle parameter to _mesa_format_convert X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3171a09c2539a3d08196d6a4cb91ad6276f9383d;p=mesa.git mesa: Add a rebase_swizzle parameter to _mesa_format_convert The new parameter allows callers to provide a rebase swizzle that the function needs to use to match the requirements of the base internal format involved. This is necessary when the source or destination internal formats (depending on whether we are doing the conversion for a pixel download or a pixel upload respectively) do not match the base formats of the source or destination formats of the conversion. This can happen when the driver does not support the internal formats and uses a different format to store pixel data internally. For example, a texture upload from RGB to Luminance in a driver that does not support textures with a Luminance format may decide to store the Luminance data as RGBA. In this case we want to store the RGBA values as (R,R,R,1). Following the same example, when we download from that texture to RGBA we want to read (R,0,0,1). The rebase_swizzle parameter allows these transforms to happen. Reviewed-by: Jason Ekstrand --- diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c index 6467307c653..2cbe80e77eb 100644 --- a/src/mesa/main/format_utils.c +++ b/src/mesa/main/format_utils.c @@ -81,6 +81,75 @@ gl_type_for_array_format_datatype(enum mesa_array_format_datatype type) } } +/* Takes a src to RGBA swizzle and applies a rebase swizzle to it. This + * is used when we need to rebase a format to match a different + * base internal format. + * + * The rebase swizzle can be NULL, which means that no rebase is necessary, + * in which case the src to RGBA swizzle is copied to the output without + * changes. + * + * The resulting rebased swizzle and well as the input swizzles are + * all 4-element swizzles, but the rebase swizzle can be NULL if no rebase + * is necessary. + */ +static void +compute_rebased_rgba_component_mapping(uint8_t *src2rgba, + uint8_t *rebase_swizzle, + uint8_t *rebased_src2rgba) +{ + int i; + + if (rebase_swizzle) { + for (i = 0; i < 4; i++) { + if (rebase_swizzle[i] > MESA_FORMAT_SWIZZLE_W) + rebased_src2rgba[i] = rebase_swizzle[i]; + else + rebased_src2rgba[i] = src2rgba[rebase_swizzle[i]]; + } + } else { + /* No rebase needed, so src2rgba is all that we need */ + memcpy(rebased_src2rgba, src2rgba, 4 * sizeof(uint8_t)); + } +} + +/* Computes the final swizzle transform to apply from src to dst in a + * conversion that might involve a rebase swizzle. + * + * This is used to compute the swizzle transform to apply in conversions + * between array formats where we have a src2rgba swizzle, a rgba2dst swizzle + * and possibly, a rebase swizzle. + * + * The final swizzle transform to apply (src2dst) when a rebase swizzle is + * involved is: src -> rgba -> base -> rgba -> dst + */ +static void +compute_src2dst_component_mapping(uint8_t *src2rgba, uint8_t *rgba2dst, + uint8_t *rebase_swizzle, uint8_t *src2dst) +{ + int i; + + if (!rebase_swizzle) { + for (i = 0; i < 4; i++) { + if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) { + src2dst[i] = rgba2dst[i]; + } else { + src2dst[i] = src2rgba[rgba2dst[i]]; + } + } + } else { + for (i = 0; i < 4; i++) { + if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) { + src2dst[i] = rgba2dst[i]; + } else if (rebase_swizzle[rgba2dst[i]] > MESA_FORMAT_SWIZZLE_W) { + src2dst[i] = rebase_swizzle[rgba2dst[i]]; + } else { + src2dst[i] = src2rgba[rebase_swizzle[rgba2dst[i]]]; + } + } + } +} + /** * This can be used to convert between most color formats. * @@ -101,24 +170,31 @@ gl_type_for_array_format_datatype(enum mesa_array_format_datatype type) * \param src_stride The stride of the source format in bytes. * \param width The width, in pixels, of the source image to convert. * \param height The height, in pixels, of the source image to convert. + * \param rebase_swizzle A swizzle transform to apply during the conversion, + * typically used to match a different internal base + * format involved. NULL if no rebase transform is needed + * (i.e. the internal base format and the base format of + * the dst or the src -depending on whether we are doing + * an upload or a download respectively- are the same). */ void _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, void *void_src, uint32_t src_format, size_t src_stride, - size_t width, size_t height) + size_t width, size_t height, uint8_t *rebase_swizzle) { uint8_t *dst = (uint8_t *)void_dst; uint8_t *src = (uint8_t *)void_src; mesa_array_format src_array_format, dst_array_format; bool src_format_is_mesa_array_format, dst_format_is_mesa_array_format; uint8_t src2dst[4], src2rgba[4], rgba2dst[4], dst2rgba[4]; + uint8_t rebased_src2rgba[4]; GLenum src_gl_type, dst_gl_type, common_gl_type; bool normalized, dst_integer, src_integer, is_signed; int src_num_channels = 0, dst_num_channels = 0; uint8_t (*tmp_ubyte)[4]; float (*tmp_float)[4]; uint32_t (*tmp_uint)[4]; - int i, bits; + int bits; size_t row; if (_mesa_format_is_mesa_array_format(src_format)) { @@ -139,67 +215,79 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, dst_array_format = _mesa_format_to_array_format(dst_format); } - /* Handle the cases where we can directly unpack */ - if (!src_format_is_mesa_array_format) { - if (dst_array_format == RGBA8888_FLOAT) { - for (row = 0; row < height; ++row) { - _mesa_unpack_rgba_row(src_format, width, - src, (float (*)[4])dst); - src += src_stride; - dst += dst_stride; - } - return; - } else if (dst_array_format == RGBA8888_UBYTE) { - assert(!_mesa_is_format_integer_color(src_format)); - for (row = 0; row < height; ++row) { - _mesa_unpack_ubyte_rgba_row(src_format, width, - src, (uint8_t (*)[4])dst); - src += src_stride; - dst += dst_stride; - } - return; - } else if (dst_array_format == RGBA8888_UINT && - _mesa_is_format_unsigned(src_format)) { - assert(_mesa_is_format_integer_color(src_format)); - for (row = 0; row < height; ++row) { - _mesa_unpack_uint_rgba_row(src_format, width, - src, (uint32_t (*)[4])dst); - src += src_stride; - dst += dst_stride; + /* First we see if we can implement the conversion with a direct pack + * or unpack. + * + * In this case we want to be careful when we need to apply a swizzle to + * match an internal base format, since in these cases a simple pack/unpack + * to the dst format from the src format may not match the requirements + * of the internal base format. For now we decide to be safe and + * avoid this path in these scenarios but in the future we may want to + * enable it for specific combinations that are known to work. + */ + if (!rebase_swizzle) { + /* Handle the cases where we can directly unpack */ + if (!src_format_is_mesa_array_format) { + if (dst_array_format == RGBA8888_FLOAT) { + for (row = 0; row < height; ++row) { + _mesa_unpack_rgba_row(src_format, width, + src, (float (*)[4])dst); + src += src_stride; + dst += dst_stride; + } + return; + } else if (dst_array_format == RGBA8888_UBYTE) { + assert(!_mesa_is_format_integer_color(src_format)); + for (row = 0; row < height; ++row) { + _mesa_unpack_ubyte_rgba_row(src_format, width, + src, (uint8_t (*)[4])dst); + src += src_stride; + dst += dst_stride; + } + return; + } else if (dst_array_format == RGBA8888_UINT && + _mesa_is_format_unsigned(src_format)) { + assert(_mesa_is_format_integer_color(src_format)); + for (row = 0; row < height; ++row) { + _mesa_unpack_uint_rgba_row(src_format, width, + src, (uint32_t (*)[4])dst); + src += src_stride; + dst += dst_stride; + } + return; } - return; } - } - /* Handle the cases where we can directly pack */ - if (!dst_format_is_mesa_array_format) { - if (src_array_format == RGBA8888_FLOAT) { - for (row = 0; row < height; ++row) { - _mesa_pack_float_rgba_row(dst_format, width, - (const float (*)[4])src, dst); - src += src_stride; - dst += dst_stride; - } - return; - } else if (src_array_format == RGBA8888_UBYTE) { - assert(!_mesa_is_format_integer_color(dst_format)); - for (row = 0; row < height; ++row) { - _mesa_pack_ubyte_rgba_row(dst_format, width, - (const uint8_t (*)[4])src, dst); - src += src_stride; - dst += dst_stride; - } - return; - } else if (src_array_format == RGBA8888_UINT && - _mesa_is_format_unsigned(dst_format)) { - assert(_mesa_is_format_integer_color(dst_format)); - for (row = 0; row < height; ++row) { - _mesa_pack_uint_rgba_row(dst_format, width, - (const uint32_t (*)[4])src, dst); - src += src_stride; - dst += dst_stride; + /* Handle the cases where we can directly pack */ + if (!dst_format_is_mesa_array_format) { + if (src_array_format == RGBA8888_FLOAT) { + for (row = 0; row < height; ++row) { + _mesa_pack_float_rgba_row(dst_format, width, + (const float (*)[4])src, dst); + src += src_stride; + dst += dst_stride; + } + return; + } else if (src_array_format == RGBA8888_UBYTE) { + assert(!_mesa_is_format_integer_color(dst_format)); + for (row = 0; row < height; ++row) { + _mesa_pack_ubyte_rgba_row(dst_format, width, + (const uint8_t (*)[4])src, dst); + src += src_stride; + dst += dst_stride; + } + return; + } else if (src_array_format == RGBA8888_UINT && + _mesa_is_format_unsigned(dst_format)) { + assert(_mesa_is_format_integer_color(dst_format)); + for (row = 0; row < height; ++row) { + _mesa_pack_uint_rgba_row(dst_format, width, + (const uint32_t (*)[4])src, dst); + src += src_stride; + dst += dst_stride; + } + return; } - return; } } @@ -234,13 +322,8 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, assert(_mesa_array_format_is_normalized(src_array_format) == _mesa_array_format_is_normalized(dst_array_format)); - for (i = 0; i < 4; i++) { - if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) { - src2dst[i] = rgba2dst[i]; - } else { - src2dst[i] = src2rgba[rgba2dst[i]]; - } - } + compute_src2dst_component_mapping(src2rgba, rgba2dst, rebase_swizzle, + src2dst); for (row = 0; row < height; ++row) { _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels, @@ -328,16 +411,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, */ common_gl_type = is_signed ? GL_INT : GL_UNSIGNED_INT; if (src_array_format) { + compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle, + rebased_src2rgba); for (row = 0; row < height; ++row) { _mesa_swizzle_and_convert(tmp_uint + row * width, common_gl_type, 4, src, src_gl_type, src_num_channels, - src2rgba, normalized, width); + rebased_src2rgba, normalized, width); src += src_stride; } } else { for (row = 0; row < height; ++row) { _mesa_unpack_uint_rgba_row(src_format, width, src, tmp_uint + row * width); + if (rebase_swizzle) + _mesa_swizzle_and_convert(tmp_uint + row * width, common_gl_type, 4, + tmp_uint + row * width, common_gl_type, 4, + rebase_swizzle, false, width); src += src_stride; } } @@ -366,16 +455,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, tmp_float = malloc(width * height * sizeof(*tmp_float)); if (src_format_is_mesa_array_format) { + compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle, + rebased_src2rgba); for (row = 0; row < height; ++row) { _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4, src, src_gl_type, src_num_channels, - src2rgba, normalized, width); + rebased_src2rgba, normalized, width); src += src_stride; } } else { for (row = 0; row < height; ++row) { _mesa_unpack_rgba_row(src_format, width, src, tmp_float + row * width); + if (rebase_swizzle) + _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4, + tmp_float + row * width, GL_FLOAT, 4, + rebase_swizzle, false, width); src += src_stride; } } @@ -400,16 +495,22 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, tmp_ubyte = malloc(width * height * sizeof(*tmp_ubyte)); if (src_format_is_mesa_array_format) { + compute_rebased_rgba_component_mapping(src2rgba, rebase_swizzle, + rebased_src2rgba); for (row = 0; row < height; ++row) { _mesa_swizzle_and_convert(tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4, src, src_gl_type, src_num_channels, - src2rgba, normalized, width); + rebased_src2rgba, normalized, width); src += src_stride; } } else { for (row = 0; row < height; ++row) { _mesa_unpack_ubyte_rgba_row(src_format, width, src, tmp_ubyte + row * width); + if (rebase_swizzle) + _mesa_swizzle_and_convert(tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4, + tmp_ubyte + row * width, GL_UNSIGNED_BYTE, 4, + rebase_swizzle, false, width); src += src_stride; } } diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h index f006e18d785..ae7926e0c75 100644 --- a/src/mesa/main/format_utils.h +++ b/src/mesa/main/format_utils.h @@ -215,6 +215,6 @@ _mesa_swizzle_and_convert(void *dst, GLenum dst_type, int num_dst_channels, void _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, void *void_src, uint32_t src_format, size_t src_stride, - size_t width, size_t height); + size_t width, size_t height, uint8_t *rebase_swizzle); #endif