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