On Wed, Jan 7, 2015 at 11:21 PM, Iago Toral Quiroga <ito...@igalia.com> wrote:
> From: Jason Ekstrand <jason.ekstr...@intel.com> > > v2 by Iago Toral <ito...@igalia.com>: > > - When testing if we can directly pack we should use the src format to > check > if we are packing from an RGBA format. The original code used the dst > format > for the ubyte case by mistake. > - Fixed incorrect number of bits for dst, it was computed using the src > format > instead of the dst format. > - If the dst format is an array format, check if it is signed. We were only > checking this for the case where it was not an array format, but we need > to know this in both scenarios. > - Fixed incorrect swizzle transform for the cases where we convert between > array formats. > - Compute is_signed and bits only once and for the dst format. We were > computing these for the src format too but they were overwritten by the > dst values immediately after. > - Be more careful when selecting the integer path. Specifically, check that > both src and dst are integer types. Checking only one of them should > suffice > since OpenGL does not allow conversions between normalized and integer > types, > but putting extra care here makes sense and also makes the actual > requirements > for this path more clear. > - The format argument for pack functions is the destination format we are > packing to, not the source format (which has to be RGBA). > - Expose RGBA8888_* to other files. These will come in handy when in need > to > test if a given array format is RGBA or in need to pass RGBA formats to > mesa_format_convert. > > v3 by Samuel Iglesias <sigles...@igalia.com>: > > - Add an RGBA8888_INT definition. > > v4 by Iago Toral <ito...@igalia.com> after review by Jason Ekstrand: > > - Added documentation for _mesa_format_convert. > - Added additional explanatory comments for integer conversions. > - Ensure that we use _messa_swizzle_and_convert for all signed source > formats. > - Squashed: do not directly (un)pack to RGBA UINT if the source is not > unsigned. > > v5 by Iago Toral <ito...@igalia.com>: > > - Adapted to the new implementation of mesa_array_format as a plain > uint32_t > bitfield. > > Reviewed-by: Jason Ekstrand <jason.ekstr...@intel.com> > --- > src/mesa/main/format_utils.c | 408 > +++++++++++++++++++++++++++++++++++++++++++ > src/mesa/main/format_utils.h | 10 ++ > 2 files changed, 418 insertions(+) > > diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c > index a6b8883..6467307 100644 > --- a/src/mesa/main/format_utils.c > +++ b/src/mesa/main/format_utils.c > @@ -24,6 +24,414 @@ > > #include "format_utils.h" > #include "glformats.h" > +#include "format_pack.h" > +#include "format_unpack.h" > + > +const mesa_array_format RGBA8888_FLOAT = > + MESA_ARRAY_FORMAT(4, 1, 1, 1, 4, 0, 1, 2, 3); > + > +const mesa_array_format RGBA8888_UBYTE = > + MESA_ARRAY_FORMAT(1, 0, 0, 1, 4, 0, 1, 2, 3); > + > +const mesa_array_format RGBA8888_UINT = > + MESA_ARRAY_FORMAT(4, 0, 0, 0, 4, 0, 1, 2, 3); > + > +const mesa_array_format RGBA8888_INT = > + MESA_ARRAY_FORMAT(4, 1, 0, 0, 4, 0, 1, 2, 3); > I'm sorry I didn't notice this before, but 8888_FLOAT doesn't make sense. We need to either drop the 8888 from each of these or maybe call them RGBA32_FLOAT, RGBA32_UINT, RGBA8_UBYTE, etc. That said, let's do that as a fixup patch later and not hold up the series for it. > + > +static void > +invert_swizzle(uint8_t dst[4], const uint8_t src[4]) > +{ > + int i, j; > + > + dst[0] = MESA_FORMAT_SWIZZLE_NONE; > + dst[1] = MESA_FORMAT_SWIZZLE_NONE; > + dst[2] = MESA_FORMAT_SWIZZLE_NONE; > + dst[3] = MESA_FORMAT_SWIZZLE_NONE; > + > + for (i = 0; i < 4; ++i) > + for (j = 0; j < 4; ++j) > + if (src[j] == i && dst[i] == MESA_FORMAT_SWIZZLE_NONE) > + dst[i] = j; > +} > + > +static GLenum > +gl_type_for_array_format_datatype(enum mesa_array_format_datatype type) > +{ > + switch (type) { > + case MESA_ARRAY_FORMAT_TYPE_UBYTE: > + return GL_UNSIGNED_BYTE; > + case MESA_ARRAY_FORMAT_TYPE_USHORT: > + return GL_UNSIGNED_SHORT; > + case MESA_ARRAY_FORMAT_TYPE_UINT: > + return GL_UNSIGNED_INT; > + case MESA_ARRAY_FORMAT_TYPE_BYTE: > + return GL_BYTE; > + case MESA_ARRAY_FORMAT_TYPE_SHORT: > + return GL_SHORT; > + case MESA_ARRAY_FORMAT_TYPE_INT: > + return GL_INT; > + case MESA_ARRAY_FORMAT_TYPE_HALF: > + return GL_HALF_FLOAT; > + case MESA_ARRAY_FORMAT_TYPE_FLOAT: > + return GL_FLOAT; > + default: > + assert(!"Invalid datatype"); > + return GL_NONE; > + } > +} > + > +/** > + * This can be used to convert between most color formats. > + * > + * Limitations: > + * - This function doesn't handle GL_COLOR_INDEX or YCBCR formats. > + * - This function doesn't handle byte-swapping or transferOps, these > should > + * be handled by the caller. > + * > + * \param void_dst The address where converted color data will be stored. > + * The caller must ensure that the buffer is large enough > + * to hold the converted pixel data. > + * \param dst_format The destination color format. It can be a > mesa_format > + * or a mesa_array_format represented as an uint32_t. > + * \param dst_stride The stride of the destination format in bytes. > + * \param void_src The address of the source color data to convert. > + * \param src_format The source color format. It can be a mesa_format > + * or a mesa_array_format represented as an uint32_t. > + * \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. > + */ > +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) > +{ > + 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]; > + 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; > + size_t row; > + > + if (_mesa_format_is_mesa_array_format(src_format)) { > + src_format_is_mesa_array_format = true; > + src_array_format = src_format; > + } else { > + assert(_mesa_is_format_color_format(src_format)); > + src_format_is_mesa_array_format = false; > + src_array_format = _mesa_format_to_array_format(src_format); > + } > + > + if (_mesa_format_is_mesa_array_format(dst_format)) { > + dst_format_is_mesa_array_format = true; > + dst_array_format = dst_format; > + } else { > + assert(_mesa_is_format_color_format(dst_format)); > + dst_format_is_mesa_array_format = false; > + 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; > + } > + 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; > + } > + return; > + } > + } > + > + /* Handle conversions between array formats */ > + normalized = false; > + if (src_array_format) { > + enum mesa_array_format_datatype datatype = > + _mesa_array_format_get_datatype(src_array_format); > + src_gl_type = gl_type_for_array_format_datatype(datatype); > + > + src_num_channels = > _mesa_array_format_get_num_channels(src_array_format); > + > + _mesa_array_format_get_swizzle(src_array_format, src2rgba); > + > + normalized = _mesa_array_format_is_normalized(src_array_format); > + } > + > + if (dst_array_format) { > + enum mesa_array_format_datatype datatype = > + _mesa_array_format_get_datatype(dst_array_format); > + dst_gl_type = gl_type_for_array_format_datatype(datatype); > + > + dst_num_channels = > _mesa_array_format_get_num_channels(dst_array_format); > + > + _mesa_array_format_get_swizzle(dst_array_format, dst2rgba); > + invert_swizzle(rgba2dst, dst2rgba); > + > + normalized |= _mesa_array_format_is_normalized(dst_array_format); > + } > + > + if (src_array_format && dst_array_format) { > + 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]]; > + } > + } > + > + for (row = 0; row < height; ++row) { > + _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels, > + src, src_gl_type, src_num_channels, > + src2dst, normalized, width); > + src += src_stride; > + dst += dst_stride; > + } > + return; > + } > + > + /* At this point, we're fresh out of fast-paths and we need to convert > + * to float, uint32, or, if we're lucky, uint8. > + */ > + dst_integer = false; > + src_integer = false; > + > + if (src_array_format) { > + if (!_mesa_array_format_is_float(src_array_format) && > + !_mesa_array_format_is_normalized(src_array_format)) > + src_integer = true; > + } else { > + switch (_mesa_get_format_datatype(src_format)) { > + case GL_UNSIGNED_INT: > + case GL_INT: > + src_integer = true; > + break; > + } > + } > + > + /* If the destination format is signed but the source is unsigned, > then we > + * don't loose any data by converting to a signed intermediate format > above > + * and beyond the precision that we loose in the conversion itself. If > the > + * destination is unsigned then, by using an unsigned intermediate > format, > + * we make the conversion function that converts from the source to the > + * intermediate format take care of truncating at zero. The exception > here > + * is if the intermediate format is float, in which case the first > + * conversion will leave it signed and the second conversion will > truncate > + * at zero. > + */ > + is_signed = false; > + if (dst_array_format) { > + if (!_mesa_array_format_is_float(dst_array_format) && > + !_mesa_array_format_is_normalized(dst_array_format)) > + dst_integer = true; > + is_signed = _mesa_array_format_is_signed(dst_array_format); > + bits = 8 * _mesa_array_format_get_type_size(dst_array_format); > + } else { > + switch (_mesa_get_format_datatype(dst_format)) { > + case GL_UNSIGNED_NORMALIZED: > + is_signed = false; > + break; > + case GL_SIGNED_NORMALIZED: > + is_signed = true; > + break; > + case GL_FLOAT: > + is_signed = true; > + break; > + case GL_UNSIGNED_INT: > + is_signed = false; > + dst_integer = true; > + break; > + case GL_INT: > + is_signed = true; > + dst_integer = true; > + break; > + } > + bits = _mesa_get_format_max_bits(dst_format); > + } > + > + assert(src_integer == dst_integer); > + > + if (src_integer && dst_integer) { > + tmp_uint = malloc(width * height * sizeof(*tmp_uint)); > + > + /* The [un]packing functions for unsigned datatypes treat the 32-bit > + * integer array as signed for signed formats and as unsigned for > + * unsigned formats. This is a bit of a problem if we ever convert > from > + * a signed to an unsigned format because the unsigned packing > function > + * doesn't know that the input is signed and will treat it as > unsigned > + * and not do the trunctation. The thing that saves us here is that > all > + * of the packed formats are unsigned, so we can just always use > + * _mesa_swizzle_and_convert for signed formats, which is aware of > the > + * truncation problem. > + */ > + common_gl_type = is_signed ? GL_INT : GL_UNSIGNED_INT; > + if (src_array_format) { > + 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); > + src += src_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_unpack_uint_rgba_row(src_format, width, > + src, tmp_uint + row * width); > + src += src_stride; > + } > + } > + > + /* At this point, we have already done the truncation if the source > is > + * signed but the destination is unsigned, so no need to force the > + * _mesa_swizzle_and_convert path. > + */ > + if (dst_format_is_mesa_array_format) { > + for (row = 0; row < height; ++row) { > + _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels, > + tmp_uint + row * width, > common_gl_type, 4, > + rgba2dst, normalized, width); > + dst += dst_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_pack_uint_rgba_row(dst_format, width, > + (const uint32_t (*)[4])tmp_uint + > row * width, dst); > + dst += dst_stride; > + } > + } > + > + free(tmp_uint); > + } else if (is_signed || bits > 8) { > + tmp_float = malloc(width * height * sizeof(*tmp_float)); > + > + if (src_format_is_mesa_array_format) { > + 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); > + src += src_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_unpack_rgba_row(src_format, width, > + src, tmp_float + row * width); > + src += src_stride; > + } > + } > + > + if (dst_format_is_mesa_array_format) { > + for (row = 0; row < height; ++row) { > + _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels, > + tmp_float + row * width, GL_FLOAT, > 4, > + rgba2dst, normalized, width); > + dst += dst_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_pack_float_rgba_row(dst_format, width, > + (const float (*)[4])tmp_float + row > * width, dst); > + dst += dst_stride; > + } > + } > + > + free(tmp_float); > + } else { > + tmp_ubyte = malloc(width * height * sizeof(*tmp_ubyte)); > + > + if (src_format_is_mesa_array_format) { > + 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); > + src += src_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_unpack_ubyte_rgba_row(src_format, width, > + src, tmp_ubyte + row * width); > + src += src_stride; > + } > + } > + > + if (dst_format_is_mesa_array_format) { > + for (row = 0; row < height; ++row) { > + _mesa_swizzle_and_convert(dst, dst_gl_type, dst_num_channels, > + tmp_ubyte + row * width, > GL_UNSIGNED_BYTE, 4, > + rgba2dst, normalized, width); > + dst += dst_stride; > + } > + } else { > + for (row = 0; row < height; ++row) { > + _mesa_pack_ubyte_rgba_row(dst_format, width, > + (const uint8_t (*)[4])tmp_ubyte + > row * width, dst); > + dst += dst_stride; > + } > + } > + > + free(tmp_ubyte); > + } > +} > > static const uint8_t map_identity[7] = { 0, 1, 2, 3, 4, 5, 6 }; > static const uint8_t map_3210[7] = { 3, 2, 1, 0, 4, 5, 6 }; > diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h > index 4e63200..f006e18 100644 > --- a/src/mesa/main/format_utils.h > +++ b/src/mesa/main/format_utils.h > @@ -34,6 +34,11 @@ > #include "imports.h" > #include "macros.h" > > +extern const mesa_array_format RGBA8888_FLOAT; > +extern const mesa_array_format RGBA8888_UBYTE; > +extern const mesa_array_format RGBA8888_UINT; > +extern const mesa_array_format RGBA8888_INT; > + > /* Only guaranteed to work for BITS <= 32 */ > #define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << (BITS)) - 1)) > #define MAX_INT(BITS) ((int)MAX_UINT((BITS) - 1)) > @@ -207,4 +212,9 @@ _mesa_swizzle_and_convert(void *dst, GLenum dst_type, > int num_dst_channels, > const void *src, GLenum src_type, int > num_src_channels, > const uint8_t swizzle[4], bool normalized, int > count); > > +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); > + > #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