[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