<div class="gmail_quote">On 16 December 2011 17:03, Ian Romanick <span dir="ltr">&lt;<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On 12/16/2011 03:33 PM, Paul Berry wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
According to the OpenGL 3.0 spec (section 2.15: Transform Feedback):<br>
<br>
     &quot;When quads and polygons are provided to transform feedback with a<br>
     primitive mode of TRIANGLES, they will be tessellated and recorded<br>
     as triangles (the order of tessellation within a primitive is<br>
     undefined). Individual lines or triangles of a strip or fan<br>
     primitive will be extracted and recorded separately.&quot;<br>
<br>
This test verifies the correctness of the tessellation and extraction<br>
from strips and fans.  It does so by feeding the output of transform<br>
feedback back into the GL pipeline and verifying that the rendered<br>
image is the same.<br>
<br>
Verified using the nVidia proprietary driver for Linux.  The nVidia<br>
driver passes all tests except &quot;tessellation polygon flat_last&quot;,<br>
&quot;tessellation quad_strip flat_last&quot;, and &quot;tessellation quads<br>
flat_last&quot;.  These tests fail because the order in which the driver<br>
tessellates polygons and quads fails to preserve the correct provoking<br>
vertex, leading to different results from flatshading.  However, this<br>
is unlikely to cause problems in practice (since transform feedback is<br>
a new feature, and quads and polygons are deprecated), and besides,<br>
the spec does caution that &quot;the order of tessellation within a<br>
primitive is undefined&quot;.  So failures with flatshading on deprecated<br>
primitive types are reported as mere warnings.<br>
</blockquote>
<br></div>
I tried this on an AMD system, and I got some odd results.  On all of the polygon tests, the second time it goes into draw() GL_INVALID_OPERATION is generated.  It looks like the only difference between the two invocations is the program used to draw.  I haven&#39;t had a chance to dig into it deeply.<br>
</blockquote><div><br></div><div>Weird.  Maybe I can have a look when I&#39;m over there on Tuesday.  The only thing I can think of at the moment is that maybe the AMD implementation of polygons isn&#39;t compatible with transform feedback for some reason, and since polygons are a deprecated drawing mode, they decided that it wasn&#39;t worth getting them to work, so they just generate an error instead.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5">
---<br>
<br>
Note: this is a re-spin of a patch I sent out in November and failed<br>
to follow up on.  Changes since then:<br>
<br>
- I added a &quot;wireframe&quot; test mode, since during development of<br>
   transform feedback for i965, I discovered that wireframe rendering<br>
   would be easy to get wrong.<br>
<br>
- After consulting with Ian Romanick about the tests that were failing<br>
   on nVidia (see above) we decided that those failures should be<br>
   reported as warnings.<br>
<br>
- I added the ability to run this test using a drawing mode of<br>
   GL_POINTS, GL_LINES, or GL_TRIANGLES.  Even though these primitive<br>
   types don&#39;t require transform feedback to do any extra tessellation,<br>
   it seems reasonable to run the test in these modes anyhow, just to<br>
   make sure that transform feedback doesn&#39;t introduce any changes that<br>
   would result in an incorrect render.<br>
<br>
<br>
  tests/all.tests                                    |   11 +<br>
  .../spec/ext_transform_<u></u>feedback/CMakeLists.gl.txt  |    1 +<br>
  tests/spec/ext_transform_<u></u>feedback/tessellation.c   |  622 ++++++++++++++++++++<br>
  3 files changed, 634 insertions(+), 0 deletions(-)<br>
  create mode 100644 tests/spec/ext_transform_<u></u>feedback/tessellation.c<br>
