On 8 September 2011 23:07, Eric Anholt <span dir="ltr">&lt;<a href="mailto:eric@anholt.net" target="_blank">eric@anholt.net</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

---<br>
 tests/all.tests                             |   15 ++<br>
 tests/spec/gl-2.0/CMakeLists.gl.txt         |   16 ++<br>
 tests/spec/gl-2.0/CMakeLists.txt            |    1 +<br>
 tests/spec/gl-2.0/vertex-program-two-side.c |  235 +++++++++++++++++++++++++++<br>
 4 files changed, 267 insertions(+), 0 deletions(-)<br>
 create mode 100644 tests/spec/gl-2.0/CMakeLists.gl.txt<br>
 create mode 100644 tests/spec/gl-2.0/vertex-program-two-side.c<br>
<br>
diff --git a/tests/all.tests b/tests/all.tests<br>
index fc66ff6..cbd40d0 100644<br>
--- a/tests/all.tests<br>
+++ b/tests/all.tests<br>
@@ -729,6 +729,21 @@ add_texwrap_test3(gl20, &#39;2D&#39;, &#39;npot&#39;, &#39;proj&#39;)<br>
 add_texwrap_test2(gl20, &#39;3D&#39;, &#39;npot&#39;)<br>
 add_texwrap_test3(gl20, &#39;3D&#39;, &#39;npot&#39;, &#39;proj&#39;)<br>
 add_plain_test(gl20, &#39;getattriblocation-conventional&#39;)<br>
+gl20[&#39;vertex-program-two-side &#39;] = concurrent_test(&#39;vertex-program-two-side&#39;)<br>
+gl20[&#39;vertex-program-two-side front&#39;] = concurrent_test(&#39;vertex-program-two-side front&#39;)<br>
+gl20[&#39;vertex-program-two-side back&#39;] = concurrent_test(&#39;vertex-program-two-side back&#39;)<br>
+gl20[&#39;vertex-program-two-side primary&#39;] = concurrent_test(&#39;vertex-program-two-side primary&#39;)<br>
+gl20[&#39;vertex-program-two-side primary front&#39;] = concurrent_test(&#39;vertex-program-two-side primary front&#39;)<br>
+gl20[&#39;vertex-program-two-side primary back&#39;] = concurrent_test(&#39;vertex-program-two-side primary back&#39;)<br>
+gl20[&#39;vertex-program-two-side secondary&#39;] = concurrent_test(&#39;vertex-program-two-side secondary&#39;)<br>
+gl20[&#39;vertex-program-two-side secondary front&#39;] = concurrent_test(&#39;vertex-program-two-side secondary front&#39;)<br>
+gl20[&#39;vertex-program-two-side secondary back&#39;] = concurrent_test(&#39;vertex-program-two-side secondary back&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled&#39;] = concurrent_test(&#39;vertex-program-two-side disabled&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled front&#39;] = concurrent_test(&#39;vertex-program-two-side disabled front&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled primary&#39;] = concurrent_test(&#39;vertex-program-two-side disabled primary&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled primary front&#39;] = concurrent_test(&#39;vertex-program-two-side disabled primary front&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled secondary&#39;] = concurrent_test(&#39;vertex-program-two-side disabled secondary&#39;)<br>
+gl20[&#39;vertex-program-two-side disabled secondary front&#39;] = concurrent_test(&#39;vertex-program-two-side disabled secondary front&#39;)<br></blockquote><div><br>I found the meaning of the arguments to be hard to follow:<br>
- &quot;front&quot; sets the global variable &quot;back&quot; to false, which means the VS doesn&#39;t set gl_BackColor or gl_BackSecondaryColor.<br>- &quot;back&quot; sets &quot;front&quot; to false, which means the VS doesn&#39;t set gl_FrontColor or gl_FrontSecondaryColor.<br>
- &quot;primary&quot; sets &quot;secondary&quot; to false, which means the VS doesn&#39;t set gl_FrontSecondaryColor or gl_BackSecondaryColor.<br>- &quot;secondary&quot; sets &quot;primary&quot; to false, which means the VS doesn&#39;t set gl_BackSecondaryColor or gl_FrontSecondaryColor.<br>
<br>So, for example, concurrent_test(&#39;vertex-program-two-side&#39;) causes the VS to set all four color outputs, where a naive reader might have expected none of them to be set.  Also, concurrent_test(&#39;vertex-program-two-side front back primary&#39;) would cause nothing to be tested, where a naive reader would probably have expected it to test both front and back.  It would be way easier to reason about this code if the globals &quot;front&quot;, &quot;back&quot;, &quot;primary&quot;, and &quot;secondary&quot; all started out false, and the presence of arguments set them to true.<br>
<br>Also, a few cases aren&#39;t tested:<br>- VS sets all colors except gl_BackSecondaryColor.<br>- VS sets all colors except gl_FrontSecondaryColor.<br>- VS sets all colors except gl_BackColor.<br>- VS sets all colors except gl_FrontColor.<br>
- VS sets only gl_FrontColor and gl_BackSecondaryColor.<br>- VS sets only gl_BackColor and gl_FrontSecondaryColor.<br><br>Granted, the standard doesn&#39;t specify the meaning of these cases, but it doesn&#39;t specify that their behavior is undefined either, so I think it&#39;s reasonable to verify that the undefined behavior is confined to the variable that wasn&#39;t set.  For instance, in the case where the VS sets all colors except gl_BackSecondaryColor, we should test that primary color works properly, and that secondary color works properly when you look at the front side of a triangle.  Considering some of the primary/secondary color code I ran across in my recent refactor of i965 VUE setup on Mesa, I would not be surprised if in some of these cases, the &quot;undefined&quot; behavior bleeds over between primary and secondary colors, or between front and back.  It might even cause mesa to abort with an assertion.  Considering the standard&#39;s vagueness on what exactly is undefined in these cases, I think it&#39;s reasonable to err on the side of testing more cases rather than fewer.<br>
<br>(Note: of course, to test these additional cases we would have to further change the meaning of the command-line options.  You might consider just having one flag per VS output variable, plus of course the enable/disable flag for VERTEX_PROGRAM_TWO_SIDE).<br>
<br>By the same token, I see that we aren&#39;t testing the cases where no well-defined color is expected at all (e.g. VERTEX_COLOR_TWO_SIDE is disabled, and the VS only sets gl_BackColor and/or gl_BackSecondaryColor).  Although we can&#39;t check the colors of the rectangles in this case (since they are undefined), I think we still should try drawing the rectangles just to make sure there isn&#39;t a crash.<br>
 </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
 # Group spec/glsl-1.00<br>
 spec[&#39;glsl-1.00&#39;] = Group()<br>
diff --git a/tests/spec/gl-2.0/CMakeLists.gl.txt b/tests/spec/gl-2.0/CMakeLists.gl.txt<br>
new file mode 100644<br>
index 0000000..bc771e7<br>
--- /dev/null<br>
+++ b/tests/spec/gl-2.0/CMakeLists.gl.txt<br>
@@ -0,0 +1,16 @@<br>
+include_directories(<br>
+       ${GLEXT_INCLUDE_DIR}<br>
+       ${OPENGL_INCLUDE_PATH}<br>
+       ${GLUT_INCLUDE_DIR}<br>
+       ${piglit_SOURCE_DIR}/tests/mesa/util<br>
+       ${piglit_SOURCE_DIR}/tests/util<br>
+)<br>
+<br>
+link_libraries (<br>
+       piglitutil<br>
+       ${OPENGL_gl_LIBRARY}<br>
+       ${OPENGL_glu_LIBRARY}<br>
+       ${GLUT_glut_LIBRARY}<br>
+)<br>
+<br>
+add_executable (vertex-program-two-side vertex-program-two-side.c)<br>
diff --git a/tests/spec/gl-2.0/CMakeLists.txt b/tests/spec/gl-2.0/CMakeLists.txt<br>
index 9a13702..6903d88 100644<br>
--- a/tests/spec/gl-2.0/CMakeLists.txt<br>
+++ b/tests/spec/gl-2.0/CMakeLists.txt<br>
@@ -1 +1,2 @@<br>
 add_subdirectory (api)<br>
+piglit_include_target_api()<br>
\ No newline at end of file<br>
diff --git a/tests/spec/gl-2.0/vertex-program-two-side.c b/tests/spec/gl-2.0/vertex-program-two-side.c<br>
new file mode 100644<br>
index 0000000..b2038e9<br>
--- /dev/null<br>
+++ b/tests/spec/gl-2.0/vertex-program-two-side.c<br>
@@ -0,0 +1,235 @@<br>
+/*<br>
+ * Copyright © 2011 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 &quot;Software&quot;),<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 &quot;AS IS&quot;, 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 DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/** @file vertex-program-two-side.c<br>
+ *<br>
+ * Tests two-sided lighting behavior.<br>
+ *<br>
+ * From the GL 2.1 spec, page 63 (page 77 of the PDF):<br>
+ *<br>
+ *     &quot;Additionally, vertex shaders can operate in two-sided color<br>
+ *      mode. When a vertex shader is active, front and back colors<br>
+ *      can be computed by the vertex shader and written to the<br>
+ *      gl_FrontColor, gl_BackColor, gl_FrontSecondaryColor and<br>
+ *      gl_BackSecondaryColor outputs. If VERTEX PROGRAM TWO SIDE is<br>
+ *      enabled, the GL chooses between front and back colors, as<br>
+ *      described below. Otherwise, the front color output is always<br>
+ *      selected. Two-sided color mode is enabled and disabled by<br>
+ *      calling Enable or Disable with the symbolic value VERTEX<br>
+ *      PROGRAM TWO SIDE.&quot;<br>
+ *<br>
+ * This appears to override the text in the GLSL 1.10 spec which<br>
+ * implies that two-sided behavior always occurs.<br>
+ */<br>
+<br>
+#define _GNU_SOURCE<br>
+#include &quot;piglit-util.h&quot;<br>
+<br>
+int piglit_width = 100, piglit_height = 100;<br>
+int piglit_window_mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE;<br>
+<br>
+static GLint prog;<br>
+<br>
+static bool primary = true;<br>
+static bool secondary = true;<br>
+static bool enabled = true;<br>
+static bool front = true;<br>
+static bool back = true;<br>
+static float frontcolor[4] = {0.0, 0.5, 0.0, 0.0};<br>
+static float backcolor[4] = {0.0, 0.0, 0.5, 0.0};<br>
+static float secondary_frontcolor[4] = {0.0, 0.25, 0.0, 0.0};<br>
+static float secondary_backcolor[4] = {0.0, 0.0, 0.25, 0.0};<br>
+<br>
+static const char *fs_source_primary =<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;       gl_FragColor = gl_Color;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char *fs_source_secondary =<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;       gl_FragColor = gl_SecondaryColor;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char *fs_source_both =<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;       gl_FragColor = gl_Color + gl_SecondaryColor;\n&quot;<br>
+       &quot;}\n&quot;;<br></blockquote><div><br>Rather than add the colors in this case, consider having a uniform variable to tell the FS whether to use gl_Color or gl_SecondaryColor, and having the program draw four rectangles instead of two.  This would make it easier to inspect the test results manually (since it&#39;s diffucult to mentally add RGB color values when viewing on screen), and it would have the advantage allowing some of the partially-undefined cases to be tested (e.g. where the VS sets only gl_FrontColor and gl_BackSecondaryColor).<br>
 </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
+<br>
+void<br>
+add(float *values, float *a)<br>
+{<br>
+       int i;<br>
+<br>
+       for (i = 0; i &lt; 4; i++)<br>
+               values[i] += a[i];<br>
+}<br>
+<br>
+void<br>
+get_expected(float *values, bool drew_front)<br>
+{<br>
+       int i;<br>
+<br>
+       for (i = 0; i &lt; 4; i++)<br>
+               values[i] = 0.0;<br>
+<br>
+       if (drew_front || !enabled) {<br>
+               if (primary)<br>
+                       add(values, frontcolor);<br>
+               if (secondary)<br>
+                       add(values, secondary_frontcolor);<br>
+       }<br>
+<br>
+       if (!drew_front &amp;&amp; enabled) {<br>
+               if (primary)<br>
+                       add(values, backcolor);<br>
+               if (secondary)<br>
+                       add(values, secondary_backcolor);<br>
+       }<br></blockquote><div><br>Minor nit: it&#39;s not immediately obvious on first reading that: (a) exactly one or the other of these if tests will always execute, and (b) the condition indicates whether we expect to see front colors or back colors.  Consider changing this to something like:<br>

<br>bool front_colors_expected = enabled ? draw_front : true;<br><br>...<br><br>if (front_colors_expected) {<br>    ...<br>} else {<br>    ...<br>}<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">


+}<br>
+<br>
+enum piglit_result<br>
+piglit_display(void)<br>
+{<br>
+       int front_x = 10;<br>
+       int front_y = 10;<br>
+       int front_w = piglit_width / 2 - 20;<br>
+       int front_h = piglit_height - 20;<br>
+       int back_x = piglit_width - 10;<br>
+       int back_y = 10;<br>
+       int back_w = -(front_w);<br></blockquote><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">
+       int back_h = piglit_height - 20; <br></blockquote><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">
+       bool pass = true;<br>
+       float expected[4];<br>
+<br>
+       piglit_ortho_projection(piglit_width, piglit_height, false);<br>
+<br>
+       glClearColor(0.5, 0.5, 0.5, 0.5);<br>
+       glClear(GL_COLOR_BUFFER_BIT);<br>
+<br>
+       if (front) {<br>
+               piglit_draw_rect(front_x, front_y, front_w, front_h);<br>
+               get_expected(expected, true);<br>
+               pass = pass &amp;&amp; piglit_probe_rect_rgba(front_x, front_y,<br>
+                                                     front_w, front_h,<br>
+                                                     expected);<br>
+       }<br>
+<br>
+       if (back || !enabled) {<br>
+               piglit_draw_rect(back_x, back_y, back_w, back_h);<br>
+               get_expected(expected, false);<br>
+               pass = pass &amp;&amp; piglit_probe_rect_rgba(back_x + back_w, back_y,<br>
+                                                     -back_w, back_h,<br>
+                                                     expected);<br>
+       }<br></blockquote><div><br>Another minor nit: usually the one-letter abbreviations x, y, w, and
 h are intuitively clear, but the fact that we&#39;re cleverly negating w 
in order to get a peek at the back side of the rectangle makes the 
second call to piglit_probe_rect_rgba() hard to follow.  Consider doing something more explicit.  Also a comment would be nice to explain the cleverness of negating the width to see the back side of the rectangle.  For example, perhaps something like this:<br>
<br>int back_x_right = piglit_width - 10;<br>int back_w = front_w;<br>int back_x = back_x_right - back_w;<br>
<br>...<br><br>if (back || !enabled) {<br>    /* Draw a reversed rectangle so we see its back side */<br>    piglit_draw_rect(back_x_right, back_y, -back_w, back_h);<br>    get_expected(expected, false);<br>    pass = pass &amp;&amp; piglit_probe_rect_rgba(back_x, back_y, back_w, back_h, expected);<br>
}<br><br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">
+<br>
+       piglit_present_results();<br>
+<br>
+       return pass ? PIGLIT_PASS : PIGLIT_FAIL;<br>
+}<br>
+<br>
+static void<br>
+setup_output(char **out, const char *name, float *values)<br>
+{<br>
+       asprintf(out,<br>
+                &quot;      %s = vec4(%f, %f, %f, %f);\n&quot;,<br>
+                name,<br>
+                values[0],<br>
+                values[1],<br>
+                values[2],<br>
+                values[3]);<br>
+}<br>
+<br>
+void<br>
+piglit_init(int argc, char **argv)<br>
+{<br>
+       GLint vs, fs;<br>
+       char *vs_outputs[4] = {&quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;};<br>
+       char *vs_source;<br>
+       const char *fs_source = fs_source_both;<br>
+       int i;<br>
+<br>
+       piglit_require_GLSL();<br>
+<br>
+       if (!GLEW_VERSION_2_0) {<br>
+               printf(&quot;Requires OpenGL 2.0\n&quot;);<br>
+               piglit_report_result(PIGLIT_SKIP);<br>
+       }<br>
+<br>
+       for (i = 1; i &lt; argc; i++) {<br>
+               if (strcmp(argv[i], &quot;disabled&quot;) == 0) {<br>
+                       enabled = false;<br>
+               } else if (strcmp(argv[i], &quot;front&quot;) == 0) {<br>
+                       back = false;<br>
+               } else if (strcmp(argv[i], &quot;back&quot;) == 0) {<br>
+                       front = false;<br>
+               } else if (strcmp(argv[i], &quot;primary&quot;) == 0) {<br>
+                       secondary = false;<br>
+                       fs_source = fs_source_primary;<br>
+               } else if (strcmp(argv[i], &quot;secondary&quot;) == 0) {<br>
+                       primary = false;<br>
+                       fs_source = fs_source_secondary;<br>
+               } else {<br>
+                       fprintf(stderr, &quot;unknown argument %s\n&quot;, argv[i]);<br>
+               }<br>
+       }<br>
+<br>
+       assert(enabled || front);<br>
+<br>
+       if (front &amp;&amp; primary)<br>
+               setup_output(&amp;vs_outputs[0], &quot;gl_FrontColor&quot;, frontcolor);<br>
+       if (back &amp;&amp; primary)<br>
+               setup_output(&amp;vs_outputs[1], &quot;gl_BackColor&quot;, backcolor);<br>
+       if (front &amp;&amp; secondary)<br>
+               setup_output(&amp;vs_outputs[2], &quot;gl_FrontSecondaryColor&quot;, secondary_frontcolor);<br>
+       if (back &amp;&amp; secondary)<br>
+               setup_output(&amp;vs_outputs[3], &quot;gl_BackSecondaryColor&quot;, secondary_backcolor);<br>
+<br>
+       asprintf(&amp;vs_source,<br>
+                &quot;void main()\n&quot;<br>
+                &quot;{\n&quot;<br>
+                &quot;      gl_Position = ftransform();\n&quot;<br>
+                &quot;%s%s%s%s&quot;<br>
+                &quot;}\n&quot;,<br>
+                vs_outputs[0],<br>
+                vs_outputs[1],<br>
+                vs_outputs[2],<br>
+                vs_outputs[3]);<br>
+<br>
+       vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);<br>
+       fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);<br>
+       prog = piglit_link_simple_program(vs, fs);<br>
+<br>
+       if (!prog || !vs || !fs) {<br>
+               printf(&quot;VS source:\n%s&quot;, vs_source);<br>
+               printf(&quot;FS source:\n%s&quot;, fs_source);<br>
+               piglit_report_result(PIGLIT_FAIL);<br>
+       }<br>
+<br>
+       glUseProgram(prog);<br>
+<br>
+       if (enabled)<br>
+               glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);<br>
+}<br>
<font color="#888888">--<br>
1.7.5.4<br>
<br>
_______________________________________________<br>
Piglit mailing list<br>
<a href="mailto:Piglit@lists.freedesktop.org" target="_blank">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></blockquote></div><br>