/* * Copyright © 2014 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. */ #include "piglit-util-gl.h" /** * @file point-vertex-id.c * * Tests glPolygonMode(GL_POINT) used in combination with gl_VertexID * or gl_InstanceID or both. * * Specify gl_VertexID or gl_InstanceID as an argument to specify * which to test. Alternatively you can specify both in order to test * a combination of both. Additionally ‘divisor’ can be specified to * make it use an instanced array. * * See bug #84677 and #91292 */ PIGLIT_GL_TEST_CONFIG_BEGIN config.supports_gl_compat_version = 20; config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE; PIGLIT_GL_TEST_CONFIG_END static const char vertex_shader[] = "uniform vec2 viewport_size;\n" "\n" "#ifdef USE_VERTEX_ID\n" "uniform vec2 pos_array[12];\n" "#else\n" "in vec2 pos;\n" "#endif" "\n" "#ifdef USE_DIVISOR\n" "in vec2 triangle_offset;\n" "#endif\n" "\n" "void\n" "main()\n" "{\n" "#ifdef USE_VERTEX_ID\n" " vec2 pos = pos_array[gl_VertexID];\n" "#endif\n" " gl_Position = vec4(pos, 0.0, 1.0);\n" "#ifdef USE_INSTANCE_ID\n" " float instance_offset = 20.0;\n" "#ifdef USE_DIVISOR\n" " instance_offset = 10.0;\n" "#endif\n" " gl_Position.t += float(gl_InstanceID) * instance_offset;\n" "#endif\n" "#ifdef USE_DIVISOR\n" " gl_Position.st += triangle_offset;\n" "#endif\n" " gl_Position.st = ((gl_Position.st + 0.5) * 2.0 /\n" " viewport_size - 1.0);\n" " gl_FrontColor = vec4(1.0);\n" "}\n"; struct vertex { int x, y; GLubyte edge_flag; }; enum test_mode_flags { TEST_MODE_VERTEX_ID = (1 << 0), TEST_MODE_INSTANCE_ID = (1 << 1), TEST_MODE_DIVISOR = (1 << 2), }; static enum test_mode_flags test_modes; static const struct vertex vertices[] = { { 10, 10, GL_TRUE }, { 20, 10, GL_TRUE }, { 10, 20, GL_TRUE }, /* This triangle won't be drawn because none of the vertices * are an edge */ { 30, 10, GL_FALSE }, { 40, 10, GL_FALSE }, { 30, 20, GL_FALSE }, /* Copy of the above two triangles but shifted up by 20. If * instanced rendering is used these will be generated based * on the gl_InstanceID or an instanced array instead. */ { 10, 30, GL_TRUE }, { 20, 30, GL_TRUE }, { 10, 40, GL_TRUE }, { 30, 30, GL_FALSE }, { 40, 30, GL_FALSE }, { 30, 40, GL_FALSE }, }; /* If a divisor is set then each pair of triangles will be drawn as an * instance and these offsets will be added to each instance. */ static const struct vertex triangle_offsets[] = { { 0, 0 }, { 0, 20 }, }; /* If both the divisor and the instance id is used then these offsets * will be used instead. The remainder of the offset will be added by * the instance ID. */ static const struct vertex triangle_offsets_with_instance_id[] = { { 0, 0 }, { 0, 10 }, }; enum piglit_result piglit_display(void) { bool pass = true; char shader_buf[sizeof vertex_shader + 512]; GLint pos_location = 0, viewport_size_location; GLuint program; float *ref_image, *p; int i; strcpy(shader_buf, "#version 130\n"); if (test_modes & TEST_MODE_INSTANCE_ID) { strcat(shader_buf, "#extension GL_ARB_draw_instanced : require\n" "#define USE_INSTANCE_ID\n"); } if (test_modes & TEST_MODE_DIVISOR) strcat(shader_buf, "#define USE_DIVISOR\n"); if (test_modes & TEST_MODE_VERTEX_ID) strcat(shader_buf, "#define USE_VERTEX_ID\n"); strcat(shader_buf, vertex_shader); program = piglit_build_simple_program(shader_buf, NULL); glUseProgram(program); glClear(GL_COLOR_BUFFER_BIT); viewport_size_location = glGetUniformLocation(program, "viewport_size"); glUniform2f(viewport_size_location, piglit_width, piglit_height); if (test_modes & TEST_MODE_VERTEX_ID) { pos_location = glGetUniformLocation(program, "pos_array"); for (i = 0; i < ARRAY_SIZE(vertices); i++) { glUniform2f(pos_location + i, vertices[i].x, vertices[i].y); } } glEnableClientState(GL_EDGE_FLAG_ARRAY); glEdgeFlagPointer(sizeof (struct vertex), &vertices[0].edge_flag); if (!(test_modes & TEST_MODE_VERTEX_ID)) { pos_location = glGetAttribLocation(program, "pos"); if (pos_location == -1) piglit_report_result(PIGLIT_FAIL); glEnableVertexAttribArray(pos_location); glVertexAttribPointer(pos_location, 2, /* size */ GL_INT, GL_FALSE, /* normalized */ sizeof (struct vertex), &vertices[0].x); } if (test_modes & TEST_MODE_DIVISOR) { pos_location = glGetAttribLocation(program, "triangle_offset"); if (pos_location == -1) piglit_report_result(PIGLIT_FAIL); glEnableVertexAttribArray(pos_location); glVertexAttribDivisor(pos_location, 1); glVertexAttribPointer(pos_location, 2, /* size */ GL_INT, GL_FALSE, /* normalized */ sizeof (struct vertex), (test_modes & TEST_MODE_INSTANCE_ID) ? &triangle_offsets_with_instance_id[0].x : &triangle_offsets[0].x); } glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); if (test_modes & (TEST_MODE_INSTANCE_ID | TEST_MODE_DIVISOR)) { glDrawArraysInstanced(GL_TRIANGLES, 0, /* first */ ARRAY_SIZE(vertices) / 2, 2 /* primcount */); } else { glDrawArrays(GL_TRIANGLES, 0, /* first */ ARRAY_SIZE(vertices)); } ref_image = malloc(piglit_width * piglit_height * 3 * sizeof (float)); memset(ref_image, 0, piglit_width * piglit_height * 3 * sizeof (float)); for (i = 0; i < ARRAY_SIZE(vertices); i++) { if (!vertices[i].edge_flag) continue; p = (ref_image + (vertices[i].x + vertices[i].y * piglit_width) * 3); p[0] = p[1] = p[2] = 1.0f; } pass = piglit_probe_image_color(0, 0, piglit_width, piglit_height, GL_RGB, ref_image); glUseProgram(0); glDeleteProgram(program); piglit_present_results(); free(ref_image); return pass ? PIGLIT_PASS : PIGLIT_FAIL; } void piglit_init(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "gl_VertexID")) { test_modes |= TEST_MODE_VERTEX_ID; } else if (!strcmp(argv[i], "gl_InstanceID")) { test_modes |= TEST_MODE_INSTANCE_ID; } else if (!strcmp(argv[i], "divisor")) { test_modes |= TEST_MODE_DIVISOR; } else { fprintf(stderr, "Unknown argument: %s\n", argv[i]); piglit_report_result(PIGLIT_FAIL); } } if (test_modes == 0) { fprintf(stderr, "usage: point-vertex-id [gl_VertexID] [gl_InstanceID] " "[divisor]\n" "At least one of the arguments must be specified\n"); piglit_report_result(PIGLIT_FAIL); } if (test_modes & (TEST_MODE_INSTANCE_ID | TEST_MODE_DIVISOR)) piglit_require_extension("GL_ARB_draw_instanced"); if (test_modes & TEST_MODE_DIVISOR) piglit_require_extension("GL_ARB_instanced_arrays"); piglit_require_GLSL_version(130); }