[Piglit] [PATCH 2/2] glsl-es-3.00: Generate tests for builtin packing functions
Chad Versace
chad.versace at linux.intel.com
Wed Jan 9 23:58:04 PST 2013
for stage in const vs fs:
for d in pack unpack:
for type in Snorm Unorm Half:
generate ${stage}-${d}${type}2x16.shader_test
The tests are generated by a new Python script,
gen_builtin_packing_tests.py, and placed into directory
spec/glsl-es-3.00/execution/built-in-functions.
Signed-off-by: Chad Versace <chad.versace at linux.intel.com>
---
generated_tests/CMakeLists.txt | 7 +-
generated_tests/gen_builtin_packing_tests.py | 899 +++++++++++++++++++++++++++
tests/util/glsl-packing.c | 18 +-
3 files changed, 912 insertions(+), 12 deletions(-)
create mode 100644 generated_tests/gen_builtin_packing_tests.py
diff --git a/generated_tests/CMakeLists.txt b/generated_tests/CMakeLists.txt
index e371ff8..3ee6d56 100644
--- a/generated_tests/CMakeLists.txt
+++ b/generated_tests/CMakeLists.txt
@@ -20,6 +20,10 @@ endfunction(piglit_make_generated_tests custom_target generator_script)
# Create custom commands and targets to build generated tests.
piglit_make_generated_tests(
+ builtin_packing_tests.list
+ gen_builtin_packing_tests.py
+ glsl-packing)
+piglit_make_generated_tests(
builtin_uniform_tests.list
gen_builtin_uniform_tests.py
builtin_function.py)
@@ -49,7 +53,8 @@ piglit_make_generated_tests(
# Add a "gen-tests" target that can be used to generate all the
# tests without doing any other compilation.
add_custom_target(gen-tests ALL
- DEPENDS builtin_uniform_tests.list
+ DEPENDS builtin_packing_tests.list
+ builtin_uniform_tests.list
constant_array_size_tests.list
interpolation_tests.list
non-lvalue_tests.list
diff --git a/generated_tests/gen_builtin_packing_tests.py b/generated_tests/gen_builtin_packing_tests.py
new file mode 100644
index 0000000..1711685
--- /dev/null
+++ b/generated_tests/gen_builtin_packing_tests.py
@@ -0,0 +1,899 @@
+#!/usr/bin/env python2
+
+import mako.template
+import mako.runtime
+import math
+import optparse
+import os
+import sys
+import textwrap as tw
+
+from collections import namedtuple
+from mako.template import Template
+from subprocess import check_output
+
+# ----------------------------------------------------------------------------
+# Overview
+# ----------------------------------------------------------------------------
+
+# This scripts generates tests for the GLSL packing functions, such as
+# packSnorm2x16.
+
+# Given an input and a packing/unpacking function, there exist multiple
+# possible outputs. The actual output is dependent on the GLSL compiler's and
+# hardware's choice of rounding mode (to even or to nearest) and handling of
+# subnormal (also called denormalized) floating point numbers. In each
+# generated test, the function's actual output is compared against
+# a reasonable subset set of possible outputs.
+
+# For details on how the expected outputs are calculated, see the source of the
+# glsl-packing tool.
+
+# ----------------------------------------------------------------------------
+# Templates
+# ----------------------------------------------------------------------------
+
+# Test evaluation of constant pack2x16 expressions.
+const_pack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ in vec4 vertex;
+ out vec4 vert_color;
+
+ void main()
+ {
+ ${func.return_precision} uint actual;
+
+ gl_Position = vertex;
+
+ % for io in func.inouts:
+ actual = ${func.name}(vec2(${io.input[0]},
+ ${io.input[1]}));
+
+ if (true
+ % for u in io.possible_outputs:
+ && actual != ${u}
+ % endfor
+ ) {
+ vert_color = red;
+ return;
+ }
+
+ % endfor
+
+ vert_color = green;
+ }
+
+ [fragment shader]
+ in vec4 vert_color;
+ out vec4 frag_color;
+
+ void main()
+ {
+ frag_color = vert_color;
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+"""))
+
+# Test evaluation of constant unpack2x16 expressions.
+const_unpack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ in vec4 vertex;
+ out vec4 vert_color;
+
+ void main()
+ {
+ ${func.return_precision} vec2 actual;
+
+ gl_Position = vertex;
+
+ % for io in func.inouts:
+ actual = ${func.name}(${io.input});
+
+ if (true
+ % for v in io.possible_outputs:
+ && actual != vec2(${v[0]}, ${v[1]})
+ % endfor
+ ) {
+ vert_color = red;
+ return;
+ }
+
+ % endfor
+
+ vert_color = green;
+ }
+
+ [fragment shader]
+ in vec4 vert_color;
+ out vec4 frag_color;
+
+ void main()
+ {
+ frag_color = vert_color;
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+"""))
+
+# Test execution of pack2x16 functions in the vertex shader.
+vs_pack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ uniform vec2 func_input;
+
+ % for j in range(func.num_possible_outputs):
+ uniform ${func.return_precision} uint expect${j};
+ % endfor
+
+ in vec4 vertex;
+ out vec4 vert_color;
+
+ void main()
+ {
+ gl_Position = vertex;
+ ${func.return_precision} uint actual = ${func.name}(func_input);
+
+ if (false
+ % for j in range(func.num_possible_outputs):
+ || actual == expect${j}
+ % endfor
+ ) {
+ vert_color = green;
+ } else {
+ vert_color = red;
+ }
+ }
+
+ [fragment shader]
+ in vec4 vert_color;
+ out vec4 frag_color;
+
+ void main()
+ {
+ frag_color = vert_color;
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ % for io in func.inouts:
+ uniform vec2 func_input ${io.input[0]} ${io.input[1]}
+ % for j in range(func.num_possible_outputs):
+ uniform uint expect${j} ${io.possible_outputs[j]}
+ % endfor
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+
+ % endfor
+"""))
+
+# Test execution of unpack2x16 functions in the vertex shader.
+vs_unpack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ uniform highp uint func_input;
+
+ % for j in range(func.num_possible_outputs):
+ uniform ${func.return_precision} vec2 expect${j};
+ % endfor
+
+ in vec4 vertex;
+ out vec4 vert_color;
+
+ void main()
+ {
+ gl_Position = vertex;
+
+ ${func.return_precision} vec2 actual = ${func.name}(func_input);
+
+ if (false
+ % for j in range(func.num_possible_outputs):
+ || actual == expect${j}
+ % endfor
+ ) {
+ vert_color = green;
+ } else {
+ vert_color = red;
+ }
+ }
+
+ [fragment shader]
+ in vec4 vert_color;
+ out vec4 frag_color;
+
+ void main()
+ {
+ frag_color = vert_color;
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ % for io in func.inouts:
+ uniform uint func_input ${io.input}
+ % for j in range(func.num_possible_outputs):
+ uniform vec2 expect${j} ${io.possible_outputs[j][0]} ${io.possible_outputs[j][1]}
+ % endfor
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+
+ % endfor
+"""))
+
+
+# Test execution of pack2x16 functions in the fragment shader.
+fs_pack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ in vec4 vertex;
+
+ void main()
+ {
+ gl_Position = vertex;
+ }
+
+ [fragment shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ uniform vec2 func_input;
+
+ % for i in range(func.num_possible_outputs):
+ uniform ${func.return_precision} uint expect${i};
+ % endfor
+
+ out vec4 frag_color;
+
+ void main()
+ {
+ ${func.return_precision} uint actual = ${func.name}(func_input);
+
+ if (false
+ % for i in range(func.num_possible_outputs):
+ || actual == expect${i}
+ % endfor
+ ) {
+ frag_color = green;
+ } else {
+ frag_color = red;
+ }
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ % for io in func.inouts:
+ uniform vec2 func_input ${io.input[0]} ${io.input[1]}
+ % for i in range(func.num_possible_outputs):
+ uniform uint expect${i} ${io.possible_outputs[i]}
+ % endfor
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+
+ % endfor
+"""))
+
+# Test execution of unpack2x16 functions in the fragment shader.
+fs_unpack_2x16_template = Template(tw.dedent("""\
+ [require]
+ GL >= 3.0 es
+ GLSL >= 3.00 es
+
+ [vertex shader]
+ in vec4 vertex;
+
+ void main()
+ {
+ gl_Position = vertex;
+ }
+
+ [fragment shader]
+ const vec4 red = vec4(1, 0, 0, 1);
+ const vec4 green = vec4(0, 1, 0, 1);
+
+ uniform highp uint func_input;
+
+ % for i in range(func.num_possible_outputs):
+ uniform ${func.return_precision} vec2 expect${i};
+ % endfor
+
+ out vec4 frag_color;
+
+ void main()
+ {
+ ${func.return_precision} vec2 actual = ${func.name}(func_input);
+
+ if (false
+ % for i in range(func.num_possible_outputs):
+ || actual == expect${i}
+ % endfor
+ ) {
+ frag_color = green;
+ } else {
+ frag_color = red;
+ }
+ }
+
+ [vertex data]
+ vertex/float/2
+ -1.0 -1.0
+ 1.0 -1.0
+ 1.0 1.0
+ -1.0 1.0
+
+ [test]
+ % for io in func.inouts:
+ uniform uint func_input ${io.input}
+ % for i in range(func.num_possible_outputs):
+ uniform vec2 expect${i} ${io.possible_outputs[i][0]} ${io.possible_outputs[i][1]}
+ % endfor
+ draw arrays GL_TRIANGLE_FAN 0 4
+ probe all rgba 0.0 1.0 0.0 1.0
+
+ % endfor
+"""))
+
+template_table = {
+ ("const", "p", "2x16") : const_pack_2x16_template,
+ ("const", "u", "2x16") : const_unpack_2x16_template,
+ ("vs", "p", "2x16") : vs_pack_2x16_template,
+ ("vs", "u", "2x16") : vs_unpack_2x16_template,
+ ("fs", "p", "2x16") : fs_pack_2x16_template,
+ ("fs", "u", "2x16") : fs_unpack_2x16_template,
+}
+
+# ----------------------------------------------------------------------------
+# Function inputs and expected outputs
+# ----------------------------------------------------------------------------
+
+inout_tuple = namedtuple("inout_tuple", ("input", "possible_outputs"))
+
+glsl_packing_exe_path = None
+
+def set_glsl_packing_exe_path():
+ global glsl_packing_exe_path
+
+ if glsl_packing_exe_path is not None:
+ return glsl_packing_exe_path
+
+ if "PIGLIT_BUILD_DIR" in os.environ:
+ piglit_build_dir = os.path.join(os.environ["PIGLIT_BUILD_DIR"])
+ else:
+ piglit_build_dir = os.path.join(os.path.dirname(__file__), os.pardir)
+
+ glsl_packing_exe_path = os.path.join(piglit_build_dir,
+ "bin",
+ "glsl-packing")
+
+ if not os.path.exists(glsl_packing_exe_path):
+ print(("error: file {0!r} does not exist. maybe you forgot to " + \
+ "build it or forgot to define environment var " + \
+ "PIGLIT_BUILD_DIR.").format(glsl_packing_exe_path))
+ sys.exit(1)
+
+ return glsl_packing_exe_path
+
+def glsl_literal(x):
+ """Represent x as a string suitable as a GLSL literal.
+
+ x must be an int or float.
+
+ If x is an integer, then it is assumed to be unsigned 32-bit integer. For
+ example, glsl_literal(1) returns "1u" and glsl_literal(-1) returns
+ "0xffffffffu".
+ """
+ if type(x) == int:
+ # The packing functions are concerned only with unsigned integers.
+ return "{0}u".format(x % 2**32)
+ elif type(x) == float:
+ if math.isnan(x):
+ # GLSL ES 3.00 and GLSL 4.10 do not require implementations to
+ # support NaN, so we do not test it.
+ assert(False)
+ elif math.isinf(x):
+ # GLSL ES 3.00 lacks a literal for infinity. However, a literal
+ # value which is too large to stored as a float will be converted to
+ # infintiy. From page 31 of the GLSL ES 3.00 spec:
+ #
+ # If the value of the floating point number is too large (small)
+ # to be stored as a single precision value, it is converted to
+ # positive (negative) infinity.
+ #
+ return repr(math.copysign(1.0e256, x))
+ else:
+ return repr(x)
+ else:
+ assert(False)
+
+class PackUnpackFunc(object):
+
+ def __init__(self, name, dimension):
+ assert(dimension in ["2x16", "4x8"])
+
+ self.__name = name
+ self.__dimension = dimension
+
+ @property
+ def name(self):
+ return self.__name
+
+ @property
+ def dimension(self):
+ return self.__dimension
+
+ @property
+ def num_possible_outputs(self):
+ return len(self.inouts[0])
+
+class Pack2x16Func(PackUnpackFunc):
+
+ def __init__(self, name):
+ PackUnpackFunc.__init__(self, name=name, dimension="2x16")
+ self.__inouts = None
+
+ @property
+ def return_precision(self):
+ return "highp"
+
+ @property
+ def inouts(self):
+ if self.__inouts is not None:
+ return self.__inouts
+
+ def get_expected_output(x, y, func_opts):
+ args = [glsl_packing_exe_path, self.name, repr(x), repr(y)]
+ args.extend(func_opts)
+ return glsl_literal(int(check_output(args)))
+
+ self.__inouts = []
+
+ for y in self.float_inputs:
+ yl = glsl_literal(y)
+
+ for x in self.float_inputs:
+ xl = glsl_literal(x)
+ input = (xl, yl)
+
+ possible_outputs = []
+ for func_opts in self.func_opts_seq:
+ possible_outputs.append(get_expected_output(x, y, func_opts))
+
+ self.__inouts.append(
+ inout_tuple(
+ input=(xl, yl),
+ possible_outputs=possible_outputs))
+
+ return self.__inouts
+
+class Unpack2x16Func(PackUnpackFunc):
+
+ def __init__(self, name, return_precision):
+ PackUnpackFunc.__init__(self, name=name, dimension="2x16")
+ self.__return_precision = return_precision
+ self.__inouts = None
+
+ @property
+ def return_precision(self):
+ return self.__return_precision
+
+ @property
+ def func_opts_seq(self):
+ return ((),
+ ("flush_float16",),
+ ("flush_float32",))
+
+ @property
+ def inouts(self):
+ if self.__inouts is not None:
+ return self.__inouts
+
+ def get_expected_output(uint32, func_opts):
+ args = [glsl_packing_exe_path, self.name, repr(uint32)]
+ args.extend(func_opts)
+ out = check_output(args)
+ vec2 = out.strip().split()
+ return (glsl_literal(float(vec2[0])),
+ glsl_literal(float(vec2[1])))
+
+ self.__inouts = []
+
+ for y in self.uint16_inputs:
+ for x in self.uint16_inputs:
+ uint32 = (y << 16) | x
+
+ possible_outputs = []
+ for func_opts in self.func_opts_seq:
+ possible_outputs.append(get_expected_output(uint32, func_opts))
+
+ self.__inouts.append(
+ inout_tuple(
+ input=glsl_literal(uint32),
+ possible_outputs=possible_outputs))
+
+ return self.__inouts
+
+class PackSnorm2x16Func(Pack2x16Func):
+
+ def __init__(self):
+ Pack2x16Func.__init__(self, name="packSnorm2x16")
+ self.__float_inputs = None
+
+ @property
+ def func_opts_seq(self):
+ return (("round_to_even",),
+ ("round_to_even", "flush_float16"),
+ ("round_to_even", "flush_float32"),
+ ("round_to_nearest",),
+ ("round_to_nearest", "flush_float16"),
+ ("round_to_nearest", "flush_float32"))
+ @property
+ def float_inputs(self):
+ if self.__float_inputs is not None:
+ return self.__float_inputs
+
+ # The domain of packSnorm2x16 is [-inf, +inf]^2, yet the function clamps
+ # its input to range [-1, +1]^2.
+ #
+ # Below are listed important classes in the function's domain, and test
+ # inputs chosen from each class.
+ # - zero: -0.0, 0.0
+ # - near zero: -0.1, 0.1
+ # - just inside the clamp range: -0.9, 0.9
+ # - on the clamp boundary: -1.0, 1.0
+ # - just outside the clamp range: -1.1, 1.1
+ # - infinity: -inf, +inf
+ #
+ # We test -0.0 in order to stress the implementation's handling of zero.
+ # The implementation should return a uint16_t that encodes -0.0; that is,
+ # with the sign bit set.
+
+ pos_floats = (0.0, 0.1, 0.9, 1.0, 1.1, float("+inf"))
+ neg_floats = tuple(reversed(tuple((-x for x in pos_floats))))
+ all_floats = pos_floats + neg_floats
+
+ self.__float_inputs = all_floats
+ return self.__float_inputs
+
+class UnpackSnorm2x16Func(Unpack2x16Func):
+
+ def __init__(self):
+ Unpack2x16Func.__init__(
+ self,
+ name="unpackSnorm2x16",
+ return_precision="highp")
+
+ @property
+ def uint16_inputs(self):
+ return (0, 1, 2, 3,
+ 2**15 - 1,
+ 2**15,
+ 2**15 + 1,
+ 2**16 - 1, # max uint16
+ )
+
+class PackUnorm2x16Func(Pack2x16Func):
+
+ def __init__(self):
+ Pack2x16Func.__init__(self, name="packUnorm2x16")
+
+ @property
+ def func_opts_seq(self):
+ return (("round_to_even",),
+ ("round_to_even", "flush_float16"),
+ ("round_to_even", "flush_float32"),
+ ("round_to_nearest",),
+ ("round_to_nearest", "flush_float16"),
+ ("round_to_nearest", "flush_float32"))
+
+ @property
+ def float_inputs(self):
+
+ # The domain of packUnorm2x16 is [-inf, +inf]^2, yet the function clamps
+ # its input to range [0, 1]^2.
+ #
+ # Below are listed important classes in the function's domain, and test
+ # inputs chosen from each class.
+ # - zero: -0.0, 0.0
+ # - just inside the clamp range: 0.1, 0.9
+ # - on the clamp boundary: 0.0, 1.0
+ # - just outside the clamp range: -0.1, 1.1
+ # - infinity: -inf, +inf
+ #
+ # We test -0.0 in order to stress the implementation's handling of zero.
+ # The implementation should return a uint16_t that encodes +0.0; that is,
+ # without the sign bit set.
+
+ return (float("-inf"),
+ -0.1, -0.0,
+ +0.0, 0.1, 0.9, 1.0, 1.1,
+ float("+inf"))
+
+class UnpackUnorm2x16Func(Unpack2x16Func):
+
+ def __init__(self):
+ Unpack2x16Func.__init__(
+ self,
+ name="unpackUnorm2x16",
+ return_precision="highp")
+
+ @property
+ def uint16_inputs(self):
+ return (0, 1, 2, 3,
+ 2**15 - 1,
+ 2**15,
+ 2**15 + 1,
+ 2**16 - 1, # max uint16
+ )
+
+class PackHalf2x16Func(Pack2x16Func):
+
+ def __init__(self):
+ Pack2x16Func.__init__(self, name="packHalf2x16")
+ self.__float_inputs = None
+
+ @property
+ def func_opts_seq(self):
+ return ((),
+ ("flush_float16",),
+ ("flush_float32",))
+
+ @property
+ def float_inputs(self):
+ if self.__float_inputs is not None:
+ return self.__float_inputs
+
+ # The domain of packHalf2x16 is ([-inf, +inf] + {NaN})^2 and the function
+ # does not clamp its input.
+ #
+ # For the min and max value of the two classes of float16 values,
+ # subnormal and normalized, choose the following test inputs:
+ # - slightly below the minmax
+ # - the exact minmax value
+ # - slightly above the minmax
+ #
+ # We also test -0.0 and +0.0 in order to stress the implementation's
+ # handling of zero.
+
+ # Get info from `glsl-packing print-float16-info`.
+ info = dict()
+ output = check_output([glsl_packing_exe_path, "print-float16-info"])
+ output = output.rstrip() # Remove trailing newline
+ lines = output.split("\n")
+ for line in lines:
+ s = line.split(":")
+ name = s[0]
+ value = s[1]
+ info[name] = float(value)
+
+ subnormal_min = info["subnormal_min"]
+ subnormal_max = info["subnormal_max"]
+ normal_min = info["normal_min"]
+ normal_max = info["normal_max"]
+ min_step = info["min_step"]
+ max_step = info["max_step"]
+
+ pos_floats = (
+ # for x = 0;
+ # x <= normal_min + min_step
+ # x += min_step
+ 0.0,
+ subnormal_min,
+ subnormal_min + 1.0 * min_step,
+
+ # for x = subnormal_max - min_step
+ # x <= normal_min + min_step
+ # x += min_step
+ subnormal_max - 1.0 * min_step,
+ subnormal_max,
+ normal_min,
+ normal_min + 1.0 * min_step,
+
+ # for x = normal_max - max_step
+ # x <= normal_max + max_step
+ # x += max_step
+ normal_max - 1.0 * max_step,
+ normal_max,
+ normal_max + 1.0 * max_step,
+
+ float("inf"),
+ )
+ neg_floats = tuple(reversed(tuple((-x for x in pos_floats))))
+ all_floats = neg_floats + pos_floats
+
+ self.__float_inputs = all_floats
+ return self.__float_inputs
+
+class UnpackHalf2x16Func(Unpack2x16Func):
+
+ def __init__(self):
+ Unpack2x16Func.__init__(
+ self,
+ name="unpackHalf2x16",
+ return_precision="mediump")
+
+ self.__uint16_inputs = None
+
+ @property
+ def uint16_inputs(self):
+ if self.__uint16_inputs is not None:
+ return self.__uint16_inputs
+
+ # Encode a float16 with the given sign, exponent, and mantissa bits into
+ # a uint16.
+ def float16(s, e, m):
+ return (s << 15) | (e << 10) | m
+
+ # For each of the two classes of float16 values, subnormal and normalized,
+ # below are listed the exponent and mantissa of the class's maximum and
+ # minimum values and of some values slightly inside the bounds.
+ bounds = (
+ ( 0, 0), # zero
+
+ ( 0, 1), # subnormal_min
+ ( 0, 2), # subnormal_min + subnormal_step
+
+ ( 0, 1022), # subnormal_max - subnormal_step
+ ( 0, 1023), # subnormal_max
+
+ ( 1, 0), # normal_min
+ ( 1, 1), # normal_min + normal_min_step
+
+ (30, 1022), # normal_max - normal_max_step
+ (30, 1023), # normal_max
+
+ (31, 0), # inf
+ )
+
+ pos_float16 = tuple(float16(0, e, m) for (e, m) in bounds)
+ neg_float16 = tuple(float16(1, e, m) for (e, m) in reversed(bounds))
+ all_float16 = neg_float16 + pos_float16
+
+ self.__uint16_inputs = all_float16
+ return self.__uint16_inputs
+
+class Test(object):
+
+ def __init__(self, func, execution_stage):
+ assert(isinstance(func, PackUnpackFunc))
+ assert(execution_stage in ("const", "vs", "fs"))
+
+ self.__template = template_table[(execution_stage,
+ func.name[0],
+ func.dimension)]
+ self.__func = func
+ self.__filename = os.path.join(
+ "spec",
+ "glsl-es-3.00",
+ "execution",
+ "built-in-functions",
+ "{0}-{1}.shader_test"\
+ .format(execution_stage, func.name))
+
+ @property
+ def filename(self):
+ return self.__filename
+
+ def write_file(self):
+ dirname = os.path.dirname(self.filename)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
+ with open(self.filename, "w") as buffer:
+ ctx = mako.runtime.Context(buffer, func=self.__func)
+ self.__template.render_context(ctx)
+
+def all_tests_iter():
+ # Format these master lists as one item per line. This allows one to
+ # easily debug by commenting out individual items.
+
+ func_classes = (
+ PackSnorm2x16Func,
+ PackUnorm2x16Func,
+ PackHalf2x16Func,
+ UnpackSnorm2x16Func,
+ UnpackUnorm2x16Func,
+ UnpackHalf2x16Func,
+ )
+
+ execution_stages = (
+ "const",
+ "vs",
+ "fs",
+ )
+
+ for stage in execution_stages:
+ for func in func_classes:
+ yield Test(func(), stage)
+
+def main():
+ set_glsl_packing_exe_path()
+
+ parser = optparse.OptionParser(
+ description="Generate shader tests that test the built-in " + \
+ "packing functions",
+ usage="usage: %prog [-h] [--names-only]")
+ parser.add_option(
+ '--names-only',
+ dest='names_only',
+ action='store_true',
+ help="Don't output files, just generate a list of filenames to stdout")
+
+ (options, args) = parser.parse_args()
+
+ if len(args) != 0:
+ # User gave extra args.
+ parser.print_help()
+ sys.exit(1)
+
+ for test in all_tests_iter():
+ print(test.filename)
+ sys.stdout.flush()
+
+ if not options.names_only:
+ test.write_file()
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/util/glsl-packing.c b/tests/util/glsl-packing.c
index 317f0d1..d02610a 100644
--- a/tests/util/glsl-packing.c
+++ b/tests/util/glsl-packing.c
@@ -30,10 +30,6 @@
#include <stdlib.h>
#include <string.h>
-/* TODO: Reject round options for pack/unpackHalf.
- * TODO: Discuss choices in packHalf.
- */
-
#define PRIf32_PRECISION "24"
#define PRIf32 "%." PRIf32_PRECISION "f"
@@ -82,7 +78,7 @@ static const char *help_text =
"FUNC_OPTS\n"
" flush_float16\n"
" flush_float32\n"
- " All PACK_FUNC and UNPACK_FUNC commands accept the flush options.\n"
+ " All PACK_FUNC and UNPACK_FUNC commands accept a flush mode.\n"
"\n"
" The GLSL ES 3.00 and GLSL 4.10 specs allows implementations to truncate\n"
" subnormal floats to zero. From section 4.5.1 \"Range and Precision\"\n"
@@ -99,8 +95,8 @@ static const char *help_text =
"\n"
" round_to_nearest\n"
" round_to_even\n"
- " All PACK_FUNC and UNPACK_FUNC commands except pack/unpackHalf2x16 accept\n"
- " the rounding option. At most one rounding option may be specified.\n"
+ " Only packSnorm and packUnorm commands accept a rounding mode. At most one\n"
+ " most one rounding mode may be specified.\n"
"\n"
" For some packing functions, the GLSL ES 3.00 specification's\n"
" definition of the function's behavior involves the `round()`\n"
@@ -591,10 +587,10 @@ parse_func_opts(struct func_options *func_opts,
usage_error("unrecognized option: %s", arg);
}
- if (func_opts->round != NULL
- && (strncmp(command_name, "packHalf", 8) == 0 ||
- strncmp(command_name, "unpackHalf", 10) == 0)) {
- usage_error("Half functions do not accept any rounding options");
+ if (func_opts->round != NULL &&
+ strncmp(command_name, "packSnorm", 9) != 0 &&
+ strncmp(command_name, "packUnorm", 9) != 0) {
+ usage_error("only packSnorm and packUnom accept a rounding mode");
}
if (!func_opts->round ) {
--
1.8.1
More information about the Piglit
mailing list