Commit 9ec4f254 authored by Paul Berry's avatar Paul Berry
Browse files

Transform feedback: Test error conditions.



This test verifies that the implementation correctly detects all of
the errors specified in the "Errors" section of the
EXT_transform_feedback spec, with the following exceptions (which seem
like they should be handled in separate tests):

- Errors related to BeginQuery and EndQuery.

- Error due to mismatch of transform feedback mode and drawing mode
  (e.g. drawing GL_LINES when transform feedback is expecting
  GL_TRIANGLES).

- Errors due to exceeding MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTIBS in
  a call to TransformFeedbackVaryings, GetTransformFeedbackVarying,
  or
  Get{Integer,Boolean}Indexedv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING).

v2: Modify "not_a_program" test to create a program and then
immediately delete it.
Reviewed-by: default avatarIan Romanick <ian.d.romanick@intel.com>
parent 83c8ef80
......@@ -1400,6 +1400,24 @@ ext_timer_query['time-elapsed'] = concurrent_test('ext_timer_query-time-elapsed'
ext_transform_feedback = Group()
spec['EXT_transform_feedback'] = ext_transform_feedback
for mode in ['interleaved_ok_base', 'interleaved_ok_range',
'interleaved_ok_offset', 'interleaved_unbound',
'interleaved_no_varyings', 'separate_ok_1',
'separate_unbound_0_1', 'separate_ok_2', 'separate_unbound_0_2',
'separate_unbound_1_2', 'separate_no_varyings', 'no_prog_active',
'begin_active', 'useprog_active', 'link_current_active',
'link_other_active', 'bind_base_active', 'bind_range_active',
'bind_offset_active', 'end_inactive', 'bind_base_max',
'bind_range_max', 'bind_offset_max', 'bind_range_size_m4',
'bind_range_size_0', 'bind_range_size_1', 'bind_range_size_2',
'bind_range_size_3', 'bind_range_size_5', 'bind_range_offset_1',
'bind_range_offset_2', 'bind_range_offset_3',
'bind_range_offset_5', 'bind_offset_offset_1',
'bind_offset_offset_2', 'bind_offset_offset_3',
'bind_offset_offset_5', 'not_a_program']:
test_name = 'api-errors {0}'.format(mode)
ext_transform_feedback[test_name] = PlainExecTest(
'ext_transform_feedback-{0} -auto'.format(test_name))
for varying in ['gl_Color', 'gl_SecondaryColor', 'gl_TexCoord',
'gl_FogFragCoord', 'gl_Position', 'gl_PointSize',
'gl_ClipVertex', 'gl_ClipDistance']:
......
......@@ -13,6 +13,7 @@ link_libraries (
)
add_executable (ext_transform_feedback-alignment alignment.c)
add_executable (ext_transform_feedback-api-errors api-errors.c)
add_executable (ext_transform_feedback-builtin-varyings builtin-varyings.c)
add_executable (ext_transform_feedback-discard-api discard-api.c)
add_executable (ext_transform_feedback-discard-bitmap discard-bitmap.c)
......
/*
* 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 api-errors.c
*
* Test that the implementation flags various
* transform-feedback-related error conditions.
*
* This test covers all of the error conditions as specified in the
* "Errors" section of the EXT_transform_feedback spec, with the
* following exceptions:
*
* - Errors related to BeginQuery and EndQuery.
*
* - Error due to mismatch of transform feedback mode and drawing mode
* (e.g. drawing GL_LINES when transform feedback is expecting
* GL_TRIANGLES).
*
* - Errors due to exceeding MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTIBS in
* a call to TransformFeedbackVaryings, GetTransformFeedbackVarying,
* or
* Get{Integer,Boolean}Indexedv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING).
*
* In addition, there are a few tests which verify that errors do not
* occur during normal operation ("interleaved_ok_*", "separate_ok_*",
* and "link_other_active"). These tests help to verify that the
* implementation is not overly aggressive in flagging errors.
*/
#include "piglit-util.h"
int piglit_width = 16;
int piglit_height = 16;
int piglit_window_mode = GLUT_DOUBLE | GLUT_RGB;
#define XFB_BUFFER_SIZE 12
#define NUM_BUFFERS 2
enum test_mode {
NORMAL,
NO_VARYINGS,
UNBOUND_BUFFER,
SKIP_USE_PROGRAM,
BEGIN_ACTIVE,
USEPROG_ACTIVE,
LINK_CURRENT_ACTIVE,
LINK_OTHER_ACTIVE,
BIND_ACTIVE,
END_INACTIVE,
BIND_MAX,
BIND_BAD_SIZE,
BIND_BAD_OFFSET,
NOT_A_PROGRAM,
};
enum bind_mode {
BASE,
RANGE,
OFFSET,
};
static const char *vstext =
"varying vec4 foo;\n"
"varying vec4 bar;\n"
"\n"
"void main()\n"
"{\n"
" foo = vec4(1.0);\n"
" bar = vec4(1.0);\n"
" gl_Position = vec4(1.0);\n"
"}\n";
static const char *varyings[] = { "foo", "bar" };
static struct test_desc
{
const char *name;
enum test_mode mode;
int param;
enum bind_mode bind_mode;
GLenum buffer_mode;
int num_buffers;
GLboolean skip_use_program;
} tests[] = {
/* name mode param num_buffers
* bind_mode
* buffer_mode
*/
{ "interleaved_ok_base", NORMAL, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "interleaved_ok_range", NORMAL, 0, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "interleaved_ok_offset", NORMAL, 0, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "interleaved_unbound", UNBOUND_BUFFER, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "interleaved_no_varyings", NO_VARYINGS, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "separate_ok_1", NORMAL, 0, BASE, GL_SEPARATE_ATTRIBS, 1 },
{ "separate_unbound_0_1", UNBOUND_BUFFER, 0, BASE, GL_SEPARATE_ATTRIBS, 1 },
{ "separate_ok_2", NORMAL, 0, BASE, GL_SEPARATE_ATTRIBS, 2 },
{ "separate_unbound_0_2", UNBOUND_BUFFER, 0, BASE, GL_SEPARATE_ATTRIBS, 2 },
{ "separate_unbound_1_2", UNBOUND_BUFFER, 1, BASE, GL_SEPARATE_ATTRIBS, 2 },
{ "separate_no_varyings", NO_VARYINGS, 0, BASE, GL_SEPARATE_ATTRIBS, 1 },
{ "no_prog_active", SKIP_USE_PROGRAM, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "begin_active", BEGIN_ACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "useprog_active", USEPROG_ACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "link_current_active", LINK_CURRENT_ACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "link_other_active", LINK_OTHER_ACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_base_active", BIND_ACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_active", BIND_ACTIVE, 0, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_active", BIND_ACTIVE, 0, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "end_inactive", END_INACTIVE, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_base_max", BIND_MAX, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_max", BIND_MAX, 0, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_max", BIND_MAX, 0, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_m4", BIND_BAD_SIZE, -4, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_0", BIND_BAD_SIZE, 0, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_1", BIND_BAD_SIZE, 1, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_2", BIND_BAD_SIZE, 2, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_3", BIND_BAD_SIZE, 3, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_size_5", BIND_BAD_SIZE, 5, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_offset_1", BIND_BAD_OFFSET, 1, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_offset_2", BIND_BAD_OFFSET, 2, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_offset_3", BIND_BAD_OFFSET, 3, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_range_offset_5", BIND_BAD_OFFSET, 5, RANGE, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_offset_1", BIND_BAD_OFFSET, 1, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_offset_2", BIND_BAD_OFFSET, 2, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_offset_3", BIND_BAD_OFFSET, 3, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "bind_offset_offset_5", BIND_BAD_OFFSET, 5, OFFSET, GL_INTERLEAVED_ATTRIBS, 1 },
{ "not_a_program", NOT_A_PROGRAM, 0, BASE, GL_INTERLEAVED_ATTRIBS, 1 },
};
static void
do_bind(const struct test_desc *test, GLuint buf, int i)
{
int size = test->mode == BIND_BAD_SIZE
? test->param : sizeof(float[XFB_BUFFER_SIZE]);
int offset = test->mode == BIND_BAD_OFFSET
? test->param : 0;
switch (test->bind_mode) {
case BASE:
printf("BindBufferBase(buffer %i)\n", i);
piglit_BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, buf);
break;
case RANGE:
printf("BindBufferRange(buffer %i, offset=%i, size=%i)\n", i,
offset, size);
piglit_BindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, buf,
offset, size);
break;
case OFFSET:
printf("BindBufferOffsetEXT(buffer %i, offset=%i)\n", i,
offset);
glBindBufferOffsetEXT(GL_TRANSFORM_FEEDBACK_BUFFER, i, buf,
offset);
break;
}
}
static GLboolean
do_test(const struct test_desc *test)
{
GLuint vs;
GLuint progs[2];
GLuint bufs[NUM_BUFFERS];
float initial_xfb_buffer_contents[XFB_BUFFER_SIZE];
GLboolean pass = GL_TRUE;
int i;
int num_varyings = test->mode == NO_VARYINGS ? 0 : test->num_buffers;
GLint max_separate_attribs;
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&max_separate_attribs);
printf("MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTIBS=%i\n",
max_separate_attribs);
printf("Compile vertex shader\n");
vs = piglit_compile_shader_text(GL_VERTEX_SHADER, vstext);
if (test->mode == NOT_A_PROGRAM) {
printf("Create a program and then delete it\n");
progs[0] = piglit_CreateProgram();
piglit_DeleteProgram(progs[0]);
} else {
progs[0] = piglit_CreateProgram();
piglit_AttachShader(progs[0], vs);
}
pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
printf("Setup transform feedback for %i varyings in %s mode\n",
num_varyings,
test->buffer_mode == GL_INTERLEAVED_ATTRIBS
? "interleaved" : "separate");
piglit_TransformFeedbackVaryings(progs[0], num_varyings,
varyings, test->buffer_mode);
if (test->mode == NOT_A_PROGRAM) {
pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass;
return pass;
}
printf("Link program\n");
piglit_LinkProgram(progs[0]);
pass = piglit_link_check_status(progs[0]) && pass;
if (test->mode == USEPROG_ACTIVE || test->mode == LINK_OTHER_ACTIVE) {
printf("Prepare 2nd program\n");
progs[1] = piglit_CreateProgram();
piglit_AttachShader(progs[1], vs);
}
if (test->mode == USEPROG_ACTIVE) {
printf("Link 2nd program\n");
piglit_LinkProgram(progs[1]);
pass = piglit_link_check_status(progs[1]) && pass;
}
if (test->mode == SKIP_USE_PROGRAM) {
printf("Don't use program\n");
} else {
printf("Use program\n");
piglit_UseProgram(progs[0]);
}
printf("Prepare %i buffers\n", test->num_buffers);
glGenBuffers(test->num_buffers, bufs);
memset(initial_xfb_buffer_contents, 0,
sizeof(initial_xfb_buffer_contents));
for (i = 0; i < test->num_buffers; ++i) {
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, bufs[i]);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
sizeof(initial_xfb_buffer_contents),
initial_xfb_buffer_contents, GL_STREAM_READ);
}
switch (test->mode) {
case BIND_MAX:
do_bind(test, bufs[0], max_separate_attribs);
pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass;
return pass;
case BIND_BAD_SIZE:
case BIND_BAD_OFFSET:
do_bind(test, bufs[0], 0);
pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass;
return pass;
default:
break;
}
for (i = 0; i < test->num_buffers; ++i) {
if (test->mode == UNBOUND_BUFFER && i == test->param) {
printf("Don't bind buffer %i\n", i);
} else {
do_bind(test, bufs[i], i);
}
}
pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
if (test->mode == END_INACTIVE) {
printf("EndTransformFeedback\n");
piglit_EndTransformFeedback();
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
return pass;
}
printf("BeginTransformFeedback\n");
piglit_BeginTransformFeedback(GL_POINTS);
switch (test->mode) {
case UNBOUND_BUFFER:
case NO_VARYINGS:
case SKIP_USE_PROGRAM:
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
break;
default:
pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
break;
}
switch (test->mode) {
case BEGIN_ACTIVE:
printf("BeginTransformFeedback\n");
piglit_BeginTransformFeedback(GL_POINTS);
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
break;
case USEPROG_ACTIVE:
printf("Use new program\n");
piglit_UseProgram(progs[1]);
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
break;
case LINK_CURRENT_ACTIVE:
printf("Link current program\n");
piglit_LinkProgram(progs[0]);
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
break;
case LINK_OTHER_ACTIVE:
printf("Link 2nd program\n");
piglit_LinkProgram(progs[1]);
pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
break;
case BIND_ACTIVE:
do_bind(test, bufs[0], 0);
pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
break;
default:
break;
}
return pass;
}
void
print_usage_and_exit(const char *prog_name)
{
int i;
printf("Usage: %s <test_name>\n"
" where <test_name> is one of:\n", prog_name);
for (i = 0; i < ARRAY_SIZE(tests); ++i)
printf(" %s\n", tests[i].name);
exit(0);
}
const struct test_desc *
find_matching_test(const char *prog_name, const char *test_name)
{
int i;
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
if (strcmp(tests[i].name, test_name) == 0)
return &tests[i];
}
print_usage_and_exit(prog_name);
return NULL; /* won't actually be reached */
}
void
piglit_init(int argc, char **argv)
{
const struct test_desc *test;
/* Parse params. */
if (argc != 2)
print_usage_and_exit(argv[0]);
test = find_matching_test(argv[0], argv[1]);
piglit_require_GLSL();
piglit_require_transform_feedback();
if (test->bind_mode == OFFSET) {
/* BindBufferOffset only exists in the EXT specification */
piglit_require_extension("GL_EXT_transform_feedback");
}
piglit_report_result(do_test(test) ? PIGLIT_PASS : PIGLIT_FAIL);
}
enum piglit_result
piglit_display(void)
{
/* Should never be reached */
return PIGLIT_FAIL;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment