/* * Copyright © 2013 The Piglit project * * 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 vertices-out.c * * Test required errors for wrong GL_GEOMETRY_VERTICES_OUT parameters with * variable number of output components. * * The value of GEOMETRY_VERTICES_OUT is limited by the implementation * dependend constants MAX_GEOMETRY_OUTPUT_VERTICES and * MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS. * * From the ARB_geometry_shader4 spec (section Errors): * "The error INVALID_VALUE is generated by ProgramParameteriARB if is * GEOMETRY_VERTICES_OUT_ARB and is negative. * * The error INVALID_VALUE is generated by ProgramParameteriARB if is * GEOMETRY_VERTICES_OUT_ARB and exceeds * MAX_GEOMETRY_OUTPUT_VERTICES_ARB. * * The error INVALID_VALUE is generated by ProgramParameteriARB if is * set to GEOMETRY_VERTICES_OUT_ARB and the product of and the sum of * all components of all active varying variables exceeds * MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB." * * And from section Geometry Shader outputs: * "[...]the product of the total number of vertices and the sum of all * components of all active varying variables may not exceed the value of * MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB. LinkProgram will fail if it * determines that the total component limit would be violated." */ #include "common.h" static const char gs_text_var[] = "uniform int vertex_count;\n" "varying out float var[n];\n" "void main()\n" "{\n" " for (int i = 0; i < vertex_count; i++) {\n" " gl_Position = vec4(0.0);\n" " for (int j = 0; j < n; j++)\n" " var[j] = 1.0 / exp2(float(j + 1));\n" " EmitVertex();\n" " }\n" "}\n"; static const char fs_text_var[] = "varying float var[n];\n" "void main()\n" "{\n" " gl_FragColor = vec4(0.0);\n" " for (int j = 0; j < n; j++)\n" " gl_FragColor += vec4(var[j]);\n" "}\n"; static bool transform_feedback = false; static int components = -1; PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 20; config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA; PIGLIT_GL_TEST_CONFIG_END static bool test_geometry_vertices_out(const GLuint prog) { bool pass = true; int max_geometry_output_vertices; int max_geometry_total_output_components; int max_vertices_out; glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &max_geometry_output_vertices); glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &max_geometry_total_output_components); printf("Testing negative (-1) vertices out.\n"); glProgramParameteri(prog, GL_GEOMETRY_VERTICES_OUT_ARB, -1); pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass; /* Setting GEOMETRY_VERTICES_OUT to zero should generate no error but * linking with a geometry shader should fail. */ printf("Testing zero (0) vertices out.\n"); glProgramParameteri(prog, GL_GEOMETRY_VERTICES_OUT_ARB, 0); glLinkProgram(prog); pass = piglit_check_gl_error(GL_NO_ERROR) && !piglit_link_check_status_quiet(prog) && pass; printf("Testing too many (%d) vertices out.\n", max_geometry_output_vertices + 1); glProgramParameteri(prog, GL_GEOMETRY_VERTICES_OUT_ARB, max_geometry_output_vertices + 1); pass = piglit_check_gl_error(GL_INVALID_VALUE) && pass; /* If MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS results in an even smaller * limit for GEOMETRY_VERTICES_OUT than GL_MAX_GEOMETRY_OUTPUT_VERTICES * test that, too. * * If (GEOMETRY_VERTICES_OUT * (sum of components of all out varyings)) * > MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, the spec requires * ProgramParameter to throw an INVALID_VALUE and subsequent linking to * fail. * But the number of output components can only be infered from the * geometry shader source (and a geometry shader might not even be * attached to the program object when ProgramParameter is called). * So, ignore any errors generated from ProgramParameter and only check * that linking failed. */ if ((components != 0) && (max_geometry_total_output_components / components < max_geometry_output_vertices)) { printf("Testing too many total output components (%d vertices " "=> %d total components).\n", max_geometry_total_output_components / components + 1, (max_geometry_total_output_components / components + 1) * components); glProgramParameteri(prog, GL_GEOMETRY_VERTICES_OUT_ARB, max_geometry_total_output_components / components + 1); piglit_reset_gl_error(); glLinkProgram(prog); pass = !piglit_link_check_status_quiet(prog) && pass; } max_vertices_out = (components != 0) ? MIN2(max_geometry_output_vertices, max_geometry_total_output_components / components) : max_geometry_output_vertices; printf("Testing maximal (%d) vertices out.\n", max_vertices_out); glProgramParameteri(prog, GL_GEOMETRY_VERTICES_OUT_ARB, max_vertices_out); glLinkProgram(prog); pass = piglit_check_gl_error(GL_NO_ERROR) && piglit_link_check_status(prog) && pass; return pass; } /* Parse command line arguments. * * Recognized command line arguments are: * * The optional argument "tf": Use transform feedback. * * An integer indicating the number of per vertex varying components * written by the geometry shader (not counting gl_Position) OR the * argument "max" which indicates to use a number of components of * MAX_GEOMETRY_VARYING_COMPONENTS_ARB or, if transform feedback is used, * the minimum of MAX_GEOMETRY_VARYING_COMPONENTS_ARB and * MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS. */ static void parse_cmd_line(int argc, char **argv) { int i, max_components; glGetIntegerv(GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB, &max_components); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "tf") == 0) { transform_feedback = true; } else if (strcmp(argv[i], "max") == 0) { components = -2; } else if(argv[i][0] != '-') { char *e; long int l = strtol(argv[i], &e, 10); if (*e == '\0') components = l; } } if (transform_feedback) { int max_tf_components; piglit_require_extension("GL_EXT_transform_feedback"); glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_tf_components); max_components = MIN2(max_components, max_tf_components); } if (components == -2) components = max_components; if ((components < 0) || components > max_components) { fprintf(stderr, "Please specify number of components " "from 0 to %d (inclusive) on the command line\n", max_components); piglit_report_result(PIGLIT_FAIL); } } void piglit_init(int argc, char **argv) { bool pass = true; GLuint prog; const char *gs_string, *fs_string; piglit_require_extension("GL_ARB_geometry_shader4"); /* NV_geometry_shader4 relaxes some restrictions on valid program * parameters. */ piglit_require_not_extension("GL_NV_geometry_shader4"); parse_cmd_line(argc, argv); /* Prepare shader source strings. */ if (components == 0) { gs_string = gs_text; fs_string = fs_text; } else { (void)!asprintf((char **)&gs_string, "#extension GL_ARB_geometry_shader4: enable\n" "const int n = %d;\n%s", components, gs_text_var); if (transform_feedback) fs_string = NULL; else (void)!asprintf((char **)&fs_string, "const int n = %d;\n%s", components, fs_text_var); } printf("Running Test with %d component(s) per output vertex and " "transform feedback %s.\n", components, transform_feedback ? "enabled" : "disabled"); /* Create shader and run test. */ prog = create_shader(vs_text, gs_string, fs_string); pass = test_geometry_vertices_out(prog) && pass; glDeleteProgram(prog); piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL); } enum piglit_result piglit_display(void) { /* Should never be reached */ return PIGLIT_FAIL; }