<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Brian,<br>Thanks for reviewing.  I'll try to get your comments incorperated and get a v2 sent out on Monday.<br></div><div class="gmail_quote"><br>On Fri, Jul 18, 2014 at 8:14 AM, Brian Paul <span dir="ltr"><<a href="mailto:brianp@vmware.com" target="_blank">brianp@vmware.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>On 07/17/2014 12:04 PM, Jason Ekstrand wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Most format conversion operations required by GL can be performed by<br>
converting one channel at a time, shuffling the channels around, and<br>
optionally filling missing channels with zeros and ones.  This adds a<br>
function to do just that in a general, yet efficient, way.<br>
<br>
Signed-off-by: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com" target="_blank">jason.ekstrand@intel.com</a>><br>
---<br>
  src/mesa/main/format_utils.c | 566 ++++++++++++++++++++++++++++++<u></u>+++++++++++++<br>
  src/mesa/main/format_utils.h |  18 ++<br>
  2 files changed, 584 insertions(+)<br>
<br>
diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c<br>
index 241c158..0cb3eae 100644<br>
--- a/src/mesa/main/format_utils.c<br>
+++ b/src/mesa/main/format_utils.c<br>
@@ -54,3 +54,569 @@ _mesa_srgb_ubyte_to_linear_<u></u>float(uint8_t cl)<br>
<br>
     return lut[cl];<br>
  }<br>
