<div dir="ltr">On 9 January 2013 23:58, Chad Versace <span dir="ltr"><<a href="mailto:chad.versace@linux.intel.com" target="_blank">chad.versace@linux.intel.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In order to generate tests for the GLSL packing functions (packSnorm2x16<br>
and friends), we must be able to simulate them. This patch adds<br>
a C executable that does exactly that.<br>
<br>
I originally tried to write this tool in Python, but manipulating 16-bit<br>
unsigned integers is not one of Python's strengths.<br>
<br>
Signed-off-by: Chad Versace <<a href="mailto:chad.versace@linux.intel.com">chad.versace@linux.intel.com</a>><br>
---<br>
 tests/util/CMakeLists.no_api.txt |   3 +<br>
 tests/util/glsl-packing.c        | 799 +++++++++++++++++++++++++++++++++++++++<br>
 2 files changed, 802 insertions(+)<br>
 create mode 100644 tests/util/glsl-packing.c<br>
<br>
diff --git a/tests/util/CMakeLists.no_api.txt b/tests/util/CMakeLists.no_api.txt<br>
index c331368..f1ac407 100644<br>
--- a/tests/util/CMakeLists.no_api.txt<br>
+++ b/tests/util/CMakeLists.no_api.txt<br>
@@ -6,8 +6,11 @@ piglit_add_library (piglitutil<br>
        ${UTIL_SOURCES}<br>
 )<br>
<br>
+piglit_add_executable(glsl-packing glsl-packing.c)<br>
+<br>
 if(UNIX)<br>
        target_link_libraries(piglitutil m)<br>
+       target_link_libraries(glsl-packing m)<br>
 endif(UNIX)<br>
<br>
 # vim: ft=cmake:<br>
