1 /**
2  * Copyright 2017 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
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /** @file compare-framebuffer-parameter-with-get.
25  *
26  * OpenGL 4.5 spec introduced new valid pnames for
27  * GetFramebufferParameter. From OpenGL 4.5 spec, Section 9.2.3
28  * "Framebuffer Object Queries":
29  *
30  *   "pname may also be one of DOUBLEBUFFER, IMPLEMENTATION_COLOR_-
31  *    READ_FORMAT, IMPLEMENTATION_COLOR_READ_TYPE, SAMPLES,
32  *    SAMPLE_BUFFERS, or STEREO, indicating the corresponding
33  *    framebuffer-dependent state from table 23.73. Values of
34  *    framebuffer-dependent state are identical to those that would be
35  *    obtained were the framebuffer object bound and queried using the
36  *    simple state queries in that table. These values may be queried
37  *    from either a framebuffer object or a default framebuffer."
38  *
39  * That "simple state queries in that table" are either glGetBooleanv
40  * or glGetIntegerv.
41  *
42  * 4.5 also defines a new method, available on previous versions
43  * through the direct state access extension,
44  * GetNamedFramebufferParameteriv:
45  *
46  * "For GetFramebufferParameteriv, the framebuffer object is that
47  *  bound to target"
48  *
49  * "For GetNamedFramebufferParameteriv, framebuffer may be zero,
50  *  indicating the default draw framebuffer, or the name of the
51  *  framebuffer object."
52  *
53  * So with the Named version, you can query the same info, but you can
54  * query for a framebuffer not bound at that moment.
55  *
56  * This test checks that the behaviour of GetFramebufferParameter,
57  * GetNamedFramebufferParameter and glGetX is the same for the bound
58  * framebuffer (default or user defined). Behaviour in the sense of
59  * same value returned or same error generated. For *Named* we will
60  * explicitly bound to a different framebuffer, to ensure that it
61  * works when the queried framebuffer is not bound at that moment.
62  *
63  * Note that we will not check if the error or the value is correct,
64  * just that are the same. Value and error correctness should be
65  * evaluated by other tests.
66  *
67  */
68 
69 #include "piglit-util-gl.h"
70 
71 PIGLIT_GL_TEST_CONFIG_BEGIN
72 
73 	config.supports_gl_core_version = 45;
74 
75 	config.window_visual = PIGLIT_GL_VISUAL_RGBA |
76 		PIGLIT_GL_VISUAL_DOUBLE;
77 
78 	config.khr_no_error_support = PIGLIT_NO_ERRORS;
79 
80 PIGLIT_GL_TEST_CONFIG_END
81 
82 /*
83  * Values of table 23.73, defined on 4.5 spec, allowed on
84  * GetFramebufferParameteriv (so the full table minus SAMPLE_POSITION)
85  */
86 static const GLenum table_23_73_allowed[] = {
87 	GL_IMPLEMENTATION_COLOR_READ_FORMAT,
88 	GL_IMPLEMENTATION_COLOR_READ_TYPE,
89 	GL_DOUBLEBUFFER,
90 	GL_STEREO,
91 	GL_SAMPLE_BUFFERS,
92 	GL_SAMPLES,
93 };
94 
95 GLuint framebuffers[3];
96 bool filter_pname = false;
97 GLenum global_pname;
98 bool filter_framebuffer = false;
99 int global_framebuffer;
100 
101 /*
102  * Returns if any of the table_23_73 enums is a boolean or not
103  */
104 static bool
is_boolean(GLenum pname)105 is_boolean(GLenum pname)
106 {
107 	switch(pname) {
108 	case GL_DOUBLEBUFFER:
109 	case GL_STEREO:
110 		return true;
111 	default:
112 		return false;
113 	}
114 }
115 
116 static void
print_usage()117 print_usage()
118 {
119 	printf("Usage: gl-4.5-compare-framebuffer-parameter-with-get <pname> <framebuffer>\n");
120 	printf("\tpname: only test this pname from table 23.73 (minus "
121 	       "SAMPLE_POSITION) to use. Optional. \n");
122 	printf("\tframebuffer: only test this framebuffer. Optional. Allowed values:\n "
123 	       "\t\t 0 (default framebuffer)\n"
124 	       "\t\t 1 (incomplete framebuffer)\n"
125 	       "\t\t 2 (complete framebuffer)\n");
126 }
127 
128 static void
parse_args(int argc,char ** argv)129 parse_args(int argc, char **argv)
130 {
131 	int i;
132 	bool found = false;
133 
134 	if (argc > 3) {
135 		printf("Only two possible params supported\n");
136 		goto bad_params;
137 	}
138 
139 	if (argc == 1)
140 		return;
141 
142 	filter_pname = true;
143 	/* Note that this call will abort if the enum is not recognized */
144 	global_pname = piglit_get_gl_enum_from_name(argv[1]);
145 	for (i = 0; i < ARRAY_SIZE(table_23_73_allowed); i++) {
146 		if (global_pname == table_23_73_allowed[i]) {
147 			found = true;
148 			break;
149 		}
150 	}
151 
152 	if (!found) {
153 		printf("pname %s is not valid for this test\n", argv[1]);
154 		goto bad_params;
155 	}
156 
157 	if (argc == 2)
158 		return;
159 
160 	filter_framebuffer = true;
161 	global_framebuffer = atoi(argv[2]);
162 	if (global_framebuffer < 0 || global_framebuffer > 2) {
163 		printf("Wrong value for framebuffer: %i\n", global_framebuffer);
164 		goto bad_params;
165 	}
166 
167 	return;
168 bad_params:
169 	print_usage();
170 	piglit_report_result(PIGLIT_FAIL);
171 }
172 
173 /*
174  * This method calls wraps glGetBooleanv and glGetInteger, as
175  * depending of the pname you will call one or the other. It also does
176  * the boolean to integer casting, as GetFramebufferParameteriv
177  * returns always int.
178  */
179 static void
call_get_x(GLenum pname,GLint * value,GLenum * error)180 call_get_x(GLenum pname,
181 	   GLint *value,
182 	   GLenum *error)
183 {
184 	if (is_boolean(pname)) {
185 		GLboolean local_value;
186 		glGetBooleanv(pname, &local_value);
187 		*value = local_value;
188 	} else {
189 		GLint local_value;
190 		glGetIntegerv(pname, &local_value);
191 		*value = local_value;
192 	}
193 
194 	*error = glGetError();
195 }
196 
197 static const char*
get_framebuffer_name(int index)198 get_framebuffer_name(int index)
199 {
200 	switch(index) {
201 	case 0:
202 		return "default framebuffer";
203 	case 1:
204 		return "incomplete framebuffer";
205 	case 2:
206 		return "complete framebuffer";
207 	default:
208 		assert(!"unknown framebuffer");
209 		return "unknown framebuffer";
210 	}
211 }
212 
213 /*
214  * Gets a framebuffer and attachs to it renderbuffer and other stuff,
215  * in order to ensure that it is a complete framebuffer.
216  *
217  * returns if it was successful.
218  */
219 static bool
complete_framebuffer(GLint fb)220 complete_framebuffer(GLint fb)
221 {
222 	GLuint rb;
223 
224 	glBindFramebuffer(GL_FRAMEBUFFER, fb);
225 	glGenRenderbuffers(1, &rb);
226 	glBindRenderbuffer(GL_RENDERBUFFER, rb);
227 	glRenderbufferStorage(GL_RENDERBUFFER, GL_R8, 1, 2);
228 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
229 
230 	if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER) &&
231 	    glGetError() == GL_NO_ERROR) {
232 		return true;
233 	} else {
234 		return false;
235 	}
236 }
237 
238 /*
239  * We pass the index inside the array of available framebuffers,
240  * instead of the fb itself, because we also want to test binding with
241  * a different valid fb.
242  */
243 static bool
execute_subtest(int index,GLenum pname)244 execute_subtest(int index,
245 		GLenum pname)
246 {
247 	GLint get_value;
248 	GLint parameter_value;
249 	GLint named_value;
250 	GLenum get_error;
251 	GLenum parameter_error;
252 	GLenum named_error;
253 	bool subtest_pass;
254 	GLuint fb;
255 	GLuint other_fb;
256 
257 	fb = framebuffers[index];
258 	other_fb = framebuffers[(index + 1) % ARRAY_SIZE(framebuffers)];
259 
260 	glBindFramebuffer(GL_FRAMEBUFFER, fb);
261 	glGetFramebufferParameteriv(GL_FRAMEBUFFER, pname, &parameter_value);
262 	parameter_error = glGetError();
263 
264 	/*
265 	 * We re-bind to a different (but valid) framebuffer, as we
266 	 * want to check that NamedFramebufferParameter gets the same
267 	 * value even if other framebuffer is bound.
268 	 */
269 	glBindFramebuffer(GL_FRAMEBUFFER, other_fb);
270 	glGetNamedFramebufferParameteriv(fb, pname, &named_value);
271 	named_error = glGetError();
272 
273 	glBindFramebuffer(GL_FRAMEBUFFER, fb);
274 	call_get_x(pname, &get_value, &get_error);
275 
276 	subtest_pass = (get_error == parameter_error &&
277 			get_value == parameter_value &&
278 			parameter_error == named_error &&
279 			parameter_value == named_value);
280 
281 	if (!subtest_pass) {
282 		printf("Different behaviour for pname %s.\n\tGetBooleanv/Integerv"
283 		       " returns %i and generate the error %s.\n"
284 		       "\tGetFramebufferParameter returns %i and generate the "
285 		       "error %s.\n\tGetNamedFramebufferParameter returns %i "
286 		       "and generate the error %s\n",
287 		       piglit_get_gl_enum_name(pname),
288 		       get_value, piglit_get_gl_error_name(get_error),
289 		       parameter_value, piglit_get_gl_error_name(parameter_error),
290 		       named_value, piglit_get_gl_error_name(named_error));
291 	}
292 
293 	return subtest_pass;
294 }
295 
296 
297 enum piglit_result
piglit_display(void)298 piglit_display(void)
299 {
300 	/* UNREACHED */
301 	return PIGLIT_FAIL;
302 }
303 
304 void
piglit_init(int argc,char ** argv)305 piglit_init(int argc, char **argv)
306 {
307 	/*
308 	 * We don't check for framebuffer object extension support an
309 	 * any other, as we are already asking core version 4.5 on
310 	 * PIGLIT CONFIG
311 	 */
312 	parse_args(argc, argv);
313 
314 	bool pass = true;
315 	int i;
316 	int c;
317 	bool subtest_pass;
318 
319 	framebuffers[0] = 0;
320 	glCreateFramebuffers(2, &framebuffers[1]);
321 	piglit_check_gl_error(GL_NO_ERROR);
322 
323 	if (!complete_framebuffer(framebuffers[2])) {
324 		printf("Not able to allocate a complete framebuffer\n");
325 
326 		piglit_report_result(PIGLIT_FAIL);
327 	}
328 
329 	for (c = 0; c < ARRAY_SIZE(framebuffers); c++) {
330 
331 		if (filter_framebuffer && global_framebuffer != c)
332 			continue;
333 
334 		for (i = 0; i < ARRAY_SIZE(table_23_73_allowed); i++) {
335                         GLenum pname = table_23_73_allowed[i];
336 
337 			if (filter_pname && global_pname != pname)
338 				continue;
339 
340 			subtest_pass = execute_subtest(c, pname);
341 
342 			PIGLIT_SUBTEST_CONDITION(subtest_pass, pass, "%s pname %s",
343 						 get_framebuffer_name(c),
344 						 piglit_get_gl_enum_name(pname));
345 		}
346 	}
347 
348 	piglit_report_result(pass ? PIGLIT_PASS : PIGLIT_FAIL);
349 }
350