[Piglit] [PATCH 2/2] arb_post_depth_coverage: Make multisampling test more robust

Lyude lyude at redhat.com
Mon May 22 18:55:10 UTC 2017


The multisampling test we currently have is not very useful. If you
modify the vertex shader it uses that enables ARB_post_depth_coverage
such that the lines enabling said extension are commented out, you will
notice that the test still "passes" with flying colors. While this makes
sure that ARB_post_depth_coverage doesn't break anything, it also
doesn't actually make sure that the extension even works.

I've tried fixing the original test, but honestly no matter how long I
look at it I still can't even start to understand how this was really
supposed to work in the first place (why exactly are we using depth
stenciling?). Since imirkin didn't have much more luck then I did with
figuring it out, we decided to just write a new and improved test.

So, write a new depth test that actually can't pass unless
ARB_post_depth_coverage is functional and changes the behavior of
gl_SampleMaskIn[] properly.

Also, as a sidenote to save people from confusion, this test no longer
passes on i965:

(0, 0) expected 0x2 in ssbo, got 0x3
(0, 0) expected 0xe in ssbo, got 0xf
(0, 0) expected 0xfe in ssbo, got 0xff
(0, 0) expected 0xfffe in ssbo, got 0xffff

That output only can occur if gl_SampleMaskIn[] actually doesn't do
anything, since enabling the extension should be unsetting the coverage
bit for the first sample. So GL_ARB_post_depth_coverage in i965 is
actually broken, not the test (this test passes 100% on the nvidia
blob).

Signed-off-by: Lyude <lyude at redhat.com>
---
 tests/spec/arb_post_depth_coverage/multisampling.c | 349 ++++++++-------------
 1 file changed, 133 insertions(+), 216 deletions(-)

diff --git a/tests/spec/arb_post_depth_coverage/multisampling.c b/tests/spec/arb_post_depth_coverage/multisampling.c
index f90208d..af23b3e 100644
--- a/tests/spec/arb_post_depth_coverage/multisampling.c
+++ b/tests/spec/arb_post_depth_coverage/multisampling.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Intel Corporation.
+ * Copyright (c) 2017 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -24,9 +24,15 @@
 #include "piglit-util-gl.h"
 
 /*
- * A test to check whether the right values are written to gl_SampleMaskIn
- * when ARB_post_depth_coverage and multisampling are enabled. Tests at
- * 2, 4, 8, 16 sample rates.
+ * A test to check that when ARB_post_depth_coverage is enabled, the values in
+ * gl_SampleMaskIn accurately reflect the results of the depth test being run
+ * before the respective fragment shader invocation. As well, we also check to
+ * make sure that when the extension is disabled, the values in
+ * gl_SampleMaskIn do not reflect the results of the depth test in each
+ * respective fragment shader invocation.
+ * For good measure, we test this behavior at sample rates of 2, 4, 8, and 16
+ * (if the GPU does not support a high enough sample rate to test all of these
+ * rates, we skip the ones we can't test).
  */
 
 PIGLIT_GL_TEST_CONFIG_BEGIN
@@ -38,24 +44,21 @@ PIGLIT_GL_TEST_CONFIG_BEGIN
 		PIGLIT_GL_VISUAL_DOUBLE;
 PIGLIT_GL_TEST_CONFIG_END
 
-static GLuint prog1, prog2, vao, ssbo, tex_color, tex_depth, fbo;
-static GLint *sample_mask;
+GLint prog1, prog2, prog3;
 
 static const char *vs_text =
 	"#version 430\n"
-	"in vec4 pos_in;\n"
-	"void main()\n"
-	"{\n"
-	"	gl_Position = pos_in;\n"
+	"in vec4 piglit_vertex;\n"
+	"void main() {\n"
+	"	gl_Position = piglit_vertex;\n"
 	"}\n";
 
 static const char *fs_text1 =
 	"#version 430\n"
 	"out vec4 color;\n"