+<br>
+static bool<br>
+swizzle_convert_try_memcpy(<u></u>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>
</blockquote>
<br></div>
Please add a comment on this function describing the parameters and what the return value means.</blockquote><div><br></div><div>Done<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+{<br>
+   int i;<br>
+<br>
+   if (src_type != dst_type)<br>
+      return false;<br>
+   if (num_src_channels != num_dst_channels)<br>
+      return false;<br>
+<br>
+   for (i = 0; i < num_dst_channels; ++i)<br>
+      if (swizzle[i] != i && swizzle[i] != MESA_FORMAT_SWIZZLE_NONE)<br>
+         return false;<br>
+<br>
+   memcpy(dst, src, count * num_src_channels * _mesa_sizeof_type(src_type));<br>
+<br>
+   return true;<br>
+}<br>
+<br>
+/* Note: This loop is carefully crafted for performance.  Be careful when<br>
+ * changing it and run some benchmarks to ensure no performance regressions<br>
+ * if you do.<br>
+ */<br>
</blockquote>
<br></div>
Comments for the macro's parameters might be nice.  And a comment saying what the macro actually does.<div><br></div></blockquote><div><br></div><div>done<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+#define SWIZZLE_CONVERT_LOOP(DST_TYPE, SRC_TYPE, CONV)   \<br>
+   do {                                                  \<br>
+      const SRC_TYPE *typed_src = void_src;              \<br>
+      DST_TYPE *typed_dst = void_dst;                    \<br>
+      DST_TYPE tmp[7];                                   \<br>
+      tmp[4] = 0;                                        \<br>
+      tmp[5] = one;                                      \<br>
+      for (s = 0; s < count; ++s) {                      \<br>
+         for (j = 0; j < num_src_channels; ++j) {        \<br>
+            SRC_TYPE src = typed_src[j];                 \<br>
+            tmp[j] = CONV;                               \<br>
+         }                                               \<br>
+                                                         \<br>
+         typed_dst[0] = tmp[swizzle_x];                  \<br>
+         if (num_dst_channels > 1) {                     \<br>
+            typed_dst[1] = tmp[swizzle_y];               \<br>
+            if (num_dst_channels > 2) {                  \<br>
+               typed_dst[2] = tmp[swizzle_z];            \<br>
+               if (num_dst_channels > 3) {               \<br>
+                  typed_dst[3] = tmp[swizzle_w];         \<br>
+               }                                         \<br>
+            }                                            \<br>
+         }                                               \<br>
</blockquote>
<br></div>
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.</blockquote>

<div><br></div><div>The primary reason why I chose 3 ifs instead of a switch is to ensure that the writes always happen in-order.  In my testing, 3 ifs is actually slightly faster than the switch (also faster than a switch with 1, 2, 3, or 4 converts in each section).  That said, I just did some more experimentation with forcing the loops to unroll like was done before in the uchar case and it seems to be substantially better.  (I had tried that before but it didn't help much.  I'm not sure what chanaged there.)<br>

<br></div><div>When doing the forced-unroll (described above), I don't notice any difference between the 3 ifs and the switch.  Maybe the compiler re-orders the writes or maybe it doesn't matter.  If you like the switch better cosmetically, I can do that.<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         typed_src += num_src_channels;                  \<br>
+         typed_dst += num_dst_channels;                  \<br>
+      }                                                  \<br>
+   } while (0);<br>
+<br>
+/**<br>
+ * Convert between array-based color formats.<br>
+ *<br>
+ * Most format conversion operations required by GL can be performed by<br>
+ * converting one channel at a time, shuffling the channels around, and<br>
+ * optionally filling missing channels with zeros and ones.  This function<br>
+ * does just that in a general, yet efficient, way.<br>
+ *<br>
+ * Most of the parameters are self-explanitory.  The swizzle parameter is<br>
</blockquote>
<br></div>
explanatory<div><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ * an array of 4 numbers (see _mesa_get_format_swizzle) that describes<br>
+ * where each channel in the destination should come from in the source.<br>
+ *<br>
+ * Under most circumstances, the source and destination images must be<br>
+ * different as no care is taken not to clobber one with the other.<br>
+ * However, if they have the same number of bits per pixel, it is safe to<br>
+ * do an in-place conversion.<br>
</blockquote>
<br></div>
Please document the function parameters too.<div><div><br></div></div></blockquote><div><br>done<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ */<br>
+void<br>
+_mesa_swizzle_and_convert(<u></u>void *void_dst, GLenum dst_type, int num_dst_channels,<br>
+                          const void *void_src, GLenum src_type, int num_src_channels,<br>
+                          const uint8_t swizzle[4], bool normalized, int count)<br>
+{<br>
+   int s, j;<br>
+   register uint8_t swizzle_x, swizzle_y, swizzle_z, swizzle_w;<br>
+<br>
+   if (swizzle_convert_try_memcpy(<u></u>void_dst, dst_type, num_dst_channels,<br>
+                                  void_src, src_type, num_src_channels,<br>
+                                  swizzle, normalized, count))<br>
+      return;<br>
+<br>
+   swizzle_x = swizzle[0];<br>
+   swizzle_y = swizzle[1];<br>
+   swizzle_z = swizzle[2];<br>
+   swizzle_w = swizzle[3];<br>
+<br>
+   switch (dst_type) {<br>
+   case GL_FLOAT:<br>
+   {<br>
+      const float one = 1.0f;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         SWIZZLE_CONVERT_LOOP(float, float, src)<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         SWIZZLE_CONVERT_LOOP(float, uint16_t, _mesa_half_to_float(src))<br>
</blockquote>
<br></div></div>
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.</blockquote><div>

<br></div><div>I was told by people on the mesa team at Intel that we were trying to get away from the GL datatypes and not to use them in new code unless it is a GL API entrypoint.  Honestly, I don't care.  I can regex the file and convert it easily enough.<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint8_t, UBYTE_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, int8_t, BYTE_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, int8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint16_t, USHORT_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, int16_t, SHORT_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, int16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint32_t, UINT_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(float, int32_t, INT_TO_FLOAT(src))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(float, int32_t, src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
</blockquote>
<br></div></div>
break on next line.</blockquote><div><br></div><div>Sure, I can change that<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+   case GL_HALF_FLOAT:<br>
+   {<br>
+      const uint16_t one = _mesa_float_to_half(1.0f);<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         SWIZZLE_CONVERT_LOOP(uint16_t, float, _mesa_float_to_half(src))<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(UBYTE_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(BYTE_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(USHORT_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(SHORT_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(UINT_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(INT_TO_<u></u>FLOAT(src)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, _mesa_float_to_half(src))<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_UNSIGNED_BYTE:<br>
+   {<br>
+      const uint8_t one = normalized ? UINT8_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_UBYTE(CLAMP(src, 0.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_UBYTE(CLAMP(_mesa_<u></u>half_to_float(src), 0.0f, 1.0f)))<br>
</blockquote>
<br></div></div>
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.<div><br></div></blockquote>
<div><br></div><div>That's a good idea<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))<br>
</blockquote>
<br></div>
src & 0x8000 is not immediately obvious.  Maybe we need a negative_half() predicate function?<div><div><br></div></div></blockquote><div><br></div><div>Good point.  A negative_half function (or macro) would probably be a good idea.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         SWIZZLE_CONVERT_LOOP(uint8_t, uint8_t, src)<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : ((uint8_t)src * 2) + ((uint8_t)src >> 6))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int8_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src >> 8)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : (uint16_t)src >> 7)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int16_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src >> 24)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 23)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, int32_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_BYTE:<br>
+   {<br>
+      const int8_t one = normalized ? INT8_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, FLOAT_TO_BYTE(CLAMP(src, -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, float, src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, FLOAT_TO_BYTE(CLAMP(_mesa_<u></u>half_to_float(src), -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint8_t, uint16_t, _mesa_half_to_float(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src >> 1)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         SWIZZLE_CONVERT_LOOP(int8_t, int8_t, src)<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src >> 9)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src >> 8)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, int16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src >> 25)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src >> 24)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int8_t, int32_t, src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_UNSIGNED_SHORT:<br>
+   {<br>
+      const uint16_t one = normalized ? UINT16_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_USHORT(CLAMP(src, 0.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_USHORT(CLAMP(_mesa_<u></u>half_to_float(src), 0.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, EXTEND_NORMALIZED_UINT((<u></u>uint16_t)src, 8, 16))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((<u></u>uint16_t)src, 7, 16))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int8_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, src)<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((<u></u>uint16_t)src, 15, 16))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int16_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src >> 16)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : (uint32_t)src >> 15)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, int32_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_SHORT:<br>
+   {<br>
+      const int16_t one = normalized ? INT16_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, FLOAT_TO_SHORT(CLAMP(src, -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, float, src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, FLOAT_TO_SHORT(CLAMP(_mesa_<u></u>half_to_float(src), -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint16_t, uint16_t, _mesa_half_to_float(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, EXTEND_NORMALIZED_UINT((int16_<u></u>t)src, 8, 15))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, int8_t, EXTEND_NORMALIZED_INT((int16_<u></u>t)src, 7, 15))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, int8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src >> 1)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         SWIZZLE_CONVERT_LOOP(int16_t, int16_t, src)<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src >> 17)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src >> 16)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int16_t, int32_t, src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_UNSIGNED_INT:<br>
+   {<br>
+      const uint32_t one = normalized ? UINT32_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_UINT(CLAMP(src, 0.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_UINT(CLAMP(_mesa_<u></u>half_to_float(src), 0.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, (src & 0x8000) ? 0 : _mesa_half_to_float(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, EXTEND_NORMALIZED_UINT((<u></u>uint32_t)src, 8, 32))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((<u></u>uint32_t)src, 7, 32))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int8_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, EXTEND_NORMALIZED_UINT((<u></u>uint32_t)src, 16, 32))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((<u></u>uint32_t)src, 15, 32))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int16_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         SWIZZLE_CONVERT_LOOP(uint32_t, uint32_t, src)<br>
+         break;<br>
+      case GL_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : EXTEND_NORMALIZED_UINT((<u></u>uint32_t)src, 31, 32))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, int32_t, (src < 0) ? 0 : src)<br>
+         }<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   case GL_INT:<br>
+   {<br>
+      const int32_t one = normalized ? INT32_MAX : 1;<br>
+      switch (src_type) {<br>
+      case GL_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, FLOAT_TO_INT(CLAMP(src, -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, float, src)<br>
+         }<br>
+         break;<br>
+      case GL_HALF_FLOAT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, FLOAT_TO_INT(CLAMP(_mesa_half_<u></u>to_float(src), -1.0f, 1.0f)))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(uint32_t, uint16_t, _mesa_half_to_float(src))<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, EXTEND_NORMALIZED_UINT((int32_<u></u>t)src, 8, 31))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_BYTE:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, int8_t, EXTEND_NORMALIZED_INT((int32_<u></u>t)src, 7, 31))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, int8_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, EXTEND_NORMALIZED_UINT((int32_<u></u>t)src, 16, 31))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_SHORT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, int16_t, EXTEND_NORMALIZED_INT((int32_<u></u>t)src, 15, 31))<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, int16_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_UNSIGNED_INT:<br>
+         if (normalized) {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src >> 1)<br>
+         } else {<br>
+            SWIZZLE_CONVERT_LOOP(int32_t, uint32_t, src)<br>
+         }<br>
+         break;<br>
+      case GL_INT:<br>
+         SWIZZLE_CONVERT_LOOP(int32_t, int32_t, src)<br>
+         break;<br>
+      default:<br>
+         assert(!"Invalid channel type combination");<br>
+      }<br>
+   } break;<br>
+   default:<br>
+      assert(!"Invalid channel type");<br>
+   }<br>
+}<br>
diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h<br>
index 6af3aa5..c5dab7b 100644<br>
--- a/src/mesa/main/format_utils.h<br>
+++ b/src/mesa/main/format_utils.h<br>
@@ -33,6 +33,19 @@<br>
<br>
  #include "macros.h"<br>
