summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2021-02-13 15:27:11 -0800
committerIan Romanick <ian.d.romanick@intel.com>2021-03-02 11:44:25 -0800
commit6d824ddb3a5c53c63372d8b5569ff9b527541551 (patch)
tree25662e44efee38bd732a558cecf6e03c95d0f634
parent1427b339399ff5f767c2c7de71da5adc022b76b6 (diff)
spec/glsl-1.20: Use min and max with NaN
In IEEE-754 and OpenCL, min and max with a single NaN parameter are required to return the other paramter. GLSL does not have this requirement, but numerous applications depend on this behavior. These tests try to exercise this behavior in a way that should be compatible GLSL implementations that cannot produce NaN or Inf. Reproduces the failure in mesa#4254. Part-of: <https://gitlab.freedesktop.org/mesa/piglit/-/merge_requests/475>
-rw-r--r--tests/spec/glsl-1.20/execution/fs-nan-builtin-max.shader_test87
-rw-r--r--tests/spec/glsl-1.20/execution/fs-nan-builtin-min.shader_test87
-rw-r--r--tests/spec/glsl-1.20/execution/vs-nan-builtin-max.shader_test89
-rw-r--r--tests/spec/glsl-1.20/execution/vs-nan-builtin-min.shader_test89
4 files changed, 352 insertions, 0 deletions
diff --git a/tests/spec/glsl-1.20/execution/fs-nan-builtin-max.shader_test b/tests/spec/glsl-1.20/execution/fs-nan-builtin-max.shader_test
new file mode 100644
index 000000000..146d56e44
--- /dev/null
+++ b/tests/spec/glsl-1.20/execution/fs-nan-builtin-max.shader_test
@@ -0,0 +1,87 @@
+# Verify that max(x, NaN) always returns x. This is *not* required by the
+# GLSL spec, but many applications depend on it.
+
+[require]
+GLSL >= 1.20
+
+[vertex shader]
+
+varying vec2 idx;
+
+void main()
+{
+ gl_Position = gl_Vertex;
+ /* Produce a value on the ragne [0, 3]. */
+ idx = abs(gl_Vertex.xy) + 2.0;
+}
+
+[fragment shader]
+#define FLT_MAX 3.40282347E+38
+
+varying vec2 idx;
+
+/* Values are packed into an array that is accessed in clever ways to avoid
+ * compiler optimizations that try to "constant propagate" uniforms at draw
+ * time.
+ */
+uniform float data[14] = float[](
+ 3.0, 3.0, 3.0, 3.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0,
+ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
+);
+
+void main()
+{
+ /* Pick an element from data that must be a number. This is crafted so
+ * that number_a and number_b are the same value, but hopefully the
+ * compiler won't be able to detect that.
+ */
+ float number_a = data[int(idx.x)];
+ float number_b = data[int(idx.y)];
+
+ /* Try to generate NaN in two different ways. Especially in GLSL 1.20,
+ * there is no guarantee that Inf or NaN are possible, so the test is
+ * trying to be very crafty here.
+ *
+ * idx is in [-1, 1], so idx + 3 is in [2, 4], etc.
+ * Fill the data in those ranges with the values that we want.
+ */
+ float zero_a = data[int(idx.x + 4.0)];
+ float zero_b = data[int(idx.y + 5.0)];
+ vec4 flt_max = vec4(data[int(idx.x + 9.0)],
+ data[int(idx.y + 10.0)],
+ data[int(idx.y + 9.0)],
+ data[int(idx.x + 10.0)]);
+ float inf_a = flt_max.x * flt_max.y;
+ float inf_b = flt_max.x + flt_max.y + flt_max.z + flt_max.w;
+
+ float not_a_number_a = zero_a / zero_b; // should be 0/0 = NaN
+ float not_a_number_b = inf_a - inf_b; // should be Inf-Inf = NaN
+
+ /* Min and max are supposed to return the non-NaN value. Use
+ * -not_a_number because implementations that don't generate NaN
+ * should generate either 0, 1, or some huge value. This
+ * guarantees that those implementations will still pass the test.
+ */
+ float result_a = max(number_a, -not_a_number_a);
+ float result_b = max(-not_a_number_b, number_b);
+
+ if (result_a == result_b) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+
+ // Sanity checking...
+ if (number_a != number_b ||
+ flt_max.x != FLT_MAX || flt_max.y != FLT_MAX ||
+ flt_max.z != FLT_MAX || flt_max.w != FLT_MAX ||
+ inf_a != inf_b ||
+ zero_a != 0.0 || zero_b != 0.0) {
+ gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
+ }
+}
+
+[test]
+draw rect -1 -1 2 2
+probe all rgb 0.0 1.0 0.0
diff --git a/tests/spec/glsl-1.20/execution/fs-nan-builtin-min.shader_test b/tests/spec/glsl-1.20/execution/fs-nan-builtin-min.shader_test
new file mode 100644
index 000000000..db6194571
--- /dev/null
+++ b/tests/spec/glsl-1.20/execution/fs-nan-builtin-min.shader_test
@@ -0,0 +1,87 @@
+# Verify that max(x, NaN) always returns x. This is *not* required by the
+# GLSL spec, but many applications depend on it.
+
+[require]
+GLSL >= 1.20
+
+[vertex shader]
+
+varying vec2 idx;
+
+void main()
+{
+ gl_Position = gl_Vertex;
+ /* Produce a value on the ragne [0, 3]. */
+ idx = abs(gl_Vertex.xy) + 2.0;
+}
+
+[fragment shader]
+#define FLT_MAX 3.40282347E+38
+
+varying vec2 idx;
+
+/* Values are packed into an array that is accessed in clever ways to avoid
+ * compiler optimizations that try to "constant propagate" uniforms at draw
+ * time.
+ */
+uniform float data[14] = float[](
+ -3.0, -3.0, -3.0, -3.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0,
+ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
+);
+
+void main()
+{
+ /* Pick an element from data that must be a number. This is crafted so
+ * that number_a and number_b are the same value, but hopefully the
+ * compiler won't be able to detect that.
+ */
+ float number_a = data[int(idx.x)];
+ float number_b = data[int(idx.y)];
+
+ /* Try to generate NaN in two different ways. Especially in GLSL 1.20,
+ * there is no guarantee that Inf or NaN are possible, so the test is
+ * trying to be very crafty here.
+ *
+ * idx is in [-1, 1], so idx + 3 is in [2, 4], etc.
+ * Fill the data in those ranges with the values that we want.
+ */
+ float zero_a = data[int(idx.x + 4.0)];
+ float zero_b = data[int(idx.y + 5.0)];
+ vec4 flt_max = vec4(data[int(idx.x + 9.0)],
+ data[int(idx.y + 10.0)],
+ data[int(idx.y + 9.0)],
+ data[int(idx.x + 10.0)]);
+ float inf_a = flt_max.x * flt_max.y;
+ float inf_b = flt_max.x + flt_max.y + flt_max.z + flt_max.w;
+
+ float not_a_number_a = zero_a / zero_b; // should be 0/0 = NaN
+ float not_a_number_b = inf_a - inf_b; // should be Inf-Inf = NaN
+
+ /* Min and max are supposed to return the non-NaN value. Implementations
+ * that don't generate NaN should generate either 0, 1, or some huge
+ * value. Since number_a should be -3, those implementations will still
+ * pass the test.
+ */
+ float result_a = min(number_a, not_a_number_a);
+ float result_b = min(not_a_number_b, number_b);
+
+ if (result_a == result_b) {
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+
+ // Sanity checking...
+ if (number_a != number_b ||
+ flt_max.x != FLT_MAX || flt_max.y != FLT_MAX ||
+ flt_max.z != FLT_MAX || flt_max.w != FLT_MAX ||
+ inf_a != inf_b ||
+ zero_a != 0.0 || zero_b != 0.0) {
+ gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
+ }
+}
+
+[test]
+draw rect -1 -1 2 2
+probe all rgb 0.0 1.0 0.0
diff --git a/tests/spec/glsl-1.20/execution/vs-nan-builtin-max.shader_test b/tests/spec/glsl-1.20/execution/vs-nan-builtin-max.shader_test
new file mode 100644
index 000000000..46c025aaf
--- /dev/null
+++ b/tests/spec/glsl-1.20/execution/vs-nan-builtin-max.shader_test
@@ -0,0 +1,89 @@
+# Verify that max(x, NaN) always returns x. This is *not* required by the
+# GLSL spec, but many applications depend on it.
+
+[require]
+GLSL >= 1.20
+
+[vertex shader]
+varying vec4 color;
+
+#define FLT_MAX 3.40282347E+38
+
+/* Values are packed into an array that is accessed in clever ways to avoid
+ * compiler optimizations that try to "constant propagate" uniforms at draw
+ * time.
+ */
+uniform float data[14] = float[](
+ 3.0, 3.0, 3.0, 3.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0,
+ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
+);
+
+void main()
+{
+ gl_Position = gl_Vertex;
+
+ /* Produce a value on the ragne [0, 3]. */
+ vec2 idx = abs(gl_Vertex.xy) + 2.0;
+
+ /* Pick an element from data that must be a number. This is crafted so
+ * that number_a and number_b are the same value, but hopefully the
+ * compiler won't be able to detect that.
+ */
+ float number_a = data[int(idx.x)];
+ float number_b = data[int(idx.y)];
+
+ /* Try to generate NaN in two different ways. Especially in GLSL 1.20,
+ * there is no guarantee that Inf or NaN are possible, so the test is
+ * trying to be very crafty here.
+ *
+ * idx is in [-1, 1], so idx + 3 is in [2, 4], etc.
+ * Fill the data in those ranges with the values that we want.
+ */
+ float zero_a = data[int(idx.x + 4.0)];
+ float zero_b = data[int(idx.y + 5.0)];
+ vec4 flt_max = vec4(data[int(idx.x + 9.0)],
+ data[int(idx.y + 10.0)],
+ data[int(idx.y + 9.0)],
+ data[int(idx.x + 10.0)]);
+ float inf_a = flt_max.x * flt_max.y;
+ float inf_b = flt_max.x + flt_max.y + flt_max.z + flt_max.w;
+
+ float not_a_number_a = zero_a / zero_b; // should be 0/0 = NaN
+ float not_a_number_b = inf_a - inf_b; // should be Inf-Inf = NaN
+
+ /* Min and max are supposed to return the non-NaN value. Use
+ * -not_a_number because implementations that don't generate NaN
+ * should generate either 0, 1, or some huge value. This
+ * guarantees that those implementations will still pass the test.
+ */
+ float result_a = max(number_a, -not_a_number_a);
+ float result_b = max(-not_a_number_b, number_b);
+
+ if (result_a == result_b) {
+ color = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+
+ // Sanity checking...
+ if (number_a != number_b ||
+ flt_max.x != FLT_MAX || flt_max.y != FLT_MAX ||
+ flt_max.z != FLT_MAX || flt_max.w != FLT_MAX ||
+ inf_a != inf_b ||
+ zero_a != 0.0 || zero_b != 0.0) {
+ color = vec4(0.0, 0.0, 1.0, 1.0);
+ }
+}
+
+[fragment shader]
+varying vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+}
+
+[test]
+draw rect -1 -1 2 2
+probe all rgb 0.0 1.0 0.0
diff --git a/tests/spec/glsl-1.20/execution/vs-nan-builtin-min.shader_test b/tests/spec/glsl-1.20/execution/vs-nan-builtin-min.shader_test
new file mode 100644
index 000000000..f27e29a24
--- /dev/null
+++ b/tests/spec/glsl-1.20/execution/vs-nan-builtin-min.shader_test
@@ -0,0 +1,89 @@
+# Verify that max(x, NaN) always returns x. This is *not* required by the
+# GLSL spec, but many applications depend on it.
+
+[require]
+GLSL >= 1.20
+
+[vertex shader]
+varying vec4 color;
+
+#define FLT_MAX 3.40282347E+38
+
+/* Values are packed into an array that is accessed in clever ways to avoid
+ * compiler optimizations that try to "constant propagate" uniforms at draw
+ * time.
+ */
+uniform float data[14] = float[](
+ -3.0, -3.0, -3.0, -3.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0,
+ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX
+);
+
+void main()
+{
+ gl_Position = gl_Vertex;
+
+ /* Produce a value on the ragne [0, 3]. */
+ vec2 idx = abs(gl_Vertex.xy) + 2.0;
+
+ /* Pick an element from data that must be a number. This is crafted so
+ * that number_a and number_b are the same value, but hopefully the
+ * compiler won't be able to detect that.
+ */
+ float number_a = data[int(idx.x)];
+ float number_b = data[int(idx.y)];
+
+ /* Try to generate NaN in two different ways. Especially in GLSL 1.20,
+ * there is no guarantee that Inf or NaN are possible, so the test is
+ * trying to be very crafty here.
+ *
+ * idx is in [-1, 1], so idx + 3 is in [2, 4], etc.
+ * Fill the data in those ranges with the values that we want.
+ */
+ float zero_a = data[int(idx.x + 4.0)];
+ float zero_b = data[int(idx.y + 5.0)];
+ vec4 flt_max = vec4(data[int(idx.x + 9.0)],
+ data[int(idx.y + 10.0)],
+ data[int(idx.y + 9.0)],
+ data[int(idx.x + 10.0)]);
+ float inf_a = flt_max.x * flt_max.y;
+ float inf_b = flt_max.x + flt_max.y + flt_max.z + flt_max.w;
+
+ float not_a_number_a = zero_a / zero_b; // should be 0/0 = NaN
+ float not_a_number_b = inf_a - inf_b; // should be Inf-Inf = NaN
+
+ /* Min and max are supposed to return the non-NaN value. Implementations
+ * that don't generate NaN should generate either 0, 1, or some huge
+ * value. Since number_a should be -3, those implementations will still
+ * pass the test.
+ */
+ float result_a = min(number_a, not_a_number_a);
+ float result_b = min(not_a_number_b, number_b);
+
+ if (result_a == result_b) {
+ color = vec4(0.0, 1.0, 0.0, 1.0);
+ } else {
+ color = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+
+ // Sanity checking...
+ if (number_a != number_b ||
+ flt_max.x != FLT_MAX || flt_max.y != FLT_MAX ||
+ flt_max.z != FLT_MAX || flt_max.w != FLT_MAX ||
+ inf_a != inf_b ||
+ zero_a != 0.0 || zero_b != 0.0) {
+ color = vec4(0.0, 0.0, 1.0, 1.0);
+ }
+}
+
+[fragment shader]
+varying vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+}
+
+[test]
+draw rect -1 -1 2 2
+probe all rgb 0.0 1.0 0.0