-	"void main()\n"
-	"{\n"
-	"  gl_FragDepth = 0.5f;\n"
-	"	color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+	"void main() {\n"
+	"	color = vec4(1.0, 0.0, 0.0, 1.0);\n"
+	"	gl_SampleMask[0] = 1;\n"
 	"}\n";
 
 static const char *fs_text2 =
@@ -67,149 +70,111 @@ static const char *fs_text2 =
 	"layout(std430, binding = 0) buffer MaskOutput {\n"
 	"	int data[];\n"
 	"} mask_output;\n"
-	"layout(location = 1) uniform int width;\n"
-	"layout(location = 2) uniform int samples;\n"
-	"void main()\n"
-	"{\n"
-	"	int index = int(gl_FragCoord.y) * width + int(gl_FragCoord.x);\n"
-	"	atomicAdd(mask_output.data[index], bitCount(gl_SampleMaskIn[0]));\n"
-	"	color = vec4(1.0, 0.0, 0.0, 1.0);\n"
+	"void main() {\n"
+	"	int index = int(gl_FragCoord.y) * 160 + int(gl_FragCoord.x);\n"
+	"	atomicOr(mask_output.data[index], gl_SampleMaskIn[0]);\n"
+	"	color = vec4(0.0, 1.0, 0.0, 1.0);\n"
 	"}\n";
 
-static GLuint
-make_shader_program1(void)
-{
-	GLuint prog;
-
-	prog = piglit_build_simple_program(vs_text, fs_text1);
-	glUseProgram(prog);
-
-	glBindAttribLocation(prog, 0, "pos_in");
-
-	glLinkProgram(prog);
-
-	if (!piglit_check_gl_error(GL_NO_ERROR)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
-
-	return prog;
-}
+static const char *fs_text3 =
+	"#version 430\n"
+	"out vec4 color;\n"
+	"layout(early_fragment_tests) in;\n"
+	"layout(std430, binding = 0) buffer MaskOutput {\n"
+	"	int data[];\n"
+	"} mask_output;\n"
+	"void main() {\n"
+	"	int index = int(gl_FragCoord.y) * 160 + int(gl_FragCoord.x);\n"
+	"	atomicOr(mask_output.data[index], gl_SampleMaskIn[0]);\n"
+	"	color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+	"}\n";
 
-static GLuint
-make_shader_program2(void)
+static inline bool
+draw_and_check_sample_mask(GLint prog, int sample_count, int ssbo_value)
 {
-	GLuint prog;
-
-	prog = piglit_build_simple_program(vs_text, fs_text2);
-	glUseProgram(prog);
+	const size_t sample_mask_size = piglit_width * piglit_height;
+	GLint *sample_mask = calloc(sizeof(GLint), sample_mask_size);
+	GLuint fbo, tex_color, tex_depth, ssbo;
+	int i;
+	bool ret = true;
 
-	glBindAttribLocation(prog, 0, "pos_in");
-
-	glLinkProgram(prog);
+	glGenFramebuffers(1, &fbo);
+	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
-	if (!piglit_check_gl_error(GL_NO_ERROR)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
+	/* Create new textures */
+	glGenTextures(1, &tex_color);
+	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_color);
+	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sample_count,
+				GL_RGBA32F, piglit_width, piglit_height,
+				false);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+			       GL_TEXTURE_2D_MULTISAMPLE, tex_color, 0);
 
-	return prog;
-}
+	glGenTextures(1, &tex_depth);
+	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_depth);
+	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sample_count,
+				GL_DEPTH_COMPONENT24,
+				piglit_width, piglit_height, false);
+	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+			       GL_TEXTURE_2D_MULTISAMPLE, tex_depth, 0);
 
-static GLuint
-make_ssbo(void)
-{
-	GLuint ssbo;
+	/* Setup the ssbo */
 	glGenBuffers(1, &ssbo);
 	glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
+	glBufferData(GL_SHADER_STORAGE_BUFFER,
+		     sample_mask_size * sizeof(GLint),
+		     sample_mask, GL_DYNAMIC_DRAW);
+	glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 	if (!piglit_check_gl_error(GL_NO_ERROR)) {
-		piglit_report_result(PIGLIT_FAIL);
+		ret = false;
+		goto finish;
 	}
 
-	return ssbo;
-}
+	/* Draw a rectangle that covers the entire depth texture, but only in
+	 * the first sample.
+	 */
+	glUseProgram(prog1);
+	piglit_draw_rect_z(0.25, -1.0, -1.0, 4.0, 4.0);
 
