[Mesa-dev] [PATCH 06/12] main/format_utils: Add a general format conversion function
Brian Paul
brianp at vmware.com
Fri Jul 18 08:14:27 PDT 2014
On 07/17/2014 12:04 PM, Jason Ekstrand wrote:
> Most format conversion operations required by GL can be performed by
> converting one channel at a time, shuffling the channels around, and
> optionally filling missing channels with zeros and ones. This adds a
> function to do just that in a general, yet efficient, way.
>
> Signed-off-by: Jason Ekstrand <jason.ekstrand at intel.com>
> ---
> src/mesa/main/format_utils.c | 566 +++++++++++++++++++++++++++++++++++++++++++
> src/mesa/main/format_utils.h | 18 ++
> 2 files changed, 584 insertions(+)
>
> diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c
> index 241c158..0cb3eae 100644
> --- a/src/mesa/main/format_utils.c
> +++ b/src/mesa/main/format_utils.c
> @@ -54,3 +54,569 @@ _mesa_srgb_ubyte_to_linear_float(uint8_t cl)
>
> return lut[cl];
> }
> +
> +static bool
> +swizzle_convert_try_memcpy(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)
Please add a comment on this function describing the parameters and what
the return value means.
> +{
> + int i;
> +
> + if (src_type != dst_type)
> + return false;
> + if (num_src_channels != num_dst_channels)
> + return false;
> +
> + for (i = 0; i < num_dst_channels; ++i)
> + if (swizzle[i] != i && swizzle[i] != MESA_FORMAT_SWIZZLE_NONE)
> + return false;
> +
> + memcpy(dst, src, count * num_src_channels * _mesa_sizeof_type(src_type));
> +
> + return true;
> +}
> +
> +/* Note: This loop is carefully crafted for performance. Be careful when
> + * changing it and run some benchmarks to ensure no performance regressions
> + * if you do.
> + */
Comments for the macro's parameters might be nice. And a comment saying
what the macro actually does.
> +#define SWIZZLE_CONVERT_LOOP(DST_TYPE, SRC_TYPE, CONV) \
> + do { \
> + const SRC_TYPE *typed_src = void_src; \
> + DST_TYPE *typed_dst = void_dst; \
> + DST_TYPE tmp[7]; \
> + tmp[4] = 0; \
> + tmp[5] = one; \
> + for (s = 0; s < count; ++s) { \
> + for (j = 0; j < num_src_channels; ++j) { \
> + SRC_TYPE src = typed_src[j]; \
> + tmp[j] = CONV; \
> + } \
> + \
> + typed_dst[0] = tmp[swizzle_x]; \
> + if (num_dst_channels > 1) { \
> + typed_dst[1] = tmp[swizzle_y]; \
> + if (num_dst_channels > 2) { \
> + typed_dst[2] = tmp[swizzle_z]; \
> + if (num_dst_channels > 3) { \
> + typed_dst[3] = tmp[swizzle_w]; \
> + } \
> + } \
> + } \
In other places in Mesa we do that sort of thing with a switch statement
with fall-throughs. That might be even more efficient. In the common
case, there's 4 channels so you're always doing 3 ifs. An optimized
switch could be one computed jump.
> + typed_src += num_src_channels; \
> + typed_dst += num_dst_channels; \
> + } \
> + } while (0);
> +
> +/**
> + * Convert between array-based color formats.
> + *
> + * Most format conversion operations required by GL can be performed by
> + * converting one channel at a time, shuffling the channels around, and
> + * optionally filling missing channels with zeros and ones. This function
> + * does just that in a general, yet efficient, way.
> + *
> + * Most of the parameters are self-explanitory. The swizzle parameter is
explanatory
> + * an array of 4 numbers (see _mesa_get_format_swizzle) that describes
> + * where each channel in the destination should come from in the source.
> + *
> + * Under most circumstances, the source and destination images must be
> + * different as no care is taken not to clobber one with the other.
> + * However, if they have the same number of bits per pixel, it is safe to
> + * do an in-place conversion.
Please document the function parameters too.
> + */
> +void
> +_mesa_swizzle_and_convert(void *void_dst, GLenum dst_type, int num_dst_channels,
> + const void *void_src, GLenum src_type, int num_src_channels,
> + const uint8_t swizzle[4], bool normalized, int count)
> +{
> + int s, j;
> + register uint8_t swizzle_x, swizzle_y, swizzle_z, swizzle_w;
> +
> + if (swizzle_convert_try_memcpy(void_dst, dst_type, num_dst_channels,
> + void_src, src_type, num_src_channels,
> + swizzle, normalized, count))
> + return;
> +
> + swizzle_x = swizzle[0];
> + swizzle_y = swizzle[1];
> + swizzle_z = swizzle[2];
> + swizzle_w = swizzle[3];
> +
> + switch (dst_type) {
> + case GL_FLOAT:
> + {
> + const float one = 1.0f;
> + switch (src_type) {
> + case GL_FLOAT:
> + SWIZZLE_CONVERT_LOOP(float, float, src)
> + break;
> + case GL_HALF_FLOAT:
> + SWIZZLE_CONVERT_LOOP(float, uint16_t, _mesa_half_to_float(src))
We generally use the GL GLubyte, GLushort, etc. types instead of
uint8_t, uint16_t, etc. when dealing with OpenGL data. I realize the
later are OK, but the former would be more consistent with other code.
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, uint8_t, UBYTE_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, int8_t, BYTE_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, int8_t, src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, uint16_t, USHORT_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, int16_t, SHORT_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, int16_t, src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, uint32_t, UINT_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(float, int32_t, INT_TO_FLOAT(src))
> + } else {
> + SWIZZLE_CONVERT_LOOP(float, int32_t, src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
break on next line.
> + case GL_HALF_FLOAT:
> + {
> + const uint16_t one = _mesa_float_to_half(1.0f);
> + switch (src_type) {
> + case GL_FLOAT:
> + SWIZZLE_CONVERT_LOOP(uint16_t, float, _mesa_float_to_half(src))
> + break;
> + case GL_HALF_FLOAT:
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(UBYTE_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(src))
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(BYTE_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(src))
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(USHORT_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(src))
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(SHORT_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(src))
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(UINT_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(src))
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(INT_TO_FLOAT(src)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(src))
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_UNSIGNED_BYTE:
> + {
> + const uint8_t one = normalized ? UINT8_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_UBYTE(CLAMP(src, 0.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, float, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_UBYTE(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
Some of these lines are kind of long. We try to use 78-char lines (or
so). In this case, maybe the whole FLOAT_TO_UBYTE(CLAMP(...)) should go
into a helper/inline half_to_ubyte() function.
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
src & 0x8000 is not immediately obvious. Maybe we need a
negative_half() predicate function?
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint8_t, src)
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : ((uint8_t)src * 2) + ((uint8_t)src >> 6))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src >> 8)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : (uint16_t)src >> 7)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src >> 24)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 23)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_BYTE:
> + {
> + const int8_t one = normalized ? INT8_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_BYTE(CLAMP(src, -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, float, src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_BYTE(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, _mesa_half_to_float(src))
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src >> 1)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + SWIZZLE_CONVERT_LOOP(int8_t, int8_t, src)
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src >> 9)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src >> 8)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src >> 25)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src >> 24)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_UNSIGNED_SHORT:
> + {
> + const uint16_t one = normalized ? UINT16_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_USHORT(CLAMP(src, 0.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, float, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_USHORT(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, EXTEND_NORMALIZED_UINT((uint16_t)src, 8, 16))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint16_t)src, 7, 16))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint16_t)src, 15, 16))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src >> 16)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 15)
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_SHORT:
> + {
> + const int16_t one = normalized ? INT16_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_SHORT(CLAMP(src, -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, float, src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_SHORT(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_half_to_float(src))
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, EXTEND_NORMALIZED_UINT((int16_t)src, 8, 15))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int16_t, int8_t, EXTEND_NORMALIZED_INT((int16_t)src, 7, 15))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int16_t, int8_t, src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src >> 1)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + SWIZZLE_CONVERT_LOOP(int16_t, int16_t, src)
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src >> 17)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src >> 16)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_UNSIGNED_INT:
> + {
> + const uint32_t one = normalized ? UINT32_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_UINT(CLAMP(src, 0.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, float, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_UINT(CLAMP(_mesa_half_to_float(src), 0.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, EXTEND_NORMALIZED_UINT((uint32_t)src, 8, 32))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 7, 32))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, EXTEND_NORMALIZED_UINT((uint32_t)src, 16, 32))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 15, 32))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint32_t, src)
> + break;
> + case GL_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((uint32_t)src, 31, 32))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : src)
> + }
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + case GL_INT:
> + {
> + const int32_t one = normalized ? INT32_MAX : 1;
> + switch (src_type) {
> + case GL_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_INT(CLAMP(src, -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, float, src)
> + }
> + break;
> + case GL_HALF_FLOAT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_INT(CLAMP(_mesa_half_to_float(src), -1.0f, 1.0f)))
> + } else {
> + SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, _mesa_half_to_float(src))
> + }
> + break;
> + case GL_UNSIGNED_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, EXTEND_NORMALIZED_UINT((int32_t)src, 8, 31))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, src)
> + }
> + break;
> + case GL_BYTE:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int32_t, int8_t, EXTEND_NORMALIZED_INT((int32_t)src, 7, 31))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int32_t, int8_t, src)
> + }
> + break;
> + case GL_UNSIGNED_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, EXTEND_NORMALIZED_UINT((int32_t)src, 16, 31))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, src)
> + }
> + break;
> + case GL_SHORT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int32_t, int16_t, EXTEND_NORMALIZED_INT((int32_t)src, 15, 31))
> + } else {
> + SWIZZLE_CONVERT_LOOP(int32_t, int16_t, src)
> + }
> + break;
> + case GL_UNSIGNED_INT:
> + if (normalized) {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src >> 1)
> + } else {
> + SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src)
> + }
> + break;
> + case GL_INT:
> + SWIZZLE_CONVERT_LOOP(int32_t, int32_t, src)
> + break;
> + default:
> + assert(!"Invalid channel type combination");
> + }
> + } break;
> + default:
> + assert(!"Invalid channel type");
> + }
> +}
> diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h
> index 6af3aa5..c5dab7b 100644
> --- a/src/mesa/main/format_utils.h
> +++ b/src/mesa/main/format_utils.h
> @@ -33,6 +33,19 @@
>
> #include "macros.h"
>
> +/* Only guaranteed to work for BITS <= 32 */
> +#define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << BITS) - 1))
> +
> +/* Extends an integer of size Sb to one of size Db in a linear way */
> +#define EXTEND_NORMALIZED_UINT(X, Sb, Db) \
> + (((X) * (__typeof__(X))(MAX_UINT(Db) / MAX_UINT(Sb))) + \
> + ((Db % Sb) ? ((X) >> (Sb - Db % Sb)) : (__typeof__(X))0))
> +
> +/* This is almost the same as extending unsigned int except that we have to
> + * handle the case of -MAX(Sb) */
> +#define EXTEND_NORMALIZED_INT(X, Sb, Db) (((X) < -(__typeof__(X))MAX_UINT(Sb)) \
> + ? -(__typeof__(X))MAX_UINT(Db) : EXTEND_NORMALIZED_UINT(X, Sb, Db))
Does __typeof__ work in MSVC, Clang, etc?
It might be simpler to just define/use BYTE_TO_SHORT(), etc. macros.
> +
> /* RGB to sRGB conversion functions */
>
> static inline float
> @@ -65,4 +78,9 @@ _mesa_srgb_to_linear(float cs)
>
> float _mesa_srgb_ubyte_to_linear_float(uint8_t cl);
>
> +void
> +_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);
> +
> #endif
>
-Brian
More information about the mesa-dev
mailing list