[Piglit] [PATCH] ARB_draw_indirect: add initial tests

Christoph Bumiller christoph.bumiller at speed.at
Thu Apr 4 11:10:42 PDT 2013


From: Christoph Bumiller <e0425955 at student.tuwien.ac.at>

Is that sufficient to get anyone looking at my mesa patches
(I've rebased them already) or do I need to make more/nicer
tests ? How many ?
If I'd get paid anything for this I'd gladly spend my time writing
loads of tests, it's rather relaxing, compared to reverse engineering.
---
 tests/spec/CMakeLists.txt                          |    1 +
 tests/spec/arb_draw_indirect/CMakeLists.gl.txt     |   19 +
 tests/spec/arb_draw_indirect/CMakeLists.txt        |    1 +
 tests/spec/arb_draw_indirect/draw-arrays-multi.c   |   66 ++++
 .../arb_draw_indirect/draw-arrays-prim-restart.c   |  141 +++++++
 tests/spec/arb_draw_indirect/draw-arrays.c         |   67 ++++
 tests/spec/arb_draw_indirect/draw-common.c         |  408 ++++++++++++++++++++
 tests/spec/arb_draw_indirect/draw-elements-multi.c |   66 ++++
 tests/spec/arb_draw_indirect/draw-elements.c       |   67 ++++
 tests/spec/arb_draw_indirect/errors-multi.c        |  140 +++++++
 tests/spec/arb_draw_indirect/errors.c              |  159 ++++++++
 11 files changed, 1135 insertions(+), 0 deletions(-)
 create mode 100644 tests/spec/arb_draw_indirect/CMakeLists.gl.txt
 create mode 100644 tests/spec/arb_draw_indirect/CMakeLists.txt
 create mode 100644 tests/spec/arb_draw_indirect/draw-arrays-multi.c
 create mode 100644 tests/spec/arb_draw_indirect/draw-arrays-prim-restart.c
 create mode 100644 tests/spec/arb_draw_indirect/draw-arrays.c
 create mode 100644 tests/spec/arb_draw_indirect/draw-common.c
 create mode 100644 tests/spec/arb_draw_indirect/draw-elements-multi.c
 create mode 100644 tests/spec/arb_draw_indirect/draw-elements.c
 create mode 100644 tests/spec/arb_draw_indirect/errors-multi.c
 create mode 100644 tests/spec/arb_draw_indirect/errors.c

diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
index a1492cc..a07a814 100644
--- a/tests/spec/CMakeLists.txt
+++ b/tests/spec/CMakeLists.txt
@@ -2,6 +2,7 @@ add_subdirectory (amd_performance_monitor)
 add_subdirectory (arb_color_buffer_float)
 add_subdirectory (arb_debug_output)
 add_subdirectory (arb_draw_instanced)
+add_subdirectory (arb_draw_indirect)
 add_subdirectory (arb_es2_compatibility)
 add_subdirectory (arb_framebuffer_object)
 add_subdirectory (arb_framebuffer_srgb)
diff --git a/tests/spec/arb_draw_indirect/CMakeLists.gl.txt b/tests/spec/arb_draw_indirect/CMakeLists.gl.txt
new file mode 100644
index 0000000..3b3d823
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/CMakeLists.gl.txt
@@ -0,0 +1,19 @@
+include_directories(
+	${GLEXT_INCLUDE_DIR}
+	${OPENGL_INCLUDE_PATH}
+	${piglit_SOURCE_DIR}/tests/util
+)
+
+link_libraries (
+	piglitutil_${piglit_target_api}
+	${OPENGL_gl_LIBRARY}
+	${OPENGL_glu_LIBRARY}
+)
+
+piglit_add_executable (arb_draw_indirect-draw-arrays-prim-restart draw-arrays-prim-restart.c)
+piglit_add_executable (arb_draw_indirect-draw-elements draw-elements.c draw-common.c)
+piglit_add_executable (arb_draw_indirect-draw-elements-multi draw-elements-multi.c draw-common.c)
+piglit_add_executable (arb_draw_indirect-draw-arrays draw-arrays.c draw-common.c)
+piglit_add_executable (arb_draw_indirect-draw-arrays-multi draw-arrays-multi.c draw-common.c)
+piglit_add_executable (arb_draw_indirect-errors errors.c)
+piglit_add_executable (arb_draw_indirect-errors-multi errors-multi.c)
diff --git a/tests/spec/arb_draw_indirect/CMakeLists.txt b/tests/spec/arb_draw_indirect/CMakeLists.txt
new file mode 100644
index 0000000..144a306
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/CMakeLists.txt
@@ -0,0 +1 @@
+piglit_include_target_api()
diff --git a/tests/spec/arb_draw_indirect/draw-arrays-multi.c b/tests/spec/arb_draw_indirect/draw-arrays-multi.c
new file mode 100644
index 0000000..b8dd1da
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-arrays-multi.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © The Piglit project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file draw-elements.c
+ *
+ * Tests that glDrawElementsIndirect works correctly with various combinations
+ * of draw command data generated via transform feedback.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+unsigned num_indirect_draws;
+
+void write_commands_tfb(int indexed, int dump);
+void setup_indirect_draw();
+int compare_results(int indexed);
+
+enum piglit_result
+piglit_display(void)
+{
+	write_commands_tfb(0, 0);
+	setup_indirect_draw();
+
+	glBeginTransformFeedback(GL_POINTS);
+	/* If <stride> is zero, the array elements are treated as
+	 * tightly packed. */
+	glMultiDrawArraysIndirect(GL_POINTS, NULL,
+				  num_indirect_draws, 0);
+	glEndTransformFeedback();
+
+	return compare_results(0) ? PIGLIT_FAIL : PIGLIT_PASS;
+}
diff --git a/tests/spec/arb_draw_indirect/draw-arrays-prim-restart.c b/tests/spec/arb_draw_indirect/draw-arrays-prim-restart.c
new file mode 100644
index 0000000..005419f
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-arrays-prim-restart.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright © The Piglit Project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file errors.c
+ *
+ * Tests that primitive restart is applied to glDrawArraysIndirect.
+ *
+ * The following vertices are drawn as a triangle strip:
+ *	1,5***3,6
+ *	****
+ *	0,4****2
+ * If the primitive is not restarted on index 3, the first 2 triangles
+ * will cover the whole window (0,1,2),(2,1,3).
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 32;
+	config.window_height = 32;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static const char *vs_source = "#version 130\n"
+	"in vec2 vertex;\n"
+	"void main()\n"
+	"{\n"
+	"  gl_Position = vec4(vertex.x, vertex.y, 0.0, 1.0);\n"
+	"}\n";
+
+static const char *fs_source = "#version 130\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0);\n"
+	"}\n";
+
+enum piglit_result
+piglit_display(void)
+{
+	const float green[] = { 0, 1, 0, 0 };
+	const float clear[] = { 0, 0, 0, 0 };
+
+	glClearColor(clear[0], clear[1], clear[2], clear[3]);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glEnable(GL_PRIMITIVE_RESTART);
+	glPrimitiveRestartIndex(3);
+	glDrawArraysIndirect(GL_TRIANGLE_STRIP, NULL);
+
+	piglit_present_results();
+
+	if (!piglit_probe_pixel_rgb(20, 16, clear) ||
+	    !piglit_probe_pixel_rgb( 1, 16, green))
+		return PIGLIT_FAIL;
+	return PIGLIT_PASS;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	const float vboData[7][2] = {
+		{ -1.0f, -1.0f },
+		{ -1.0f, +1.0f },
+		{ +1.0f, -1.0f },
+		{ +1.0f, +1.0f }, /* restart */
+		{ -1.0f, -1.0f },
+		{ -1.0f, +1.0f },
+		{ +1.0f, +1.0f }
+	};
+	const uint32_t cmdData[4] = {
+		7, /* count */
+		1, /* primCount */
+		0, /* first */
+		0 /* reservedMustBeZero */
+	};
+	GLuint vs, fs, prog;
+	GLuint vbo, cmd;
+	GLint vertex_location;
+
+	piglit_require_extension("GL_ARB_draw_indirect");
+	piglit_require_GLSL_version(130);
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
+
+	prog = piglit_link_simple_program(vs, fs);
+
+	if (!vs || !fs || !prog)
+		piglit_report_result(PIGLIT_FAIL);
+
+	glDeleteShader(vs);
+	glDeleteShader(fs);
+
+	vertex_location = glGetAttribLocation(prog, "vertex");
+
+	if (piglit_get_gl_version() >= 31) {
+		GLuint vao;
+		glGenVertexArrays(1, &vao);
+		glBindVertexArray(vao);
+	}
+	glGenBuffers(1, &vbo);
+	glBindBuffer(GL_ARRAY_BUFFER, vbo);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(vboData), vboData, GL_STATIC_DRAW);
+	glEnableVertexAttribArray(vertex_location);
+	glVertexAttribPointer(vertex_location, 2, GL_FLOAT, GL_FALSE, 0, NULL);
+
+	glGenBuffers(1, &cmd);
+	glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmd);
+	glBufferData(GL_DRAW_INDIRECT_BUFFER,
+		     sizeof(cmdData), cmdData, GL_STATIC_DRAW);
+
+	glUseProgram(prog);
+}
diff --git a/tests/spec/arb_draw_indirect/draw-arrays.c b/tests/spec/arb_draw_indirect/draw-arrays.c
new file mode 100644
index 0000000..c6c4521
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-arrays.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © The Piglit project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file draw-elements.c
+ *
+ * Tests that glDrawElementsIndirect works correctly with various combinations
+ * of draw command data generated via transform feedback.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+unsigned num_indirect_draws;
+
+void write_commands_tfb(int indexed, int dump);
+void setup_indirect_draw();
+int compare_results(int indexed);
+
+enum piglit_result
+piglit_display(void)
+{
+	unsigned int i;
+
+	write_commands_tfb(0, 0);
+	setup_indirect_draw();
+
+	glBeginTransformFeedback(GL_POINTS);
+	for (i = 0; i < num_indirect_draws; ++i)
+		glDrawArraysIndirect(GL_POINTS,
+				     (void *)(4 * sizeof(GLuint) * i));
+	glEndTransformFeedback();
+
+	return compare_results(0) ? PIGLIT_FAIL : PIGLIT_PASS;
+}
diff --git a/tests/spec/arb_draw_indirect/draw-common.c b/tests/spec/arb_draw_indirect/draw-common.c
new file mode 100644
index 0000000..290dcb5
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-common.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright © The Piglit project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file draw-common.c
+ *
+ * Common initialization and generation of draw commands for testing the 4
+ * gl[Multi]DrawIndirect{Elements,Arrays} functions.
+ *
+ * The draw commands:
+ *
+ * typedef struct {
+ * 	GLuint count;
+ * 	GLuint primCount;
+ * 	GLuint firstIndex;
+ * 	GLint  baseVertex;
+ * 	GLuint reservedMustBeZero;
+ * } DrawElementsIndirectCommand;
+ *
+ * typedef struct {
+ * 	GLuint count;
+ * 	GLuint primCount;
+ * 	GLuint first;
+ * 	GLuint reservedMustBeZero;
+ * } DrawArraysIndirectCommand;
+ *
+ * are generated by a vertex shader and written to the DRAW_INDIRECT_BUFFER via
+ * transform feedback.
+ * The vertex shader uses gl_VertexID as source to derive the various paramters.
+ *
+ * Then, the DrawIndirect commands stream vertices into a result buffer, also
+ * via transform feedback.
+ * Each vertex consists of a single uint that has the value of the vertex index.
+ * The sequence in which these values are written to the result buffer is used
+ * to check that the intended draw command has been executed.
+ */
+
+#include "piglit-util-gl-common.h"
+
+unsigned num_indirect_draws = 0;
+
+static GLuint tfb[2];
+static GLuint prog[2];
+static GLuint vao[2];
+
+static GLuint vtxbuf;
+static GLuint idxbuf;
+static GLuint cmdbuf;
+static GLuint resbuf;
+
+static const GLsizei vertices_size = 32 * sizeof(uint32_t);
+
+static GLsizei results_size;
+static GLsizei commands_size;
+
+static uint32_t *results;
+
+static void
+clear_buffer(GLenum target)
+{
+	void *map;
+	GLint size;
+
+	glGetBufferParameteriv(target, GL_BUFFER_SIZE, &size);
+
+	map = glMapBufferRange(target, 0, size,
+			       GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+	assert(map);
+	memset(map, 0, size);
+
+	glUnmapBuffer(target);
+}
+
+static int
+generate_data(int indexed)
+{
+	static const GLushort indices[16] = {
+		 5,  1,  3,  7,  6,  0,  4,  2,
+		15, 11, 10,  9, 13, 14,  8, 12
+	};
+
+	unsigned int ni, nv;
+	unsigned int i, b, r, v;
+	unsigned int p;
+
+	uint32_t *vertices;
+
+	num_indirect_draws = 3 * 8 * 2 * 2;
+
+	commands_size = num_indirect_draws * (5 * 4);
+
+	/* calculate size of the result buffer */
+	results_size = 0;
+	for (ni = 1; ni <= 3; ++ni) /* 1 to 3 instances */
+	for (nv = 1; nv <= 8; ++nv) /* 1 to 8 vertices */
+	for (r = 0; r < 2; ++r) /* 2 index ranges */
+	for (b = 0; b < 2; ++b) /* 2 index biases */
+	for (i = 0; i < ni; ++i) /* instance */
+	for (v = 0; v < nv; ++v) /* vertex */
+		results_size += sizeof(uint32_t);
+
+	vertices = malloc(vertices_size);
+	results = malloc(results_size);
+	if (!vertices || !results) {
+		fprintf(stderr, "memory allocation failed\n");
+		return -1;
+	}
+
+	/* generate vertices */
+	for (v = 0; v < 32; ++v)
+		vertices[v] = v;
+
+	/* generate result data for memcmp */
+	p = 0;
+	for (ni = 1; ni <= 3; ++ni) { /* 1 to 3 instances */
+	for (nv = 1; nv <= 8; ++nv) { /* 1 to 8 vertices */
+	for (r = 0; r < 2; ++r) { /* 2 index ranges */
+	for (b = 0; b < 2; ++b) { /* 2 index biases */
+	for (i = 0; i < ni; ++i) { /* instance */
+	for (v = 0; v < nv; ++v) { /* vertex */
+		GLushort index = indexed ?
+			indices[v + (r * 8)] + (b * 16) :
+			v + (r * 16) + (b * 8);
+		results[p++] = (i << 28) | vertices[index];
+	}}}}}}
+
+	/* setup vertex and index buffer */
+	if (indexed) {
+		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbuf);
+		glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+			     sizeof(indices), indices, GL_STATIC_DRAW);
+	}
+
+	glBindBuffer(GL_ARRAY_BUFFER, vtxbuf);
+	glBufferData(GL_ARRAY_BUFFER, vertices_size, vertices, GL_STATIC_DRAW);
+	free(vertices);
+
+	/* setup command and result buffer and hook them up to TFB objects */
+	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, resbuf);
+	glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
+		     results_size, NULL, GL_STREAM_DRAW);
+	clear_buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+
+	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, cmdbuf);
+	glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
+		     commands_size, NULL, GL_STATIC_DRAW);
+	clear_buffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[1]);
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, resbuf);
+
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[0]);
+	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, cmdbuf);
+
+	return 0;
+}
+
+static void
+dump_draw_commands(int indexed)
+{
+	const uint32_t *cmd;
+	unsigned int i;
+
+	fprintf(stderr, "number of draw commands: %u\n", num_indirect_draws);
+	fprintf(stderr, "command buffer size: 0x%x bytes\n", commands_size);
+
+	glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdbuf);
+	cmd = glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, commands_size,
+			       GL_MAP_READ_BIT);
+	assert(cmd);
+	for (i = 0; i < num_indirect_draws; ++i) {
+		if (indexed) {
+			fprintf(stderr, "=== %u ===:\n"
+				" count = %u\n"
+				" primCount = %u\n"
+				" firstIndex = %u\n"
+				" baseVertex = %u\n"
+				" reservedMustBeZero = %u\n", i,
+				cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]);
+			cmd += 5;
+		} else {
+			fprintf(stderr, "=== %u ===:\n"
+				" count = %u\n"
+				" primCount = %u\n"
+				" first = %u\n"
+				" reservedMustBeZero = %u\n", i,
+				cmd[0], cmd[1], cmd[2], cmd[3]);
+			cmd += 4;
+		}
+	}
+	glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
+}
+
+int
+compare_results(int indexed)
+{
+	const uint32_t *map;
+	int ret;
+	unsigned int ni, nv;
+	unsigned int i, b, r, v;
+	unsigned int p;
+
+	int silent = 0;
+
+	glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, resbuf);
+	map = (uint32_t *)glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,
+					   0, results_size, GL_MAP_READ_BIT);
+	if (!map)
+		return -1;
+	ret = 0;
+	p = 0;
+	for (ni = 1; ni <= 3; ++ni) {
+	for (nv = 1; nv <= 8; ++nv) {
+	for (r = 0; r < 2; ++r) {
+	for (b = 0; b < 2; ++b) {
+	for (i = 0; i < ni; ++i) {
+	for (v = 0; v < nv; ++v, ++p) {
+		if (map[p] == results[p])
+			continue;
+		ret = -1;
+
+		if (!map[p]) {
+			if (!silent) {
+				fprintf(stderr, "incorrect at [%u]: 0\n", p);
+				silent = 1;
+			} else {
+				if (silent == 1)
+					fprintf(stderr, "...\n");
+				silent = 2;
+			}
+			break;
+		} else {
+			silent = 0;
+		}
+		fprintf(stderr,
+			"incorrect at "
+			"[%u](ni=%u,nv=%u,i=%u,r=%u,b=%u,v=%u): %08x / %08x\n",
+			p,ni,nv,i,r,b,v,map[p],results[p]);
+	}}}}}}
+
+	glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
+	return ret;
+}
+
+void
+write_commands_tfb(int indexed, int dump)
+{
+	static const char *varyingsIndexed[2] = { "commandIndexed", "zero" };
+	static const char *varyingsArrays[2] = { "commandArrays", "zero" };
+
+	if (generate_data(indexed))
+		piglit_report_result(PIGLIT_FAIL);
+
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[0]);
+	glTransformFeedbackVaryings(prog[0], 2,
+				    indexed ? varyingsIndexed : varyingsArrays,
+				    GL_INTERLEAVED_ATTRIBS);
+	glLinkProgram(prog[0]);
+
+	glUseProgram(prog[0]);
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[0]);
+	glBeginTransformFeedback(GL_POINTS);
+	glBindVertexArray(vao[0]);
+	glDrawArrays(GL_POINTS, 0, num_indirect_draws);
+	glEndTransformFeedback();
+
+	if (dump)
+		dump_draw_commands(indexed);
+}
+
+void
+setup_indirect_draw()
+{
+	glUseProgram(prog[1]);
+
+	glBindVertexArray(vao[1]);
+	/* GL_[ELEMENT]_ARRAY_BUFFER already bound */
+
+	glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdbuf);
+
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[1]);
+}
+
+/* Vertex program the writes the DrawIndirect command to output variables
+ * to be captured by transform feedback.
+ */
+static const char *vs_source_gen = "#version 140\n"
+	"flat out uvec4 commandIndexed;\n"
+	"flat out uvec3 commandArrays;\n"
+	"flat out uint zero;\n"
+	"void main() {\n"
+	"   uint id = uint(gl_VertexID);\n"
+
+	"   commandIndexed.x = ((id >> 2u) & 0x7u) + 1u;\n" /* vertex count */
+	"   commandIndexed.y = ((id >> 5u) & 0x3u) + 1u;\n" /* instance count */
+	"   commandIndexed.z = ((id >> 1u) & 0x1u) * 8u;\n" /* first index */
+	"   commandIndexed.w = ((id >> 0u) & 0x1u) * 16u;\n" /* base vertex */
+
+	"   commandArrays.x = ((id >> 2u) & 0x7u) + 1u;\n" /* vertex count */
+	"   commandArrays.y = ((id >> 5u) & 0x3u) + 1u;\n" /* instance count */
+	"   commandArrays.z = ((id >> 0u) & 0x3u) * 8u;\n" /* first vertex */
+
+	"   zero = 0u;\n"
+	"}\n";
+
+/* Vertex program that writes the vertex input combined with gl_InstanceID
+ * (to check instanced drawing) to an output variable to be capture in the
+ * result buffer via transform feedback.
+ */
+static const char *vs_source_use = "#version 140\n"
+	"in uint vertex;\n"
+	"flat out uint result;\n"
+	"void main() {\n"
+	"   result = vertex | (uint(gl_InstanceID) << 28u);\n"
+	"}\n";
+
+/* No-op fragment program.
+ */
+static const char *fs_source = "#version 140\n"
+	"void main() {\n"
+	"   gl_FragColor = vec4(0.0);\n"
+	"}\n";
+
+void
+piglit_init(int argc, char **argv)
+{
+	static const char *resvar[1] = { "result" };
+	GLuint vs, fs;
+	GLint loc;
+
+	piglit_require_extension("GL_ARB_draw_indirect");
+	piglit_require_extension("GL_ARB_transform_feedback2");
+	piglit_require_extension("GL_ARB_map_buffer_range");
+	piglit_require_extension("GL_ARB_vertex_array_object");
+	piglit_require_GLSL_version(140);
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source_gen);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
+
+	prog[0] = piglit_link_simple_program(vs, fs);
+
+	if (!vs || !fs || !prog[0])
+		piglit_report_result(PIGLIT_FAIL);
+
+	glDeleteShader(vs);
+	glDeleteShader(fs);
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source_use);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
+
+	prog[1] = piglit_link_simple_program(vs, fs);
+
+	if (!vs || !fs || !prog[1])
+		piglit_report_result(PIGLIT_FAIL);
+
+	glDeleteShader(vs);
+	glDeleteShader(fs);
+
+
+	glGenTransformFeedbacks(2, tfb);
+
+	/* TFB for prog[0] is generated in generate_data, it depends on whether
+	 * we want to test DrawElements or DrawArrays.
+	 */
+
+	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb[1]);
+	glTransformFeedbackVaryings(prog[1], 1, resvar, GL_INTERLEAVED_ATTRIBS);
+	glLinkProgram(prog[1]);
+
+
+	glGenBuffers(1, &cmdbuf);
+	glGenBuffers(1, &resbuf);
+	glGenBuffers(1, &vtxbuf);
+	glGenBuffers(1, &idxbuf);
+
+
+	glGenVertexArrays(2, vao);
+
+	loc = glGetAttribLocation(prog[1], "vertex");
+	assert(loc >= 0);
+
+	glBindVertexArray(vao[1]);
+	glBindBuffer(GL_ARRAY_BUFFER, vtxbuf);
+	glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, 0, NULL);
+	glEnableVertexAttribArray(loc);
+}
diff --git a/tests/spec/arb_draw_indirect/draw-elements-multi.c b/tests/spec/arb_draw_indirect/draw-elements-multi.c
new file mode 100644
index 0000000..36d2067
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-elements-multi.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © The Piglit project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file draw-elements.c
+ *
+ * Tests that glDrawElementsIndirect works correctly with various combinations
+ * of draw command data generated via transform feedback.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+unsigned num_indirect_draws;
+
+void write_commands_tfb(int indexed, int dump);
+void setup_indirect_draw();
+int compare_results(int indexed);
+
+enum piglit_result
+piglit_display(void)
+{
+	write_commands_tfb(1, 0);
+	setup_indirect_draw();
+
+	glBeginTransformFeedback(GL_POINTS);
+	/* If <stride> is zero, the array elements are treated as
+	 * tightly packed. */
+	glMultiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_SHORT, NULL,
+				    num_indirect_draws, 0);
+	glEndTransformFeedback();
+
+	return compare_results(1) ? PIGLIT_FAIL : PIGLIT_PASS;
+}
diff --git a/tests/spec/arb_draw_indirect/draw-elements.c b/tests/spec/arb_draw_indirect/draw-elements.c
new file mode 100644
index 0000000..6e50931
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/draw-elements.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © The Piglit project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file draw-elements.c
+ *
+ * Tests that glDrawElementsIndirect works correctly with various combinations
+ * of draw command data generated via transform feedback.
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+unsigned num_indirect_draws;
+
+void write_commands_tfb(int indexed, int dump);
+void setup_indirect_draw();
+int compare_results(int indexed);
+
+enum piglit_result
+piglit_display(void)
+{
+	unsigned int i;
+
+	write_commands_tfb(1, 0);
+	setup_indirect_draw();
+
+	glBeginTransformFeedback(GL_POINTS);
+	for (i = 0; i < num_indirect_draws; ++i)
+		glDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_SHORT,
+				       (void *)(5 * sizeof(GLuint) * i));
+	glEndTransformFeedback();
+
+	return compare_results(1) ? PIGLIT_FAIL : PIGLIT_PASS;
+}
diff --git a/tests/spec/arb_draw_indirect/errors-multi.c b/tests/spec/arb_draw_indirect/errors-multi.c
new file mode 100644
index 0000000..399b209
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/errors-multi.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 2012 The Piglit project 2013.
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file errors.c
+ *
+ * Tests error conditions for for glMultiDraw*Indirect:
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static const char *vs_source = "#version 130\n"
+	"void main()\n"
+	"{\n"
+	"  gl_Position = vec4(0.0);\n"
+	"}\n";
+
+static const char *fs_source = "#version 130\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.0);\n"
+	"}\n";
+
+enum piglit_result
+piglit_display(void)
+{
+	GLuint zeroData[128];
+	GLuint cmdBuf;
+	GLuint idxBuf;
+
+	memset(zeroData, 0, sizeof(zeroData));
+
+	if (piglit_get_gl_version() >= 31) {
+		GLuint vao;
+		glGenVertexArrays(1, &vao);
+		glBindVertexArray(vao);
+	}
+
+	glClearColor(0.0, 0.0, 0.0, 0.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glGenBuffers(1, &cmdBuf);
+	glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBuf);
+	glBufferData(GL_DRAW_INDIRECT_BUFFER,
+		     sizeof(zeroData), zeroData, GL_STATIC_DRAW);
+        glGenBuffers(1, &idxBuf);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxBuf);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+                     sizeof(zeroData), zeroData, GL_STATIC_DRAW);
+
+	/* <stride> must be a multiple of four, otherwise an INVALID_VALUE
+	 * error is generated.
+	 *
+	 * Test both functions with strides 3,4,5 and 8.
+	 */
+	glMultiDrawArraysIndirect(GL_POINTS, NULL, 1, 3);
+	if (!piglit_check_gl_error(GL_INVALID_VALUE))
+		return PIGLIT_FAIL;
+	glMultiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_BYTE, NULL, 1, 3);
+	if (!piglit_check_gl_error(GL_INVALID_VALUE))
+		return PIGLIT_FAIL;
+
+	glMultiDrawArraysIndirect(GL_POINTS, NULL, 1, 4);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+	glMultiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_BYTE, NULL, 1, 4);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+
+	glMultiDrawArraysIndirect(GL_POINTS, NULL, 1, 5);
+	if (!piglit_check_gl_error(GL_INVALID_VALUE))
+		return PIGLIT_FAIL;
+	glMultiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_BYTE, NULL, 1, 5);
+	if (!piglit_check_gl_error(GL_INVALID_VALUE))
+		return PIGLIT_FAIL;
+
+	glMultiDrawArraysIndirect(GL_POINTS, NULL, 1, 8);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+	glMultiDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_BYTE, NULL, 1, 8);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+
+	glFinish(); /* force hardware driver execute */
+	return PIGLIT_PASS;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	GLuint vs, fs, prog;
+
+	piglit_require_extension("GL_ARB_multi_draw_indirect");
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
+
+	prog = piglit_link_simple_program(vs, fs);
+
+	if (!vs || !fs || !prog)
+		piglit_report_result(PIGLIT_FAIL);
+
+	glDeleteShader(vs);
+	glDeleteShader(fs);
+
+	glUseProgram(prog);
+}
diff --git a/tests/spec/arb_draw_indirect/errors.c b/tests/spec/arb_draw_indirect/errors.c
new file mode 100644
index 0000000..c9ca75b
--- /dev/null
+++ b/tests/spec/arb_draw_indirect/errors.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © The Piglit Project 2012
+ *
+ * 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.
+ *
+ * Authors: Christoph Bumiller
+ */
+
+/**
+ * @file errors.c
+ *
+ * Tests various error conditions for glDraw*Indirect:
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+	config.supports_gl_compat_version = 10;
+	config.supports_gl_core_version = 31;
+
+	config.window_width = 1;
+	config.window_height = 1;
+	config.window_visual = PIGLIT_GL_VISUAL_RGB | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+static const char *vs_source = "#version 130\n"
+	"void main()\n"
+	"{\n"
+	"  gl_Position = vec4(0.0);\n"
+	"}\n";
+
+static const char *fs_source = "#version 130\n"
+	"void main()\n"
+	"{\n"
+	"  gl_FragColor = vec4(0.0);\n"
+	"}\n";
+
+enum piglit_result
+piglit_display(void)
+{
+	GLuint zeroData[32];
+	GLuint cmdBuf;
+	GLuint idxBuf;
+
+	memset(zeroData, 0, sizeof(zeroData));
+
+	if (piglit_get_gl_version() >= 31) {
+		GLuint vao;
+		glGenVertexArrays(1, &vao);
+		glBindVertexArray(vao);
+	}
+
+	glClearColor(0.0, 0.0, 0.0, 0.0);
+	glClear(GL_COLOR_BUFFER_BIT);
+
+	glGenBuffers(1, &cmdBuf);
+	glBindBuffer(GL_DRAW_INDIRECT_BUFFER, cmdBuf);
+	glBufferData(GL_DRAW_INDIRECT_BUFFER, 8, zeroData, GL_STATIC_DRAW);
+
+	/* Check that buffer handling worked normally. */
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+
+	/* An INVALID_OPERATION error is generated if the commands source
+	 * data beyond the end of the buffer object or if <indirect> is not
+	 * word aligned.
+	 */
+
+	/* The buffer object is too small. */
+	glDrawArraysIndirect(GL_POINTS, NULL);
+	if (!piglit_check_gl_error(GL_INVALID_OPERATION))
+		return PIGLIT_FAIL;
+
+	/* Create a large enough buffer object. */
+	glBufferData(GL_DRAW_INDIRECT_BUFFER,
+		     sizeof(zeroData), zeroData, GL_STATIC_DRAW);
+
+	/* But read from END - 4. */
+	glDrawArraysIndirect(GL_POINTS, (void *)(sizeof(zeroData) - 4));
+	if (!piglit_check_gl_error(GL_INVALID_OPERATION))
+		return PIGLIT_FAIL;
+
+	/* Use an unaligned offset. */
+	if (sizeof(GLuint) / 2) {
+		glDrawArraysIndirect(GL_POINTS, (void *)(sizeof(GLuint) / 2));
+		if (!piglit_check_gl_error(GL_INVALID_OPERATION))
+			return PIGLIT_FAIL;
+	}
+
+	/* Make sure we can draw without producing an error. */
+	glDrawArraysIndirect(GL_POINTS, NULL);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+
+	/* Unlike regular DrawElementsInstancedBaseVertex commands,
+	 * the indices may not come from a client array and must come from
+	 * an index buffer.
+	 * If no element array buffer is bound, an INVALID_OPERATION
+	 * error is generated.
+	 */
+	glGenBuffers(1, &idxBuf);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxBuf);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+		     sizeof(zeroData), zeroData, GL_STATIC_DRAW);
+
+	/* Check that drawing with an index buffer worked. */
+	glDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT, NULL);
+	if (!piglit_check_gl_error(GL_NO_ERROR))
+		return PIGLIT_FAIL;
+
+	/* Unbind the index buffer and check that a client array does not. */
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+	glDrawElementsIndirect(GL_POINTS, GL_UNSIGNED_INT, NULL);
+	if (!piglit_check_gl_error(GL_INVALID_OPERATION))
+		return PIGLIT_FAIL;
+
+	glFinish(); /* force hardware driver execute */
+	return PIGLIT_PASS;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+	GLuint vs, fs, prog;
+
+	piglit_require_extension("GL_ARB_draw_indirect");
+
+	vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_source);
+	fs = piglit_compile_shader_text(GL_FRAGMENT_SHADER, fs_source);
+
+	prog = piglit_link_simple_program(vs, fs);
+
+	if (!vs || !fs || !prog)
+		piglit_report_result(PIGLIT_FAIL);
+
+	glDeleteShader(vs);
+	glDeleteShader(fs);
+
+	glUseProgram(prog);
+}
-- 
1.7.3.4



More information about the Piglit mailing list