1 /*
2  * Copyright (c) 2015 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file interpolateAtSample-dynamically-nonuniform.c
26  *
27  * Test ARB_gpu_shader5 interpolateAtSample builtin using dynamically
28  * non-uniform sample IDs.
29  *
30  * A 2x2 multisample floating-point framebuffer is created with four
31  * samples. The buffer is then filled with a single triangle four
32  * times, once with interpolation at each different sample location.
33  * The interpolation values are written into the framebuffer and read
34  * back so that it will know the sample location of each sample for
35  * each pixel. This process is then repeated but with each pixel
36  * specifying the sample IDs in a different order so that the sample
37  * ID will be dynamically non-uniform. The results are checked to
38  * ensure that the sample locations are the same as the previous
39  * render.
40  */
41 
42 #include "piglit-util-gl.h"
43 
44 PIGLIT_GL_TEST_CONFIG_BEGIN
45 
46 	config.supports_gl_core_version = 32;
47 
48 	config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGB;
49 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
50 
51 PIGLIT_GL_TEST_CONFIG_END
52 
53 #define N_SAMPLES 4
54 #define FBO_WIDTH 2
55 #define FBO_HEIGHT 2
56 
57 static const char
58 vertex_shader[] =
59 	"#version 150\n"
60 	"in vec2 piglit_vertex;\n"
61 	"out vec2 pos;\n"
62 	"\n"
63 	"void\n"
64 	"main()\n"
65 	"{\n"
66 	"        gl_Position = vec4(piglit_vertex, 0.0, 1.0);\n"
67 	"        pos = piglit_vertex;\n"
68 	"}\n";
69 
70 static const char
71 fragment_shader_dynamically_uniform[] =
72 	"#version 150\n"
73 	"#extension GL_ARB_gpu_shader5 : require\n"
74 	"in vec2 pos;\n"
75 	"uniform int sample_id;\n"
76 	"\n"
77 	"void\n"
78 	"main()\n"
79 	"{\n"
80 	"        gl_FragColor.rg = interpolateAtSample(pos, sample_id);\n"
81 	"        gl_FragColor.ba = vec2(0.0, 1.0);\n"
82 	"}\n";
83 
84 static const char
85 fragment_shader_dynamically_non_uniform[] =
86 	"#version 150\n"
87 	"#extension GL_ARB_gpu_shader5 : require\n"
88 	"in vec2 pos;\n"
89 	"uniform int sample_id;\n"
90 	"\n"
91 	"void\n"
92 	"main()\n"
93 	"{\n"
94 	"        int sid = sample_id ^ int(ceil(pos.x)) ^\n"
95 	"                  (int(ceil(pos.y)) << 1);\n"
96 	"        gl_FragColor.rg = interpolateAtSample(pos, sid);\n"
97 	"        gl_FragColor.ba = vec2(0.0, 1.0);\n"
98 	"}\n";
99 
100 enum piglit_result
piglit_display(void)101 piglit_display(void)
102 {
103 	/* not used */
104 	return PIGLIT_FAIL;
105 }
106 
107 static void
create_framebuffer(int sample_count,GLuint * fbo,GLuint * rb)108 create_framebuffer(int sample_count,
109 		   GLuint *fbo,
110 		   GLuint *rb)
111 {
112 	GLenum status;
113 
114 	glGenFramebuffers(1, fbo);
115 	glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
116 	glGenRenderbuffers(1, rb);
117 	glBindRenderbuffer(GL_RENDERBUFFER, *rb);
118 	if (sample_count > 1)
119 		glRenderbufferStorageMultisample(GL_RENDERBUFFER,
120 						 sample_count, /* samples */
121 						 GL_RG32F,
122 						 FBO_WIDTH, FBO_HEIGHT);
123 	else
124 		glRenderbufferStorage(GL_RENDERBUFFER,
125 				      GL_RG32F,
126 				      FBO_WIDTH, FBO_HEIGHT);
127 	glFramebufferRenderbuffer(GL_FRAMEBUFFER,
128 				  GL_COLOR_ATTACHMENT0,
129 				  GL_RENDERBUFFER,
130 				  *rb);
131 
132 	status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
133 	if (status != GL_FRAMEBUFFER_COMPLETE) {
134 		fprintf(stderr, "Multisample FBO incomplete\n");
135 		piglit_report_result(PIGLIT_SKIP);
136 	}
137 }
138 
139 static void
get_samples(bool dynamically_uniform,GLuint ms_fbo,GLuint ss_fbo,GLfloat results[N_SAMPLES][FBO_WIDTH * FBO_HEIGHT * 2])140 get_samples(bool dynamically_uniform,
141 	    GLuint ms_fbo,
142 	    GLuint ss_fbo,
143 	    GLfloat results[N_SAMPLES][FBO_WIDTH * FBO_HEIGHT * 2])
144 {
145 	static const float verts[] = {
146 		-1.0f, -1.0f,
147 		8.0f, -1.0f,
148 		-1.0f, 8.0f
149 	};
150 	const char *fragment_source;
151 	GLuint vbo, vao;
152 	GLuint prog;
153 	GLuint shader_id_location;
154 	int attr;
155 	int i;
156 
157 	if (dynamically_uniform)
158 		fragment_source = fragment_shader_dynamically_uniform;
159 	else
160 		fragment_source = fragment_shader_dynamically_non_uniform;
161 
162 	prog = piglit_build_simple_program(vertex_shader, fragment_source);
163 	glUseProgram(prog);
164 	shader_id_location = glGetUniformLocation(prog, "sample_id");
165 
166 	glViewport(0, 0, FBO_WIDTH, FBO_HEIGHT);
167 
168 	glGenBuffers(1, &vbo);
169 	glBindBuffer(GL_ARRAY_BUFFER, vbo);
170 	glBufferData(GL_ARRAY_BUFFER, sizeof verts, verts, GL_STATIC_DRAW);
171 
172 	glGenVertexArrays(1, &vao);
173 	glBindVertexArray(vao);
174 
175 	attr = glGetAttribLocation(prog, "piglit_vertex");
176 	glEnableVertexAttribArray(attr);
177 	glVertexAttribPointer(attr,
178 			      2, /* size */
179 			      GL_FLOAT,
180 			      GL_FALSE, /* normalized */
181 			      sizeof (GLfloat) * 2,
182 			      NULL /* pointer */);
183 
184 	for (i = 0; i < N_SAMPLES; i++) {
185 		glUniform1i(shader_id_location, i);
186 
187 		glBindFramebuffer(GL_FRAMEBUFFER, ms_fbo);
188 		glClear(GL_COLOR_BUFFER_BIT);
189 
190 		glDrawArrays(GL_TRIANGLES, 0, 3);
191 
192 		glBindFramebuffer(GL_READ_FRAMEBUFFER, ms_fbo);
193 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ss_fbo);
194 
195 		glClear(GL_COLOR_BUFFER_BIT);
196 		glBlitFramebuffer(0, 0, /* srcX/Y0 */
197 				  FBO_WIDTH, FBO_HEIGHT, /* srcX/Y1 */
198 				  0, 0, /* dstX/Y0 */
199 				  FBO_WIDTH, FBO_HEIGHT, /* dstX/Y1 */
200 				  GL_COLOR_BUFFER_BIT,
201 				  GL_NEAREST);
202 
203 		glBindFramebuffer(GL_FRAMEBUFFER, ss_fbo);
204 
205 		glReadPixels(0, 0, /* x/y */
206 			     FBO_WIDTH, FBO_HEIGHT,
207 			     GL_RG, GL_FLOAT,
208 			     results[i]);
209 	}
210 
211 	glDeleteBuffers(1, &vbo);
212 	glDeleteVertexArrays(1, &vao);
213 
214 	glDeleteProgram(prog);
215 }
216 
217 static void
print_coords(int x,int y,const GLfloat * results)218 print_coords(int x, int y,
219 	     const GLfloat *results)
220 {
221 	printf(" %f,%f",
222 	       results[(x + y * FBO_WIDTH) * 2] + 1.0f - x,
223 	       results[(x + y * FBO_WIDTH) * 2 + 1] + 1.0f - y);
224 }
225 
226 void
piglit_init(int argc,char ** argv)227 piglit_init(int argc, char**argv)
228 {
229 	GLuint ms_fbo, ms_rb;
230 	GLuint ss_fbo, ss_rb;
231 	GLfloat du_results[N_SAMPLES][FBO_WIDTH * FBO_HEIGHT * 2];
232 	GLfloat dnu_results[N_SAMPLES][FBO_WIDTH * FBO_HEIGHT * 2];
233 	bool pass = true;
234 	int x, y, i, j;
235 
236 	piglit_require_extension("GL_ARB_gpu_shader5");
237 	piglit_require_GLSL_version(150);
238 
239 	create_framebuffer(N_SAMPLES,
240 			   &ms_fbo, &ms_rb);
241 	create_framebuffer(1, /* sample_count */
242 			   &ss_fbo, &ss_rb);
243 
244 	get_samples(true, ms_fbo, ss_fbo, du_results);
245 	get_samples(false, ms_fbo, ss_fbo, dnu_results);
246 
247 	glDeleteFramebuffers(1, &ms_fbo);
248 	glDeleteRenderbuffers(1, &ms_rb);
249 	glDeleteFramebuffers(1, &ss_fbo);
250 	glDeleteRenderbuffers(1, &ss_rb);
251 
252 	for (y = 0; y < FBO_HEIGHT; y++) {
253 		for (x = 0; x < FBO_WIDTH; x++) {
254 			printf("Dynamically uniform coords at     (%i,%i):",
255 			       x, y);
256 			for (i = 0; i < N_SAMPLES; i++)
257 				print_coords(x, y, du_results[i]);
258 			fputc('\n', stdout);
259 			printf("Dynamically non-uniform coords at (%i,%i):",
260 			       x, y);
261 			for (i = 0; i < N_SAMPLES; i++) {
262 				j = i ^ x ^ (y << 1);
263 				print_coords(x, y, dnu_results[j]);
264 				if (memcmp(&du_results[i]
265 					   [(y * FBO_WIDTH + x) * 2],
266 					   &dnu_results[j]
267 					   [(y * FBO_WIDTH + x) * 2],
268 					   sizeof (GLfloat) * 2))
269 					pass = false;
270 
271 			}
272 			fputc('\n', stdout);
273 		}
274 	}
275 
276 	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
277 }
278 
279