[Piglit] [PATCH v5 6/6] program_interface_query: add tests for getprogramresourceiv
Tapani Pälli
tapani.palli at intel.com
Thu Apr 2 04:10:40 PDT 2015
On 04/01/2015 01:56 PM, Martin Peres wrote:
> Tested on NVIDIA's proprietary driver version 346.35.
>
> Signed-off-by: Martin Peres <martin.peres at linux.intel.com>
> ---
> .../arb_program_interface_query/CMakeLists.gl.txt | 1 +
> .../getprogramresourceiv.c | 1063 ++++++++++++++++++++
> 2 files changed, 1064 insertions(+)
> create mode 100755 tests/spec/arb_program_interface_query/getprogramresourceiv.c
>
> diff --git a/tests/spec/arb_program_interface_query/CMakeLists.gl.txt b/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
> index 2508342..91da8ac 100755
> --- a/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
> +++ b/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
> @@ -14,3 +14,4 @@ piglit_add_executable (arb_program_interface_query-resource-query resource-query
> piglit_add_executable (arb_program_interface_query-getprograminterfaceiv getprograminterfaceiv.c)
> piglit_add_executable (arb_program_interface_query-getprogramresourceindex getprogramresourceindex.c)
> piglit_add_executable (arb_program_interface_query-getprogramresourcename getprogramresourcename.c)
> +piglit_add_executable (arb_program_interface_query-getprogramresourceiv getprogramresourceiv.c)
> diff --git a/tests/spec/arb_program_interface_query/getprogramresourceiv.c b/tests/spec/arb_program_interface_query/getprogramresourceiv.c
> new file mode 100755
> index 0000000..0f6239c
> --- /dev/null
> +++ b/tests/spec/arb_program_interface_query/getprogramresourceiv.c
> @@ -0,0 +1,1063 @@
> +/*
> + * Copyright © 2015 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
--- 8< ---
> +};
> +
> +/* WARNING: ATOMIC_COUNTER_BUFFER is left untested because it is impossible to
> + * fetch the index of variables which means we cannot reliably test anything
> + */
One can fetch indices but do you mean it is impossible to verify the
these indices later? You could cross-check indices against
glGetActiveAtomicCounterBufferiv, not sure if this is worth it though
because it will call the very same functionality anyway.
> +
> +static bool
> +check_extensions_prop(GLenum prop)
> +{
> + /* First check the availability of the extensions */
> + if (prop == GL_ATOMIC_COUNTER_BUFFER_INDEX &&
> + !piglit_is_extension_supported("GL_ARB_shader_atomic_counters")) {
> + return false;
> + }
> +
> + if ((prop == GL_TOP_LEVEL_ARRAY_SIZE ||
> + prop == GL_TOP_LEVEL_ARRAY_STRIDE) &&
> + !piglit_is_extension_supported("GL_ARB_shader_storage_buffer_object")) {
> + return false;
> + }
> +
> + if ((prop == GL_NUM_COMPATIBLE_SUBROUTINES ||
> + prop == GL_COMPATIBLE_SUBROUTINES) &&
> + !piglit_is_extension_supported("GL_ARB_shader_subroutine")) {
> + return false;
> + }
> +
> + if ((prop == GL_REFERENCED_BY_TESS_CONTROL_SHADER ||
> + prop == GL_REFERENCED_BY_TESS_EVALUATION_SHADER) &&
> + !piglit_is_extension_supported("GL_ARB_tessellation_shader")) {
> + return false;
> + }
> +
> + if ((prop == GL_REFERENCED_BY_COMPUTE_SHADER ||
> + prop == GL_COMPUTE_SUBROUTINE_UNIFORM ||
> + prop == GL_IS_PER_PATCH) &&
> + !piglit_is_extension_supported("GL_ARB_compute_shader") &&
> + !piglit_is_extension_supported("GL_ARB_shader_image_load_store")) {
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool
> +is_resource_in_list(const char **list, const char *resource, int index,
> + bool check_order)
> +{
> + int i = 0;
> + while (list && list[i]) {
> + if (strcmp(list[i], resource) == 0) {
> + return !check_order || index == i;
> + }
> + i++;
> + }
> +
> + return false;
> +}
> +
> +static void
> +basic_check(const char *subsubtest, int value, int expected_value, bool *pass)
> +{
> + /* no real check can be done other than checking that
> + * the index or offset is not invalid when it was
> + * supposed to be valid (or the other way round).
> + */
> + if ((value >= 0 && expected_value == -1) ||
> + (value == -1 && expected_value >= 0)) {
> + const char *validity = expected_value == -1 ?
> + "an invalid" : "a valid";
> + fprintf(stderr, "'%s' expected %s offset or index but "
> + "got %i\n", subsubtest, validity, value);
> + *pass = false;
> + }
> +}
> +
> +static void
> +check_prop(GLuint prog, GLenum programInterface, int index, const char *name,
> + void *inputs, struct check_t c, bool *pass)
> +{
> + int values[10], parent_idx, i;
> + char subsubtest[150];
> + GLsizei length, tmp = -1;
> + char buf[21];
> + GLenum pif;
> + GLuint loc;
> +
> + /* skip the test if it is not supported */
> + if(!check_extensions_prop(c.prop)) {
> + return;
> + }
> +
> + /* generate the name of the subsubtest for error-reporting purposes */
> + snprintf(subsubtest, sizeof(subsubtest), "%s: %s on %s",
> + name, piglit_get_gl_enum_name(c.prop),
> + piglit_get_gl_enum_name(programInterface));
> +
> + /* retrieve the property */
> + glGetProgramResourceiv(prog, programInterface, index, 1, &c.prop, 10,
> + &length, values);
> + if (!piglit_check_gl_error(GL_NO_ERROR)) {
> + printf(" Latest error generated while running '%s'\n",
> + subsubtest);
> + *pass = false;
> + return;
> + }
> +
> + /* check the return value */
> + switch (c.prop) {
> + case GL_OFFSET:
> + case GL_ARRAY_STRIDE:
> + case GL_ATOMIC_COUNTER_BUFFER_INDEX:
> + basic_check(subsubtest, values[0], c.values[0], pass);
> + break;
> +
> + case GL_BLOCK_INDEX:
> + /* check that the index of the parent matches the name
> + * of the parent
> + */
> + switch (programInterface) {
> + case GL_UNIFORM: pif = GL_UNIFORM_BLOCK; break;
> + case GL_BUFFER_VARIABLE: pif = GL_SHADER_STORAGE_BLOCK; break;
Please be consistent with the style and move the breaks on their own lines.
> + }
> +
> + parent_idx = glGetProgramResourceIndex(prog, pif,
> + (char*)inputs);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (parent_idx != values[0]) {
> + glGetProgramResourceName(prog, programInterface,
> + values[0], sizeof(buf), NULL,
> + buf);
> +
> + fprintf(stderr, "'%s' expected parent name to be %s"
> + "(idx = %i) but got parent name %s(idx = %i)\n",
> + subsubtest, (char*)inputs, parent_idx, buf,
> + values[0]);
> + *pass = false;
> + }
> + break;
> +
> + case GL_BUFFER_BINDING:
> + if (values[0] < 0) {
> + fprintf(stderr, "'%s' invalid buffer binding point\n",
> + subsubtest);
> + *pass = false;
> + }
> +
> + /* check against another API call */
> + if (programInterface != GL_UNIFORM_BLOCK) {
> + break;
> + }
> +
> + glGetActiveUniformBlockiv(prog, index, GL_UNIFORM_BLOCK_BINDING,
> + &tmp);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (tmp != values[0]) {
> + fprintf(stderr, "'%s' inconsitent buffer binding point"
inconsistent
> + "(%i) with glGetActiveUniformBlockiv"
> + "(%i)\n", subsubtest, values[0], tmp);
> + *pass = false;
> + }
> +
> + /* TODO: Create a more complete program where we actually bind
> + * buffers to some bind points to check this.
> + */
IMO this is fine to be left as a 'future task'.
> + break;
> +
> + case GL_ACTIVE_VARIABLES:
> + case GL_COMPATIBLE_SUBROUTINES:
> + switch (programInterface) {
> + case GL_UNIFORM_BLOCK:
> + pif = GL_UNIFORM;
> + break;
> + case GL_SHADER_STORAGE_BLOCK:
> + pif = GL_BUFFER_VARIABLE;
> + break;
> + case GL_VERTEX_SUBROUTINE_UNIFORM:
> + pif = GL_VERTEX_SUBROUTINE;
> + break;
> + case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
> + pif = GL_TESS_CONTROL_SUBROUTINE;
> + break;
> + case GL_COMPUTE_SUBROUTINE_UNIFORM:
> + pif = GL_COMPUTE_SUBROUTINE;
> + break;
> + }
> +
> + /* check that the return count is as expected */
> + if (c.count != length) {
> + fprintf(stderr, "'%s' expected %zu entries but got %i"
> + "\n", subsubtest, c.count, length);
> + length = 1;
> + *pass = false;
> + break;
> + }
> +
> + for (i = 0; i < length; i++) {
> + buf[0] = '\0';
> + glGetProgramResourceName(prog, pif, values[i],
> + sizeof(buf), NULL, buf);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (!is_resource_in_list(inputs, buf, i, false)) {
> + fprintf(stderr, "'%s' could not find active "
> + "resource '%s' (idx = %i) in the active"
> + " list\n", subsubtest, buf, values[i]);
> + *pass = false;
> + }
> + }
> + break;
> +
> + case GL_BUFFER_DATA_SIZE:
> + /* Nothing we can check here... */
> + break;
> +
> + case GL_LOCATION:
> + loc = glGetProgramResourceLocation(prog, programInterface,
> + name);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (loc != values[0]) {
> + fprintf(stderr, "'%s' inconsistent value between "
> + "glGetProgramResourceiv(%i) and "
> + "glGetProgramResourceLocation(%i).\n",
> + subsubtest, values[0], loc);
> + *pass = false;
> + break;
> + }
> +
> + if (prog == prog_loc && values[0] != c.values[0]) {
> + fprintf(stderr, "'%s' expected location %i but got "
> + "%i\n", subsubtest, c.values[0],
> + values[0]);
> + *pass = false;
> + break;
> + }
> +
> + /* continue by testing the (in)validity of the index */
> + basic_check(subsubtest, values[0], c.values[0], pass);
> + break;
> +
> + case GL_LOCATION_INDEX:
> + loc = glGetProgramResourceLocationIndex(prog, programInterface,
> + name);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (loc != values[0]) {
> + fprintf(stderr, "'%s' inconsistent value between "
> + "glGetProgramResourceiv(%i) and "
> + "glGetProgramResourceLocationIndex(%i)."
> + "\n", subsubtest, values[0], loc);
> + *pass = false;
> + break;
> + }
> +
> + /* continue by testing the (in)validity of the index */
> + basic_check(subsubtest, values[0], c.values[0], pass);
> + break;
> +
> + default:
> + /* check that the return count is as expected */
> + if (c.count != length) {
> + fprintf(stderr, "'%s' expected %zu entries but got %i"
> + "\n", subsubtest, c.count, length);
> + length = 1;
> + *pass = false;
> + break;
> + }
> +
> + /* go through all the values returned */
> + for (i = 0; i < length; i++) {
> + if (values[i] != c.values[i]) {
> + fprintf(stderr, "'%s' expected %i but got %i at"
> + " index %i\n", subsubtest, c.values[i],
> + values[i], i);
> + *pass = false;
> + }
> + }
> +
> + break;
> + }
> +}
> +
> +static bool
> +check_extensions(GLuint prog, GLenum programInterface)
> +{
> + /* First check the availability of the extensions */
> + if ((programInterface == GL_BUFFER_VARIABLE ||
> + programInterface == GL_SHADER_STORAGE_BLOCK ||
> + prog == prog_stor) &&
> + !piglit_is_extension_supported("GL_ARB_shader_storage_buffer_object")) {
> + return false;
> + }
> +
> + if ((programInterface == GL_VERTEX_SUBROUTINE ||
> + programInterface == GL_GEOMETRY_SUBROUTINE ||
> + programInterface == GL_FRAGMENT_SUBROUTINE ||
> + programInterface == GL_COMPUTE_SUBROUTINE ||
> + programInterface == GL_VERTEX_SUBROUTINE_UNIFORM ||
> + programInterface == GL_GEOMETRY_SUBROUTINE_UNIFORM ||
> + programInterface == GL_FRAGMENT_SUBROUTINE_UNIFORM ||
> + programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
> + programInterface == GL_TESS_CONTROL_SUBROUTINE ||
> + programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
> + programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
> + programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
> + programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
> + prog == prog_sub || prog == prog_sub_tess) &&
> + !piglit_is_extension_supported("GL_ARB_shader_subroutine")) {
> + return false;
> + }
> +
> + if ((programInterface == GL_TESS_CONTROL_SUBROUTINE ||
> + programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
> + programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
> + programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
> + prog == prog_sub_tess) &&
> + !piglit_is_extension_supported("GL_ARB_tessellation_shader")) {
> + return false;
> + }
> +
> + if ((programInterface == GL_COMPUTE_SUBROUTINE ||
> + programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
> + prog == prog_cs) &&
> + !piglit_is_extension_supported("GL_ARB_compute_shader") &&
> + !piglit_is_extension_supported("GL_ARB_shader_image_load_store")) {
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void
> +run_subtest(const struct subtest_t st, bool *pass)
> +{
> + enum piglit_result result;
> + bool local_pass = true;
> + int index, i = 0;
> +
> + if (*st.prog == -1 || !check_extensions(*st.prog, st.programInterface)) {
> + result = PIGLIT_SKIP;
> + goto report_result;
> + }
> +
> + index = glGetProgramResourceIndex(*st.prog, st.programInterface,
> + st.name);
> + piglit_check_gl_error(GL_NO_ERROR);
> + if (index < 0) {
> + printf(" Could not find resource '%s' in program %u\n",
> + st.name, *st.prog);
> + result = PIGLIT_FAIL;
> + goto report_result;
> + }
> +
> + while (st.props[i].prop != 0) {
> + check_prop(*st.prog, st.programInterface, index, st.name,
> + st.inputs, st.props[i], &local_pass);
> + i++;
> + }
> +
> + *pass = *pass && local_pass;
> + result = local_pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +
> +report_result:
> + piglit_report_subtest_result(result, "%s on %s", st.name,
> + piglit_get_gl_enum_name(st.programInterface));
> +}
> +
> +void
> +piglit_init(int argc, char **argv)
> +{
> + static const char *st_r_tf_varying[] = {"gs_output0", NULL};
> +
> + piglit_require_extension("GL_ARB_program_interface_query");
please require GL_ARB_separate_shader_objects :)
> +
> + /* Allocate the different programs */
> + prog_std = piglit_build_simple_program_unlinked_multiple_shaders(
> + GL_VERTEX_SHADER, vs_std,
> + GL_GEOMETRY_SHADER, gs_std,
> + GL_FRAGMENT_SHADER, fs_std,
> + 0);
> + glTransformFeedbackVaryings(prog_std, 1, st_r_tf_varying,
> + GL_INTERLEAVED_ATTRIBS);
> + piglit_check_gl_error(GL_NO_ERROR);
There was additional linker validation code added which makes the shader
above fail. As we use it also for some SSO cases in other tests let's
just mark it separable to pass validation:
glProgramParameteri(prog_std, GL_PROGRAM_SEPARABLE, GL_TRUE);
> +
> + glLinkProgram(prog_std);
> + if (!piglit_link_check_status(prog_std)) {
> + glDeleteProgram(prog_std);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + if (piglit_is_extension_supported("GL_ARB_shader_storage_buffer_object")) {
> + prog_stor = piglit_build_simple_program_multiple_shaders(
> + GL_VERTEX_SHADER, vs_stor,
> + GL_GEOMETRY_SHADER, gs_stor,
> + GL_FRAGMENT_SHADER, fs_stor,
> + 0);
> + if (!piglit_link_check_status(prog_stor)) {
> + glDeleteProgram(prog_stor);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +
> + if (piglit_is_extension_supported("GL_ARB_explicit_attrib_location") &&
> + piglit_is_extension_supported("GL_ARB_explicit_uniform_location")) {
> + prog_loc = piglit_build_simple_program_multiple_shaders(
> + GL_VERTEX_SHADER, vs_loc,
> + GL_FRAGMENT_SHADER, fs_loc,
> + 0);
> + if (!piglit_link_check_status(prog_loc)) {
> + glDeleteProgram(prog_loc);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +
> + if (!piglit_is_extension_supported("GL_ARB_shader_subroutine")) {
> + return;
> + }
> +
> + prog_sub = piglit_build_simple_program_multiple_shaders(
> + GL_VERTEX_SHADER, vs_sub,
> + GL_GEOMETRY_SHADER, gs_sub,
> + GL_FRAGMENT_SHADER, fs_sub,
> + 0);
> + if (!piglit_link_check_status(prog_sub)) {
> + glDeleteProgram(prog_sub);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> +
> + if (piglit_is_extension_supported("GL_ARB_tessellation_shader")) {
> + prog_sub_tess =
> + piglit_build_simple_program_unlinked_multiple_shaders(
> + GL_TESS_CONTROL_SHADER, tcs_sub,
> + 0);
> + /* force the compiler not to optimise away inputs/outputs */
> + glProgramParameteri(prog_sub_tess, GL_PROGRAM_SEPARABLE,
> + GL_TRUE);
> + piglit_check_gl_error(GL_NO_ERROR);
> +
> + glLinkProgram(prog_sub_tess);
> + if (!piglit_link_check_status(prog_sub_tess)) {
> + glDeleteProgram(prog_sub_tess);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +
> + if (piglit_is_extension_supported("GL_ARB_compute_shader")) {
> + prog_cs = piglit_build_simple_program_multiple_shaders(
> + GL_COMPUTE_SHADER, cs_sub,
> + 0);
> + if (!piglit_link_check_status(prog_cs)) {
> + glDeleteProgram(prog_cs);
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +}
> +
> +static void
> +test_error_cases(bool *pass)
> +{
> + GLenum props[] = {GL_NAME_LENGTH};
> + GLenum props_invalid[] = {GL_NAME_LENGTH, GL_TRUE, GL_TYPE};
> + GLenum props_error[] = {GL_NAME_LENGTH, GL_OFFSET, GL_TYPE};
> + int values[10];
> + GLuint shader;
> + bool prg_tst;
> +
> + /* test using an unexisting program ID */
> + glGetProgramResourceiv(1337, GL_UNIFORM, 0, 1, props, 10, NULL, values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_VALUE);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "Invalid program (undefined ID)");
> +
> + /* test using a shader ID */
> + shader = piglit_compile_shader_text(GL_VERTEX_SHADER, vs_empty);
> + glGetProgramResourceIndex(shader, GL_UNIFORM, "resource");
> + prg_tst = piglit_check_gl_error(GL_INVALID_OPERATION);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "Invalid program (call on shader)");
> +
> + /* invalid index. This is unspecified but let's check it is consistent
> + * with GetProgramResourceName.
> + */
> + glGetProgramResourceiv(prog_std, GL_UNIFORM, 1337, 0, props, 10, NULL,
> + values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_VALUE);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "Invalid index");
> +
> + /* test propcount == 0 */
> + glGetProgramResourceiv(prog_std, GL_UNIFORM, 0, 0, props, 10, NULL,
> + values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_VALUE);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "<propcount> == 0");
> +
> + /* test propcount < 0 */
> + glGetProgramResourceiv(prog_std, GL_UNIFORM, 0, -1, props, 10, NULL,
> + values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_VALUE);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "<propcount> < 0");
> +
> + /* one invalid property */
> + glGetProgramResourceiv(prog_std, GL_UNIFORM, 0, 3, props_invalid, 10,
> + NULL, values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_ENUM);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "prop == GL_TRUE");
> +
> + /* property not acceptable for one program interface */
> + glGetProgramResourceiv(prog_std, GL_PROGRAM_INPUT, 0, 3, props_error,
> + 10, NULL, values);
> + prg_tst = piglit_check_gl_error(GL_INVALID_OPERATION);
> + *pass = *pass && prg_tst;
> + piglit_report_subtest_result(prg_tst ? PIGLIT_PASS : PIGLIT_FAIL,
> + "GL_OFFSET on GL_PROGRAM_INPUT");
> +}
> +
> +static void
> +glDeleteProgramSafe(GLuint prog)
> +{
> + if (prog != -1)
> + glDeleteProgram(prog);
> +}
> +
> +enum piglit_result
> +piglit_display(void)
> +{
> + bool pass = true;
> + int i;
> +
> + test_error_cases(&pass);
> +
> + /* run all the getprogramresourceiv tests */
> + for (i = 0; i < sizeof(subtests) / sizeof(struct subtest_t); i++) {
> + run_subtest(subtests[i], &pass);
> + }
> +
> + glDeleteProgramSafe(prog_loc);
> + glDeleteProgramSafe(prog_cs);
> + glDeleteProgramSafe(prog_sub_tess);
> + glDeleteProgramSafe(prog_sub);
> + glDeleteProgramSafe(prog_stor);
> + glDeleteProgramSafe(prog_std);
> +
> + return pass ? PIGLIT_PASS : PIGLIT_FAIL;
> +}
>
More information about the Piglit
mailing list