diff options
-rw-r--r-- | src/mesa/main/format_utils.c | 239 | ||||
-rw-r--r-- | src/mesa/main/format_utils.h | 2 |
2 files changed, 171 insertions, 70 deletions
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 |