-static GLuint
-make_fbo(void)
-{
-	GLuint fbo;
-	glGenFramebuffers(1, &fbo);
-	glBindFramebuffer(GL_FRAMEBUFFER, fbo );
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_color);
-	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-		GL_TEXTURE_2D_MULTISAMPLE, tex_color, 0);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_depth);
-	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-		GL_TEXTURE_2D_MULTISAMPLE, tex_depth, 0);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
-
-	return fbo;
-}
-
-static GLuint
-make_texture_color(void)
-{
-	GLuint tex;
-
-	glGenTextures(1, &tex);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
-	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2,
-		GL_RGBA32F, piglit_width, piglit_height, false);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
-
-	return tex;
-}
-
-static GLuint
-make_texture_depth(void)
-{
-	GLuint tex;
-
-	glGenTextures(1, &tex);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
-	glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2,
-		GL_DEPTH24_STENCIL8, piglit_width, piglit_height, false);
-	glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
-
-	return tex;
-}
-
-static GLuint
-make_vao(void)
-{
-	static const float pos_tc[12][2] = {
-		{ -1.0, -1.0 },
-		{  0.0, -1.0 },
-		{  0.0,  1.0 },
-		{  0.0,  1.0 },
-		{ -1.0,  1.0 },
-		{ -1.0, -1.0 },
-		{ -1.0, -1.0 },
-		{  1.0, -1.0 },
-		{  1.0,  1.0 },
-		{  1.0,  1.0 },
-		{ -1.0,  1.0 },
-		{ -1.0, -1.0 }
-	};
-	const int stride = sizeof(pos_tc[0]);
-	GLuint vbo, vao;
-
-	glGenVertexArrays(1, &vao);
-	glBindVertexArray(vao);
-
-	glGenBuffers(1, &vbo);
-	glBindBuffer(GL_ARRAY_BUFFER, vbo);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(pos_tc), pos_tc, GL_STATIC_DRAW);
-	piglit_check_gl_error(GL_NO_ERROR);
+	/* Now draw another rectangle that inhabits all of the samples, and
+	 * see which ones are covered in gl_SampleMaskIn when the fragment
+	 * shader is executed.
+	 */
+	glUseProgram(prog);
+	piglit_draw_rect_z(0.5, -1.0, -1.0, 4.0, 4.0);
+
+	glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0,
+			   sample_mask_size * sizeof(GLint), sample_mask);
+	for (i = 0; i < sample_mask_size; i++) {
+		if (sample_mask[i] != ssbo_value) {
+			fprintf(stderr,
+				"(%d, %d) expected 0x%x in ssbo, got 0x%x\n",
+				i % 160, i / 160, ssbo_value, sample_mask[i]);
+			ret = false;
+			break;
+		}
+	}
 
-	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, (void *) 0);
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, piglit_winsys_fbo);
+	glBlitFramebuffer(0, 0, piglit_width, piglit_height,
+			  0, 0, piglit_width, piglit_height,
+			  GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
+			  GL_NEAREST);
+	glBindFramebuffer(GL_FRAMEBUFFER, piglit_winsys_fbo);
 
-	glEnableVertexAttribArray(0);
+	piglit_present_results();
 
-	if (!piglit_check_gl_error(GL_NO_ERROR)) {
-		piglit_report_result(PIGLIT_FAIL);
-	}
+finish:
+	glDeleteTextures(2, (GLuint[2]) { tex_color, tex_depth });
+	glDeleteBuffers(1, &ssbo);
+	glDeleteFramebuffers(1, &fbo);
+	free(sample_mask);
 
-	return vbo;
+	return ret;
 }
 
 void
@@ -218,96 +183,48 @@ piglit_init(int argc, char **argv)
 	piglit_require_extension("GL_ARB_post_depth_coverage");
 
 	glEnable(GL_DEPTH_TEST);
-	glEnable(GL_STENCIL_TEST);
 	glEnable(GL_MULTISAMPLE);
