On 27 October 2011 10:32, Ian Romanick <span dir="ltr"><<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>></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;">
<div><div></div><div class="h5">On 10/20/2011 02:12 PM, Paul Berry wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
This patch adds the ability for shader_runner tests to include a<br>
"[vertex data]" section containing data in columnar format, for example:<br>
<br>
[vertex data]<br>
vertex/float/3 foo/uint/1 bar/int/2<br>
0.0 0.0 0.0 0xe0000000 0 0<br>
0.0 1.0 0.0 0x70000000 1 1<br>
1.0 1.0 0.0 0x00000000 0 1<br>
<br>
Each column header is of the form ATTRNAME/TYPE/COUNT, where ATTRNAME<br>
is the name of the vertex attribute to be bound to this column, TYPE<br>
is the type of data that follows ("float", "int", or "uint"), and<br>
COUNT is the vector length of the data (e.g. "3" for vec3 data).<br>
<br>
To send vertex data to the shader, use the new shader_runner command<br>
"draw arrays". The parameters are the same as for the glDrawArrays()<br>
command, so for example to draw triangle primitives using 3 elements<br>
from the vertex data array starting at element 0, use the command:<br>
<br>
draw arrays GL_TRIANGLES 0 3<br>
<br>
More detailed examples can be found in the tests/shaders/vbo<br>
directory.<br>
<br>
The implementation is largely in a new file, piglit-vbo.cpp, so that<br>
it can be re-used by other piglit tests if necessary.<br>
---<br>
tests/shaders/shader_runner.c | 80 ++++<br>
tests/shaders/vbo/vbo-generic-<u></u>float.shader_test | 37 ++<br>
tests/shaders/vbo/vbo-generic-<u></u>int.shader_test | 39 ++<br>
tests/shaders/vbo/vbo-generic-<u></u>uint.shader_test | 39 ++<br>
tests/util/CMakeLists.gl.txt | 1 +<br>
tests/util/piglit-vbo.cpp | 514 +++++++++++++++++++++++<br>
tests/util/piglit-vbo.h | 35 ++<br>
7 files changed, 745 insertions(+), 0 deletions(-)<br>
create mode 100644 tests/shaders/vbo/vbo-generic-<u></u>float.shader_test<br>
create mode 100644 tests/shaders/vbo/vbo-generic-<u></u>int.shader_test<br>
create mode 100644 tests/shaders/vbo/vbo-generic-<u></u>uint.shader_test<br>
create mode 100644 tests/util/piglit-vbo.cpp<br>
create mode 100644 tests/util/piglit-vbo.h<br>
<br>
diff --git a/tests/shaders/shader_runner.<u></u>c b/tests/shaders/shader_runner.<u></u>c<br>
index b07ff55..77a753c 100644<br>
--- a/tests/shaders/shader_runner.<u></u>c<br>
+++ b/tests/shaders/shader_runner.<u></u>c<br>
@@ -37,6 +37,7 @@<br>
#include<libgen.h><br>
#endif<br>
#include "piglit-util.h"<br>
+#include "piglit-vbo.h"<br>
<br>
int piglit_width = 250, piglit_height = 250;<br>
int piglit_window_mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE;<br>
@@ -65,7 +66,10 @@ unsigned num_fragment_shaders = 0;<br>
char *shader_strings[256];<br>
GLsizei shader_string_sizes[256];<br>
unsigned num_shader_strings = 0;<br>
+const char *vertex_data_start = NULL;<br>
+const char *vertex_data_end = NULL;<br>
GLuint prog;<br>
+size_t num_vbo_rows = 0;<br>
<br>
enum states {<br>
none = 0,<br>
@@ -79,6 +83,7 @@ enum states {<br>
fragment_shader,<br>
fragment_shader_file,<br>
fragment_program,<br>
+ vertex_data,<br>
test,<br>
};<br>
<br>
@@ -473,6 +478,10 @@ leave_state(enum states state, const char *line)<br>
case fragment_program:<br>
break;<br>
<br>
+ case vertex_data:<br>
+ vertex_data_end = line;<br>
+ break;<br>
+<br>
case test:<br>
break;<br>
<br>
@@ -592,6 +601,9 @@ process_test_script(const char *script_name)<br>
state = fragment_shader_file;<br>
shader_strings[0] = NULL;<br>
num_shader_strings = 0;<br>
+ } else if (strncmp(line, "[vertex data]", 13) == 0) {<br>
+ state = vertex_data;<br>
+ vertex_data_start = NULL;<br>
} else if (strncmp(line, "[test]", 6) == 0) {<br>
test_start = strchrnul(line, '\n');<br>
if (test_start[0] != '\0')<br>
@@ -625,6 +637,11 @@ process_test_script(const char *script_name)<br>
load_shader_file(line);<br>
break;<br>
<br>
+ case vertex_data:<br>
+ if (vertex_data_start == NULL)<br>
+ vertex_data_start = line;<br>
+ break;<br>
+<br>
case test:<br>
break;<br>
}<br>
@@ -884,6 +901,43 @@ draw_instanced_rect(int primcount, float x, float y, float w, float h)<br>
glDisableClientState(GL_<u></u>VERTEX_ARRAY);<br>
}<br>
<br>
+<br>
+struct mode_table {<br>
+ const char *name;<br>
+ GLenum value;<br>
+} mode_table[] = {<br>
+ { "GL_POINTS", GL_POINTS },<br>
+ { "GL_LINE_STRIP", GL_LINE_STRIP },<br>
+ { "GL_LINE_LOOP", GL_LINE_LOOP },<br>
+ { "GL_LINES", GL_LINES },<br>
+ { "GL_POLYGON", GL_POLYGON },<br>
+ { "GL_TRIANGLE_STRIP", GL_TRIANGLE_STRIP },<br>
+ { "GL_TRIANGLE_FAN", GL_TRIANGLE_FAN },<br>
+ { "GL_TRIANGLES", GL_TRIANGLES },<br>
+ { "GL_QUAD_STRIP", GL_QUAD_STRIP },<br>
+ { "GL_QUADS", GL_QUADS },<br>
+ { NULL, 0 }<br>
+};<br>
+<br>
+<br>
+GLenum<br>
+decode_mode(const char *mode_str)<br>
+{<br>
+ int i;<br>
+<br>
+ for (i = 0; mode_table[i].name; ++i) {<br>
+ if (0 == strcmp(mode_str, mode_table[i].name))<br>
+ return mode_table[i].value;<br>
+ }<br>
+<br>
+ printf("unknown drawing mode \"%s\"", mode_str);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+<br>
+ /* Should not be reached, but return 0 to avoid compiler warning */<br>
+ return 0;<br>
+}<br>
+<br>
+<br>
enum piglit_result<br>
piglit_display(void)<br>
{<br>
@@ -900,6 +954,7 @@ piglit_display(void)<br>
float c[32];<br>
double d[4];<br>
int x, y, w, h, l, tex, level;<br>
+ char s[32];<br>
<br>
line = eat_whitespace(line);<br>
<br>
@@ -927,6 +982,28 @@ piglit_display(void)<br>
&primcount,<br>
c + 0, c + 1, c + 2, c + 3);<br>
draw_instanced_rect(primcount, c[0], c[1], c[2], c[3]);<br>
+ } else if (sscanf(line, "draw arrays %31s %d %d", s,&x,&y)) {<br>
+ GLenum mode = decode_mode(s);<br>
+ int first = x;<br>
+ size_t count = (size_t) y;<br>
+ if (first< 0) {<br>
+ printf("draw arrays 'first' must be>= 0\n");<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ } else if ((size_t) first>= num_vbo_rows) {<br>
+ printf("draw arrays 'first' must be< %lu\n",<br>
+ num_vbo_rows);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ if (count<= 0) {<br>
+ printf("draw arrays 'count' must be> 0\n");<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ } else if (count> num_vbo_rows - (size_t) first) {<br>
+ printf("draw arrays cannot draw beyond %lu\n",<br>
+ num_vbo_rows);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ /* TODO: wrapper? */<br>
+ glDrawArrays(mode, first, count);<br>
} else if (string_match("disable", line)) {<br>
do_enable_disable(line + 7, false);<br>
} else if (string_match("enable", line)) {<br>
@@ -1523,4 +1600,7 @@ piglit_init(int argc, char **argv)<br>
<br>
process_test_script(argv[1]);<br>
link_and_use_shaders();<br>
+ if (vertex_data_start != NULL)<br>
+ num_vbo_rows = setup_vbo_from_text(prog, vertex_data_start,<br>
+ vertex_data_end);<br>
}<br>
diff --git a/tests/shaders/vbo/vbo-<u></u>generic-float.shader_test b/tests/shaders/vbo/vbo-<u></u>generic-float.shader_test<br>
new file mode 100644<br>
index 0000000..8982211<br>
--- /dev/null<br>
+++ b/tests/shaders/vbo/vbo-<u></u>generic-float.shader_test<br>
@@ -0,0 +1,37 @@<br>
+[require]<br>
+GLSL>= 1.10<br>
+GL>= 2.1<br>
+<br>
+[vertex shader]<br>
+attribute vec4 vertex;<br>
+attribute float foo;<br>
+attribute vec2 bar;<br>
+<br>
+void main()<br>
+{<br>
+ gl_Position = gl_ModelViewProjectionMatrix * vertex;<br>
+ gl_FrontColor = vec4(foo, bar, 1.0);<br>
+}<br>
+<br>
+[fragment shader]<br>
+void main()<br>
+{<br>
+ gl_FragColor = gl_Color;<br>
+}<br>
+<br>
+[vertex data]<br>
+vertex/float/3 foo/float/1 bar/float/2<br>
+0.0 0.0 0.0 1.0 0.0 0.0<br>
+0.0 1.0 0.0 0.5 1.0 1.0<br>
+1.0 1.0 0.0 0.0 0.0 1.0<br>
+<br>
+[test]<br>
+ortho 0.0 1.0 0.0 1.0<br>
+clear color 0.0 0.0 0.0 0.0<br>
+clear<br>
+draw arrays GL_TRIANGLES 0 3<br>
+relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)<br>
+relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)<br>
+relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)<br>
+relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)<br>
+relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)<br>
diff --git a/tests/shaders/vbo/vbo-<u></u>generic-int.shader_test b/tests/shaders/vbo/vbo-<u></u>generic-int.shader_test<br>
new file mode 100644<br>
index 0000000..669b85d<br>
--- /dev/null<br>
+++ b/tests/shaders/vbo/vbo-<u></u>generic-int.shader_test<br>
@@ -0,0 +1,39 @@<br>
+[require]<br>
+GLSL>= 1.30<br>
+GL>= 3.0<br>
+<br>
+[vertex shader]<br>
+#version 130<br>
+attribute vec4 vertex;<br>
+attribute int foo;<br>
+attribute ivec2 bar;<br>
+<br>
+void main()<br>
+{<br>
+ gl_Position = gl_ModelViewProjectionMatrix * vertex;<br>
+ gl_FrontColor = vec4(foo/10.0, bar, 1.0);<br>
+}<br>
+<br>
+[fragment shader]<br>
+#version 130<br>
+void main()<br>
+{<br>
+ gl_FragColor = gl_Color;<br>
+}<br>
+<br>
+[vertex data]<br>
+vertex/float/3 foo/int/1 bar/int/2<br>
+0.0 0.0 0.0 10 0 0<br>
+0.0 1.0 0.0 5 1 1<br>
+1.0 1.0 0.0 0 0 1<br>
+<br>
+[test]<br>
+ortho 0.0 1.0 0.0 1.0<br>
+clear color 0.0 0.0 0.0 0.0<br>
+clear<br>
+draw arrays GL_TRIANGLES 0 3<br>
+relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)<br>
+relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)<br>
+relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)<br>
+relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)<br>
+relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)<br>
diff --git a/tests/shaders/vbo/vbo-<u></u>generic-uint.shader_test b/tests/shaders/vbo/vbo-<u></u>generic-uint.shader_test<br>
new file mode 100644<br>
index 0000000..6f56dd1<br>
--- /dev/null<br>
+++ b/tests/shaders/vbo/vbo-<u></u>generic-uint.shader_test<br>
@@ -0,0 +1,39 @@<br>
+[require]<br>
+GLSL>= 1.30<br>
+GL>= 3.0<br>
+<br>
+[vertex shader]<br>
+#version 130<br>
+attribute vec4 vertex;<br>
+attribute uint foo;<br>
+attribute ivec2 bar;<br>
+<br>
+void main()<br>
+{<br>
+ gl_Position = gl_ModelViewProjectionMatrix * vertex;<br>
+ gl_FrontColor = vec4(float(foo)/float(<u></u>0xe0000000u), bar, 1.0);<br>
+}<br>
+<br>
+[fragment shader]<br>
+#version 130<br>
+void main()<br>
+{<br>
+ gl_FragColor = gl_Color;<br>
+}<br>
+<br>
+[vertex data]<br>
+vertex/float/3 foo/uint/1 bar/int/2<br>
+0.0 0.0 0.0 0xe0000000 0 0<br>
+0.0 1.0 0.0 0x70000000 1 1<br>
+1.0 1.0 0.0 0x00000000 0 1<br>
+<br>
+[test]<br>
+ortho 0.0 1.0 0.0 1.0<br>
+clear color 0.0 0.0 0.0 0.0<br>
+clear<br>
+draw arrays GL_TRIANGLES 0 3<br>
+relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)<br>
+relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)<br>
+relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)<br>
+relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)<br>
+relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)<br>
diff --git a/tests/util/CMakeLists.gl.txt b/tests/util/CMakeLists.gl.txt<br>
index a03b50b..df1bfb9 100644<br>
--- a/tests/util/CMakeLists.gl.txt<br>
+++ b/tests/util/CMakeLists.gl.txt<br>
@@ -10,6 +10,7 @@ set(UTIL_SOURCES<br>
piglit-shader.c<br>
piglit-shader-gl.c<br>
piglit-util-gl.c<br>
+ piglit-vbo.cpp<br>
)<br>
<br>
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")<br>
diff --git a/tests/util/piglit-vbo.cpp b/tests/util/piglit-vbo.cpp<br>
new file mode 100644<br>
index 0000000..fdba6b1<br>
--- /dev/null<br>
+++ b/tests/util/piglit-vbo.cpp<br>
@@ -0,0 +1,514 @@<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 piglit-vbo.cpp<br>
+ *<br>
+ * This file adds the facility for specifying vertex data to piglit<br>
+ * tests using a columnar text format, for example:<br>
+ *<br>
+ * \verbatim<br>
+ * vertex/float/3 foo/uint/1 bar/int/2<br>
+ * 0.0 0.0 0.0 10 0 0 # comment<br>
+ * 0.0 1.0 0.0 5 1 1<br>
+ * 1.0 1.0 0.0 0 0 1<br>
+ * \endverbatim<br>
+ *<br>
+ * The format consists of a row of column headers followed by any<br>
+ * number of rows of data. Each column header has the form<br>
+ * "ATTRNAME/TYPE/COUNT", where ATTRNAME is the name of the vertex<br>
+ * attribute to be bound to this column, TYPE is the type of data that<br>
+ * follows ("float", "int", or "uint"), and COUNT is the vector length<br>
+ * of the data (e.g. "3" for vec3 data).<br>
+ *<br>
+ * The data follows the column headers in space-separated form. "#"<br>
+ * can be used for comments, as in shell scripts.<br>
+ *<br>
+ * To process textual vertex data, call the function<br>
+ * setup_vbo_from_text(), passing the int identifying the linked<br>
+ * program, and the string containing the vertex data. The return<br>
+ * value is the number of rows of vertex data found.<br>
+ *<br>
+ * If an error occurs, setup_vbo_from_text() will print out a<br>
+ * description of the error and exit with PIGLIT_FAIL.<br>
+ *<br>
+ * For the example above, the call to setup_vbo_from_text() is roughly<br>
+ * equivalent to the following GL operations:<br>
+ *<br>
+ * \code<br>
+ * struct vertex_attributes {<br>
+ * GLfloat vertex[3];<br>
+ * GLuint foo;<br>
+ * GLint bar[2];<br>
+ * } vertex_data[] = {<br>
+ * { { 0.0, 0.0, 0.0 }, 10, { 0, 0 } },<br>
+ * { { 0.0, 1.0, 0.0 }, 5, { 1, 1 } },<br>
+ * { { 1.0, 1.0, 0.0 }, 0, { 0, 1 } }<br>
+ * };<br>
+ * size_t stride = sizeof(vertex_data[0]);<br>
+ * GLint vertex_index = glGetAttribLocation(prog, "vertex");<br>
+ * GLint foo_index = glGetAttribLocation(prog, "foo");<br>
+ * GLint bar_index = glGetAttribLocation(prog, "bar");<br>
+ * GLuint buffer_handle;<br>
+ * glGenBuffers(1,&buffer_handle)<u></u>;<br>
+ * glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);<br>
+ * glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data),&vertex_<u></u>data,<br>
+ * GL_STATIC_DRAW);<br>
+ * glVertexAttribPointer(vertex_<u></u>index, 3, GL_FLOAT, GL_FALSE, stride,<br>
+ * (void *) offsetof(vertex_attributes, vertex));<br>
+ * glVertexAttribIPointer(foo_<u></u>index, 3, GL_UNSIGNED_INT, stride,<br>
+ * (void *) offsetof(vertex_attributes, foo));<br>
+ * glVertexAttribIPointer(bar_<u></u>index, 3, GL_INT, stride,<br>
+ * (void *) offsetof(vertex_attributes, bar));<br>
+ * glEnableVertexAttribArray(<u></u>vertex_index);<br>
+ * glEnableVertexAttribArray(foo_<u></u>index);<br>
+ * glEnableVertexAttribArray(bar_<u></u>index);<br>
+ * \endcode<br>
+ */<br>
+<br>
+#ifndef _GNU_SOURCE<br>
+#define _GNU_SOURCE<br>
+#endif<br>
+<br>
+#if defined(_MSC_VER)<br>
+#define bool BOOL<br>
+#define true 1<br>
+#define false 0<br>
+#else<br>
+#include<stdbool.h><br>
+#endif<br>
</blockquote>
<br></div></div>
Is any of the above necessary (or even correct) in C++?<br></blockquote><div><br>Whoops, good catch. I blindly copied this stuff out of shader_runner.c without engaging my brain. You're right, of course. It's not necessary in C++ and it probably would make things mighty confusing for people trying to build Piglit on Windows. I'll pull it out.<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>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div></div><div class="h5">
+#include<string.h><br>
+#include<ctype.h><br>
+#if defined(_WIN32)<br>
+#include<stdlib.h><br>
+#else<br>
+#include<libgen.h><br>
+#endif<br>
+#include "piglit-util.h"<br>
+#include "piglit-vbo.h"<br>
+#include<vector><br>
+#include<string><br>
+#include<errno.h><br>
+<br>
+<br>
+/**<br>
+ * Currently all the attribute types we support (int, uint, and float)<br>
+ * are 4 bytes in width.<br>
+ */<br>
+const int ATTRIBUTE_SIZE = 4;<br>
+<br>
+<br>
+/**<br>
+ * Convert a type name string to a GLenum.<br>
+ */<br>
+GLenum<br>
+decode_type(const char *type)<br>
+{<br>
+ static struct type_table_entry {<br>
+ const char *type; /* NULL means end of table */<br>
+ GLenum enum_value;<br>
+ } const type_table[] = {<br>
+ { "int", GL_INT },<br>
+ { "uint", GL_UNSIGNED_INT },<br>
+ { "float", GL_FLOAT },<br>
+ { NULL, 0 }<br>
+ };<br>
+<br>
+<br>
+ for (int i = 0; type_table[i].type; ++i) {<br>
+ if (0 == strcmp(type, type_table[i].type))<br>
+ return type_table[i].enum_value;<br>
+ }<br>
+<br>
+ printf("Unrecognized type: %s\n", type);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ return 0;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Description of a vertex attribute, built from its column header<br>
+ */<br>
+class vertex_attrib_description<br>
+{<br>
+public:<br>
+ vertex_attrib_description(<u></u>GLuint prog, const char *text);<br>
+ bool parse_datum(const char **text, void *data) const;<br>
+ void setup(size_t *offset, size_t stride) const;<br>
+<br>
+ /**<br>
+ * Data type of this attribute.<br>
+ */<br>
+ GLenum data_type;<br>
+<br>
+ /**<br>
+ * Vector length of this attribute.<br>
+ */<br>
+ size_t count;<br>
+<br>
+ /**<br>
+ * Index of this vertex attribute in the linked program.<br>
+ */<br>
+ GLuint index;<br>
+};<br>
+<br>
+<br>
+/**<br>
+ * Build a vertex_attrib_description from a column header, by looking<br>
+ * up the vertex attribute in the linked program and interpreting the<br>
+ * type and count parts of the header.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then exit with PIGLIT_FAIL.<br>
+ */<br>
+vertex_attrib_description::<u></u>vertex_attrib_description(<u></u>GLuint prog,<br>
+ const char *text)<br>
+{<br>
+ /* Split the column header into name/type/count fields */<br>
+ const char *first_slash = strchr(text, '/');<br>
+ if (first_slash == NULL) {<br>
+ printf("Column headers must be in the form name/type/count. "<br>
+ "Got: %s\n",<br>
+ text);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ std::string name(text, first_slash);<br>
+ const char *second_slash = strchr(first_slash + 1, '/');<br>
+ if (second_slash == NULL) {<br>
+ printf("Column headers must be in the form name/type/count. "<br>
+ "Got: %s\n",<br>
+ text);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ std::string type_str(first_slash + 1, second_slash);<br>
+ this->data_type = decode_type(type_str.c_str());<br>
+ char *endptr;<br></div></div>
+ this->count = strtoul(second_slash + 1,&endptr, 10);<div><div></div><div class="h5"><br>
+ if (*endptr != '\0') {<br>
+ printf("Column headers must be in the form name/type/count. "<br>
+ "Got: %s\n",<br>
+ text);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+<br>
+ GLint attrib_location = glGetAttribLocation(prog, name.c_str());<br>
+ if (attrib_location == -1) {<br>
+ printf("Unexpected vbo column name. Got: %s\n", name.c_str());<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ this->index = attrib_location;<br>
+ /* If the type is integral, verify that integer vertex<br>
+ * attribute support is present. Note: we treat it as a FAIL<br>
+ * if support is not present, because it's up to the test to<br>
+ * either (a) not require integer vertex attribute support, or<br>
+ * (b) skip itself if integer vertex attribute support is not<br>
+ * present.<br>
+ */<br>
+ if (this->data_type != GL_FLOAT&&<br>
+ (piglit_is_gles() || piglit_get_gl_version()< 30)) {<br>
+ printf("Test uses glVertexAttribIPointer(),"<br>
+ " which is unsupported.\n");<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+<br>
+ if (this->count< 1 || this->count> 4) {<br>
+ printf("Count must be between 1 and 4. Got: %lu\n", count);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Parse a single number (floating point or integral) from one of the<br>
+ * data rows, and store it in the location pointed to by \c data.<br>
+ * Update \c text to point to the next character of input.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then return false. Otherwise return true.<br>
+ */<br>
+bool<br>
+vertex_attrib_description::<u></u>parse_datum(const char **text, void *data) const<br>
+{<br>
+ char *endptr;<br>
+ errno = 0;<br>
+ switch (this->data_type) {<br>
+ case GL_FLOAT: {<br>
+ double value = strtod(*text,&endptr);<br>
+ if (errno == ERANGE) {<br>
+ printf("Could not parse as double\n");<br>
+ return false;<br>
+ }<br>
+ *((GLfloat *) data) = (float) value;<br>
+ break;<br>
+ }<br>
+ case GL_INT: {<br></div></div>
+ long value = strtol(*text,&endptr, 0);<div class="im"><br>
+ if (errno == ERANGE) {<br>
+ printf("Could not parse as signed integer\n");<br>
+ return false;<br>
+ }<br>
+ *((GLint *) data) = (GLint) value;<br>
+ break;<br>
+ }<br>
+ case GL_UNSIGNED_INT: {<br></div>
+ unsigned long value = strtoul(*text,&endptr, 0);<div><div></div><div class="h5"><br>
+ if (errno == ERANGE) {<br>
+ printf("Could not parse as unsigned integer\n");<br>
+ return false;<br>
+ }<br>
+ *((GLuint *) data) = (GLuint) value;<br>
+ break;<br>
+ }<br>
+ }<br>
+ *text = endptr;<br>
+ return true;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Execute the necessary GL calls to bind this attribute to its data.<br>
+ */<br>
+void<br>
+vertex_attrib_description::<u></u>setup(size_t *offset, size_t stride) const<br>
+{<br>
+ if (this->data_type == GL_FLOAT) {<br>
+ glVertexAttribPointer(this-><u></u>index, this->count,<br>
+ this->data_type, GL_FALSE, stride,<br>
+ (void *) *offset);<br>
+ } else {<br>
+ glVertexAttribIPointer(this-><u></u>index, this->count,<br>
+ this->data_type, stride,<br>
+ (void *) *offset);<br>
+ }<br>
+ glEnableVertexAttribArray(<u></u>index);<br>
+ *offset += ATTRIBUTE_SIZE * this->count;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Data structure containing all of the data parsed from the text<br>
+ * input, as well as the methods that parse it and convert it to GL<br>
+ * calls.<br>
+ */<br>
+class vbo_data<br>
+{<br>
+public:<br></div></div>
+ vbo_data(std::string const&text, GLuint prog);<div class="im"><br>
+ size_t setup() const;<br>
+<br>
+private:<br></div>
+ void parse_header_line(const std::string&line, GLuint prog);<br>
+ void parse_data_line(const std::string&line, unsigned int line_num);<div><div></div><div class="h5"><br>
+ void parse_line(std::string line, unsigned int line_num, GLuint prog);<br>
+<br>
+ /**<br>
+ * True if the header line has already been parsed.<br>
+ */<br>
+ bool header_seen;<br>
+<br>
+ /**<br>
+ * Description of each attribute.<br>
+ */<br>
+ std::vector<vertex_attrib_<u></u>description> attribs;<br>
+<br>
+ /**<br>
+ * Raw data buffer containing parsed numbers.<br>
+ */<br>
+ std::vector<char> raw_data;<br>
+<br>
+ /**<br>
+ * Number of bytes in each row of raw_data.<br>
+ */<br>
+ size_t stride;<br>
+<br>
+ /**<br>
+ * Number of rows in raw_data.<br>
+ */<br>
+ size_t num_rows;<br>
+};<br>
+<br>
+<br>
+<br>
+static bool<br>
+is_blank_line(const std::string&line)<br>
+{<br>
+ for (size_t i = 0; i< line.size(); ++i) {<br>
+ if (!isspace(line[i]))<br>
+ return false;<br>
+ }<br>
+ return true;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Populate this->attribs and compute this->stride based on column<br>
+ * headers.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then exit with PIGLIT_FAIL.<br>
+ */<br>
+void<br></div></div>
+vbo_data::parse_header_line(<u></u>const std::string&line, GLuint prog)<div><div></div><div class="h5"><br>
+{<br>
+ size_t pos = 0;<br>
+ this->stride = 0;<br>
+ while (pos< line.size()) {<br>
+ if (isspace(line[pos])) {<br>
+ ++pos;<br>
+ } else {<br>
+ size_t column_header_end = pos;<br>
+ while (column_header_end< line.size()&&<br>
+ !isspace(line[column_header_<u></u>end]))<br>
+ ++column_header_end;<br>
+ std::string column_header = line.substr(<br>
+ pos, column_header_end - pos);<br>
+ vertex_attrib_description desc(<br>
+ prog, column_header.c_str());<br>
+ attribs.push_back(desc);<br>
+ this->stride += ATTRIBUTE_SIZE * desc.count;<br>
+ pos = column_header_end + 1;<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Convert a data row into binary form and append it to this->raw_data.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then exit with PIGLIT_FAIL.<br>
+ */<br>
+void<br></div></div>
+vbo_data::parse_data_line(<u></u>const std::string&line, unsigned int line_num)<div class="im"><br>
+{<br>
+ /* Allocate space in raw_data for this line */<br>
+ size_t old_size = this->raw_data.size();<br>
+ this->raw_data.resize(old_size + this->stride);<br></div>
+ char *data_ptr =&this->raw_data[old_size];<div><div></div><div class="h5"><br>
+<br>
+ const char *line_ptr = line.c_str();<br>
+ for (size_t i = 0; i< this->attribs.size(); ++i) {<br>
+ for (size_t j = 0; j< this->attribs[i].count; ++j) {<br>
+ if (!this->attribs[i].parse_<u></u>datum(&line_ptr,<br>
+ data_ptr)) {<br>
+ printf("At line %u of [vertex data] section\n",<br>
+ line_num);<br>
+ printf("Offending text: %s\n", line_ptr);<br>
+ piglit_report_result(PIGLIT_<u></u>FAIL);<br>
+ }<br>
+ data_ptr += ATTRIBUTE_SIZE;<br>
+ }<br>
+ }<br>
+<br>
+ ++this->num_rows;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Parse a line of input text.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then exit with PIGLIT_FAIL.<br>
+ */<br>
+void<br>
+vbo_data::parse_line(std::<u></u>string line, unsigned int line_num, GLuint prog)<br>
+{<br>
+ /* Ignore end-of-line comments */<br>
+ line = line.substr(0, line.find('#'));<br>
+<br>
+ /* Ignore blank or comment-only lines */<br>
+ if (is_blank_line(line))<br>
+ return;<br>
+<br>
+ if (!this->header_seen) {<br>
+ this->header_seen = true;<br>
+ parse_header_line(line, prog);<br>
+ } else {<br>
+ parse_data_line(line, line_num);<br>
+ }<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Parse the input but don't execute any GL commands.<br>
+ *<br>
+ * If there is a parse failure, print a description of the problem and<br>
+ * then exit with PIGLIT_FAIL.<br>
+ */<br></div></div>
+vbo_data::vbo_data(const std::string&text, GLuint prog)<div><div></div><div class="h5"><br>
+ : header_seen(false), num_rows(0)<br>
+{<br>
+ unsigned int line_num = 1;<br>
+<br>
+ size_t pos = 0;<br>
+ while (pos< text.size()) {<br>
+ size_t end_of_line = text.find('\n', pos);<br>
+ if (end_of_line == std::string::npos)<br>
+ end_of_line = text.size();<br>
+ parse_line(text.substr(pos, end_of_line), line_num++, prog);<br>
+ pos = end_of_line + 1;<br>
+ }<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Execute the necessary GL commands to set up the vertex data passed<br>
+ * to the constructor.<br>
+ */<br>
+size_t<br>
+vbo_data::setup() const<br>
+{<br>
+ GLuint buffer_handle;<br>
+ glGenBuffers(1,&buffer_handle)<u></u>;<br>
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);<br>
+ glBufferData(GL_ARRAY_BUFFER, this->stride * this->num_rows,<br>
+ &this->raw_data[0], GL_STATIC_DRAW);<br>
+<br>
+ size_t offset = 0;<br>
+ for (size_t i = 0; i< attribs.size(); ++i)<br>
+ attribs[i].setup(&offset, this->stride);<br>
+<br>
+ /* Leave buffer bound for later draw calls */<br>
+<br>
+ return this->num_rows;<br>
+}<br>
+<br>
+<br>
+/**<br>
+ * Set up a vertex buffer object for the program prog based on the<br>
+ * data encoded in text_start. text_end indicates the end of the text<br>
+ * string; if it is NULL, the string is assumed to be null-terminated.<br>
+ *<br>
+ * Return value is the number of rows of vertex data found.<br>
+ *<br>
+ * For details about the format of the text string, see the comment at<br>
+ * the top of this file.<br>
+ */<br>
+size_t<br>
+setup_vbo_from_text(GLuint prog, const char *text_start, const char *text_end)<br>
+{<br>
+ if (text_end == NULL)<br>
+ text_end = text_start + strlen(text_start);<br>
+ std::string text(text_start, text_end);<br>
+ return vbo_data(text, prog).setup();<br>
+}<br>
diff --git a/tests/util/piglit-vbo.h b/tests/util/piglit-vbo.h<br>
new file mode 100644<br>
index 0000000..22935e3<br>
--- /dev/null<br>
+++ b/tests/util/piglit-vbo.h<br>
@@ -0,0 +1,35 @@<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>
+#pragma once<br>
+<br>
+#ifdef __cplusplus<br>
+extern "C" {<br>
+#endif<br>
+<br>
+size_t<br>
+setup_vbo_from_text(GLuint prog, const char *text_start, const char *text_end);<br>
+<br>
+#ifdef __cplusplus<br>
+} /* end extern "C" */<br>
+#endif<br>
</div></div></blockquote>
<br>
</blockquote></div><br>