diff --git a/tests/util/glsl-packing.c b/tests/util/glsl-packing.c<br>
new file mode 100644<br>
index 0000000..317f0d1<br>
--- /dev/null<br>
+++ b/tests/util/glsl-packing.c<br>
@@ -0,0 +1,799 @@<br>
+/*<br>
+ * Copyright © 2012 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include <assert.h><br>
+#include <inttypes.h><br>
+#include <math.h><br>
+#include <stdarg.h><br>
+#include <stdbool.h><br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+<br>
+/* TODO: Reject round options for pack/unpackHalf.<br>
+ * TODO: Discuss choices in packHalf.<br>
+ */<br>
+<br>
+#define PRIf32_PRECISION "24"<br>
+#define PRIf32 "%." PRIf32_PRECISION "f"<br></blockquote><div><br></div><div>This seems like premature generalization to me.  My preference would be to just say "%.24f" in the printf() calls.  If we later determine that precision needs to be tweakable, we can introduce something more complicated.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+static const char *help_text =<br>
+       "NAME\n"<br>
+       "    glsl-packing - Print the result of a GLSL packing function\n"<br>
+       "\n"<br>
+       "SYNOPSIS\n"<br>
+       "    glsl-packing PACK_FUNC X Y [FUNC_OPTS]\n"<br>
+       "    glsl-packing UNPACK_FUNC U [FUNC_OPTS]\n"<br>
+       "    glsl-packing print-float16-info\n"<br>
+       "\n"<br>
+       "COMMANDS\n"<br>
+       "    All floats are printed with the printf specifier " PRIf32 ".\n"<br>
+       "\n"<br>
+       "    glsl-packing PACK_FUNC X Y [FUNC_OPTS]\n"<br>
+       "        Print the result of calling PACK_FUNC on vec2(X, Y).\n"<br>
+       "\n"<br>
+       "        PACK_FUNC must be one of:\n"<br>
+       "            packSnorm2x16\n"<br>
+       "            packUnorm2x16\n"<br>
+       "            packHalf2x16\n"<br>
+       "\n"<br>
+       "        X and Y must be floating point numbers in a format consumable\n"<br>
+       "        by strof(3).\n"<br>
+       "\n"<br>
+       "    glsl-packing UNPACK_FUNC U [FUNC_OPTS]\n"<br>
+       "        Print the result of calling UNPACK_FUNC on uint(U).\n"<br>
+       "\n"<br>
+       "        UNPACK_FUNC must be one of:\n"<br>
+       "            unpackSnorm2x16\n"<br>
+       "            unpackUnorm2x16\n"<br>
+       "            unpackHalf2x16\n"<br>
+       "\n"<br>
+       "        U must be an unsigned integer in a format consumable by scanf(3).\n"<br>
+       "\n"<br>
+       "    glsl-packing print-float16-info\n"<br>
+       "        Print the following special values of IEEE 754 16-bit floats:\n"<br>
+       "            subnormal_min\n"<br>
+       "            subnormal_max\n"<br>
+       "            normal_min\n"<br>
+       "            normal_max\n"<br>
+       "            min_step\n"<br>
+       "            max_step\n"<br>
+       "\n"<br>
+       "FUNC_OPTS\n"<br>
+       "    flush_float16\n"<br>
+       "    flush_float32\n"<br>
+       "        All PACK_FUNC and UNPACK_FUNC commands accept the flush options.\n"<br>
+       "\n"<br>
+       "        The GLSL ES 3.00 and GLSL 4.10 specs allows implementations to truncate\n"<br>
+       "        subnormal floats to zero. From section 4.5.1 \"Range and Precision\"\n"<br>
+       "        of the two specs:\n"<br>
+       "            Any subnormal (denormalized) value input into a shader or\n"<br>
+       "            potentially generated by any operation in a shader can be\n"<br>
+       "            flushed to 0.\n"<br>
+       "\n"<br>
+       "        If flush_float32 is specified, then glsl-packing will simulate the behavior\n"<br>
+       "        of a GLSL implementation that flushes subnormal 32-bit floating-point values\n"<br>
+       "        to 0. Likewise if flush_float16 is enabled.\n"<br>
+       "\n"<br>
+       "        Enabling flush_float16 implicitly enables flush_float32.\n"<br>
+       "\n"<br>
+       "    round_to_nearest\n"<br>
+       "    round_to_even\n"<br>
+       "        All PACK_FUNC and UNPACK_FUNC commands except pack/unpackHalf2x16 accept\n"<br>
+       "        the rounding option. At most one rounding option may be specified.\n"<br>
+       "\n"<br>
+       "        For some packing functions, the GLSL ES 3.00 specification's\n"<br>
+       "        definition of the function's behavior involves the `round()`\n"<br>
+       "        function, whose behavior at 0.5 is not specified. From section \n"<br>
+       "        8.3 of the spec:\n"<br>
+       "            The fraction 0.5 will round in a direction chosen by the\n"<br>
+       "            implementation, presumably the direction that is fastest.\n"<br>
+       "\n"<br>
+       "        If a rounding option is given, it determines the rounding behavior at 0.5.\n"<br>
+       ;<br>
+<br>
+struct func_options;<br>
+<br>
+typedef uint16_t<br>
+(*pack_1x16_func_t)(float, struct func_options*);<br>
+<br>
+typedef void<br>
+(*unpack_1x16_func_t)(uint16_t, float*, struct func_options*);<br>
+<br>
+typedef float<br>
+(*round_func_t)(float);<br>
+<br>
+struct func_options {<br>
+       round_func_t round;<br>
+       bool flush_float16;<br>
+       bool flush_float32;<br>
+};<br>
+<br>
+/**<br>
+ * Flush subnormal 32-bit floating point numbers to ±0.0, preserving the<br>
+ * sign bit.<br>
+ */<br>
+static float<br>
+flush_float32(float f)<br>
+{<br>
+       if (fpclassify(f) == FP_SUBNORMAL) {<br>
+               return copysign(0.0, f);<br>
+       } else {<br>
+               return f;<br>
+       }<br>
+}<br>
+<br>
+/**<br>
+ * Flush subnormal 16-bit floating point numbers to to ±0.0, preserving the<br>
+ * sign bit.<br>
+ */<br>
+static uint16_t<br>
+flush_float16(uint16_t u)<br>
+{<br>
+       if (!(u & 0x7c00)) {<br>
+               return u & 0x8000;<br>
+       } else {<br>
+               return u;<br>
+       }<br>
+}<br>
+<br>
+static float<br>
+clampf(float x, float min, float max)<br>
+{<br>
+       if (x < min)<br>
+               return min;<br>
+       else if (x > max)<br>
+               return max;<br>
+       else<br>
+               return x;<br>
+}<br>
+<br>
+static float<br>
+round_to_nearest(float x)<br>
+{<br>
+       float i;<br>
+       float f;<br>
+<br>
+       f = modff(x, &i);<br>
+<br>
+       if (fabs(f) < 0.5f)<br>
+               return i;<br>
+       else<br>
+               return i + copysignf(1.0f, x);<br>
+}<br>
+<br>
+static float<br>
+round_to_even(float x)<br>
+{<br>
+       float i;<br>
+       float f;<br>
+<br>
+       f = modff(x, &i);<br>
+<br>
+       if (fabs(f) < 0.5f)<br>
+               return i;<br>
+       else if (fabs(f) == 0.5f)<br>
+               return i + fmodf(i, copysignf(2.0f, x));<br>
+       else<br>
+               return i + copysignf(1.0f, x);<br>
+}<br>
+<br>
+static void<br>
+func_options_init(struct func_options *func_opts)<br>
+{<br>
+       memset(func_opts, 0, sizeof(*func_opts));<br>
+}<br>
+<br>
+static uint32_t<br>
+pack_2x16(pack_1x16_func_t pack_1x16,<br>
+         float x, float y,<br>
+         struct func_options *func_opts)<br>
+{<br>
+       uint16_t ux;<br>
+       uint16_t uy;<br>
+<br>
+       if (func_opts->flush_float32) {<br>
+               x = flush_float32(x);<br>
+               y = flush_float32(y);<br>
+       }<br>
+<br>
+       ux = pack_1x16(x, func_opts);<br>
+       uy = pack_1x16(y, func_opts);<br>
+<br>
+       if (func_opts->flush_float16) {<br>
+               ux = flush_float16(ux);<br>
+               uy = flush_float16(uy);<br>
+       }<br>
+<br>
+       return ((uint32_t) uy << 16) | ux;<br>
+}<br>
+<br>
+static void<br>
+unpack_2x16(unpack_1x16_func_t unpack_1x16,<br>
+            uint32_t u,<br>
+            float *x, float *y,<br>
+            struct func_options *func_opts)<br>
+<br>
+{<br>
+        uint16_t ux = u & 0xffff;<br>
+        uint16_t uy = u >> 16;<br>
+<br>
+        if (func_opts->flush_float16) {<br>
+                ux = flush_float16(ux);<br>
+                uy = flush_float16(uy);<br>
+        }<br>
+<br>
+        unpack_1x16(ux, x, func_opts);<br>
+        unpack_1x16(uy, y, func_opts);<br>
+<br>
+        if (func_opts->flush_float32) {<br>
+                *x = flush_float32(*x);<br>
+                *y = flush_float32(*y);<br>
+        }<br>
+}<br>
+<br>
+static uint16_t<br>
+pack_snorm_1x16(float x, struct func_options *func_opts)<br>
+{<br>
+       return (uint16_t) func_opts->round(clampf(x, -1.0f, +1.0f) * 32767.0f);<br>
+}<br>
+<br>
+static void<br>
+unpack_snorm_1x16(uint16_t u, float *f, struct func_options *func_opts)<br>
+{<br>
+        *f = clampf((int16_t) u / 32767.0f, -1.0f, +1.0f);<br>
+}<br>
+<br>
+static uint16_t<br>
+pack_unorm_1x16(float x, struct func_options *func_opts)<br>
+{<br>
+       return (uint16_t) func_opts->round(clampf(x, 0.0f, 1.0f) * 65535.0f);<br>
+}<br>
+<br>
+static void<br>
+unpack_unorm_1x16(uint16_t u, float *f, struct func_options *func_opts)<br>
+{<br>
+        *f = (float) u / 65535.0f;<br>
+}<br>
+<br>
+static uint16_t<br>
+pack_half_1x16(float x, struct func_options *func_opts)<br>
+{<br>
+       /* The bit layout of a float16 is:<br>
+        *   sign: 15<br>
+        *   exponent: 10:14<br>
+        *   mantissa: 0:9<br>
+        *<br>
+        * The sign, exponent, and mantissa of a float16 determine its value<br>
+        * thus:<br>
+        *<br>
+        *  if e = 0 and m = 0, then zero:       (-1)^s * 0<br>
+        *  if e = 0 and m != 0, then subnormal: (-1)^s * 2^(e - 14) * m / 2^10<br>
+        *  if 0 < e < 31, then normal:          (-1)^s * 2^(e - 15) * (1 + m / 2^10)<br>
+        *  if e = 31 and m = 0, then inf:       (-1)^s * inf<br>
+        *  if e = 31 and m != 0, then nan<br>
+        *<br>
+        *  where 0 <= m < 2^10 .<br>
+        */<br>
+<br>
+       /* Calculate the resultant float16's sign, exponent, and mantissa<br>
+        * bits.<br>
+        */<br>
+       const int s = (copysignf(1.0f, x) < 0) ? 1 : 0;<br>
+       int e;<br>
+       int m;<br>
+<br>
+       switch (fpclassify(x)) {<br>
+       case FP_NAN:<br>
+               return 0xffffu;<br>
+       case FP_INFINITE:<br>
+               e = 31;<br>
+               m = 0;<br>
+               break;<br>
+       case FP_SUBNORMAL:<br>
+       case FP_ZERO:<br>
+               e = 0;<br>
+               m = 0;<br>
+               break;<br>
+       case FP_NORMAL: {<br>
+               /* Recall that the form of subnormal and normal float16 values<br>
+                * are<br>
+                *<br>
+                *   subnormal: 2^(e - 14) * m / 2^10 where e = 0<br>
+                *   normal: 2^(e - 15) * (1 + m / 2^10) where 1 <= e <= 30<br>
+                *<br>
+                * where 0 <= m < 2^10. Therefore some key boundary values of<br>
+                * float16 are:<br>
+                *<br>
+                *   min_subnormal = 2^(-14) * 1 / 2^10<br>
+                *   max_subnormal = 2^(-14) * 1023 / 2^10<br>
+                *   min_normal    = 2^(1-15) * (1 + 0 / 2^10)<br>
+                *   max_normal    = 2^(30 - 15) * (1 + 1023 / 2^10)<br>
+                *<br>
+                * Representing the same boundary values in the form returned<br>
+                * by frexpf(), 2^e * f where 0.5 <= f < 1, gives<br>
+                *<br>
+                *   min_subnormal = 2^(-14) * 1 / 2^10<br>
+                *                 = 2^(-23) * 1 / 2<br>
+                *                 = 2^(-23) * 0.5<br>
+                *<br>
+                *   max_subnormal = 2^(-14) * 1023 / 2^10<br>
+                *                 = 2^(-14) * 0.9990234375<br>
+                *<br>
+                *   min_normal    = 2^(1 - 15) * (1 + 0 / 2^10)<br>
+                *                 = 2^(-14)<br>
+                *                 = 2^(-13) * 0.5<br>
+                *<br>
+                *   max_normal    = 2^(30 - 15) * (1 + 1023 / 2^10)<br>
+                *                 = 2^15 * (2^10 + 1023) / 2^10<br>
+                *                 = 2^16 * (2^10 + 1023) / 2^11<br>
+                *                 = 2^16 * 0.99951171875<br>
+                */<br>
+<br>
+               /* Represent the absolute value of the input in form 2^E * F<br>
+                * where 0.5 <= F < 1.<br>
+                */<br>
+               int E;<br>
+               float F;<br>
+<br>
+               F = frexpf(fabs(x), &E);<br>
+<br>
+               /* Now calculate the results's exponent and mantissa by<br>
+                * comparing the input against the boundary values above.<br>
+                */<br>
+               if (E == -23 && F < 0.5f) {<br>
+                       /* The float32 input is too small to be represented as<br>
+                        * a float16. The result is zero.<br>
+                        */<br>
+                       e = 0;<br>
+                       m = 0;<br>
+               } else if (E < -13 || (E == -13 && F < 0.5f)) {<br>
+                       /* The resultant float16 value is subnormal. Let's<br>
+                        * calculate m.<br>
+                        *<br>
+                        *   2^E * F = 2^(-14) * m / 2^10<br>
+                        *         m = 2^(E + 24) * F<br>
+                        */<br>
+                       e = 0;<br>
+                       m = powf(2, E + 24) * F;<br>
+               } else if (E < 16 || (E == 16 && F <= 0.99951171875f)) {<br>
+                       /* The resultant float16 is normal. Let's calculate<br>
+                        * e and m.<br>
+                        *<br>
+                        *   2^E * F = 2^(e - 15) * (1 + m / 2^10)          (1)<br>
+                        *           = 2^(e - 15) * (2^10 + m) / 2^10       (2)<br>
+                        *           = 2^(e - 14) * (2^10 + m) / 2^11       (3)<br>
+                        *<br>
+                        * Substituting<br>
+                        *<br>
+                        *   e1 := E                                        (4)<br>
+                        *   f1 := F                                        (5)<br>
+                        *   e2 := e - 14                                   (6)<br>
+                        *   f2 := (2^10 + m) / 2^11                        (7)<br>
+                        *<br>
+                        * transforms the equation to<br>
+                        *<br>
+                        *   2^e1 * f1 = 2^e2 * f2                          (8)<br>
+                        *<br>
+                        * By definition, f1 lies in the range [0.5, 1). By<br>
+                        * equation 7, f2 lies there also. This observation<br>
+                        * combined with equation 8 implies f1 = f2, which in<br>
+                        * turn implies e1 = e2. Therefore<br>
+                        *<br>
+                        *   e = E + 14<br>
+                        *   m = 2^11 * F - 2^10<br>
+                        */<br>
+                       e = E + 14;<br>
+                       m = powf(2, 11) * F - powf(2, 10);<br>
+               } else {<br>
+                       /* The float32 input is too large to represent as a<br>
+                        * float16. The result is infinite.<br>
+                        */<br>
+                       e = 31;<br>
+                       m = 0;<br>
+               }<br>
+               break;<br>
+       }<br>
+       default:<br>
+               assert(0);<br>
+               break;<br>
+       }<br>
+<br>
+       assert(s == 0 || s == 1);<br>
+       assert(0 <= e && e <= 31);<br>
+       assert(0 <= m && m <= 1023);<br>
+<br>
+       return (s << 15) | (e << 10) | m;<br>
+}<br>
+<br>
+static void<br>
+unpack_half_1x16(uint16_t u, float *f, struct func_options *func_opts)<br>
+{<br>
+       /* The bit layout of a float16 is:<br>
+        *   sign: 15<br>
+        *   exponent: 10:14<br>
+        *   mantissa: 0:9<br>
+        *<br>
+        * The sign, exponent, and mantissa of a float16 determine its value<br>
+        * thus:<br>
+        *<br>
+        *  if e = 0 and m = 0, then zero:       (-1)^s * 0<br>
+        *  if e = 0 and m != 0, then subnormal: (-1)^s * 2^(e - 14) * m / 2^10<br>
+        *  if 0 < e < 31, then normal:          (-1)^s * 2^(e - 15) * (1 + m / 2^10)<br>
+        *  if e = 31 and m = 0, then inf:       (-1)^s * inf<br>
+        *  if e = 31 and m != 0, then nan<br>
+        *<br>
+        *  where 0 <= m < 2^10 .<br>
+        */<br>
+<br>
+       int s = (u >> 15) & 0x1;<br>
+       int e = (u >> 10) & 0x1f;<br>
+       int m = u & 0x3ff;<br>
+<br>
+       float sign = s ? -1 : 1;<br>
+<br>
+       if (e == 0) {<br>
+               *f = sign * pow(2, -24) * m;<br>
+       } else if (1 <= e && e <= 30) {<br>
+               *f = sign * pow(2, e - 15) * (1.0 + m / 1024.0);<br>
+       } else if (e == 31 && m == 0) {<br>
+               *f = sign * INFINITY;<br>
+       } else if (e == 31 && m != 0) {<br>
+               *f = NAN;<br>
+       } else {<br>
+               assert(0);<br>
+       }<br>
+}<br>
+<br>
+struct round_func_key {<br>
+       const char *name;<br>
+       round_func_t func;<br>
+};<br></blockquote><div><br></div><div>Minor nit pick: calling this struct a "key" seems kind of weird, because it actually represents a key/value pair.  The "name" field is the key.  Having said that, I don't have a good recommendation for anything better :)<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+static struct round_func_key round_func_list[] = {<br>
+       {"round_to_even",           round_to_even},<br>
+       {"round_to_nearest",        round_to_nearest},<br>
+       {0,                         0},<br>
+};<br>
+<br>
+struct pack_func_2x16_key {<br>
+       const char *name;<br>
+       pack_1x16_func_t func;<br>
+};<br>
+<br>
+static struct pack_func_2x16_key pack_func_2x16_list[] = {<br>
+       {"packSnorm2x16",           pack_snorm_1x16},<br>
+       {"packUnorm2x16",           pack_unorm_1x16},<br>
+       {"packHalf2x16",            pack_half_1x16},<br>
+       {0,                         0},<br>
+};<br>
+<br>
+struct unpack_2x16_func_key {<br>
+       const char *name;<br>
+       unpack_1x16_func_t func;<br>
+};<br>
+<br>
+static struct unpack_2x16_func_key unpack_2x16_func_list[] = {<br>
+       {"unpackSnorm2x16",         unpack_snorm_1x16},<br>
+       {"unpackUnorm2x16",         unpack_unorm_1x16},<br>
+       {"unpackHalf2x16",          unpack_half_1x16},<br>
+       {0,                         0},<br>
+};<br>
+<br>
+struct pack_2x16_args {<br>
+       pack_1x16_func_t pack_func;<br>
+       float x;<br>
+       float y;<br>
+       struct func_options func_opts;<br>
+};<br>
+<br>
+struct unpack_2x16_args {<br>
+       unpack_1x16_func_t unpack_func;<br>
+       uint32_t u;<br>
+       struct func_options func_opts;<br>
+};<br>
+<br>
+struct args {<br>
+       enum {<br>
+               ARG_HELP,<br>
+               ARG_PACK_2x16,<br>
+               ARG_UNPACK_2x16,<br>
+               ARG_PRINT_FLOAT16_INFO,<br>
+       } tag;<br>
+<br>
+       union {<br>
+               struct pack_2x16_args pack_2x16;<br>
+               struct unpack_2x16_args unpack_2x16;<br>
+       };<br>
+};<br>
+<br>
+static void<br>
+usage_error(const char *fmt, ...)<br>
+{<br>
+       printf("usage error");<br>
+       if (fmt && strcmp(fmt, "") != 0) {<br>
+               va_list va;<br>
+               va_start(va, fmt);<br>
+               printf(": ");<br>
+               vprintf(fmt, va);<br>
+               va_end(va);<br>
+       }<br>
+       printf("\n");<br>
+       printf("for help, call `glsl-packing -h`\n");<br>
+       exit(1);<br>
+}<br>
+<br>
+static void<br>
+parse_func_opts(struct func_options *func_opts,<br>
+                const char *command_name,<br>
+                int argc, char **argv)<br>
+{<br>
+       int i;<br>
+<br>
+       assert(strcmp(command_name, "print-float16-info") != 0);<br>
+<br>
+       func_options_init(func_opts);<br>
+<br>
+       for (i = 0; i < argc; ++i) {<br>
+               const char *arg = argv[i];<br>
+<br>
+               if (strcmp(arg, "flush_float16") == 0) {<br>
+                       /* flush_float16 implies flush_float32. */<br>
+                       func_opts->flush_float16 = true;<br>
+                       func_opts->flush_float32 = true;<br>
+                       continue;<br>
+               } else if (strcmp(arg, "flush_float32") == 0) {<br>
+                       func_opts->flush_float32 = true;<br>
+                       continue;<br>
+               } else {<br>
+                       /* Assume the arg is a rounding options. */<br>
+                       round_func_t round_func = NULL;<br>
+                       int i;<br>
+<br>
+                       for (i = 0; round_func_list[i].name != NULL; ++i) {<br>
+                               if (strcmp(arg, round_func_list[i].name) == 0) {<br>
+                                       round_func = round_func_list[i].func;<br>
+                                       break;<br>
+                               }<br>
+                       }<br></blockquote><div><br></div><div>Considering there are only two possible rounding options, having a for loop to walk an array seems like overkill to me.  Consider just doing this:<br><br></div>
<div>if (strcmp(arg, "round_to_even") == 0)<br></div><div>   round_func = round_to_even;<br>else if (strcmp(arg, "round_to_nearest") == 0)<br></div><div>   round_func = round_to_nearest;<br></div><div>
 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+                       if (round_func) {<br>
+                               if (func_opts->round) {<br>
+                                       usage_error("multiple rounding "<br>
+                                                   "options were given");<br>
+                               }<br>
+<br>
+                               func_opts->round = round_func;<br>
+                               continue;<br>
+                       }<br>
+               }<br>
+<br>
+               usage_error("unrecognized option: %s", arg);<br>
+       }<br>
+<br>
+       if (func_opts->round != NULL<br>
+           && (strncmp(command_name, "packHalf", 8) == 0 ||<br>
+               strncmp(command_name, "unpackHalf", 10) == 0)) {<br>
+          usage_error("Half functions do not accept any rounding options");<br>
+       }<br>
+<br>
+       if (!func_opts->round ) {<br>
+               /* default */<br>
+               func_opts->round = round_to_even;<br>
+       }<br>
+}<br>
+<br>
+static bool<br>
+parse_pack_2x16_args(struct pack_2x16_args *args, int argc, char **argv)<br>
+{<br>
+       int i;<br>
+       char *endptr;<br>
+       const char *func_name = NULL;<br>
+<br>
+       memset(args, 0, sizeof(*args));<br>
+<br>
+       /* Parse function name. */<br>
+       if (argc < 2)<br>
+               return false;<br>
+<br>
+       for (i = 0; (func_name = pack_func_2x16_list[i].name) != NULL; ++i) {<br>
+               if (strcmp(argv[1], func_name) == 0) {<br>
+                       args->pack_func = pack_func_2x16_list[i].func;<br>
+                       break;<br>
+               }<br>
+       }<br></blockquote><div><br></div><div>Similar nit pick here (and in parse_unpack_2x16_args below).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+<br>
+       if (args->pack_func == NULL) {<br>
+               /* Failed to parse function name. */<br>
+               return false;<br>
+       }<br>
+<br>
+       /* Parse inputs to packing function. */<br>
+       if (argc < 4)<br>
+               usage_error("not enough inputs for pack function");<br>
+<br>
+       args->x = strtof(argv[2], &endptr);<br>
+       if (endptr == argv[2])<br>
+               usage_error("unable parse input to pack function: %s", argv[2]);<br></blockquote><div><br></div><div>This permits extra garbage after the argument.  I'd recommend instead doing:<br><br></div>
<div>if (*endptr != '\0')<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+       args->y = strtof(argv[3], &endptr);<br>
+       if (endptr == argv[3])<br>
+               usage_error("unable parse input to pack function: %s", argv[3]);<br>
+<br>
+       parse_func_opts(&args->func_opts, func_name, argc - 4, argv + 4);<br>
+       return true;<br>
+}<br>
+<br>
+static bool<br>
+parse_unpack_2x16_args(struct unpack_2x16_args *args, int argc, char **argv)<br>
+{<br>
+       int i;<br>
+        const char *func_name = NULL;<br>
+<br>
+       memset(args, 0, sizeof(*args));<br>
+<br>
+       /* Parse function name. */<br>
+       if (argc < 2)<br>
+               return false;<br>
+<br>
+       for (i = 0; (func_name = unpack_2x16_func_list[i].name) != NULL; ++i) {<br>
+               if (strcmp(argv[1], func_name) == 0) {<br>
+                       args->unpack_func = unpack_2x16_func_list[i].func;<br>
+                       break;<br>
+               }<br>
+       }<br>
+<br>
+       if (args->unpack_func == NULL) {<br>
+               /* Failed to parse function name. */<br>
+               return false;<br>
+       }<br>
+<br>
+       /* Parse inputs to unpacking function. */<br>
+       if (argc < 3)<br>
+               usage_error("not enough inputs for unpack function");<br>
+       if (sscanf(argv[2],"%u", &args->u) != 1)<br>
+               usage_error("unable to parse input to unpack function: %s", argv[2]);<br>
+<br>
+       parse_func_opts(&args->func_opts, func_name, argc - 3, argv + 3);<br>
+       return true;<br>
+}<br>
+<br>
+static void<br>
+parse_args(struct args *args, int argc, char **argv)<br>
+{<br>
+       memset(args, 0, sizeof(*args));<br>
+<br>
+       if (argc < 2) {<br>
+               usage_error("no command was given");<br>
+       }<br>
+<br>
+       if (strcmp(argv[1], "-h") == 0 ||<br>
+           strcmp(argv[1], "--help") == 0) {<br>
+          args->tag = ARG_HELP;<br>
+          return;<br>
+       }<br>
+<br>
+       if (parse_pack_2x16_args(&args->pack_2x16, argc, argv)) {<br>
+               args->tag = ARG_PACK_2x16;<br>
+               return;<br>
+       }<br>
+<br>
+       if (parse_unpack_2x16_args(&args->unpack_2x16, argc, argv)) {<br>
+               args->tag = ARG_UNPACK_2x16;<br>
+               return;<br>
+       }<br>
+<br>
+       if (strcmp(argv[1], "print-float16-info") == 0) {<br>
+               if (argc > 2) {<br>
+                       usage_error("print-float16-info takes no args");<br>
+               }<br>
+               args->tag = ARG_PRINT_FLOAT16_INFO;<br>
+               return;<br>
+       };<br>
+<br>
+       usage_error("unrecognized command: %s", argv[1]);<br>
+}<br>
+<br>
+static void<br>
+cmd_pack_2x16(struct pack_2x16_args *args)<br>
+{<br>
+       uint32_t u = pack_2x16(args->pack_func,<br>
+                              args->x, args->y,<br>
+                              &args->func_opts);<br>
+       printf("%u\n", u);<br>
+}<br>
+<br>
+static void<br>
+cmd_unpack_2x16(struct unpack_2x16_args *args)<br>
+{<br>
+       float x;<br>
+       float y;<br>
+<br>
+       unpack_2x16(args->unpack_func,<br>
+                   args->u, &x, &y,<br>
+                   &args->func_opts);<br>
+       printf(PRIf32 " " PRIf32 "\n", x, y);<br>
+}<br>
+<br>
+static void<br>
+print_float16_value(const char *name, int e, int m)<br>
+{<br>
+       struct func_options func_opts;<br>
+       int s = 0;<br>
+       float f;<br>
+<br>
+       func_options_init(&func_opts);<br>
+       unpack_half_1x16((s << 15) | (e << 10) | m, &f, &func_opts);<br>
+       printf("%s: " PRIf32 "\n", name, f);<br>
+<br>
+}<br>
+<br>
+static void<br>
+print_float16_step(const char *name, int exp)<br>
+{<br>
+       printf("%s: " PRIf32 "\n", name, powf(2, exp));<br>
+}<br>
+<br>
+static void<br>
+cmd_print_float16_info(void)<br>
+{<br>
+       print_float16_value("subnormal_min", 0, 1);<br>
+       print_float16_value("subnormal_max", 0, 1023);<br>
+       print_float16_value("normal_min", 1, 0);<br>
+       print_float16_value("normal_max", 30, 1023);<br>
+       print_float16_step("min_step", -14 - 10);<br>
+       print_float16_step("max_step", 15 - 10);<br>
+}<br>
+<br>
+static void<br>
+exec_args(struct args *args)<br>
+{<br>
+       switch (args->tag) {<br>
+       case ARG_HELP:<br>
+               printf("%s", help_text);<br>
+               break;<br>
+       case ARG_PACK_2x16:<br>
+               cmd_pack_2x16(&args->pack_2x16);<br>
+               break;<br>
+       case ARG_UNPACK_2x16:<br>
+               cmd_unpack_2x16(&args->unpack_2x16);<br>
+               break;<br>
+       case ARG_PRINT_FLOAT16_INFO:<br>
+               cmd_print_float16_info();<br>
+               break;<br>
+       default:<br>
+               assert(0);<br>
+               break;<br>
+       }<br>
+}<br></blockquote><div><br></div><div>The separation between parse_args and exec_args seems artificial to me.  My preference would be to fuse these into one function, so that we don't need struct args (with its union) to carry data between them.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+int<br>
+main(int argc, char **argv)<br>
+{<br>
+       struct args args;<br>
+<br>
+       parse_args(&args, argc, argv);<br>
+       exec_args(&args);<br>
+<br>
+       return 0;<br>
+}<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.1<br>
<br>
_______________________________________________<br>
Piglit mailing list<br>
<a href="mailto:Piglit@lists.freedesktop.org">Piglit@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/piglit" target="_blank">http://lists.freedesktop.org/mailman/listinfo/piglit</a><br>
</font></span></blockquote></div><br></div><div class="gmail_extra">A lot of my comments on this patch have been nit-picks--the rounding stuff I spoke about yesterday is the only thing I think is critical to fix.<br></div>
</div>