-	glClearColor(0.0, 0.0, 0.0, 1.0);
+	glClearColor(0.2, 0.2, 0.2, 0.2);
 
-	prog1 = make_shader_program1();
-	prog2 = make_shader_program2();
-	vao = make_vao();
-	ssbo = make_ssbo();
-	tex_color = make_texture_color();
-	tex_depth = make_texture_depth();
-	fbo = make_fbo();
+	prog1 = piglit_build_simple_program(vs_text, fs_text1);
+	prog2 = piglit_build_simple_program(vs_text, fs_text2);
+	prog3 = piglit_build_simple_program(vs_text, fs_text3);
 }
 
-
 enum piglit_result
 piglit_display(void)
 {
-	int samples[4] = { 2, 4, 8, 16 };
-	int max_samples;
+	const int samples[] = {2, 4, 8, 16};
+	int max_sample_count, mask, i, j;
 	bool pass = true;
-	int i, j, k;
 
+	glGetIntegerv(GL_MAX_SAMPLES, &max_sample_count);
 	glViewport(0, 0, piglit_width, piglit_height);
-	glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
-
-	for (j = 0; j < 4 && samples[j] <= max_samples; j++) {
-		sample_mask = (GLint*) calloc (piglit_width * piglit_height,
-			sizeof(GLint));
-		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * piglit_width *
-			piglit_height, &sample_mask[0], GL_DYNAMIC_DRAW);
-		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
-
-		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_color);
-		glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples[j],
-			GL_RGBA8, piglit_width, piglit_height, false);
-		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex_depth);
-		glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples[j],
-			GL_DEPTH24_STENCIL8, piglit_width, piglit_height, false);
-
-		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
-			GL_STENCIL_BUFFER_BIT);
 
-		glUseProgram(prog1);
-		glStencilFunc(GL_ALWAYS, 1, 0xFF);
-		glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
-		glDrawArrays(GL_TRIANGLES, 0, 6);
-
-		glUseProgram(prog2);
-		glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
-		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-		glUniform1i(1, piglit_width);
-		glUniform1i(2, samples[j]);
-		glDrawArrays(GL_TRIANGLES, 6, 6);
-
-		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) *
-			piglit_width * piglit_height, sample_mask);
-
-		for (i = 0; i < piglit_width; i++) {
-			for (k = 0; k < piglit_height; k++) {
-				if (i >= piglit_width / 2) {
-					if (sample_mask[piglit_width * k + i] != samples[j]) {
-						pass = false;
-						break;
-					}
-				} else {
-					if (sample_mask[piglit_width * k + i] != 0) {
-						pass = false;
-						break;
-					}
-				}
-			}
-
-			if (!pass)
-				break;
-		}
-
-		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-		glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
-		glDrawBuffer(GL_BACK);
-		glBlitFramebuffer(0, 0, piglit_width, piglit_height, 0, 0, piglit_width,
-			piglit_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
-
-		piglit_present_results();
-		free(sample_mask);
-		if (!pass)
-			break;
+	for (i = 0;
+	     i < ARRAY_SIZE(samples) && samples[i] <= max_sample_count;
+	     i++)
+	{
+		for (j = 0, mask = 0; j < samples[i]; j++)
+			mask |= (1 << j);
+
+		/* With post depth coverage, the depth test will be run on
+		 * each sample before the fragment shader's invocation. As a
+		 * result, sample 0 should fail the depth test and
+		 * gl_SampleMaskIn[0] should indicate that all samples but 0
+		 * are covered by the fragment shader.
+		 */
+		if (!draw_and_check_sample_mask(prog2, samples[i], mask & ~1))
+			pass = false;
+
+		/* Without post depth coverage, the depth test will not have
+		 * been run by the time that the fragment shader is invoked,
+		 * and thus gl_SampleMaskIn[0] will indicate that all samples
+		 * are covered by the fragment shader.
+		 */
+		if (!draw_and_check_sample_mask(prog3, samples[i], mask))
+			pass = false;
 	}
 
-	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
-
 	return pass ? PIGLIT_PASS : PIGLIT_FAIL;
 }
-- 
2.9.4



More information about the Piglit mailing list