2 * Copyright 2017 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 /** \file samplemask.c
26 * Test two properties of gl_SampleMask and gl_SampleMaskIn for different
27 * sample rates, while rendering a slightly off-center triangle fan that
28 * covers the entire window, to thoroughly exercise cases where pixels are
31 * 1. Setting all bits of gl_SampleMask in all fragment shader invocations will
32 * cause all samples to be written exactly once. I.e., setting
33 * bits outside the rasterization coverage has no effect.
34 * 2. The bits of gl_SampleMaskIn over all fragment shader invocations form a
35 * partition of the set of samples. This subtest requires
36 * ARB_shader_atomic_counters to disambiguate between fragment shader
37 * invocations. (Also verifies sampleID is 0 when msaa is disabled.)
38 * Additionally, there's a test to just verify gl_SampleMaskIn is 1 when
39 * msaa is disabled (regardless of per-sample frequency shader or sample
40 * shading). (Omitted from test 2 because it's difficult to track down
41 * what's going wrong if drivers fail too many parts of the test.)
43 * The sample rate is controlled in one of two ways: Either glMinSampleShading
44 * or a fragment shader variant that uses gl_SampleID is used.
47 #include "piglit-fbo.h"
49 using namespace piglit_util_fbo
;
51 /* Produce lots of very narrow triangles, but some fully covered pixels as well. */
52 #define WINDOW_SIZE 256
53 #define VERTICES_PER_EDGE 80
55 PIGLIT_GL_TEST_CONFIG_BEGIN
57 config
.supports_gl_core_version
= 31;
59 config
.window_width
= WINDOW_SIZE
;
60 config
.window_height
= WINDOW_SIZE
;
61 config
.window_visual
= PIGLIT_GL_VISUAL_DOUBLE
| PIGLIT_GL_VISUAL_RGBA
;
62 config
.khr_no_error_support
= PIGLIT_NO_ERRORS
;
64 PIGLIT_GL_TEST_CONFIG_END
67 #define STRINGIFY(x) STR(x)
70 rate_mode_sampleshading
,
72 rate_mode_sampleid_noms
,
75 static int num_samples
;
76 static int actual_num_samples
;
77 static bool partition_check_supported
;
78 static bool mask_in_one_supported
;
79 static const char *procname
;
80 static const char *testname
;
81 static const char *sample_rate
;
82 static unsigned prog_fix_sample_mask
[2];
83 static unsigned prog_fix_check
;
84 static unsigned prog_mask_in_one
[2];
85 static unsigned prog_partition_write
[2];
86 static unsigned prog_partition_check
;
87 static unsigned prog_partition_check_have_sampleid
;
88 static unsigned prog_partition_check_msaa_disabled
;
93 print_usage_and_exit(const char *prog_name
)
95 printf("Usage: %s <num_samples> <rate> {fix|partition|mask_in_one|all}\n"
96 "where <rate> is either a floating point MinSampleShading value\n"
97 " or 'sample', 'noms', or 'all'\n",
99 piglit_report_result(PIGLIT_FAIL
);
103 build_program_variants(unsigned prog
[2], const char *vert
, const char *frag_template
)
107 if (asprintf(&frag
, frag_template
, "0") < 0)
108 piglit_report_result(PIGLIT_FAIL
);
109 prog
[0] = piglit_build_simple_program(vert
, frag
);
112 if (asprintf(&frag
, frag_template
, "gl_SampleID") < 0)
113 piglit_report_result(PIGLIT_FAIL
);
114 prog
[1] = piglit_build_simple_program(vert
, frag
);
119 compile_shaders(void)
121 static const char vert_passthrough
[] =
123 "in vec4 piglit_vertex;\n"
126 " gl_Position = piglit_vertex;\n"
128 static const char vert_fan
[] =
132 /* Calculate vertices of the triangle fan based on gl_VertexID */
133 " if (gl_VertexID == 0) {\n"
134 " gl_Position = vec4(0.01, 0.011, 0, 1);\n"
136 " int edge = ((gl_VertexID - 1) / " STRINGIFY(VERTICES_PER_EDGE
) ") % 4;\n"
137 " int vertex = (gl_VertexID - 1) % " STRINGIFY(VERTICES_PER_EDGE
) ";\n"
138 " float t = 2.0 / " STRINGIFY(VERTICES_PER_EDGE
) " * vertex;\n"
140 " gl_Position = vec4(-1 + t, -1, 0, 1);\n"
141 " else if (edge == 1)\n"
142 " gl_Position = vec4(1, -1 + t, 0, 1);\n"
143 " else if (edge == 2)\n"
144 " gl_Position = vec4(1 - t, 1, 0, 1);\n"
146 " gl_Position = vec4(-1, 1 - t, 0, 1);\n"
150 static const char frag_fix_sample_mask
[] =
152 "#extension GL_ARB_sample_shading : enable\n"
153 "out vec4 out_color;\n"
156 " gl_SampleMask[0] = ~0;\n"
157 " out_color = vec4(0.1, 0.0, %s, 0.0);\n"
159 static const char frag_fix_check
[] =
161 "#extension GL_ARB_texture_multisample : require\n"
162 "uniform sampler2DMS tex;\n"
163 "uniform int num_samples;\n"
164 "out vec4 out_color;\n"
167 " out_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
168 " for (int i = 0; i < num_samples; ++i) {\n"
169 " float v = texelFetch(tex, ivec2(gl_FragCoord.xy), i).x;\n"
170 " if (abs(v - 0.1) > 0.01)\n"
171 " out_color = vec4(1.0, float(i) / 255, v, 0.0);\n"
175 static const char frag_mask_in_one
[] =
177 "#extension GL_ARB_gpu_shader5 : enable\n"
178 "#extension GL_ARB_sample_shading : enable\n"
179 "out vec4 out_color;\n"
182 " out_color = vec4(float(gl_SampleMaskIn[0]) / 10.0, 0.0, %s, 0.0);\n"
185 static const char frag_partition_write
[] =
187 "#extension GL_ARB_gpu_shader5 : enable\n"
188 "#extension GL_ARB_sample_shading : enable\n"
189 "#extension GL_ARB_shader_atomic_counters : enable\n"
190 "layout(binding = 0, offset = 0) uniform atomic_uint counter;\n"
191 "out ivec4 out_color;\n"
194 " int invocation = int(atomicCounterIncrement(counter));\n"
195 " out_color = ivec4(gl_SampleMaskIn[0], invocation, %s, 0);\n"
197 static const char frag_partition_check
[] =
199 "#extension GL_ARB_texture_multisample : require\n"
200 "uniform isampler2DMS tex;\n"
201 "uniform int num_samples;\n"
202 "uniform bool have_sampleid;\n"
203 "uniform bool msaa_disabled;\n"
204 "out vec4 out_color;\n"
207 " out_color = vec4(0, 1, 0, 1);\n"
208 " for (int i = 0; i < num_samples; ++i) {\n"
209 " ivec4 di = texelFetch(tex, ivec2(gl_FragCoord.xy), i);\n"
210 " if (msaa_disabled) {\n"
211 " /* omit di.x == 1 test here, drivers fail multiple parts already... */\n"
213 " out_color = vec4(0.2, float(i) / 255, float(di.z) / 255, 0);\n"
215 " if ((di.x & (1 << i)) == 0)\n"
216 " out_color = vec4(0.1, float(i) / 255, float(di.x) / 255, 0);\n"
217 " if (have_sampleid && di.z != i)\n"
218 " out_color = vec4(0.2, float(i) / 255, float(di.z) / 255, 0);\n"
220 " for (int j = i + 1; j < num_samples; ++j) {\n"
221 " ivec2 dj = texelFetch(tex, ivec2(gl_FragCoord.xy), j).xy;\n"
222 " bool overlap = (di.x & dj.x) != 0;\n"
223 " bool equal = di.x == dj.x;\n"
224 " bool same_invoc = di.y == dj.y;\n"
225 " if (same_invoc && !equal)\n"
226 " out_color = vec4(0.5, float(i) / 255, float(j) / 255, 0);\n"
227 " if (!same_invoc && overlap)\n"
228 " out_color = vec4(0.6, float(i) / 255, float(j) / 255, 0);\n"
233 build_program_variants(prog_fix_sample_mask
, vert_fan
, frag_fix_sample_mask
);
234 prog_fix_check
= piglit_build_simple_program(vert_passthrough
, frag_fix_check
);
235 glUseProgram(prog_fix_check
);
236 glUniform1i(glGetUniformLocation(prog_fix_check
, "tex"), 0);
237 glUniform1i(glGetUniformLocation(prog_fix_check
, "num_samples"), actual_num_samples
);
239 if (mask_in_one_supported
) {
240 build_program_variants(prog_mask_in_one
, vert_fan
, frag_mask_in_one
);
243 if (partition_check_supported
) {
244 build_program_variants(prog_partition_write
, vert_fan
, frag_partition_write
);
245 prog_partition_check
= piglit_build_simple_program(vert_passthrough
, frag_partition_check
);
246 glUseProgram(prog_partition_check
);
247 glUniform1i(glGetUniformLocation(prog_partition_check
, "tex"), 0);
248 glUniform1i(glGetUniformLocation(prog_partition_check
, "num_samples"),
250 prog_partition_check_have_sampleid
=
251 glGetUniformLocation(prog_partition_check
, "have_sampleid");
252 prog_partition_check_msaa_disabled
=
253 glGetUniformLocation(prog_partition_check
, "msaa_disabled");
258 draw_fan(enum rate_mode mode
, float sample_rate
, bool msaa_force_disable
)
260 if (mode
== rate_mode_sampleid_noms
|| msaa_force_disable
) {
261 glDisable(GL_MULTISAMPLE
);
263 if (mode
== rate_mode_sampleshading
) {
264 glEnable(GL_SAMPLE_SHADING
);
265 glMinSampleShading(sample_rate
);
267 glDrawArrays(GL_TRIANGLE_FAN
, 0, 2 + 4 * VERTICES_PER_EDGE
);
268 glDisable(GL_SAMPLE_SHADING
);
269 glEnable(GL_MULTISAMPLE
);
272 static enum piglit_result
273 test_fix(enum rate_mode mode
, float sample_rate
)
275 glClearColor(0.0, 0.0, 0.0, 0.0);
277 /* 1. Draw everything with gl_SampleMask = ~0; */
278 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, ms_fbo
.handle
);
279 glClear(GL_COLOR_BUFFER_BIT
);
281 glUseProgram(prog_fix_sample_mask
[mode
!= rate_mode_sampleshading
]);
284 glBlendFunc(GL_ONE
, GL_ONE
);
286 draw_fan(mode
, sample_rate
, false);
290 /* 2. Use the check shader to check correctness. */
291 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
292 glClear(GL_COLOR_BUFFER_BIT
);
294 glUseProgram(prog_fix_check
);
295 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE
, ms_fbo
.color_tex
[0]);
297 piglit_draw_rect(-1, -1, 2, 2);
299 static const float expected
[4] = { 0, 1, 0, 1 };
300 if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE
, WINDOW_SIZE
, expected
))
303 if (!piglit_check_gl_error(GL_NO_ERROR
))
304 piglit_report_result(PIGLIT_FAIL
);
309 static enum piglit_result
310 test_mask_in_one(enum rate_mode mode
, float sample_rate
)
312 if (!mask_in_one_supported
)
315 glClearColor(0.0, 0.0, 0.0, 0.0);
317 /* 1. Draw everything outputting gl_SampleMaskIn, with msaa disabled; */
318 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, ms_fbo
.handle
);
319 glClear(GL_COLOR_BUFFER_BIT
);
322 * We'll abuse the sampleid_noms mode here and use the prog without
323 * sample id to so we still have 3 somewhat meaningful modes - of
324 * course with msaa always disabled it should always be the same.
326 glUseProgram(prog_mask_in_one
[mode
== rate_mode_sampleid
]);
329 glBlendFunc(GL_ONE
, GL_ONE
);
331 draw_fan(mode
, sample_rate
, true);
335 /* 2. Use the check shader to check correctness. */
336 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
337 glClear(GL_COLOR_BUFFER_BIT
);
339 glUseProgram(prog_fix_check
);
340 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE
, ms_fbo
.color_tex
[0]);
342 piglit_draw_rect(-1, -1, 2, 2);
344 static const float expected
[4] = { 0, 1, 0, 1 };
345 if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE
, WINDOW_SIZE
, expected
))
348 if (!piglit_check_gl_error(GL_NO_ERROR
))
349 piglit_report_result(PIGLIT_FAIL
);
354 static enum piglit_result
355 test_partition(enum rate_mode mode
, float sample_rate
)
357 if (!partition_check_supported
)
360 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, ms_ifbo
.handle
);
362 glUseProgram(prog_partition_write
[mode
!= rate_mode_sampleshading
]);
364 draw_fan(mode
, sample_rate
, false);
366 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
367 glClearColor(0.0, 0.0, 0.0, 0.0);
368 glClear(GL_COLOR_BUFFER_BIT
);
370 glUseProgram(prog_partition_check
);
371 glUniform1i(prog_partition_check_have_sampleid
, mode
== rate_mode_sampleid
);
372 glUniform1i(prog_partition_check_msaa_disabled
, mode
== rate_mode_sampleid_noms
);
373 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE
, ms_ifbo
.color_tex
[0]);
375 piglit_draw_rect(-1, -1, 2, 2);
377 static const float expected
[4] = { 0, 1, 0, 1 };
378 if (!piglit_probe_rect_rgba(0, 0, WINDOW_SIZE
, WINDOW_SIZE
, expected
))
381 if (!piglit_check_gl_error(GL_NO_ERROR
))
382 piglit_report_result(PIGLIT_FAIL
);
388 iterate_sample_rates(const char *testname
, enum piglit_result (*test
)(enum rate_mode
, float))
390 bool all
= !strcmp(sample_rate
, "all");
391 bool sample
= all
|| !strcmp(sample_rate
, "sample");
392 bool noms
= all
|| !strcmp(sample_rate
, "noms");
394 enum piglit_result result
;
397 result
= test(rate_mode_sampleid
, 0);
398 piglit_report_subtest_result(result
, "sample %s", testname
);
399 if (result
== PIGLIT_FAIL
)
404 result
= test(rate_mode_sampleid_noms
, 0);
405 piglit_report_subtest_result(result
, "noms %s", testname
);
406 if (result
== PIGLIT_FAIL
)
413 result
= test(rate_mode_sampleshading
, rate
);
414 piglit_report_subtest_result(result
, "%f %s", rate
, testname
);
415 if (result
== PIGLIT_FAIL
)
418 if (actual_num_samples
* rate
<= 1)
425 if (!all
&& !sample
&& !noms
) {
426 float rate
= atof(sample_rate
);
427 result
= test(rate_mode_sampleshading
, rate
);
428 piglit_report_subtest_result(result
, "%f %s", rate
, testname
);
429 if (result
== PIGLIT_FAIL
)
441 bool all
= !strcmp(testname
, "all");
443 if (all
|| !strcmp(testname
, "fix")) {
445 pass
= iterate_sample_rates("fix", test_fix
) && pass
;
448 if (all
|| !strcmp(testname
, "mask_in_one")) {
450 pass
= iterate_sample_rates("mask_in_one", test_mask_in_one
) && pass
;
453 if (all
|| !strcmp(testname
, "partition")) {
455 pass
= iterate_sample_rates("partition", test_partition
) && pass
;
459 print_usage_and_exit(procname
);
461 piglit_present_results();
463 return pass
? PIGLIT_PASS
: PIGLIT_FAIL
;
467 piglit_init(int argc
, char **argv
)
470 print_usage_and_exit(argv
[0]);
474 /* 1st arg: num_samples */
476 num_samples
= strtol(argv
[1], &endptr
, 0);
477 if (endptr
!= argv
[1] + strlen(argv
[1]))
478 print_usage_and_exit(argv
[0]);
480 /* 2nd arg: sample rate */
481 sample_rate
= argv
[2];
483 /* 3rd arg: testname */
486 piglit_require_extension("GL_ARB_texture_multisample");
487 piglit_require_extension("GL_ARB_sample_shading");
489 partition_check_supported
=
490 piglit_is_extension_supported("GL_ARB_gpu_shader5") &&
491 piglit_is_extension_supported("GL_ARB_shader_atomic_counters");
493 mask_in_one_supported
=
494 piglit_is_extension_supported("GL_ARB_gpu_shader5");
496 /* Skip the test if num_samples > GL_MAX_SAMPLES */
498 glGetIntegerv(GL_MAX_SAMPLES
, &max_samples
);
499 if (num_samples
> max_samples
)
500 piglit_report_result(PIGLIT_SKIP
);
502 /* Dummy vertex array */
504 glGenVertexArrays(1, &empty_vao
);
505 glBindVertexArray(empty_vao
);
507 /* Multi-sample framebuffer setup */
508 FboConfig
fbo_config(num_samples
, WINDOW_SIZE
, WINDOW_SIZE
);
509 fbo_config
.num_tex_attachments
= 1;
510 fbo_config
.num_rb_attachments
= 0;
511 fbo_config
.depth_internalformat
= GL_NONE
;
512 fbo_config
.stencil_internalformat
= GL_NONE
;
513 ms_fbo
.setup(fbo_config
);
515 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, ms_fbo
.handle
);
516 glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER
, GL_SAMPLES
, &actual_num_samples
);
517 glBindFramebuffer(GL_DRAW_FRAMEBUFFER
, piglit_winsys_fbo
);
519 printf("Requested %d samples, got %d samples\n", num_samples
, actual_num_samples
);
521 /* Integer multi-sample framebuffer setup */
522 fbo_config
.color_internalformat
= GL_RGBA32I
;
523 ms_ifbo
.setup(fbo_config
);
528 if (partition_check_supported
) {
530 glGenBuffers(1, &atomic_bo
);
531 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER
, 0, atomic_bo
);
532 glBufferData(GL_ATOMIC_COUNTER_BUFFER
, 4, NULL
, GL_STATIC_DRAW
);
535 if (!piglit_check_gl_error(GL_NO_ERROR
))
536 piglit_report_result(PIGLIT_FAIL
);