[Piglit] [PATCH 2/6] Add vbo support to shader_runner.
Ian Romanick
idr at freedesktop.org
Thu Oct 27 10:32:15 PDT 2011
On 10/20/2011 02:12 PM, Paul Berry wrote:
> This patch adds the ability for shader_runner tests to include a
> "[vertex data]" section containing data in columnar format, for example:
>
> [vertex data]
> vertex/float/3 foo/uint/1 bar/int/2
> 0.0 0.0 0.0 0xe0000000 0 0
> 0.0 1.0 0.0 0x70000000 1 1
> 1.0 1.0 0.0 0x00000000 0 1
>
> Each column header is of the form ATTRNAME/TYPE/COUNT, where ATTRNAME
> is the name of the vertex attribute to be bound to this column, TYPE
> is the type of data that follows ("float", "int", or "uint"), and
> COUNT is the vector length of the data (e.g. "3" for vec3 data).
>
> To send vertex data to the shader, use the new shader_runner command
> "draw arrays". The parameters are the same as for the glDrawArrays()
> command, so for example to draw triangle primitives using 3 elements
> from the vertex data array starting at element 0, use the command:
>
> draw arrays GL_TRIANGLES 0 3
>
> More detailed examples can be found in the tests/shaders/vbo
> directory.
>
> The implementation is largely in a new file, piglit-vbo.cpp, so that
> it can be re-used by other piglit tests if necessary.
> ---
> tests/shaders/shader_runner.c | 80 ++++
> tests/shaders/vbo/vbo-generic-float.shader_test | 37 ++
> tests/shaders/vbo/vbo-generic-int.shader_test | 39 ++
> tests/shaders/vbo/vbo-generic-uint.shader_test | 39 ++
> tests/util/CMakeLists.gl.txt | 1 +
> tests/util/piglit-vbo.cpp | 514 +++++++++++++++++++++++
> tests/util/piglit-vbo.h | 35 ++
> 7 files changed, 745 insertions(+), 0 deletions(-)
> create mode 100644 tests/shaders/vbo/vbo-generic-float.shader_test
> create mode 100644 tests/shaders/vbo/vbo-generic-int.shader_test
> create mode 100644 tests/shaders/vbo/vbo-generic-uint.shader_test
> create mode 100644 tests/util/piglit-vbo.cpp
> create mode 100644 tests/util/piglit-vbo.h
>
> diff --git a/tests/shaders/shader_runner.c b/tests/shaders/shader_runner.c
> index b07ff55..77a753c 100644
> --- a/tests/shaders/shader_runner.c
> +++ b/tests/shaders/shader_runner.c
> @@ -37,6 +37,7 @@
> #include<libgen.h>
> #endif
> #include "piglit-util.h"
> +#include "piglit-vbo.h"
>
> int piglit_width = 250, piglit_height = 250;
> int piglit_window_mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE;
> @@ -65,7 +66,10 @@ unsigned num_fragment_shaders = 0;
> char *shader_strings[256];
> GLsizei shader_string_sizes[256];
> unsigned num_shader_strings = 0;
> +const char *vertex_data_start = NULL;
> +const char *vertex_data_end = NULL;
> GLuint prog;
> +size_t num_vbo_rows = 0;
>
> enum states {
> none = 0,
> @@ -79,6 +83,7 @@ enum states {
> fragment_shader,
> fragment_shader_file,
> fragment_program,
> + vertex_data,
> test,
> };
>
> @@ -473,6 +478,10 @@ leave_state(enum states state, const char *line)
> case fragment_program:
> break;
>
> + case vertex_data:
> + vertex_data_end = line;
> + break;
> +
> case test:
> break;
>
> @@ -592,6 +601,9 @@ process_test_script(const char *script_name)
> state = fragment_shader_file;
> shader_strings[0] = NULL;
> num_shader_strings = 0;
> + } else if (strncmp(line, "[vertex data]", 13) == 0) {
> + state = vertex_data;
> + vertex_data_start = NULL;
> } else if (strncmp(line, "[test]", 6) == 0) {
> test_start = strchrnul(line, '\n');
> if (test_start[0] != '\0')
> @@ -625,6 +637,11 @@ process_test_script(const char *script_name)
> load_shader_file(line);
> break;
>
> + case vertex_data:
> + if (vertex_data_start == NULL)
> + vertex_data_start = line;
> + break;
> +
> case test:
> break;
> }
> @@ -884,6 +901,43 @@ draw_instanced_rect(int primcount, float x, float y, float w, float h)
> glDisableClientState(GL_VERTEX_ARRAY);
> }
>
> +
> +struct mode_table {
> + const char *name;
> + GLenum value;
> +} mode_table[] = {
> + { "GL_POINTS", GL_POINTS },
> + { "GL_LINE_STRIP", GL_LINE_STRIP },
> + { "GL_LINE_LOOP", GL_LINE_LOOP },
> + { "GL_LINES", GL_LINES },
> + { "GL_POLYGON", GL_POLYGON },
> + { "GL_TRIANGLE_STRIP", GL_TRIANGLE_STRIP },
> + { "GL_TRIANGLE_FAN", GL_TRIANGLE_FAN },
> + { "GL_TRIANGLES", GL_TRIANGLES },
> + { "GL_QUAD_STRIP", GL_QUAD_STRIP },
> + { "GL_QUADS", GL_QUADS },
> + { NULL, 0 }
> +};
> +
> +
> +GLenum
> +decode_mode(const char *mode_str)
> +{
> + int i;
> +
> + for (i = 0; mode_table[i].name; ++i) {
> + if (0 == strcmp(mode_str, mode_table[i].name))
> + return mode_table[i].value;
> + }
> +
> + printf("unknown drawing mode \"%s\"", mode_str);
> + piglit_report_result(PIGLIT_FAIL);
> +
> + /* Should not be reached, but return 0 to avoid compiler warning */
> + return 0;
> +}
> +
> +
> enum piglit_result
> piglit_display(void)
> {
> @@ -900,6 +954,7 @@ piglit_display(void)
> float c[32];
> double d[4];
> int x, y, w, h, l, tex, level;
> + char s[32];
>
> line = eat_whitespace(line);
>
> @@ -927,6 +982,28 @@ piglit_display(void)
> &primcount,
> c + 0, c + 1, c + 2, c + 3);
> draw_instanced_rect(primcount, c[0], c[1], c[2], c[3]);
> + } else if (sscanf(line, "draw arrays %31s %d %d", s,&x,&y)) {
> + GLenum mode = decode_mode(s);
> + int first = x;
> + size_t count = (size_t) y;
> + if (first< 0) {
> + printf("draw arrays 'first' must be>= 0\n");
> + piglit_report_result(PIGLIT_FAIL);
> + } else if ((size_t) first>= num_vbo_rows) {
> + printf("draw arrays 'first' must be< %lu\n",
> + num_vbo_rows);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + if (count<= 0) {
> + printf("draw arrays 'count' must be> 0\n");
> + piglit_report_result(PIGLIT_FAIL);
> + } else if (count> num_vbo_rows - (size_t) first) {
> + printf("draw arrays cannot draw beyond %lu\n",
> + num_vbo_rows);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + /* TODO: wrapper? */
> + glDrawArrays(mode, first, count);
> } else if (string_match("disable", line)) {
> do_enable_disable(line + 7, false);
> } else if (string_match("enable", line)) {
> @@ -1523,4 +1600,7 @@ piglit_init(int argc, char **argv)
>
> process_test_script(argv[1]);
> link_and_use_shaders();
> + if (vertex_data_start != NULL)
> + num_vbo_rows = setup_vbo_from_text(prog, vertex_data_start,
> + vertex_data_end);
> }
> diff --git a/tests/shaders/vbo/vbo-generic-float.shader_test b/tests/shaders/vbo/vbo-generic-float.shader_test
> new file mode 100644
> index 0000000..8982211
> --- /dev/null
> +++ b/tests/shaders/vbo/vbo-generic-float.shader_test
> @@ -0,0 +1,37 @@
> +[require]
> +GLSL>= 1.10
> +GL>= 2.1
> +
> +[vertex shader]
> +attribute vec4 vertex;
> +attribute float foo;
> +attribute vec2 bar;
> +
> +void main()
> +{
> + gl_Position = gl_ModelViewProjectionMatrix * vertex;
> + gl_FrontColor = vec4(foo, bar, 1.0);
> +}
> +
> +[fragment shader]
> +void main()
> +{
> + gl_FragColor = gl_Color;
> +}
> +
> +[vertex data]
> +vertex/float/3 foo/float/1 bar/float/2
> +0.0 0.0 0.0 1.0 0.0 0.0
> +0.0 1.0 0.0 0.5 1.0 1.0
> +1.0 1.0 0.0 0.0 0.0 1.0
> +
> +[test]
> +ortho 0.0 1.0 0.0 1.0
> +clear color 0.0 0.0 0.0 0.0
> +clear
> +draw arrays GL_TRIANGLES 0 3
> +relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)
> +relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)
> +relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)
> +relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)
> +relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)
> diff --git a/tests/shaders/vbo/vbo-generic-int.shader_test b/tests/shaders/vbo/vbo-generic-int.shader_test
> new file mode 100644
> index 0000000..669b85d
> --- /dev/null
> +++ b/tests/shaders/vbo/vbo-generic-int.shader_test
> @@ -0,0 +1,39 @@
> +[require]
> +GLSL>= 1.30
> +GL>= 3.0
> +
> +[vertex shader]
> +#version 130
> +attribute vec4 vertex;
> +attribute int foo;
> +attribute ivec2 bar;
> +
> +void main()
> +{
> + gl_Position = gl_ModelViewProjectionMatrix * vertex;
> + gl_FrontColor = vec4(foo/10.0, bar, 1.0);
> +}
> +
> +[fragment shader]
> +#version 130
> +void main()
> +{
> + gl_FragColor = gl_Color;
> +}
> +
> +[vertex data]
> +vertex/float/3 foo/int/1 bar/int/2
> +0.0 0.0 0.0 10 0 0
> +0.0 1.0 0.0 5 1 1
> +1.0 1.0 0.0 0 0 1
> +
> +[test]
> +ortho 0.0 1.0 0.0 1.0
> +clear color 0.0 0.0 0.0 0.0
> +clear
> +draw arrays GL_TRIANGLES 0 3
> +relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)
> +relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)
> +relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)
> +relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)
> +relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)
> diff --git a/tests/shaders/vbo/vbo-generic-uint.shader_test b/tests/shaders/vbo/vbo-generic-uint.shader_test
> new file mode 100644
> index 0000000..6f56dd1
> --- /dev/null
> +++ b/tests/shaders/vbo/vbo-generic-uint.shader_test
> @@ -0,0 +1,39 @@
> +[require]
> +GLSL>= 1.30
> +GL>= 3.0
> +
> +[vertex shader]
> +#version 130
> +attribute vec4 vertex;
> +attribute uint foo;
> +attribute ivec2 bar;
> +
> +void main()
> +{
> + gl_Position = gl_ModelViewProjectionMatrix * vertex;
> + gl_FrontColor = vec4(float(foo)/float(0xe0000000u), bar, 1.0);
> +}
> +
> +[fragment shader]
> +#version 130
> +void main()
> +{
> + gl_FragColor = gl_Color;
> +}
> +
> +[vertex data]
> +vertex/float/3 foo/uint/1 bar/int/2
> +0.0 0.0 0.0 0xe0000000 0 0
> +0.0 1.0 0.0 0x70000000 1 1
> +1.0 1.0 0.0 0x00000000 0 1
> +
> +[test]
> +ortho 0.0 1.0 0.0 1.0
> +clear color 0.0 0.0 0.0 0.0
> +clear
> +draw arrays GL_TRIANGLES 0 3
> +relative probe rgba (0.3, 0.7) (0.5, 0.4, 0.7, 1.0)
> +relative probe rgba (0.1, 0.5) (0.7, 0.4, 0.5, 1.0)
> +relative probe rgba (0.1, 0.9) (0.5, 0.8, 0.9, 1.0)
> +relative probe rgba (0.5, 0.9) (0.3, 0.4, 0.9, 1.0)
> +relative probe rgba (0.7, 0.3) (0.0, 0.0, 0.0, 0.0)
> diff --git a/tests/util/CMakeLists.gl.txt b/tests/util/CMakeLists.gl.txt
> index a03b50b..df1bfb9 100644
> --- a/tests/util/CMakeLists.gl.txt
> +++ b/tests/util/CMakeLists.gl.txt
> @@ -10,6 +10,7 @@ set(UTIL_SOURCES
> piglit-shader.c
> piglit-shader-gl.c
> piglit-util-gl.c
> + piglit-vbo.cpp
> )
>
> IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
> diff --git a/tests/util/piglit-vbo.cpp b/tests/util/piglit-vbo.cpp
> new file mode 100644
> index 0000000..fdba6b1
> --- /dev/null
> +++ b/tests/util/piglit-vbo.cpp
> @@ -0,0 +1,514 @@
> +/*
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +/**
> + * \file piglit-vbo.cpp
> + *
> + * This file adds the facility for specifying vertex data to piglit
> + * tests using a columnar text format, for example:
> + *
> + * \verbatim
> + * vertex/float/3 foo/uint/1 bar/int/2
> + * 0.0 0.0 0.0 10 0 0 # comment
> + * 0.0 1.0 0.0 5 1 1
> + * 1.0 1.0 0.0 0 0 1
> + * \endverbatim
> + *
> + * The format consists of a row of column headers followed by any
> + * number of rows of data. Each column header has the form
> + * "ATTRNAME/TYPE/COUNT", where ATTRNAME is the name of the vertex
> + * attribute to be bound to this column, TYPE is the type of data that
> + * follows ("float", "int", or "uint"), and COUNT is the vector length
> + * of the data (e.g. "3" for vec3 data).
> + *
> + * The data follows the column headers in space-separated form. "#"
> + * can be used for comments, as in shell scripts.
> + *
> + * To process textual vertex data, call the function
> + * setup_vbo_from_text(), passing the int identifying the linked
> + * program, and the string containing the vertex data. The return
> + * value is the number of rows of vertex data found.
> + *
> + * If an error occurs, setup_vbo_from_text() will print out a
> + * description of the error and exit with PIGLIT_FAIL.
> + *
> + * For the example above, the call to setup_vbo_from_text() is roughly
> + * equivalent to the following GL operations:
> + *
> + * \code
> + * struct vertex_attributes {
> + * GLfloat vertex[3];
> + * GLuint foo;
> + * GLint bar[2];
> + * } vertex_data[] = {
> + * { { 0.0, 0.0, 0.0 }, 10, { 0, 0 } },
> + * { { 0.0, 1.0, 0.0 }, 5, { 1, 1 } },
> + * { { 1.0, 1.0, 0.0 }, 0, { 0, 1 } }
> + * };
> + * size_t stride = sizeof(vertex_data[0]);
> + * GLint vertex_index = glGetAttribLocation(prog, "vertex");
> + * GLint foo_index = glGetAttribLocation(prog, "foo");
> + * GLint bar_index = glGetAttribLocation(prog, "bar");
> + * GLuint buffer_handle;
> + * glGenBuffers(1,&buffer_handle);
> + * glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
> + * glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data),&vertex_data,
> + * GL_STATIC_DRAW);
> + * glVertexAttribPointer(vertex_index, 3, GL_FLOAT, GL_FALSE, stride,
> + * (void *) offsetof(vertex_attributes, vertex));
> + * glVertexAttribIPointer(foo_index, 3, GL_UNSIGNED_INT, stride,
> + * (void *) offsetof(vertex_attributes, foo));
> + * glVertexAttribIPointer(bar_index, 3, GL_INT, stride,
> + * (void *) offsetof(vertex_attributes, bar));
> + * glEnableVertexAttribArray(vertex_index);
> + * glEnableVertexAttribArray(foo_index);
> + * glEnableVertexAttribArray(bar_index);
> + * \endcode
> + */
> +
> +#ifndef _GNU_SOURCE
> +#define _GNU_SOURCE
> +#endif
> +
> +#if defined(_MSC_VER)
> +#define bool BOOL
> +#define true 1
> +#define false 0
> +#else
> +#include<stdbool.h>
> +#endif
Is any of the above necessary (or even correct) in C++?
> +#include<string.h>
> +#include<ctype.h>
> +#if defined(_WIN32)
> +#include<stdlib.h>
> +#else
> +#include<libgen.h>
> +#endif
> +#include "piglit-util.h"
> +#include "piglit-vbo.h"
> +#include<vector>
> +#include<string>
> +#include<errno.h>
> +
> +
> +/**
> + * Currently all the attribute types we support (int, uint, and float)
> + * are 4 bytes in width.
> + */
> +const int ATTRIBUTE_SIZE = 4;
> +
> +
> +/**
> + * Convert a type name string to a GLenum.
> + */
> +GLenum
> +decode_type(const char *type)
> +{
> + static struct type_table_entry {
> + const char *type; /* NULL means end of table */
> + GLenum enum_value;
> + } const type_table[] = {
> + { "int", GL_INT },
> + { "uint", GL_UNSIGNED_INT },
> + { "float", GL_FLOAT },
> + { NULL, 0 }
> + };
> +
> +
> + for (int i = 0; type_table[i].type; ++i) {
> + if (0 == strcmp(type, type_table[i].type))
> + return type_table[i].enum_value;
> + }
> +
> + printf("Unrecognized type: %s\n", type);
> + piglit_report_result(PIGLIT_FAIL);
> + return 0;
> +}
> +
> +
> +/**
> + * Description of a vertex attribute, built from its column header
> + */
> +class vertex_attrib_description
> +{
> +public:
> + vertex_attrib_description(GLuint prog, const char *text);
> + bool parse_datum(const char **text, void *data) const;
> + void setup(size_t *offset, size_t stride) const;
> +
> + /**
> + * Data type of this attribute.
> + */
> + GLenum data_type;
> +
> + /**
> + * Vector length of this attribute.
> + */
> + size_t count;
> +
> + /**
> + * Index of this vertex attribute in the linked program.
> + */
> + GLuint index;
> +};
> +
> +
> +/**
> + * Build a vertex_attrib_description from a column header, by looking
> + * up the vertex attribute in the linked program and interpreting the
> + * type and count parts of the header.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then exit with PIGLIT_FAIL.
> + */
> +vertex_attrib_description::vertex_attrib_description(GLuint prog,
> + const char *text)
> +{
> + /* Split the column header into name/type/count fields */
> + const char *first_slash = strchr(text, '/');
> + if (first_slash == NULL) {
> + printf("Column headers must be in the form name/type/count. "
> + "Got: %s\n",
> + text);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + std::string name(text, first_slash);
> + const char *second_slash = strchr(first_slash + 1, '/');
> + if (second_slash == NULL) {
> + printf("Column headers must be in the form name/type/count. "
> + "Got: %s\n",
> + text);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + std::string type_str(first_slash + 1, second_slash);
> + this->data_type = decode_type(type_str.c_str());
> + char *endptr;
> + this->count = strtoul(second_slash + 1,&endptr, 10);
> + if (*endptr != '\0') {
> + printf("Column headers must be in the form name/type/count. "
> + "Got: %s\n",
> + text);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + GLint attrib_location = glGetAttribLocation(prog, name.c_str());
> + if (attrib_location == -1) {
> + printf("Unexpected vbo column name. Got: %s\n", name.c_str());
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + this->index = attrib_location;
> + /* If the type is integral, verify that integer vertex
> + * attribute support is present. Note: we treat it as a FAIL
> + * if support is not present, because it's up to the test to
> + * either (a) not require integer vertex attribute support, or
> + * (b) skip itself if integer vertex attribute support is not
> + * present.
> + */
> + if (this->data_type != GL_FLOAT&&
> + (piglit_is_gles() || piglit_get_gl_version()< 30)) {
> + printf("Test uses glVertexAttribIPointer(),"
> + " which is unsupported.\n");
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + if (this->count< 1 || this->count> 4) {
> + printf("Count must be between 1 and 4. Got: %lu\n", count);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +}
> +
> +
> +/**
> + * Parse a single number (floating point or integral) from one of the
> + * data rows, and store it in the location pointed to by \c data.
> + * Update \c text to point to the next character of input.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then return false. Otherwise return true.
> + */
> +bool
> +vertex_attrib_description::parse_datum(const char **text, void *data) const
> +{
> + char *endptr;
> + errno = 0;
> + switch (this->data_type) {
> + case GL_FLOAT: {
> + double value = strtod(*text,&endptr);
> + if (errno == ERANGE) {
> + printf("Could not parse as double\n");
> + return false;
> + }
> + *((GLfloat *) data) = (float) value;
> + break;
> + }
> + case GL_INT: {
> + long value = strtol(*text,&endptr, 0);
> + if (errno == ERANGE) {
> + printf("Could not parse as signed integer\n");
> + return false;
> + }
> + *((GLint *) data) = (GLint) value;
> + break;
> + }
> + case GL_UNSIGNED_INT: {
> + unsigned long value = strtoul(*text,&endptr, 0);
> + if (errno == ERANGE) {
> + printf("Could not parse as unsigned integer\n");
> + return false;
> + }
> + *((GLuint *) data) = (GLuint) value;
> + break;
> + }
> + }
> + *text = endptr;
> + return true;
> +}
> +
> +
> +/**
> + * Execute the necessary GL calls to bind this attribute to its data.
> + */
> +void
> +vertex_attrib_description::setup(size_t *offset, size_t stride) const
> +{
> + if (this->data_type == GL_FLOAT) {
> + glVertexAttribPointer(this->index, this->count,
> + this->data_type, GL_FALSE, stride,
> + (void *) *offset);
> + } else {
> + glVertexAttribIPointer(this->index, this->count,
> + this->data_type, stride,
> + (void *) *offset);
> + }
> + glEnableVertexAttribArray(index);
> + *offset += ATTRIBUTE_SIZE * this->count;
> +}
> +
> +
> +/**
> + * Data structure containing all of the data parsed from the text
> + * input, as well as the methods that parse it and convert it to GL
> + * calls.
> + */
> +class vbo_data
> +{
> +public:
> + vbo_data(std::string const&text, GLuint prog);
> + size_t setup() const;
> +
> +private:
> + void parse_header_line(const std::string&line, GLuint prog);
> + void parse_data_line(const std::string&line, unsigned int line_num);
> + void parse_line(std::string line, unsigned int line_num, GLuint prog);
> +
> + /**
> + * True if the header line has already been parsed.
> + */
> + bool header_seen;
> +
> + /**
> + * Description of each attribute.
> + */
> + std::vector<vertex_attrib_description> attribs;
> +
> + /**
> + * Raw data buffer containing parsed numbers.
> + */
> + std::vector<char> raw_data;
> +
> + /**
> + * Number of bytes in each row of raw_data.
> + */
> + size_t stride;
> +
> + /**
> + * Number of rows in raw_data.
> + */
> + size_t num_rows;
> +};
> +
> +
> +
> +static bool
> +is_blank_line(const std::string&line)
> +{
> + for (size_t i = 0; i< line.size(); ++i) {
> + if (!isspace(line[i]))
> + return false;
> + }
> + return true;
> +}
> +
> +
> +/**
> + * Populate this->attribs and compute this->stride based on column
> + * headers.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then exit with PIGLIT_FAIL.
> + */
> +void
> +vbo_data::parse_header_line(const std::string&line, GLuint prog)
> +{
> + size_t pos = 0;
> + this->stride = 0;
> + while (pos< line.size()) {
> + if (isspace(line[pos])) {
> + ++pos;
> + } else {
> + size_t column_header_end = pos;
> + while (column_header_end< line.size()&&
> + !isspace(line[column_header_end]))
> + ++column_header_end;
> + std::string column_header = line.substr(
> + pos, column_header_end - pos);
> + vertex_attrib_description desc(
> + prog, column_header.c_str());
> + attribs.push_back(desc);
> + this->stride += ATTRIBUTE_SIZE * desc.count;
> + pos = column_header_end + 1;
> + }
> + }
> +}
> +
> +
> +/**
> + * Convert a data row into binary form and append it to this->raw_data.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then exit with PIGLIT_FAIL.
> + */
> +void
> +vbo_data::parse_data_line(const std::string&line, unsigned int line_num)
> +{
> + /* Allocate space in raw_data for this line */
> + size_t old_size = this->raw_data.size();
> + this->raw_data.resize(old_size + this->stride);
> + char *data_ptr =&this->raw_data[old_size];
> +
> + const char *line_ptr = line.c_str();
> + for (size_t i = 0; i< this->attribs.size(); ++i) {
> + for (size_t j = 0; j< this->attribs[i].count; ++j) {
> + if (!this->attribs[i].parse_datum(&line_ptr,
> + data_ptr)) {
> + printf("At line %u of [vertex data] section\n",
> + line_num);
> + printf("Offending text: %s\n", line_ptr);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + data_ptr += ATTRIBUTE_SIZE;
> + }
> + }
> +
> + ++this->num_rows;
> +}
> +
> +
> +/**
> + * Parse a line of input text.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then exit with PIGLIT_FAIL.
> + */
> +void
> +vbo_data::parse_line(std::string line, unsigned int line_num, GLuint prog)
> +{
> + /* Ignore end-of-line comments */
> + line = line.substr(0, line.find('#'));
> +
> + /* Ignore blank or comment-only lines */
> + if (is_blank_line(line))
> + return;
> +
> + if (!this->header_seen) {
> + this->header_seen = true;
> + parse_header_line(line, prog);
> + } else {
> + parse_data_line(line, line_num);
> + }
> +}
> +
> +
> +/**
> + * Parse the input but don't execute any GL commands.
> + *
> + * If there is a parse failure, print a description of the problem and
> + * then exit with PIGLIT_FAIL.
> + */
> +vbo_data::vbo_data(const std::string&text, GLuint prog)
> + : header_seen(false), num_rows(0)
> +{
> + unsigned int line_num = 1;
> +
> + size_t pos = 0;
> + while (pos< text.size()) {
> + size_t end_of_line = text.find('\n', pos);
> + if (end_of_line == std::string::npos)
> + end_of_line = text.size();
> + parse_line(text.substr(pos, end_of_line), line_num++, prog);
> + pos = end_of_line + 1;
> + }
> +}
> +
> +
> +/**
> + * Execute the necessary GL commands to set up the vertex data passed
> + * to the constructor.
> + */
> +size_t
> +vbo_data::setup() const
> +{
> + GLuint buffer_handle;
> + glGenBuffers(1,&buffer_handle);
> + glBindBuffer(GL_ARRAY_BUFFER, buffer_handle);
> + glBufferData(GL_ARRAY_BUFFER, this->stride * this->num_rows,
> + &this->raw_data[0], GL_STATIC_DRAW);
> +
> + size_t offset = 0;
> + for (size_t i = 0; i< attribs.size(); ++i)
> + attribs[i].setup(&offset, this->stride);
> +
> + /* Leave buffer bound for later draw calls */
> +
> + return this->num_rows;
> +}
> +
> +
> +/**
> + * Set up a vertex buffer object for the program prog based on the
> + * data encoded in text_start. text_end indicates the end of the text
> + * string; if it is NULL, the string is assumed to be null-terminated.
> + *
> + * Return value is the number of rows of vertex data found.
> + *
> + * For details about the format of the text string, see the comment at
> + * the top of this file.
> + */
> +size_t
> +setup_vbo_from_text(GLuint prog, const char *text_start, const char *text_end)
> +{
> + if (text_end == NULL)
> + text_end = text_start + strlen(text_start);
> + std::string text(text_start, text_end);
> + return vbo_data(text, prog).setup();
> +}
> diff --git a/tests/util/piglit-vbo.h b/tests/util/piglit-vbo.h
> new file mode 100644
> index 0000000..22935e3
> --- /dev/null
> +++ b/tests/util/piglit-vbo.h
> @@ -0,0 +1,35 @@
> +/*
> + * Copyright © 2011 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +#pragma once
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +size_t
> +setup_vbo_from_text(GLuint prog, const char *text_start, const char *text_end);
> +
> +#ifdef __cplusplus
> +} /* end extern "C" */
> +#endif
More information about the Piglit
mailing list