<br>
diff --git a/tests/all.tests b/tests/all.tests<br>
index b713de0..4b1ba49 100644<br>
--- a/tests/all.tests<br>
+++ b/tests/all.tests<br>
@@ -1414,6 +1414,17 @@ for drawcall in [&#39;arrays&#39;, &#39;elements&#39;]:<br>
                  test_name = &#39;order {0} {1}&#39;.format(drawcall, mode)<br>
                  ext_transform_feedback[test_<u></u>name] = PlainExecTest(<br>
                          &#39;ext_transform_feedback-{0} -auto&#39;.format(test_name))<br>
+for draw_mode in [&#39;points&#39;, &#39;lines&#39;, &#39;line_loop&#39;, &#39;line_strip&#39;,<br>
+                  &#39;triangles&#39;, &#39;triangle_strip&#39;, &#39;triangle_fan&#39;,<br>
+                  &#39;quads&#39;, &#39;quad_strip&#39;, &#39;polygon&#39;]:<br>
+        for shade_mode in [&#39;monochrome&#39;, &#39;smooth&#39;, &#39;flat_first&#39;, &#39;flat_last&#39;, &#39;wireframe&#39;]:<br>
+                if shade_mode == &#39;wireframe&#39; and \<br>
+                            draw_mode in [&#39;points&#39;, &#39;lines&#39;, &#39;line_loop&#39;, &#39;line_strip&#39;]:<br>
+                        continue<br>
+                test_name = &#39;tessellation {0} {1}&#39;.format(<br>
+                        draw_mode, shade_mode)<br>
+                ext_transform_feedback[test_<u></u>name] = PlainExecTest(<br>
+                        &#39;ext_transform_feedback-{0} -auto&#39;.format(test_name))<br>
<br>
  ext_transform_feedback[&#39;<u></u>output-type float&#39;] = PlainExecTest([&#39;ext_transform_<u></u>feedback-output-type&#39;, &#39;-auto&#39;, &#39;float&#39;])<br>
  ext_transform_feedback[&#39;<u></u>output-type float[2]&#39;] = PlainExecTest([&#39;ext_transform_<u></u>feedback-output-type&#39;, &#39;-auto&#39;, &#39;float[2]&#39;])<br>
diff --git a/tests/spec/ext_transform_<u></u>feedback/CMakeLists.gl.txt b/tests/spec/ext_transform_<u></u>feedback/CMakeLists.gl.txt<br>
index 35c5dce..06dd099 100644<br>
--- a/tests/spec/ext_transform_<u></u>feedback/CMakeLists.gl.txt<br>
+++ b/tests/spec/ext_transform_<u></u>feedback/CMakeLists.gl.txt<br>
@@ -23,5 +23,6 @@ add_executable (ext_transform_feedback-<u></u>interleaved interleaved.c)<br>
  add_executable (ext_transform_feedback-<u></u>separate separate.c)<br>
  add_executable (ext_transform_feedback-<u></u>output-type output-type.c)<br>
  add_executable (ext_transform_feedback-order order.c)<br>
+add_executable (ext_transform_feedback-<u></u>tessellation tessellation.c)<br>
<br>
  # vim: ft=cmake:<br>
diff --git a/tests/spec/ext_transform_<u></u>feedback/tessellation.c b/tests/spec/ext_transform_<u></u>feedback/tessellation.c<br>
new file mode 100644<br>
index 0000000..7874354<br>
--- /dev/null<br>
+++ b/tests/spec/ext_transform_<u></u>feedback/tessellation.c<br>
@@ -0,0 +1,622 @@<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<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/**<br>
+ * \file tessellation.c<br>
+ *<br>
+ * Verify that transform feedback properly converts primitives of<br>
+ * types GL_LINE_LOOP, GL_LINE_STRIP, GL_TRIANGLE_STRIP,<br>
+ * GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON into<br>
+ * primitives of type GL_LINES or GL_TRIANGLES, as appropriate.<br>
+ *<br>
+ * According to the OpenGL 3.0 spec (section 2.15: Transform Feedback):<br>
+ *<br>
+ *     &quot;When quads and polygons are provided to transform feedback<br>
+ *     with a primitive mode of TRIANGLES, they will be tessellated<br>
+ *     and recorded as triangles (the order of tessellation within a<br>
+ *     primitive is undefined). Individual lines or triangles of a<br>
+ *     strip or fan primitive will be extracted and recorded<br>
+ *     separately.&quot;<br>
+ *<br>
+ * Although it is not stated explicitly, it is clear from context that<br>
+ * individual lines of a LINE_LOOP primitive are also expected to be<br>
+ * extracted and recorded separately.  Also, the spec does not place<br>
+ * any requirement on the order in which vertices are output when<br>
+ * extracting individual lines or triangles of a strip, fan, or<br>
+ * LINE_LOOP primitive.<br>
+ *<br>
+ * Because the spec allows variability in how these primitives are<br>
+ * tessellated and extracted, we can&#39;t verify correct operation by<br>
+ * examining the vertices themselves.  However, we can check that if<br>
+ * the transform feedback output is fed back into the GL pipeline<br>
+ * (using GL_TRIANGLES or GL_LINES, as appropriate), the same image<br>
+ * will be rendered.<br>
+ *<br>
+ * This test operates by first rendering an image without transform<br>
+ * feedback, then rendering the same image with transform feedback,<br>
+ * then rendering the transform feedback output.  Then it checks that<br>
+ * the 3 generated images match exactly.<br>
+ *<br>
+ * In addition, the test verifies that the expected number of vertices<br>
+ * was output by transform feedback.<br>
+ *<br>
+ * The images are rendered using a fragment shader that attenuates the<br>
+ * color of back-facing primitives, so that the test will verify that<br>
+ * tesellation preserves winding order properly.<br>
+ *<br>
+ * The test can be run in four different coloring modes:<br>
+ *<br>
+ * - &quot;monochrome&quot;, meaning that all vertices are assigned the same<br>
+ *   color.  A failure in this mode means that the tessellated image<br>
+ *   did not have the correct shape.<br>
+ *<br>
+ * - &quot;wireframe&quot;, meaning that all vertices are assigned the same<br>
+ *   color, but the image is drawn using<br>
+ *   glPolygonMode(GL_FRONT_AND_<u></u>BACK, GL_LINE).  This test only makes<br>
+ *   sense for shapes that would normally be filled (e.g. polygons).<br>
+ *   Since we don&#39;t expect a tessellated polygon to have the same<br>
+ *   appearance as the original image (since additional edges are<br>
+ *   added), in this mode we merely check that the correct number of<br>
+ *   vertices are output and that the image renders the same with<br>
+ *   transform feedback active as with transform feedback inactive.<br>
+ *<br>
+ * - &quot;smooth&quot;, meaning that all vertices are assigned different<br>
+ *   colors, and the primitives are drawn with smooth interpolation.<br>
+ *   A failure in this mode means that the tessellation performed by<br>
+ *   transform feedback failed to match the tessellation performed by<br>
+ *   the GL pipeline under normal operation.<br>
+ *<br>
+ * - &quot;flat_last&quot; or &quot;flat_first&quot;, meaning that all vertices are<br>
+ *   assigned different colors, and the primitives are flatshaded.  In<br>
+ *   the &quot;flat_last&quot; case, they are flatshaded using the GL standard<br>
+ *   &quot;last vertex&quot; convention to select the provoking vertex.  In the<br>
+ *   &quot;flat_first&quot; case, they are flatshaded using the alternative<br>
+ *   &quot;first vertex&quot; convention provided by GL_EXT_provoking_vertex or<br>
+ *   GL_ARB_provoking_vertex.  A failure in one of these modes means<br>
+ *   that within at least one of the tessellated primitives, transform<br>
+ *   feedback failed to output the vertices in the correct order for<br>
+ *   proper flatshading.<br>
+ *<br>
+ * Note: the test can also be run on primitive types &quot;points&quot;,<br>
+ * &quot;lines&quot;, and &quot;triangles&quot;.  Although these primitive types are not<br>
+ * subject to tessellation, the test is still useful for verifying<br>
+ * that correct transform feedback output is generated.<br>
+ *<br>
+ * Note: some OpenGL implementations do not pass the &quot;flat_first&quot; and<br>
+ * &quot;flat_last&quot; tests when rendering quads or polygons.  That is, they<br>
+ * produce a tessellation which contains the correct vertices, but not<br>
+ * in the order required to preserve flat shaded colors.  This is<br>
+ * unlikely to cause problems for client programs, since client<br>
+ * programs that use new features like transform feedback are unlikely<br>
+ * to also use deprecated features like quads and polygons.  Also, it<br>
+ * is a matter of interpretation whether these tests are expected to<br>
+ * pass at all--after all, the spec does say that &quot;the order of<br>
+ * tessellation within a primitive is undefined&quot;.  Accordingly, these<br>
+ * failures, should they occur, are flagged as warnings rather than<br>
+ * failures.<br>
+ */<br>
+<br>
+#include &quot;piglit-util.h&quot;<br>
+<br>
+#define BUFFER_SIZE 20<br>
+<br>
+int piglit_width = 256;<br>
+int piglit_height = 256;<br>
+int piglit_window_mode = GLUT_DOUBLE | GLUT_RGB | GLUT_ALPHA;<br>
+<br>
+/* Test parameters */<br>
+static GLenum draw_mode;<br>
+static GLenum xfb_mode;<br>
+static unsigned num_input_vertices;<br>
+static unsigned expected_num_output_vertices;<br>
+static float (*vertex_positions)[2];<br>
+static GLboolean monochrome;<br>
+static GLboolean use_flat_color;<br>
+static GLboolean wireframe;<br>
+static GLboolean is_deprecated_draw_mode;<br>
+<br>
+/* Other globals */<br>
+static GLuint normal_prog;<br>
+static GLuint xfb_prog;<br>
+static GLuint xfb_buf;<br>
+static float vertex_colors[][4] = {<br>
+       { 0.00, 0.00, 0.00, 0.00 },<br>
+       { 1.00, 0.25, 0.25, 1.00 },<br>
+       { 0.15, 0.37, 0.98, 1.00 },<br>
+       { 0.50, 0.93, 0.07, 1.00 },<br>
+       { 0.85, 0.02, 0.63, 1.00 },<br>
+       { 0.0,  0.75, 0.75, 1.00 },<br>
+       { 0.85, 0.63, 0.02, 1.00 },<br>
+       { 0.5,  0.07, 0.93, 1.00 },<br>
+       { 0.15, 0.98, 0.37, 1.00 }<br>
+};<br>
+<br>
+static struct vertex_data {<br>
+       float vertex[2];<br>
+       float smooth_color[4];<br>
+       float flat_color[4];<br>
+} verts[BUFFER_SIZE];<br>
+<br>
+/* Note: vertices are chosen to be on pixel centers to minimize the<br>
+ * risk that rounding errors change the image.<br>
+ */<br>
+static float points_vertices[][2] = {<br>
+       {  2.5, 62.5 },<br>
+       { 62.5, 62.5 },<br>
+       {  2.5,  2.5 },<br>
+       { 62.5,  2.5 }<br>
+};<br>
+<br>
+/* Note: vertices are chosen to be on pixel centers to minimize the<br>
+ * risk that rounding errors change the image.<br>
+ */<br>
+static float lines_vertices[][2] = {<br>
+       {  2.5, 62.5 },<br>
+       { 62.5, 62.5 },<br>
+       {  2.5,  2.5 },<br>
+       { 62.5,  2.5 }<br>
+};<br>
+<br>
+/* Note: vertices are chosen to be on pixel centers to minimize the<br>
+ * risk that rounding errors change the image.<br>
+ */<br>
+static float line_loop_vertices[][2] = {<br>
+       {  2.5,  2.5 },<br>
+       {  2.5, 62.5 },<br>
+       { 62.5, 62.5 },<br>
+       { 62.5,  2.5 }<br>
+};<br>
+<br>
+/* Note: vertices are chosen to be on pixel centers to minimize the<br>
+ * risk that rounding errors change the image.<br>
+ */<br>
+static float line_strip_vertices[][2] = {<br>
+       {  2.5,  2.5 },<br>
+       {  2.5, 32.5 },<br>
+       { 32.5, 32.5 },<br>
+       { 32.5, 62.5 }<br>
+};<br>
+<br>
+static float triangles_vertices[][2] = {<br>
+       {   2,  2 },<br>
+       {   2, 62 },<br>
+       {  42,  2 },<br>
+       {  62,  2 },<br>
+       {  62, 62 },<br>
+       { 102,  2 }<br>
+};<br>
+<br>
+static float triangle_strip_vertices[][2] = {<br>
+       {  2,  2 },<br>
+       {  2, 62 },<br>
+       { 42,  2 },<br>
+       { 42, 62 },<br>
+       { 82,  2 }<br>
+};<br>
+<br>
+static float triangle_fan_vertices[][2] = {<br>
+       {  2,  2 },<br>
+       {  2, 62 },<br>
+       { 32, 47 },<br>
+       { 52, 27 },<br>
+       { 57, 12 }<br>
+};<br>
+<br>
+static float quads_vertices[][2] = {<br>
+       {   2,  2 },<br>
+       {   2, 62 },<br>
+       {  62, 62 },<br>
+       {  62,  2 },<br>
+       { 102,  2 },<br>
+       { 102, 62 },<br>
+       { 162, 62 },<br>
+       { 162,  2 }<br>
+};<br>
+<br>
+static float quad_strip_vertices[][2] = {<br>
+       {   2,  2 },<br>
+       {   2, 62 },<br>
+       {  62,  2 },<br>
+       {  62, 62 },<br>
+       { 122,  2 },<br>
+       { 122, 62 }<br>
+};<br>
+<br>
+static float polygon_vertices[][2] = {<br>
+       { 12,  2 },<br>
+       {  2, 42 },<br>
+       { 32, 62 },<br>
+       { 62, 42 },<br>
+       { 52,  2 }<br>
+};<br>
+<br>
+static const char *vstext =<br>
+       &quot;#version 130\n&quot;<br>
+       &quot;uniform vec2 vertex_offset;\n&quot;<br>
+       &quot;in vec2 vertex;\n&quot;<br>
+       &quot;in vec4 smooth_color;\n&quot;<br>
+       &quot;in vec4 flat_color;\n&quot;<br>
+       &quot;out vec2 vertex_varying;\n&quot;<br>
+       &quot;out vec4 smooth_color_varying;\n&quot;<br>
+       &quot;flat out vec4 flat_color_varying;\n&quot;<br>
+       &quot;\n&quot;<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  gl_Position = vec4(vertex + vertex_offset, 0, 128.0);\n&quot;<br>
+       &quot;  vertex_varying = vertex;\n&quot;<br>
+       &quot;  smooth_color_varying = smooth_color;\n&quot;<br>
+       &quot;  flat_color_varying = flat_color;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char *fstext =<br>
+       &quot;#version 130\n&quot;<br>
+       &quot;uniform bool use_flat_color;\n&quot;<br>
+       &quot;in vec4 smooth_color_varying;\n&quot;<br>
+       &quot;flat in vec4 flat_color_varying;\n&quot;<br>
+       &quot;\n&quot;<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  vec4 color = use_flat_color ? flat_color_varying\n&quot;<br>
+       &quot;                              : smooth_color_varying;\n&quot;<br>
+       &quot;  if (!gl_FrontFacing)\n&quot;<br>
+       &quot;    color *= 0.5;\n&quot;<br>
+       &quot;  gl_FragColor = color;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char *varyings[] = {<br>
+       &quot;vertex_varying&quot;, &quot;smooth_color_varying&quot;, &quot;flat_color_varying&quot;<br>
+};<br>
+<br>
+static void<br>
+initialize_shader_and_xfb()<br>
+{<br>
+       GLuint vs, fs;<br>
+<br>
+       piglit_require_GLSL_version(<u></u>130);<br>
+       piglit_require_transform_<u></u>feedback();<br>
+       vs = piglit_compile_shader_text(GL_<u></u>VERTEX_SHADER, vstext);<br>
+       fs = piglit_compile_shader_text(GL_<u></u>FRAGMENT_SHADER, fstext);<br>
+       normal_prog = piglit_CreateProgram();<br>
+       piglit_AttachShader(normal_<u></u>prog, vs);<br>
+       piglit_AttachShader(normal_<u></u>prog, fs);<br>
+       piglit_LinkProgram(normal_<u></u>prog);<br>
+       if (!piglit_link_check_status(<u></u>normal_prog)) {<br>
+               piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+       }<br>
+       xfb_prog = piglit_CreateProgram();<br>
+       piglit_AttachShader(xfb_prog, vs);<br>
+       piglit_AttachShader(xfb_prog, fs);<br>
+       piglit_<u></u>TransformFeedbackVaryings(xfb_<u></u>prog, 3, varyings,<br>
+                                        GL_INTERLEAVED_ATTRIBS);<br>
+       piglit_LinkProgram(xfb_prog);<br>
+       if (!piglit_link_check_status(<u></u>xfb_prog)) {<br>
+               piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+       }<br>
+       glGenBuffers(1,&amp;xfb_buf);<br>
+       glFrontFace(GL_CW);<br>
+       piglit_check_gl_error(0, PIGLIT_FAIL);<br>
+}<br>
+<br>
+static void<br>
+setup_vertex_shader_inputs(<u></u>GLuint prog)<br>
+{<br>
+       GLint vertex_index = glGetAttribLocation(prog, &quot;vertex&quot;);<br>
+       GLint smooth_color_index = glGetAttribLocation(prog, &quot;smooth_color&quot;);<br>
+       GLint flat_color_index = glGetAttribLocation(prog, &quot;flat_color&quot;);<br>
+<br>
+       glVertexAttribPointer(vertex_<u></u>index, 2, GL_FLOAT, GL_FALSE,<br></div></div>
+                             sizeof(verts[0]),&amp;verts[0].<u></u>vertex);<div class="im"><br>
+       glVertexAttribPointer(smooth_<u></u>color_index, 4, GL_FLOAT, GL_FALSE,<br></div>
+                             sizeof(verts[0]),&amp;verts[0].<u></u>smooth_color);<div class="im"><br>
+       glVertexAttribPointer(flat_<u></u>color_index, 4, GL_FLOAT, GL_FALSE,<br></div>
+                             sizeof(verts[0]),&amp;verts[0].<u></u>flat_color);<div><div class="h5"><br>
+       glEnableVertexAttribArray(<u></u>vertex_index);<br>
+       glEnableVertexAttribArray(<u></u>smooth_color_index);<br>
+       glEnableVertexAttribArray(<u></u>flat_color_index);<br>
+       piglit_check_gl_error(0, PIGLIT_FAIL);<br>
+}<br>
+<br>
+static void<br>
+initialize_vertex_shader_<u></u>inputs()<br>
+{<br>
+       unsigned i;<br>
+<br>
+       if (monochrome) {<br>
+               for (i = 1; i&lt;  ARRAY_SIZE(vertex_colors); ++i) {<br>
+                       vertex_colors[i][0] = 1.0;<br>
+                       vertex_colors[i][1] = 1.0;<br>
+                       vertex_colors[i][2] = 1.0;<br>
+                       vertex_colors[i][3] = 1.0;<br>
+               }<br>
+       }<br>
+<br>
+       for (i = 0; i&lt;  num_input_vertices; ++i) {<br>
+               memcpy(verts[i].vertex, vertex_positions[i],<br>
+                      sizeof(verts[i].vertex));<br>
+               memcpy(verts[i].smooth_color, vertex_colors[i+1],<br>
+                      sizeof(verts[i].smooth_color))<u></u>;<br>
+               memcpy(verts[i].flat_color, vertex_colors[i+1],<br>
+                      sizeof(verts[i].flat_color));<br>
+       }<br>
+}<br>
+<br>
+/**<br>
+ * Determine how many vertices were output by transform feedback by<br>
+ * seeing which elements of the transform feedback buffer have been<br>
+ * changed from their zero-initialized value.<br>
+ */<br>
+static unsigned<br>
+count_output_vertices(struct vertex_data *vertices)<br>
+{<br>
+       struct vertex_data zero_initialized;<br>
+       unsigned i;<br>
+<br>
+       memset(&amp;zero_initialized, 0, sizeof(zero_initialized));<br>
+<br>
+       for (i = 0; i&lt;  BUFFER_SIZE; ++i) {<br>
+               if (memcmp(&amp;vertices[i],&amp;zero_<u></u>initialized,<br>
+                          sizeof(zero_initialized)) == 0)<br>
+                       break;<br>
+       }<br>
+       return i;<br>
+}<br>
+<br>
+/**<br>
+ * Check that two strips of the window match.  Strips are numbered<br>
+ * from the top from 0 to 3.<br>
+ */<br>
+static GLboolean<br>
+match_strips(int reference, int compare)<br>
+{<br>
+       GLfloat *reference_image =<br>
+               malloc(piglit_width * (piglit_height / 4) * 4 * sizeof(float));<br>
+       int reference_offset = (3 - reference) * (piglit_height / 4);<br>
+       int compare_offset = (3 - compare) * (piglit_height / 4);<br>
+       glReadPixels(0, reference_offset, piglit_width, piglit_height / 4,<br>
+                    GL_RGBA, GL_FLOAT, reference_image);<br>
+       GLboolean result =<br>
+               piglit_probe_image_rgba(0, compare_offset, piglit_width,<br>
+                                       piglit_height / 4, reference_image);<br>
+       free(reference_image);<br>
+       return result;<br>
+}<br>
+<br>
+static void<br>
+draw(GLuint prog, bool use_xfb, float y_offset, GLenum mode,<br>
+     unsigned num_vertices)<br>
+{<br>
+       float vertex_offset[2] = { -82.0, y_offset };<br>
+       struct vertex_data buffer[BUFFER_SIZE];<br>
+<br>
+       piglit_UseProgram(prog);<br>
+       setup_vertex_shader_inputs(<u></u>prog);<br>
+       piglit_Uniform2fv(piglit_<u></u>GetUniformLocation(prog, &quot;vertex_offset&quot;),<br>
+                         1, vertex_offset);<br>
+       piglit_Uniform1i(piglit_<u></u>GetUniformLocation(prog, &quot;use_flat_color&quot;),<br>
+                        use_flat_color);<br>
+       glBindBuffer(GL_ARRAY_BUFFER, 0);<br>
+       if (use_xfb) {<br>
+               glBindBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, xfb_buf);<br>
+               /* Initialize the buffer with 0 so that we will be<br>
+                * able to identify membory that was not overwitten by<br>
+                * the transform feedback.<br>
+                */<br>
+               memset(buffer, 0, sizeof(buffer));<br>
+               glBufferData(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, sizeof(buffer),<br>
+                            buffer, GL_STREAM_READ);<br>
+               piglit_BindBufferBase(GL_<u></u>TRANSFORM_FEEDBACK_BUFFER, 0,<br>
+                                     xfb_buf);<br>
+               piglit_BeginTransformFeedback(<u></u>xfb_mode);<br>
+       }<br>
+       glDrawArrays(mode, 0, num_vertices);<br>
+       if (use_xfb)<br>
+               piglit_EndTransformFeedback();<br>
+       piglit_check_gl_error(0, PIGLIT_FAIL);<br>
+}<br>
+<br>
+static void<br>
+print_usage_and_exit(char *prog_name)<br>
+{<br>
+       printf(&quot;Usage: %s&lt;draw_mode&gt;  &lt;shade_mode&gt;\n&quot;<br>
+              &quot;  where&lt;draw_mode&gt;  is one of:\n&quot;<br>
+              &quot;    points\n&quot;<br>
+              &quot;    lines\n&quot;<br>
+              &quot;    line_loop\n&quot;<br>
+              &quot;    line_strip\n&quot;<br>
+              &quot;    triangles\n&quot;<br>
+              &quot;    triangle_strip\n&quot;<br>
+              &quot;    triangle_fan\n&quot;<br>
+              &quot;    quads\n&quot;<br>
+              &quot;    quad_strip\n&quot;<br>
+              &quot;    polygon\n&quot;<br>
+              &quot;  and&lt;shade_mode&gt;  is one of:\n&quot;<br>
+              &quot;    monochrome\n&quot;<br>
+              &quot;    smooth\n&quot;<br>
+              &quot;    flat_first\n&quot;<br>
+              &quot;    flat_last\n&quot;, prog_name);<br>
+       exit(1);<br>
+}<br>
+<br>
+void<br>
+piglit_init(int argc, char **argv)<br>
+{<br>
+       /* Interpret command line args */<br>
+       if (argc != 3)<br>
+               print_usage_and_exit(argv[0]);<br>
+       if (strcmp(argv[1], &quot;points&quot;) == 0) {<br>
+               draw_mode = GL_POINTS;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_POINTS;<br>
+               num_input_vertices = 4;<br>
+               expected_num_output_vertices = 4;<br>
+               vertex_positions = points_vertices;<br>
+       } else if (strcmp(argv[1], &quot;lines&quot;) == 0) {<br>
+               draw_mode = GL_LINES;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_LINES;<br>
+               num_input_vertices = 4;<br>
+               expected_num_output_vertices = 4;<br>
+               vertex_positions = lines_vertices;<br>
+       } else if (strcmp(argv[1], &quot;line_loop&quot;) == 0) {<br>
+               draw_mode = GL_LINE_LOOP;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_LINES;<br>
+               num_input_vertices = 4;<br>
+               expected_num_output_vertices = 8;<br>
+               vertex_positions = line_loop_vertices;<br>
+       } else if (strcmp(argv[1], &quot;line_strip&quot;) == 0) {<br>
+               draw_mode = GL_LINE_STRIP;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_LINES;<br>
+               num_input_vertices = 4;<br>
+               expected_num_output_vertices = 6;<br>
+               vertex_positions = line_strip_vertices;<br>
+       } else if (strcmp(argv[1], &quot;triangles&quot;) == 0) {<br>
+               draw_mode = GL_TRIANGLES;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 6;<br>
+               expected_num_output_vertices = 6;<br>
+               vertex_positions = triangles_vertices;<br>
+       } else if (strcmp(argv[1], &quot;triangle_strip&quot;) == 0) {<br>
+               draw_mode = GL_TRIANGLE_STRIP;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 5;<br>
+               expected_num_output_vertices = 9;<br>
+               vertex_positions = triangle_strip_vertices;<br>
+       } else if (strcmp(argv[1], &quot;triangle_fan&quot;) == 0) {<br>
+               draw_mode = GL_TRIANGLE_FAN;<br>
+                is_deprecated_draw_mode = GL_FALSE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 5;<br>
+               expected_num_output_vertices = 9;<br>
+               vertex_positions = triangle_fan_vertices;<br>
+       } else if (strcmp(argv[1], &quot;quads&quot;) == 0) {<br>
+               draw_mode = GL_QUADS;<br>
+                is_deprecated_draw_mode = GL_TRUE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 8;<br>
+               expected_num_output_vertices = 12;<br>
+               vertex_positions = quads_vertices;<br>
+       } else if (strcmp(argv[1], &quot;quad_strip&quot;) == 0) {<br>
+               draw_mode = GL_QUAD_STRIP;<br>
+                is_deprecated_draw_mode = GL_TRUE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 6;<br>
+               expected_num_output_vertices = 12;<br>
+               vertex_positions = quad_strip_vertices;<br>
+       } else if (strcmp(argv[1], &quot;polygon&quot;) == 0) {<br>
+               draw_mode = GL_POLYGON;<br>
+                is_deprecated_draw_mode = GL_TRUE;<br>
+               xfb_mode = GL_TRIANGLES;<br>
+               num_input_vertices = 5;<br>
+               expected_num_output_vertices = 9;<br>
+               vertex_positions = polygon_vertices;<br>
+       } else {<br>
+               print_usage_and_exit(argv[0]);<br>
+       }<br>
+       if (strcmp(argv[2], &quot;monochrome&quot;) == 0) {<br>
+               monochrome = GL_TRUE;<br>
+               use_flat_color = GL_FALSE;<br>
+               wireframe = GL_FALSE;<br>
+       } else if (strcmp(argv[2], &quot;smooth&quot;) == 0) {<br>
+               monochrome = GL_FALSE;<br>
+               use_flat_color = GL_FALSE;<br>
+               wireframe = GL_FALSE;<br>
+       } else if (strcmp(argv[2], &quot;flat_last&quot;) == 0) {<br>
+               monochrome = GL_FALSE;<br>
+               use_flat_color = GL_TRUE;<br>
+               wireframe = GL_FALSE;<br>
+       } else if (strcmp(argv[2], &quot;flat_first&quot;) == 0) {<br>
+               monochrome = GL_FALSE;<br>
+               use_flat_color = GL_TRUE;<br>
+               if (piglit_is_extension_<u></u>supported(&quot;GL_EXT_provoking_<u></u>vertex&quot;)) {<br>
+                       glProvokingVertexEXT(GL_FIRST_<u></u>VERTEX_CONVENTION);<br>
+               } else if (piglit_is_extension_<u></u>supported(&quot;GL_ARB_provoking_<u></u>vertex&quot;)) {<br>
+                       glProvokingVertex(GL_FIRST_<u></u>VERTEX_CONVENTION);<br>
+               } else {<br>
+                       printf(&quot;Test requires GL_EXT_provoking_vertex &quot;<br>
+                              &quot;or GL_ARB_provoking_vertex\n&quot;);<br>
+                       piglit_report_result(PIGLIT_<u></u>SKIP);<br>
+               }<br>
+               wireframe = GL_FALSE;<br>
+       } else if (strcmp(argv[2], &quot;wireframe&quot;) == 0) {<br>
+               monochrome = GL_TRUE;<br>
+               use_flat_color = GL_FALSE;<br>
+               wireframe = GL_TRUE;<br>
+       } else {<br>
+               print_usage_and_exit(argv[0]);<br>
+       }<br>
+<br>
+       initialize_shader_and_xfb();<br>
+}<br>
+<br>
+enum piglit_result piglit_display(void)<br>
+{<br>
+       struct vertex_data *readback;<br>
+       unsigned num_output_vertices;<br>
+       GLboolean pass = GL_TRUE;<br>
+       GLboolean warn = GL_FALSE;<br>
+<br>
+       initialize_vertex_shader_<u></u>inputs();<br>
+<br>
+       glClear(GL_COLOR_BUFFER_BIT);<br>
+       if (wireframe)<br>
+               glPolygonMode(GL_FRONT_AND_<u></u>BACK, GL_LINE);<br>
+       draw(normal_prog, false, 64.0, draw_mode, num_input_vertices);<br>
+       draw(xfb_prog, true, 0.0, draw_mode, num_input_vertices);<br>
+<br></div></div>
+       pass = match_strips(0, 1)&amp;&amp;  pass;<div class="im"><br>
+<br>
+       readback = glMapBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, GL_READ_ONLY);<br>
+       piglit_check_gl_error(0, PIGLIT_FAIL);<br>
+<br>
+       num_output_vertices = count_output_vertices(<u></u>readback);<br>
+       if (num_output_vertices != expected_num_output_vertices) {<br>
+               printf(&quot;Expected %u output vertices, but got %u\n&quot;,<br>
+                      expected_num_output_vertices, num_output_vertices);<br>
+               pass = GL_FALSE;<br>
+       }<br>
+<br>
+       memcpy(verts, readback, sizeof(verts));<br>
+       glUnmapBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER);<br>
+<br>
+       draw(normal_prog, false, -64.0, xfb_mode, num_output_vertices);<br>
+<br>
+       if (!wireframe) {<br></div>
+               if (use_flat_color&amp;&amp;  is_deprecated_draw_mode)<div class="im"><br>
+                       warn = (!match_strips(0, 2)) || warn;<br>
+               else<br></div>
+                       pass = match_strips(0, 2)&amp;&amp;  pass;<div class="im"><br>
+       }<br>
+<br>
+       piglit_present_results();<br>
+<br>
+       if (!pass)<br>
+               return PIGLIT_FAIL;<br>
+       else if (warn)<br>
+               return PIGLIT_WARN;<br>
+       else<br>
+               return PIGLIT_PASS;<br>
+}<br>
</div></blockquote>
<br>
</blockquote></div><br>