1 /*
2  * Copyright © 2019 Advanced Micro Devices, Inc.
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 #include "piglit-util-gl.h"
25 
26 static int
parse_gl_version(int argc,char ** argv)27 parse_gl_version(int argc, char** argv)
28 {
29 	int version;
30 	if (argc < 2) {
31 		piglit_loge("Usage: %s 12|30\n", argv[0]);
32 		exit(1);
33 	}
34 	version = atoi(argv[1]);
35 	if (version != 12 && version != 30) {
36 		piglit_loge("Usage: %s 12|30\n", argv[0]);
37 		exit(1);
38 	}
39 	return version;
40 }
41 
42 static int gl_compat_version;
43 
44 PIGLIT_GL_TEST_CONFIG_BEGIN
45 
46 	gl_compat_version = parse_gl_version(argc, argv);
47 	config.supports_gl_compat_version = gl_compat_version;
48 	config.khr_no_error_support = PIGLIT_HAS_ERRORS;
49 
50 PIGLIT_GL_TEST_CONFIG_END
51 
52 static GLint max_units;
53 static GLint max_tex_coords;
54 
55 struct get_float_indexed_t {
56 	void (*get_float_fn) (GLenum, GLuint, GLfloat *);
57 	const char* name;
58 	int min_gl_compat_version;
59 };
60 struct get_double_indexed_t {
61 	void (*get_double_fn) (GLenum, GLuint, GLdouble *);
62 	const char* name;
63 	int min_gl_compat_version;
64 };
65 struct get_pointer_indexed_t {
66 	void (*get_pointer_fn) (GLenum, GLuint, GLvoid **);
67 	const char* name;
68 	int min_gl_compat_version;
69 };
70 
71 
72 static enum piglit_result
test_GetBooleanIndexedvEXT(void * data)73 test_GetBooleanIndexedvEXT(void* data)
74 {
75 	static const GLenum targets[] = {
76 		/*
77 		 * Targets for which:
78 		 *	glGetBooleanIndexedvEXT(target, index, params)
79 		 * is equivalent to:
80 		 *	glActiveTexture(GL_TEXTURE0+index);
81 	         *	glGetBooleanv(target, params);
82 		 */
83 		GL_TEXTURE_1D,
84 		GL_TEXTURE_2D,
85 		GL_TEXTURE_3D,
86 		GL_TEXTURE_CUBE_MAP,
87 
88 		/* Separator */
89 		GL_NONE,
90 
91 		/*
92 		 * Targets for which:
93 		 *	glGetBooleanIndexedvEXT(target, index, params)
94 		 * is equivalent to:
95 	         *	glClientActiveTexture(GL_TEXTURE0+index);
96 	         *	glGetBooleanv(target, params);
97 		 */
98 		GL_TEXTURE_COORD_ARRAY
99 	};
100 	int i, index;
101 	GLboolean value, expected_value;
102 	bool useActiveTexture = true;
103 
104 	for (i = 0; i < ARRAY_SIZE(targets); i++) {
105 		if (targets[i] == GL_NONE) {
106 			useActiveTexture = false;
107 			continue;
108 		}
109 
110 		if (useActiveTexture) {
111 			index = rand() % max_units;
112 		} else {
113 			index = rand() % max_tex_coords;
114 		}
115 
116 		glGetBooleanIndexedvEXT(targets[i], index, &value);
117 
118 		if (useActiveTexture) {
119 			glActiveTexture(GL_TEXTURE0 + index);
120 		} else {
121 			glClientActiveTexture(GL_TEXTURE0 + index);
122 		}
123 		glGetBooleanv(targets[i], &expected_value);
124 
125 		if (value != expected_value || !piglit_check_gl_error(GL_NO_ERROR)) {
126 			piglit_loge("glGetBooleanIndexedvEXT(%s, %d, ...) failed. Expected: %d but got %d\n",
127 				piglit_get_gl_enum_name(targets[i]),
128 				index,
129 				expected_value,
130 				value);
131 			return PIGLIT_FAIL;
132 		}
133 	}
134 
135 	return PIGLIT_PASS;
136 }
137 
138 static enum piglit_result
test_GetIntegerIndexedvEXT(void * data)139 test_GetIntegerIndexedvEXT(void* data)
140 {
141 	static const GLenum targets[] = {
142 		GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_1D_ARRAY,
143 		GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_2D_ARRAY,
144 		GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP
145 	};
146 	int i;
147 	int value, expected_value;
148 
149 	for (i = 0; i < ARRAY_SIZE(targets); i++) {
150 		int index = rand() % max_units;
151 		glActiveTexture(GL_TEXTURE0 + (index + 1) % max_units);
152 
153 		glGetIntegerIndexedvEXT(targets[i], index, &value);
154 
155 		glActiveTexture(GL_TEXTURE0 + index);
156 		glGetIntegerv(targets[i], &expected_value);
157 
158 		if (value != expected_value || !piglit_check_gl_error(GL_NO_ERROR)) {
159 			piglit_loge("glGetIntegerIndexedvEXT(%s, %d, ...) failed. Expected: %d but got %d\n",
160 				piglit_get_gl_enum_name(targets[i]),
161 				index,
162 				expected_value,
163 				value);
164 			return PIGLIT_FAIL;
165 		}
166 	}
167 	return PIGLIT_PASS;
168 }
169 
170 static enum piglit_result
test_GetFloatIndexedvEXT(void * data)171 test_GetFloatIndexedvEXT(void* data)
172 {
173 	static const GLenum targets[] = {
174 		GL_TEXTURE_MATRIX, GL_TRANSPOSE_TEXTURE_MATRIX,
175 	};
176 	int i;
177 	float value[16], expected_value[16];
178 
179 	struct get_float_indexed_t* test = (struct get_float_indexed_t*) data;
180 
181 	if (gl_compat_version < test->min_gl_compat_version) {
182 		return PIGLIT_SKIP;
183 	}
184 
185 	for (i = 0; i < ARRAY_SIZE(targets); i++) {
186 		int index = rand() % max_tex_coords;
187 		glActiveTexture(GL_TEXTURE0 + (index + 1) % max_tex_coords);
188 
189 		test->get_float_fn(targets[i], index, value);
190 
191 		glActiveTexture(GL_TEXTURE0 + index);
192 		glGetFloatv(targets[i], expected_value);
193 
194 		if (memcmp(value, expected_value, sizeof(value)) != 0 ||
195 		    !piglit_check_gl_error(GL_NO_ERROR)) {
196 			piglit_loge("%s(%s, %d, ...) failed.\n",
197 				test->name,
198 				piglit_get_gl_enum_name(targets[i]),
199 				index);
200 			return PIGLIT_FAIL;
201 		}
202 	}
203 	return PIGLIT_PASS;
204 }
205 
206 static enum piglit_result
test_GetDoubleIndexedvEXT(void * data)207 test_GetDoubleIndexedvEXT(void* data)
208 {
209 	static const GLenum targets[] = {
210 		GL_TEXTURE_MATRIX, GL_TRANSPOSE_TEXTURE_MATRIX,
211 	};
212 	int i;
213 	double value[16], expected_value[16];
214 
215 	struct get_double_indexed_t* test = (struct get_double_indexed_t*) data;
216 	if (gl_compat_version < test->min_gl_compat_version) {
217 		return PIGLIT_SKIP;
218 	}
219 
220 	for (i = 0; i < ARRAY_SIZE(targets); i++) {
221 		int index = rand() % max_tex_coords;
222 		glActiveTexture(GL_TEXTURE0 + (index + 1) % max_tex_coords);
223 
224 		test->get_double_fn(targets[i], index, value);
225 
226 		glActiveTexture(GL_TEXTURE0 + index);
227 		glGetDoublev(targets[i], expected_value);
228 
229 		if (memcmp(value, expected_value, sizeof(value)) != 0 ||
230 		    !piglit_check_gl_error(GL_NO_ERROR)) {
231 			piglit_loge("%s(%s, %d, ...) failed.\n",
232 				test->name,
233 				piglit_get_gl_enum_name(targets[i]),
234 				index);
235 			return PIGLIT_FAIL;
236 		}
237 	}
238 	return PIGLIT_PASS;
239 }
240 
241 static enum piglit_result
test_GetPointerIndexedvEXT(void * data)242 test_GetPointerIndexedvEXT(void* data)
243 {
244 	/* The GL_EXT_direct_state_access spec says:
245 	 *
246 	 *   The following query
247 	 *
248 	 *       void GetPointerIndexedvEXT(enum pname, uint index, void **params);
249 	 *
250 	 *   is equivalent (assuming no errors) to the following:
251 	 *
252 	 *       int savedClientActiveTexture;
253 	 *
254 	 *       GetIntegerv(CLIENT_ACTIVE_TEXTURE, &savedClientActiveTexture);
255 	 *       ClientActiveTexture(TEXTURE0+index);
256 	 *       GetPointerv(pname, params);
257 	 *       ClientActiveTexture(savedClientActiveTexture);
258 	 *
259 	 *   [...] when the pname parameter is TEXTURE_COORD_ARRAY_POINTER.
260 	 *
261 	 */
262 	static const GLenum invalid_pnames[] = {
263 		GL_COLOR_ARRAY_POINTER, GL_EDGE_FLAG_ARRAY_POINTER,
264 		GL_FOG_COORD_ARRAY_POINTER, GL_FEEDBACK_BUFFER_POINTER,
265 		GL_INDEX_ARRAY_POINTER, GL_NORMAL_ARRAY_POINTER,
266 		GL_SECONDARY_COLOR_ARRAY_POINTER, GL_SELECTION_BUFFER_POINTER,
267 		GL_VERTEX_ARRAY_POINTER
268 	};
269 	int i;
270 	void* ptr, *expected_ptr;
271 
272 	int index = rand() % max_tex_coords;
273 
274 	struct get_pointer_indexed_t* test = (struct get_pointer_indexed_t*) data;
275 	if (gl_compat_version < test->min_gl_compat_version) {
276 		return PIGLIT_SKIP;
277 	}
278 
279 	glActiveTexture(GL_TEXTURE0 + (index + 1) % max_tex_coords);
280 
281 	test->get_pointer_fn(GL_TEXTURE_COORD_ARRAY_POINTER, index, &ptr);
282 
283 	glActiveTexture(GL_TEXTURE0 + index);
284 
285 	glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &expected_ptr);
286 
287 	if (expected_ptr != ptr || !piglit_check_gl_error(GL_NO_ERROR)) {
288 		return PIGLIT_FAIL;
289 	}
290 
291 	for (i = 0; i < ARRAY_SIZE(invalid_pnames); i++) {
292 		glGetPointerIndexedvEXT(invalid_pnames[i], index, &ptr);
293 
294 		if (!piglit_check_gl_error(GL_INVALID_ENUM)) {
295 			piglit_loge("glGetPointerIndexedvEXT(%s, ..., ...) should emit GL_INVALID_ENUM.\n",
296 				piglit_get_gl_enum_name(invalid_pnames[i]));
297 			return PIGLIT_FAIL;
298 		}
299 	}
300 	return PIGLIT_PASS;
301 }
302 
303 void
piglit_init(int argc,char ** argv)304 piglit_init(int argc, char **argv)
305 {
306 	piglit_require_extension("GL_EXT_direct_state_access");
307 
308 	glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_tex_coords);
309 	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_units);
310 
311 	/* The GL_EXT_direct_state_access spec says:
312 	 *
313 	 *     Add OpenGL 3.0-style aliases for the version 1.0 commands
314 	 *     and queries that have "Indexed" in the name.  OpenGL 3.0 has a
315 	 *     convention where an "i" indexed indexed commands and queries.
316 	 *     For example, glGetFloati_v and glGetFloatIndexedvEXT are
317 	 *     identical queries
318 	 *
319 	 * So glGetFloatIndexedvEXT/GetFloati_vEXT, GetDoubleIndexedvEXT/GetDoublei_vEXT
320 	 * and GetPointerIndexedvEXT/GetPointeri_vEXT use the same subtest
321 	 * where data describes which function is being tested.
322 	 */
323 
324 	const struct get_float_indexed_t get_float_12 = {
325 		glGetFloatIndexedvEXT, "GetFloatIndexedvEXT", 12
326 	};
327 	const struct get_float_indexed_t get_float_30 = {
328 		glGetFloati_vEXT, "GetFloati_vEXT", 30
329 	};
330 	const struct get_double_indexed_t get_double_12 = {
331 		glGetDoubleIndexedvEXT, "GetDoubleIndexedvEXT", 12
332 	};
333 	const struct get_double_indexed_t get_double_30 = {
334 		glGetDoublei_vEXT, "GetDoublei_vEXT", 30
335 	};
336 	const struct get_pointer_indexed_t get_pointer_12 = {
337 		glGetPointerIndexedvEXT, "GetPointerIndexedvEXT", 12
338 	};
339 	const struct get_pointer_indexed_t get_pointer_30 = {
340 		glGetPointeri_vEXT, "GetPointeri_vEXT", 30
341 	};
342 
343 	const struct piglit_subtest tests[] = {
344 		{
345 			"GetBooleanIndexedvEXT",
346 			NULL,
347 			test_GetBooleanIndexedvEXT
348 		},
349 		{
350 			"GetIntegerIndexedvEXT",
351 			NULL,
352 			test_GetIntegerIndexedvEXT
353 		},
354 		{
355 			"GetFloatIndexedvEXT",
356 			NULL,
357 			test_GetFloatIndexedvEXT,
358 			(void*) &get_float_12
359 		},
360 		{
361 			"GetFloati_vEXT",
362 			NULL,
363 			test_GetFloatIndexedvEXT,
364 			(void*) &get_float_30,
365 		},
366 		{
367 			"GetDoubleIndexedvEXT",
368 			NULL,
369 			test_GetDoubleIndexedvEXT,
370 			(void*) &get_double_12
371 		},
372 		{
373 			"GetDoublei_vEXT",
374 			NULL,
375 			test_GetDoubleIndexedvEXT,
376 			(void*) &get_double_30,
377 		},
378 		{
379 			"GetPointerIndexedvEXT",
380 			NULL,
381 			test_GetPointerIndexedvEXT,
382 			(void*) &get_pointer_12
383 		},
384 		{
385 			"GetPointeri_vEXT",
386 			NULL,
387 			test_GetPointerIndexedvEXT,
388 			(void*) &get_pointer_30,
389 		},
390 		{
391 			NULL
392 		}
393 	};
394 	piglit_report_result(piglit_run_selected_subtests(tests, NULL, 0, PIGLIT_PASS));
395 }
396 
397 enum piglit_result
piglit_display(void)398 piglit_display(void)
399 {
400 	/* UNREACHABLE */
401 	return PIGLIT_FAIL;
402 }