/* * 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 vertex-program-two-side.c * * Tests two-sided lighting behavior. * * From the GL 2.1 spec, page 63 (page 77 of the PDF): * * "Additionally, vertex shaders can operate in two-sided color * mode. When a vertex shader is active, front and back colors * can be computed by the vertex shader and written to the * gl_FrontColor, gl_BackColor, gl_FrontSecondaryColor and * gl_BackSecondaryColor outputs. If VERTEX PROGRAM TWO SIDE is * enabled, the GL chooses between front and back colors, as * described below. Otherwise, the front color output is always * selected. Two-sided color mode is enabled and disabled by * calling Enable or Disable with the symbolic value VERTEX * PROGRAM TWO SIDE." * * This appears to override the text in the GLSL 1.10 spec which * implies that two-sided behavior always occurs. */ #include "piglit-util-gl.h" PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 10; config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE; config.khr_no_error_support = PIGLIT_NO_ERRORS; PIGLIT_GL_TEST_CONFIG_END static GLint prog; static bool enabled = false; static bool front = false; static bool back = false; static bool front2 = false; static bool back2 = false; static float frontcolor[4] = {0.0, 0.5, 0.0, 0.0}; static float backcolor[4] = {0.0, 0.0, 0.5, 0.0}; static float secondary_frontcolor[4] = {0.0, 0.25, 0.0, 0.0}; static float secondary_backcolor[4] = {0.0, 0.0, 0.25, 0.0}; static int draw_secondary_loc; char *dummy_outputs[4] = {"", "", "", ""}; char *vs_outputs[4] = {"", "", "", ""}; char *gs_outputs[4] = {"", "", "", ""}; char *gs_inputs_outputs[4] = {"", "", "", ""}; char *tcs_outputs[4] = {"", "", "", ""}; char *tcs_inputs_outputs[4] = {"", "", "", ""}; char *tes_outputs[4] = {"", "", "", ""}; char *tes_inputs_outputs[4] = {"", "", "", ""}; const char * tests[7] = {"vs and fs", "gs-out and fs", "vs, gs and fs", "tes-out and fs", "tcs-out, tes and fs", "vs, tcs, tes and fs", NULL }; static const char *dummy_vs_source = "void main()\n" "{\n" " gl_Position = gl_Vertex;\n" "}\n"; static const char *fs_source = "uniform bool draw_secondary;\n" "void main()\n" "{\n" " if (draw_secondary)\n" " gl_FragColor = gl_SecondaryColor;\n" " else\n" " gl_FragColor = gl_Color;\n" "}\n"; static bool probe_colors() { bool pass = true; int x1 = 0, y1 = 0; int w = piglit_width / 2, h = piglit_height / 2; int x2 = piglit_width - w, y2 = piglit_height - h; if (front) { pass = pass && piglit_probe_rect_rgba(x1, y2, w, h, frontcolor); } if (front2) { pass = pass && piglit_probe_rect_rgba(x1, y1, w, h, secondary_frontcolor); } if (enabled) { /* Two-sided: Get the back color/secondarycolor. */ if (back) { pass = pass && piglit_probe_rect_rgba(x2, y2, w, h, backcolor); } if (back2) { pass = pass && piglit_probe_rect_rgba(x2, y1, w, h, secondary_backcolor); } } else { /* Non-two-sided: Get the front color/secondarycolor. */ if (front) { pass = pass && piglit_probe_rect_rgba(x2, y2, w, h, frontcolor); } if (front2) { pass = pass && piglit_probe_rect_rgba(x2, y1, w, h, secondary_frontcolor); } } return pass; } static bool test_prog(unsigned prog, const char *test_name, bool use_patches) { glUseProgram(prog); draw_secondary_loc = glGetUniformLocation(prog, "draw_secondary"); if (enabled) glEnable(GL_VERTEX_PROGRAM_TWO_SIDE); /* Draw */ glClearColor(0.5, 0.5, 0.5, 0.5); glClear(GL_COLOR_BUFFER_BIT); glUniform1i(draw_secondary_loc, false); piglit_draw_rect_custom(-1, 0, 1, 1, use_patches, 1); /* top left */ piglit_draw_rect_custom( 1, 0, -1, 1, use_patches, 1); /* top right */ glUniform1i(draw_secondary_loc, true); piglit_draw_rect_custom(-1, -1, 1, 1, use_patches, 1); /* bot left */ piglit_draw_rect_custom( 1, -1, -1, 1, use_patches, 1); /* bot right */ /* probe and report result */ bool pass = probe_colors(); piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL, "%s", test_name); return pass; } static void setup_vs_output(char **out, const char *name, float *values) { (void)!asprintf(out, " %s = vec4(%f, %f, %f, %f);\n", name, values[0], values[1], values[2], values[3]); } static void setup_gs_vars(char **in_out, char **out, const char *name, float *values) { (void)!asprintf(in_out, " %s = gl_in[i].%s;\n", name, name); (void)!asprintf(out, " %s = vec4(%f, %f, %f, %f);\n", name, values[0], values[1], values[2], values[3]); } static void setup_tcs_vars(char **in_out, char **out, const char *name, float *values) { (void)!asprintf(in_out, " gl_out[gl_InvocationID].%s = gl_in[gl_InvocationID].%s;\n", name, name); (void)!asprintf(out, " gl_out[gl_InvocationID].%s = vec4(%f, %f, %f, %f);\n", name, values[0], values[1], values[2], values[3]); } static void setup_tes_vars(char **in_out, char **out, const char *name, float *values) { (void)!asprintf(in_out, " INTERP_QUAD(gl_in[0].%s, %s);\n", name, name); (void)!asprintf(out, " INTERP_QUAD(vec4(%f, %f, %f, %f), %s);\n", values[0], values[1], values[2], values[3], name); } static void create_gs_source(char **gs_source, char **builtins) { (void)!asprintf(gs_source, "#version 150 compatibility\n" "layout(triangles) in;\n" "layout(triangle_strip, max_vertices = 3) out;\n" "\n" "void main()\n" "{\n" " for (int i = 0; i < 3; i++) {\n" " gl_Position = gl_in[i].gl_Position;\n" " %s%s%s%s\n" " EmitVertex();\n" " }\n" "}\n", builtins[0], builtins[1], builtins[2], builtins[3]); } static void create_tess_source(char **tcs_source, char **tcs_builtins, char **tes_source, char **tes_builtins) { (void)!asprintf(tcs_source, "#version 150 compatibility\n" "#extension GL_ARB_tessellation_shader: require\n" "layout(vertices = 4) out;\n" "\n" "void main()\n" "{\n" " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" " gl_TessLevelOuter = float[4](1.0, 1.0, 1.0, 1.0);\n" " gl_TessLevelInner = float[2](1.0, 1.0);\n" " %s%s%s%s\n" "}\n", tcs_builtins[0], tcs_builtins[1], tcs_builtins[2], tcs_builtins[3]); (void)!asprintf(tes_source, "#version 150 compatibility\n" "#extension GL_ARB_tessellation_shader: require\n" "layout(quads) in;\n" "\n" "#define INTERP_QUAD(INi, OUT) do { \\\n" " vec4 v[4]; \\\n" " for (int i = 0; i < 4; i++) v[i] = INi; \\\n" " OUT = mix(mix(v[0], v[1], gl_TessCoord[0]), mix(v[2], v[3], \\\n" " gl_TessCoord[0]), gl_TessCoord[1]); \\\n" "} while(false);\n" "\n" "void main()\n" "{\n" " INTERP_QUAD(gl_in[i].gl_Position, gl_Position);\n" " %s%s%s%s\n" "}\n", tes_builtins[0], tes_builtins[1], tes_builtins[2], tes_builtins[3]); } enum piglit_result piglit_display(void) { char *vs_source; char *gs_source; char *gs_source2; char *tcs_source; char *tes_source; bool pass; (void)!asprintf(&vs_source, "void main()\n" "{\n" " gl_Position = gl_Vertex;\n" "%s%s%s%s" "}\n", vs_outputs[0], vs_outputs[1], vs_outputs[2], vs_outputs[3]); prog = piglit_build_simple_program(vs_source, fs_source); pass = test_prog(prog, tests[0], false); if (piglit_get_gl_version() >= 32) { /* Test the gs outputs only */ create_gs_source(&gs_source, gs_outputs); prog = piglit_build_simple_program_multiple_shaders( GL_VERTEX_SHADER, dummy_vs_source, GL_GEOMETRY_SHADER, gs_source, GL_FRAGMENT_SHADER, fs_source, 0); pass = pass && test_prog(prog, tests[1], false); /* Test both the gs outputs and inputs */ create_gs_source(&gs_source2, gs_inputs_outputs); prog = piglit_build_simple_program_multiple_shaders( GL_VERTEX_SHADER, vs_source, GL_GEOMETRY_SHADER, gs_source2, GL_FRAGMENT_SHADER, fs_source, 0); pass = pass && test_prog(prog, tests[2], false); if (piglit_is_extension_supported("GL_ARB_tessellation_shader")) { /* Test tes outputs only */ create_tess_source(&tcs_source, dummy_outputs, &tes_source, tes_outputs); prog = piglit_build_simple_program_multiple_shaders( GL_VERTEX_SHADER, dummy_vs_source, GL_TESS_CONTROL_SHADER, tcs_source, GL_TESS_EVALUATION_SHADER, tes_source, GL_FRAGMENT_SHADER, fs_source, 0); pass = pass && test_prog(prog, tests[3], true); free(tcs_source); free(tes_source); /* Test tcs outputs and tes inputs/outputs */ create_tess_source(&tcs_source, tcs_outputs, &tes_source, tes_inputs_outputs); prog = piglit_build_simple_program_multiple_shaders( GL_VERTEX_SHADER, dummy_vs_source, GL_TESS_CONTROL_SHADER, tcs_source, GL_TESS_EVALUATION_SHADER, tes_source, GL_FRAGMENT_SHADER, fs_source, 0); pass = pass && test_prog(prog, tests[4], true); free(tcs_source); free(tes_source); /* Test tcs inputs/outputs and tes inputs/outputs */ create_tess_source(&tcs_source, tcs_inputs_outputs, &tes_source, tes_inputs_outputs); prog = piglit_build_simple_program_multiple_shaders( GL_VERTEX_SHADER, vs_source, GL_TESS_CONTROL_SHADER, tcs_source, GL_TESS_EVALUATION_SHADER, tes_source, GL_FRAGMENT_SHADER, fs_source, 0); pass = pass && test_prog(prog, tests[5], true); free(tcs_source); free(tes_source); } else { piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[3]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[4]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[5]); } } else { piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[1]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[2]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[3]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[4]); piglit_report_subtest_result(PIGLIT_SKIP, "%s", tests[5]); } free(vs_source); return pass ? PIGLIT_PASS : PIGLIT_FAIL; } void piglit_init(int argc, char **argv) { piglit_require_GLSL(); piglit_require_gl_version(20); printf("Window quadrants show:\n"); printf("+-------------------------+------------------------+\n"); printf("| front gl_Color | back gl_Color |\n"); printf("+-------------------------+------------------------+\n"); printf("| front gl_SecondaryColor | back gl_SecondaryColor |\n"); printf("+-------------------------+------------------------+\n"); for (unsigned i = 1; i < argc; i++) { if (strcmp(argv[i], "enabled") == 0) { enabled = true; } else if (strcmp(argv[i], "front") == 0) { front = true; } else if (strcmp(argv[i], "back") == 0) { back = true; } else if (strcmp(argv[i], "front2") == 0) { front2 = true; } else if (strcmp(argv[i], "back2") == 0) { back2 = true; } else { fprintf(stderr, "unknown argument %s\n", argv[i]); } } piglit_register_subtests(tests); if (front) { setup_vs_output(&vs_outputs[0], "gl_FrontColor", frontcolor); setup_gs_vars(&gs_inputs_outputs[0], &gs_outputs[0], "gl_FrontColor", frontcolor); setup_tcs_vars(&tcs_inputs_outputs[0], &tcs_outputs[0], "gl_FrontColor", frontcolor); setup_tes_vars(&tes_inputs_outputs[0], &tes_outputs[0], "gl_FrontColor", frontcolor); } if (back) { setup_vs_output(&vs_outputs[1], "gl_BackColor", backcolor); setup_gs_vars(&gs_inputs_outputs[1], &gs_outputs[1], "gl_BackColor", backcolor); setup_tcs_vars(&tcs_inputs_outputs[1], &tcs_outputs[1], "gl_BackColor", backcolor); setup_tes_vars(&tes_inputs_outputs[1], &tes_outputs[1], "gl_BackColor", backcolor); } if (front2) { setup_vs_output(&vs_outputs[2], "gl_FrontSecondaryColor", secondary_frontcolor); setup_gs_vars(&gs_inputs_outputs[2], &gs_outputs[2], "gl_FrontSecondaryColor", secondary_frontcolor); setup_tcs_vars(&tcs_inputs_outputs[2], &tcs_outputs[2], "gl_FrontSecondaryColor", secondary_frontcolor); setup_tes_vars(&tes_inputs_outputs[2], &tes_outputs[2], "gl_FrontSecondaryColor", secondary_frontcolor); } if (back2) { setup_vs_output(&vs_outputs[3], "gl_BackSecondaryColor", secondary_backcolor); setup_gs_vars(&gs_inputs_outputs[3], &gs_outputs[3], "gl_BackSecondaryColor", secondary_backcolor); setup_tcs_vars(&tcs_inputs_outputs[3], &tcs_outputs[3], "gl_BackSecondaryColor", secondary_backcolor); setup_tes_vars(&tes_inputs_outputs[3], &tes_outputs[3], "gl_BackSecondaryColor", secondary_backcolor); } }