<div class="gmail_quote">On 16 December 2011 17:03, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>></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>
"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."<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 "tessellation polygon flat_last",<br>
"tessellation quad_strip flat_last", and "tessellation quads<br>
flat_last". 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 "the order of tessellation within a<br>
primitive is undefined". 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't had a chance to dig into it deeply.<br>
</blockquote><div><br></div><div>Weird. Maybe I can have a look when I'm over there on Tuesday. The only thing I can think of at the moment is that maybe the AMD implementation of polygons isn't compatible with transform feedback for some reason, and since polygons are a deprecated drawing mode, they decided that it wasn'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 "wireframe" 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'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'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 ['arrays', 'elements']:<br>
test_name = 'order {0} {1}'.format(drawcall, mode)<br>
ext_transform_feedback[test_<u></u>name] = PlainExecTest(<br>
'ext_transform_feedback-{0} -auto'.format(test_name))<br>
+for draw_mode in ['points', 'lines', 'line_loop', 'line_strip',<br>
+ 'triangles', 'triangle_strip', 'triangle_fan',<br>
+ 'quads', 'quad_strip', 'polygon']:<br>
+ for shade_mode in ['monochrome', 'smooth', 'flat_first', 'flat_last', 'wireframe']:<br>
+ if shade_mode == 'wireframe' and \<br>
+ draw_mode in ['points', 'lines', 'line_loop', 'line_strip']:<br>
+ continue<br>
+ test_name = 'tessellation {0} {1}'.format(<br>
+ draw_mode, shade_mode)<br>
+ ext_transform_feedback[test_<u></u>name] = PlainExecTest(<br>
+ 'ext_transform_feedback-{0} -auto'.format(test_name))<br>
<br>
ext_transform_feedback['<u></u>output-type float'] = PlainExecTest(['ext_transform_<u></u>feedback-output-type', '-auto', 'float'])<br>
ext_transform_feedback['<u></u>output-type float[2]'] = PlainExecTest(['ext_transform_<u></u>feedback-output-type', '-auto', 'float[2]'])<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 "Software"),<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 "AS IS", 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>
+ * "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."<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'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>
+ * - "monochrome", 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>
+ * - "wireframe", 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'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>
+ * - "smooth", 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>
+ * - "flat_last" or "flat_first", meaning that all vertices are<br>
+ * assigned different colors, and the primitives are flatshaded. In<br>
+ * the "flat_last" case, they are flatshaded using the GL standard<br>
+ * "last vertex" convention to select the provoking vertex. In the<br>
+ * "flat_first" case, they are flatshaded using the alternative<br>
+ * "first vertex" 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 "points",<br>
+ * "lines", and "triangles". 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 "flat_first" and<br>
+ * "flat_last" 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 "the order of<br>
+ * tessellation within a primitive is undefined". Accordingly, these<br>
+ * failures, should they occur, are flagged as warnings rather than<br>
+ * failures.<br>
+ */<br>
+<br>
+#include "piglit-util.h"<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>
+ "#version 130\n"<br>
+ "uniform vec2 vertex_offset;\n"<br>
+ "in vec2 vertex;\n"<br>
+ "in vec4 smooth_color;\n"<br>
+ "in vec4 flat_color;\n"<br>
+ "out vec2 vertex_varying;\n"<br>
+ "out vec4 smooth_color_varying;\n"<br>
+ "flat out vec4 flat_color_varying;\n"<br>
+ "\n"<br>
+ "void main()\n"<br>
+ "{\n"<br>
+ " gl_Position = vec4(vertex + vertex_offset, 0, 128.0);\n"<br>
+ " vertex_varying = vertex;\n"<br>
+ " smooth_color_varying = smooth_color;\n"<br>
+ " flat_color_varying = flat_color;\n"<br>
+ "}\n";<br>
+<br>
+static const char *fstext =<br>
+ "#version 130\n"<br>
+ "uniform bool use_flat_color;\n"<br>
+ "in vec4 smooth_color_varying;\n"<br>
+ "flat in vec4 flat_color_varying;\n"<br>
+ "\n"<br>
+ "void main()\n"<br>
+ "{\n"<br>
+ " vec4 color = use_flat_color ? flat_color_varying\n"<br>
+ " : smooth_color_varying;\n"<br>
+ " if (!gl_FrontFacing)\n"<br>
+ " color *= 0.5;\n"<br>
+ " gl_FragColor = color;\n"<br>
+ "}\n";<br>
+<br>
+static const char *varyings[] = {<br>
+ "vertex_varying", "smooth_color_varying", "flat_color_varying"<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,&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, "vertex");<br>
+ GLint smooth_color_index = glGetAttribLocation(prog, "smooth_color");<br>
+ GLint flat_color_index = glGetAttribLocation(prog, "flat_color");<br>
+<br>
+ glVertexAttribPointer(vertex_<u></u>index, 2, GL_FLOAT, GL_FALSE,<br></div></div>
+ sizeof(verts[0]),&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]),&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]),&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< 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< 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(&zero_initialized, 0, sizeof(zero_initialized));<br>
+<br>
+ for (i = 0; i< BUFFER_SIZE; ++i) {<br>
+ if (memcmp(&vertices[i],&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, "vertex_offset"),<br>
+ 1, vertex_offset);<br>
+ piglit_Uniform1i(piglit_<u></u>GetUniformLocation(prog, "use_flat_color"),<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("Usage: %s<draw_mode> <shade_mode>\n"<br>
+ " where<draw_mode> is one of:\n"<br>
+ " points\n"<br>
+ " lines\n"<br>
+ " line_loop\n"<br>
+ " line_strip\n"<br>
+ " triangles\n"<br>
+ " triangle_strip\n"<br>
+ " triangle_fan\n"<br>
+ " quads\n"<br>
+ " quad_strip\n"<br>
+ " polygon\n"<br>
+ " and<shade_mode> is one of:\n"<br>
+ " monochrome\n"<br>
+ " smooth\n"<br>
+ " flat_first\n"<br>
+ " flat_last\n", 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], "points") == 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], "lines") == 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], "line_loop") == 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], "line_strip") == 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], "triangles") == 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], "triangle_strip") == 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], "triangle_fan") == 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], "quads") == 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], "quad_strip") == 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], "polygon") == 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], "monochrome") == 0) {<br>
+ monochrome = GL_TRUE;<br>
+ use_flat_color = GL_FALSE;<br>
+ wireframe = GL_FALSE;<br>
+ } else if (strcmp(argv[2], "smooth") == 0) {<br>
+ monochrome = GL_FALSE;<br>
+ use_flat_color = GL_FALSE;<br>
+ wireframe = GL_FALSE;<br>
+ } else if (strcmp(argv[2], "flat_last") == 0) {<br>
+ monochrome = GL_FALSE;<br>
+ use_flat_color = GL_TRUE;<br>
+ wireframe = GL_FALSE;<br>
+ } else if (strcmp(argv[2], "flat_first") == 0) {<br>
+ monochrome = GL_FALSE;<br>
+ use_flat_color = GL_TRUE;<br>
+ if (piglit_is_extension_<u></u>supported("GL_EXT_provoking_<u></u>vertex")) {<br>
+ glProvokingVertexEXT(GL_FIRST_<u></u>VERTEX_CONVENTION);<br>
+ } else if (piglit_is_extension_<u></u>supported("GL_ARB_provoking_<u></u>vertex")) {<br>
+ glProvokingVertex(GL_FIRST_<u></u>VERTEX_CONVENTION);<br>
+ } else {<br>
+ printf("Test requires GL_EXT_provoking_vertex "<br>
+ "or GL_ARB_provoking_vertex\n");<br>
+ piglit_report_result(PIGLIT_<u></u>SKIP);<br>
+ }<br>
+ wireframe = GL_FALSE;<br>
+ } else if (strcmp(argv[2], "wireframe") == 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)&& 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("Expected %u output vertices, but got %u\n",<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&& is_deprecated_draw_mode)<div class="im"><br>
+ warn = (!match_strips(0, 2)) || warn;<br>
+ else<br></div>
+ pass = match_strips(0, 2)&& 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>