1 #include "piglit-util-gl.h"
6 * This test verifies that GL_ARB_sample_locations is implemented correctly.
7 * It does so by retrieving the sample positions using gl_SamplePosition,
8 * interpolateAtSample() and a method described in
9 * https://urldefense.proofpoint.com/v2/url?u=https-3A__mynameismjp.wordpress.com_2010_07_07_msaa-2Dsample-2Dpattern-2Ddetector_&d=DwIBAg&c=uilaK90D4TOVoH58JNXRgQ&r=Ie7_encNUsqxbSRbqbNgofw0ITcfE8JKfaUjIQhncGA&m=_I4YfQ6nzOyQ71BgwYmlUsP4O5-Pi2DfoZIGctuFnLs&s=RhpkXqf6twp4gawhoCbMx1cmqWZv4eRpX4d6JJ6_tmE&e=
10 * which draws a rectangle covering each possible sample location within a pixel.
11 * Each rectangle writes it's position within the pixel, which is then read
14 * The retrieved sample locations are then tested against expectations. This is
15 * done with various MSAA levels and sample locations.
17 * The test can be rather slow by default, but it can be made less exhaustive by
18 * passing the argument --quick.
20 * Sample locations are typically represented in this test as 0.4 fixed point
21 * integers where 0 is the top.
24 /* new_locations in do_test_set() needs to be expanded when this is */
25 #define LOG2_MAX_SAMPLES 5
26 #define MAX_SAMPLES (1<<LOG2_MAX_SAMPLES)
29 /* the height is 7 pixels to test pixel grid flipping */
32 PIGLIT_GL_TEST_CONFIG_BEGIN
34 config
.supports_gl_core_version
= 32;
36 config
.window_width
= 200;
37 config
.window_height
= 200;
38 config
.window_visual
= PIGLIT_GL_VISUAL_RGB
;
40 PIGLIT_GL_TEST_CONFIG_END
44 static GLuint draw_program
;
45 static GLuint read_program
;
46 static GLuint fb_textures
[LOG2_MAX_SAMPLES
+1];
47 static GLuint fbs
[LOG2_MAX_SAMPLES
+1];
49 static unsigned cur_fb
;
50 static GLint grid_width
, grid_height
, samples
;
53 get_sample_locations(GLubyte
*locations
, unsigned count
,
54 unsigned pixel_x
, unsigned pixel_y
)
56 glViewport(pixel_x
, pixel_y
, 1, 1);
57 glBindFramebuffer(GL_FRAMEBUFFER
, fbs
[cur_fb
]);
58 glClearColor(1.0, 1.0, 1.0, 1.0);
59 glClear(GL_COLOR_BUFFER_BIT
);
60 glUseProgram(draw_program
);
61 for (int x
= 0; x
< 16; x
++) {
62 for (int y
= 0; y
< 16; y
++) {
63 float left
= x
/16.0 - (1.0/32.0);
64 float bottom
= (16-y
)/16.0 - (1.0/32.0);
65 float width
= 1.0 / 16.0;
66 float height
= 1.0 / 16.0;
67 glUniform2f(glGetUniformLocation(draw_program
, "loc"), x
/16.0, y
/16.0);
68 piglit_draw_rect(left
, bottom
, width
, height
);
72 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE
, fb_textures
[cur_fb
]);
73 glViewport(0, 0, count
, 1);
74 glBindFramebuffer(GL_FRAMEBUFFER
, 0);
75 glClearColor(0.5, 0.5, 0.5, 1.0);
76 glClear(GL_COLOR_BUFFER_BIT
);
77 glUseProgram(read_program
);
78 glUniform1i(glGetUniformLocation(read_program
, "input"), 0);
79 glUniform2i(glGetUniformLocation(read_program
, "offset"), pixel_x
, pixel_y
);
80 piglit_draw_rect(0.0, 0.0, 1.0, 1.0);
82 glReadPixels(0, 0, count
, 1, GL_RGBA
, GL_UNSIGNED_BYTE
, locations
);
85 static enum piglit_result
86 test_pixel(const unsigned *expected
, unsigned pixel_x
, unsigned pixel_y
)
88 GLubyte actual_locations
[32*4];
89 get_sample_locations(actual_locations
, samples
, pixel_x
, pixel_y
);
91 unsigned grid_x
= pixel_x
% grid_width
;
92 unsigned grid_y
= pixel_y
% grid_height
;
94 for (unsigned i
= 0; i
< samples
; i
++) {
95 for (unsigned j
= 0; j
< 3; j
++) {
97 (const char*[]){"Uniform", "gl_SamplePosition", "interpolateAtSample"}[j
];
98 unsigned x
= actual_locations
[i
*4+j
] & 0xf;
99 unsigned y
= actual_locations
[i
*4+j
] >> 4;
100 unsigned expected_x
= expected
? expected
[i
*2] : 8;
101 unsigned expected_y
= expected
? expected
[i
*2+1] : 8;
103 if (x
!= expected_x
) {
104 printf("Expected X coordinate of sample %u to be %u, got %u from %s (at pixel %u, %u and grid %u, %u)\n",
105 i
, expected_x
, x
, src
, pixel_x
, pixel_y
, grid_x
, grid_y
);
109 if (y
!= expected_y
) {
110 printf("Expected Y coordinate of sample %u to be %u, got %u from %s (at pixel %u, %u and grid %u, %u)\n",
111 i
, expected_y
, y
, src
, pixel_x
, pixel_y
, grid_x
, grid_y
);
120 static enum piglit_result
121 do_test(const unsigned *locations
, unsigned pixel_x
, unsigned pixel_y
, bool grid
)
123 if (!fbs
[cur_fb
]) return PIGLIT_SKIP
;
125 glBindFramebuffer(GL_FRAMEBUFFER
, fbs
[cur_fb
]);
128 glGetIntegerv(GL_SAMPLES
, &samples
);
129 glGetIntegerv(GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB
, &grid_width
);
130 glGetIntegerv(GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB
, &grid_height
);
131 glGetIntegerv(GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB
, &table_size
);
133 unsigned grid_x
= pixel_x
% grid_width
;
134 unsigned grid_y
= pixel_y
% grid_height
;
136 glFramebufferParameteri(GL_FRAMEBUFFER
, GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB
, grid
);
137 glFramebufferParameteri(GL_FRAMEBUFFER
, GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB
, 1);
139 for (GLint i
= 0; i
< table_size
; i
++) {
140 GLfloat loc
[2] = {0.5f
, 0.5f
};
141 glFramebufferSampleLocationsfvARB(GL_FRAMEBUFFER
, i
, 1, loc
);
144 for (GLint i
= 0; i
< samples
; i
++) {
145 GLfloat loc
[2] = {locations
[i
*2] / 16.0f
, 1.0f
- locations
[i
*2+1] / 16.0f
};
148 index
+= (grid_y
*grid_width
+grid_x
) * samples
;
149 glFramebufferSampleLocationsfvARB(GL_FRAMEBUFFER
, index
, 1, loc
);
152 enum piglit_result result
= PIGLIT_PASS
;
154 piglit_merge_result(&result
, test_pixel(locations
, grid_x
, grid_y
));
156 for (unsigned x
= 0; x
< WIDTH
; x
++) {
157 for (unsigned y
= 0; y
< HEIGHT
; y
++) {
158 const unsigned *expected
= locations
;
159 unsigned grid_x_2
= x
% grid_width
;
160 unsigned grid_y_2
= y
% grid_height
;
161 if ((grid_x_2
!= grid_x
|| grid_y_2
!= grid_y
) && grid
)
163 piglit_merge_result(&result
, test_pixel(expected
, x
, y
));
171 static enum piglit_result
172 do_test_set(unsigned x
, unsigned y
, bool grid
)
174 static const unsigned new_locations
[32][2] = {
175 {1, 3}, {4, 1}, {2, 5}, {5, 5}, {3, 5}, {5, 2}, {1, 6}, {2, 6},
176 {7, 2}, {5, 7}, {4, 8}, {2, 8}, {8, 1}, {8, 6}, {8, 3}, {9, 8},
177 {2, 9}, {9, 3}, {1, 10}, {9, 10}, {10, 1}, {1, 11}, {6, 11}, {11, 6},
178 {12, 5}, {10, 12}, {8, 13}, {13, 8}, {13, 12}, {6, 13}, {4, 14}, {14, 8}};
179 enum piglit_result result
= do_test(&new_locations
[0][0], x
, y
, grid
);
181 piglit_report_subtest_result(result
, "MSAA: %u, X: %u, Y: %u, Grid: %s",
182 1<<cur_fb
, x
, y
, grid
?"true":"false");
188 create_shader_sources(char *vertex
, char *fragment
)
190 static const char *fragment_exts
=
191 "#extension GL_ARB_gpu_shader5 : enable\n"
192 "#extension GL_ARB_sample_shading : enable\n";
193 static const char *fragment_main
=
194 "uniform vec2 loc;\n"
197 "float encode_location(in vec2 loc) { return (loc.x*16.0 + loc.y*256.0) / 255.0; }\n"
199 " color.xyz = vec3(encode_location(loc));\n";
200 static const char *fragment_gl_sample_position
=
201 "color.y = encode_location(vec2(gl_SamplePosition.x, 1.0-gl_SamplePosition.y));\n";
202 static const char *fragment_interpolate_at_sample
=
203 "color.z = encode_location(vec2(interpolateAtSample(pos, gl_SampleID).x, 1.0-interpolateAtSample(pos, gl_SampleID).y));\n";
204 static const char *vertex_main
=
205 "in vec2 piglit_vertex;\n"
207 "void main() { gl_Position = vec4(piglit_vertex*2.0-1.0, 0.0, 1.0); pos = piglit_vertex; }\n";
209 int glsl_major
, glsl_minor
, glsl_ver
;
210 bool use_gl_sample_position
, use_interpolate_at_sample
;
212 piglit_get_glsl_version(NULL
, &glsl_major
, &glsl_minor
);
213 glsl_ver
= glsl_major
*100 + glsl_minor
;
216 use_gl_sample_position
= use_interpolate_at_sample
= true;
217 if (piglit_is_extension_supported("GL_ARB_gpu_shader5"))
218 use_interpolate_at_sample
= true;
219 if (piglit_is_extension_supported("GL_ARB_sample_shading"))
220 use_gl_sample_position
= true;
222 sprintf(fragment
, "#version %u\n%s", glsl_ver
, fragment_exts
);
223 strcat(fragment
, fragment_main
);
224 if (use_gl_sample_position
)
225 strcat(fragment
, fragment_gl_sample_position
);
226 if (use_interpolate_at_sample
)
227 strcat(fragment
, fragment_interpolate_at_sample
);
228 strcat(fragment
, "}");
230 sprintf(vertex
, "#version %u\n%s", glsl_ver
, fragment_exts
);
231 strcat(vertex
, vertex_main
);
235 piglit_init(int argc
, char **argv
)
237 char vertex_source
[1024];
238 char fragment_source
[1024];
239 piglit_require_extension("GL_ARB_sample_locations");
241 if (argc
> 1 && strcmp(argv
[1], "--quick") == 0)
244 create_shader_sources(vertex_source
, fragment_source
);
246 draw_program
= piglit_build_simple_program(vertex_source
, fragment_source
);
248 read_program
= piglit_build_simple_program(
250 "in vec2 piglit_vertex;\n"
251 "void main() { gl_Position = vec4(piglit_vertex*2.0-1.0, 0.0, 1.0); }\n",
253 "uniform sampler2DMS tex;\n"
254 "uniform ivec2 offset;\n"
256 "void main() { color = texelFetch(tex, offset, int(gl_FragCoord.x)); }\n");
259 glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES
, &count
);
260 if (count
> MAX_SAMPLES
)
262 count
= log2u(count
) + 1;
264 glGenTextures(count
, fb_textures
);
265 glGenFramebuffers(count
, fbs
);
266 for (cur_fb
= 0; cur_fb
< count
; cur_fb
++) {
267 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE
, fb_textures
[cur_fb
]);
268 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE
, 1<<cur_fb
, GL_RGBA8
, WIDTH
, HEIGHT
, GL_TRUE
);
269 glBindFramebuffer(GL_FRAMEBUFFER
, fbs
[cur_fb
]);
270 glFramebufferTexture(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, fb_textures
[cur_fb
], 0);
277 enum piglit_result result
= PIGLIT_PASS
;
278 for (cur_fb
= 0; cur_fb
< sizeof(fb_textures
)/sizeof(fb_textures
[0]); cur_fb
++) {
279 for (unsigned x
= 0; x
< WIDTH
; x
++) {
280 for (unsigned y
= 0; y
< HEIGHT
; y
++) {
281 piglit_merge_result(&result
, do_test_set(x
, y
, false));
282 piglit_merge_result(&result
, do_test_set(x
, y
, true));
287 piglit_present_results();