[v1] opengl: test of zero-vector rotation

Submitted by Sergii Romantsov on Oct. 10, 2018, 10:43 a.m.

Details

Message ID 1539168232-10146-1-git-send-email-sergii.romantsov@globallogic.com
State New
Headers show
Series "opengl: test of zero-vector rotation" ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

Sergii Romantsov Oct. 10, 2018, 10:43 a.m.
Specification doesn't define behaviour for rotation of 0-vector.
In https://github.com/KhronosGroup/OpenGL-API/issues/41 said that
behaviour is undefined and agreed that it would be fine for
implementation to do something useful for this.
Windows and Nvidia drivers have a workaround for that.
For compatibility proposed optimized version of computations.
Specification defines a formula of rotation (see "OpenGL 4.6
(Compatibility Profile) - May 14, 2018", paragraph "12.1.1 Matrices").

Optimized formula will look so:

              R = cos(angle) * I

That is equivalent to logic that magnitude of (0,0,0)-vector is 1.0.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100960
Signed-off-by: Sergii Romantsov <sergii.romantsov@globallogic.com>
CC: Brian Paul <brianp@vmware.com>
CC: Timothy Arceri <tarceri@itsqueeze.com>
---
 tests/general/CMakeLists.gl.txt    |   1 +
 tests/general/zero-vector-rotate.c | 252 +++++++++++++++++++++++++++++++++++++
 tests/opengl.py                    |   1 +
 3 files changed, 254 insertions(+)
 create mode 100644 tests/general/zero-vector-rotate.c

Patch hide | download patch | download mbox

diff --git a/tests/general/CMakeLists.gl.txt b/tests/general/CMakeLists.gl.txt
index ceec9f0..c713f63 100644
--- a/tests/general/CMakeLists.gl.txt
+++ b/tests/general/CMakeLists.gl.txt
@@ -122,6 +122,7 @@  piglit_add_executable (vbo-map-unsync vbo-map-unsync.c)
 piglit_add_executable (vbo-bufferdata vbo-bufferdata.c)
 piglit_add_executable (vbo-subdata-zero vbo-subdata-zero.c)
 piglit_add_executable (vbo-subdata-sync vbo-subdata-sync.c)
+piglit_add_executable (zero-vector-rotate zero-vector-rotate.c)
 piglit_add_executable (object_purgeable-api-pbo object_purgeable-api-pbo.c object_purgeable.c)
 piglit_add_executable (object_purgeable-api-texture object_purgeable-api-texture.c object_purgeable.c)
 piglit_add_executable (object_purgeable-api-vbo object_purgeable-api-vbo.c object_purgeable.c)
diff --git a/tests/general/zero-vector-rotate.c b/tests/general/zero-vector-rotate.c
new file mode 100644
index 0000000..7b1b605
--- /dev/null
+++ b/tests/general/zero-vector-rotate.c
@@ -0,0 +1,252 @@ 
+/*
+ * Copyright © 2018 Sergii Romantsov (sergii.romantsov@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "piglit-util-gl.h"
+
+/*
+ * Specification doesn't define behaviour for rotation of 0-vector.
+ * In https://github.com/KhronosGroup/OpenGL-API/issues/41 said that
+ * behaviour is undefined and agreed that it would be fine for
+ * implementation to do something useful for this.
+ * Windows and Nvidia drivers have a workaround for that.
+ * For compatibility proposed optimized version of computations.
+ * Specification defines a formula of rotation (see "OpenGL 4.6
+ * (Compatibility Profile) - May 14, 2018", paragraph "12.1.1 Matrices").
+ *
+ * Optimized formula will look so:
+ *
+ *               R = cos(angle) * I
+ *
+ * That is equivalent to logic that magnitude of (0,0,0)-vector is 1.0.
+ *
+ * Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100960
+ */
+
+const float g_inconsistency_x = 2.0;
+const float g_inconsistency_y = 3.0;
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.window_width = 1008;
+	config.window_height = 1008;
+
+	config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+void
+piglit_init(int argc, char **argv)
+{
+	piglit_gen_ortho_projection(0, piglit_width, 0, piglit_height, -piglit_height, piglit_height, false);
+
+	glEnable(GL_CULL_FACE);
+		glFrontFace(GL_CW);
+}
+
+static inline int
+above_zero(float value)
+{
+	return value > 0.000001;
+}
+
+static inline int
+below_zero(float value)
+{
+	return value < -0.000001;
+}
+
+static void
+get_color(int step, float color[3])
+{
+	const static int g_colors = 8;
+	switch(step) {
+	case 0:
+		color[0] = 0.0, color[1] = 0.0, color[2] = 0.0;
+		break;
+	case 1:
+		color[0] = 0.0, color[1] = 0.0, color[2] = 1.0;
+		break;
+	case 2:
+		color[0] = 0.0, color[1] = 1.0, color[2] = 0.0;
+		break;
+	case 3:
+		color[0] = 0.0, color[1] = 1.0, color[2] = 1.0;
+		break;
+	case 4:
+		color[0] = 1.0, color[1] = 0.0, color[2] = 0.0;
+		break;
+	case 5:
+		color[0] = 1.0, color[1] = 0.0, color[2] = 1.0;
+		break;
+	case 6:
+		color[0] = 1.0, color[1] = 1.0, color[2] = 0.0;
+		break;
+	case 7:
+		color[0] = 1.0, color[1] = 1.0, color[2] = 1.0;
+		break;
+	default:
+		get_color(step % g_colors, color);
+	}
+}
+
+static int
+draw_triangles(float pos_x, float pos_y, float base_angle)
+{
+	/* A number of draws for each base angle */
+	const int steps = 24;
+	/* Size of triangle edge */
+	const float size = piglit_width / steps;
+	const float size_half = size / 2;
+	const float angle_shift = 360 / steps;
+	/* Rotation is similar to scaling for 0-vector */
+	const float scale = cos(base_angle * M_PI / 180.0);
+
+	/* Triangle coordinates */
+	float x1 = 0, y1 = 0;
+	float x2 = x1 + size_half, y2 = y1 + size;
+	float x3 = x2 + size_half, y3 = y1;
+
+	int step = steps;
+	float angle = 0;
+	int is_failed = 0;
+
+	glTranslatef(pos_x, pos_y, 0);
+	glRotatef(base_angle, 0.0, 0.0, 0.0);
+
+	while (step--) {
+		const float scale2 = cos(angle * M_PI / 180.0);
+		float color[3];
+
+		glPushMatrix();
+		get_color(step, color);
+		glColor3f(color[0], color[1], color[2]);
+		glRotatef(angle, 1.0, 0.0, 0.0);
+		piglit_draw_triangle(x1, y1, x2, y2, x3, y3);
+
+		/* Checking correctness of drawing */
+		if (pos_x + x3 * scale < piglit_width && pos_y + y3 * scale < piglit_height
+			&& above_zero(scale2)) { /* a triangle is in scope of the window */
+			/* Get approximal position of x1,y1, scaled according to base_angle */
+			const float scaled_x1 = roundf(x1 * scale) + (above_zero(scale) ? g_inconsistency_x : -g_inconsistency_x);
+			const float scaled_y1 = roundf(y1 * scale) + (below_zero(scale) ? -1.0 : 0.0);
+
+			/* Get approximal position of x2,y2, scaled according to base_angle and additional x-axis angle */
+			const float scaled_x2 = roundf(x2 * scale);
+			float scaled_y2 = roundf(y2 * scale * scale2);
+			scaled_y2 = fabs(scaled_y2) > g_inconsistency_y
+				? scaled_y2 + (below_zero(scale)
+					? g_inconsistency_y : -g_inconsistency_y)
+				: below_zero(scaled_y2) ? -1.0 : 1.0;
+
+			/* Get approximal position of x3,y3, scaled according to base_angle */
+			const float scaled_x3 = roundf(x3 * scale) + (above_zero(scale) ? -g_inconsistency_x : g_inconsistency_x);
+			const float scaled_y3 = roundf(y3 * scale) + (below_zero(scale) ? -1.0 : 0.0);
+
+			const float pos_x1 = (pos_x) + scaled_x1;
+			const float pos_y1 = (pos_y) + scaled_y1;
+			const float pos_x2 = (pos_x) + scaled_x2;
+			const float pos_y2 = (pos_y) + scaled_y2;
+			const float pos_x3 = (pos_x) + scaled_x3;
+			const float pos_y3 = (pos_y) + scaled_y3;
+
+			if (pos_x1 < piglit_width && pos_x1 >= 0 && pos_y1 < piglit_height) {
+				int res = piglit_probe_pixel_rgb(pos_x1, pos_y1, color);
+				if (!res) {
+					is_failed |= 1;
+					fprintf(stderr, "Failed x1,y1 [%f,%f][%f,%f][%f,%f] base_angle: %f scale: %f: [%f,%f] cos(%f): %f \n",
+						pos_x + x1, pos_y + y1, pos_x + x2, pos_y + y2, pos_x + x3, pos_y + y3,
+						base_angle, scale,
+						pos_x1, pos_y1,
+						angle, scale2);
+				}
+			}
+			if (pos_x2 < piglit_width && pos_x2 >= 0 && pos_y2 < piglit_height) {
+				int res = piglit_probe_pixel_rgb(pos_x2, pos_y2, color);
+				if (!res) {
+					is_failed |= 1;
+					fprintf(stderr, "Failed x2,y2 [%f,%f][%f,%f][%f,%f] base_angle: %f scale: %f: [%f,%f] cos(%f): %f \n",
+						pos_x + x1, pos_y + y1, pos_x + x2, pos_y + y2, pos_x + x3, pos_y + y3,
+						base_angle, scale,
+						pos_x2, pos_y2,
+						angle, scale2);
+				}
+			}
+			if (pos_x3 < piglit_width && pos_x3 >= 0 && pos_y3 < piglit_height) {
+				int res = piglit_probe_pixel_rgb(pos_x3, pos_y3, color);
+				if (!res) {
+					is_failed |= 1;
+					fprintf(stderr, "Failed x3,y3 [%f,%f][%f,%f][%f,%f] base_angle: %f scale: %f: [%f,%f] cos(%f): %f \n",
+						pos_x + x1, pos_y + y1, pos_x + x2, pos_y + y2, pos_x + x3, pos_y + y3,
+						base_angle, scale,
+						pos_x3, pos_y3,
+						angle, scale2);
+				}
+			}
+		}
+
+		glPopMatrix();
+		angle += angle_shift;
+		x1 += size;
+		x2 += size;
+		x3 += size;
+	}
+	return is_failed;
+}
+
+enum piglit_result
+piglit_display()
+{
+	int is_failed = 0;
+
+	/* Angle-step to rotate 0-vector */
+	const float angle_shift = 20.0;
+	const int steps = 360 / angle_shift;
+	/* Initial positions to start drawing */
+	const float pos_x_initial = piglit_width / 2;
+	const float pos_y_initial = piglit_height;
+	/* Max height of triangle */
+	const int size = piglit_height / steps;
+
+	float pos_x = pos_x_initial;
+	float pos_y = pos_y_initial - size;
+	float angle = 0.0;
+	/* We are drawing 'steps'-times going by y-axis */
+	const float pos_y_shift = -size;
+
+	glClearColor(0.5, 0.5, 0.5, 1.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	while(angle < 360.0) {
+		glPushMatrix();
+		is_failed |= draw_triangles(pos_x, pos_y, angle);
+		glPopMatrix();
+		angle += angle_shift;
+		pos_y += pos_y_shift;
+	}
+
+	piglit_present_results();
+
+	return is_failed ? PIGLIT_FAIL : PIGLIT_PASS;
+}
diff --git a/tests/opengl.py b/tests/opengl.py
index c599eb1..63afead 100644
--- a/tests/opengl.py
+++ b/tests/opengl.py
@@ -684,6 +684,7 @@  with profile.test_list.group_manager(
     g(['two-sided-lighting'])
     g(['user-clip'])
     g(['varray-disabled'])
+    g(['zero-vector-rotate'])
     g(['windowoverlap'])
     g(['copyteximage-border'])
     g(['copyteximage-clipping'])