<br>
+/* Only guaranteed to work for BITS <= 32 */<br>
+#define MAX_UINT(BITS) ((BITS) == 32 ? UINT32_MAX : ((1u << BITS) - 1))<br>
+<br>
+/* Extends an integer of size Sb to one of size Db in a linear way */<br>
+#define EXTEND_NORMALIZED_UINT(X, Sb, Db) \<br>
+      (((X) * (__typeof__(X))(MAX_UINT(Db) / MAX_UINT(Sb))) + \<br>
+       ((Db % Sb) ? ((X) >> (Sb - Db % Sb)) : (__typeof__(X))0))<br>
+<br>
+/* This is almost the same as extending unsigned int except that we have to<br>
+ * handle the case of -MAX(Sb) */<br>
+#define EXTEND_NORMALIZED_INT(X, Sb, Db) (((X) < -(__typeof__(X))MAX_UINT(Sb)) \<br>
+      ? -(__typeof__(X))MAX_UINT(Db) : EXTEND_NORMALIZED_UINT(X, Sb, Db))<br>
</blockquote>
<br></div></div>
Does __typeof__ work in MSVC, Clang, etc?<br></blockquote><div><br></div><div>No, not in MSVC.  I meant to change that before I sent it out.  At one point, I thought I had performance problems when everything casted to int, but now that I look at it, I'm not seeing a difference anymore.<br>

</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
It might be simpler to just define/use BYTE_TO_SHORT(), etc. macros.</blockquote><div><br></div><div>I thought about that.  However, there doesn't seem to be much of a rhyme or reason to some of the BYTE_TO_SHORT-style macros: which ones exist, how they're written, etc.  And a couple of them (BYTE_TO_UBYTE) are even wrong.  If you'd rather I put together a patch to clean them up and standardize them, I can do that.  The EXTEND_NORMALIZED_INT macro is also really nice if we're going to autogenerate things because you can use it on 3, 5, and 10-biit datatypes.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div> </div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
  /* RGB to sRGB conversion functions */<br>
<br>
  static inline float<br>
@@ -65,4 +78,9 @@ _mesa_srgb_to_linear(float cs)<br>
<br>
  float _mesa_srgb_ubyte_to_linear_<u></u>float(uint8_t cl);<br>
<br>
+void<br>
+_mesa_swizzle_and_convert(<u></u>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>
  #endif<br>
<br>
</blockquote>
<br></div></div><span><font color="#888888">
-Brian<br>
<br>
</font></span></blockquote></div><br></div></div>