Looks good! Reviewed-by: Jason Ekstrand <jason.ekstr...@intel.com>
On Tue, Dec 9, 2014 at 4:07 AM, Iago Toral Quiroga <ito...@igalia.com> wrote: > > 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. > --- > src/mesa/main/format_utils.c | 239 > ++++++++++++++++++++++++++++++------------- > 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 ba0be13..040c79a 100644 > --- a/src/mesa/main/format_utils.c > +++ b/src/mesa/main/format_utils.c > @@ -279,6 +279,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. > * > @@ -299,24 +368,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)) { > @@ -337,67 +413,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; > } > } > > @@ -432,13 +520,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, > @@ -526,16 +609,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; > } > } > @@ -564,16 +653,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; > } > } > @@ -598,16 +693,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 28b4715..1633f1e 100644 > --- a/src/mesa/main/format_utils.h > +++ b/src/mesa/main/format_utils.h > @@ -184,6 +184,6 @@ _mesa_compute_component_mapping(GLenum inFormat, > GLenum outFormat, GLubyte *map) > 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 > -- > 1.9.1 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev >
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev