1 /*
2  * Copyright © 2013 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 api.c
26  *
27  * Basic AMD_performance_monitor infrastructure tests.  These test the
28  * mechanism to retrieve counter and group information, string processing,
29  * and various error conditions.  They do not actually activate monitoring.
30  */
31 
32 #define __STDC_FORMAT_MACROS
33 #include <inttypes.h>
34 #include "piglit-util-gl.h"
35 
36 PIGLIT_GL_TEST_CONFIG_BEGIN
37 
38 	config.supports_gl_compat_version = 10;
39 	config.window_visual = PIGLIT_GL_VISUAL_RGB;
40 
41 PIGLIT_GL_TEST_CONFIG_END
42 
43 /******************************************************************************/
44 
45 /**
46  * Get a list of group IDs.
47  */
48 static void
get_groups(unsigned ** groups,int * num_groups)49 get_groups(unsigned **groups, int *num_groups)
50 {
51 	glGetPerfMonitorGroupsAMD(num_groups, 0, NULL);
52 	*groups = calloc(*num_groups, sizeof(unsigned));
53 	glGetPerfMonitorGroupsAMD(NULL, *num_groups, *groups);
54 }
55 
56 /**
57  * Get a list of counter IDs in a given group.
58  */
59 static void
get_counters(unsigned group,unsigned ** counters,int * num_counters)60 get_counters(unsigned group, unsigned **counters, int *num_counters)
61 {
62 	glGetPerfMonitorCountersAMD(group, num_counters, NULL, 0, NULL);
63 	*counters = calloc(*num_counters, sizeof(unsigned));
64 	glGetPerfMonitorCountersAMD(group, NULL, NULL, *num_counters, *counters);
65 }
66 
67 /**
68  * Return true if x is in xs.
69  */
70 static bool
in_list(int x,unsigned * xs,int elts)71 in_list(int x, unsigned *xs, int elts)
72 {
73 	int i;
74 	for (i = 0; i < elts; i++) {
75 		if (x == xs[i])
76 			return true;
77 	}
78 	return false;
79 }
80 
81 /**
82  * Find an invalid group ID.
83  */
84 static unsigned
find_invalid_group(unsigned * groups,int num_groups)85 find_invalid_group(unsigned *groups, int num_groups)
86 {
87 	unsigned invalid_group = ~0;
88 
89 	/* Most implementations probably use small consecutive integers, so
90 	 * start at ~0 and work backwards.  Hopefully we shouldn't loop.
91 	 */
92 	while (in_list(invalid_group, groups, num_groups))
93 		--invalid_group;
94 
95 	return invalid_group;
96 }
97 
98 /**
99  * Find an invalid counter ID.
100  */
101 static unsigned
find_invalid_counter(unsigned * counters,int num_counters)102 find_invalid_counter(unsigned *counters, int num_counters)
103 {
104 	unsigned invalid_counter = ~0;
105 
106 	/* Most implementations probably use small consecutive integers, so
107 	 * start at ~0 and work backwards.  Hopefully we shouldn't loop.
108 	 */
109 	while (in_list(invalid_counter, counters, num_counters))
110 		--invalid_counter;
111 
112 	return invalid_counter;
113 }
114 
115 #define report(pass) \
116 	do { \
117 		piglit_report_subtest_result((pass) ? PIGLIT_PASS : PIGLIT_FAIL, __FUNCTION__); \
118 		return; \
119 	} while (0)
120 
121 /******************************************************************************/
122 
123 /**
124  * Call glGetPerfMonitorGroupsAMD() with a NULL numGroups pointer.
125  *
126  * Verify that it doesn't attempt to write the number of groups and crash.
127  */
128 static void
test_number_of_groups_null_num_groups_pointer(void)129 test_number_of_groups_null_num_groups_pointer(void)
130 {
131 	glGetPerfMonitorGroupsAMD(NULL, 0, NULL);
132 	report(piglit_check_gl_error(GL_NO_ERROR));
133 }
134 
135 
136 /**
137  * Call glGetPerfMonitorGroupsAMD() with NULL for groups but non-zero groupSize.
138  *
139  * Verify that it returns the number of groups but doesn't try to write any
140  * group IDs and crash.
141  */
142 static void
test_number_of_groups_null_groups_pointer(void)143 test_number_of_groups_null_groups_pointer(void)
144 {
145 	bool pass = true;
146 	int num_groups = -1;
147 
148 	glGetPerfMonitorGroupsAMD(&num_groups, 777, NULL);
149 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
150 	pass = num_groups >= 0 && pass;
151 	report(pass);
152 }
153 
154 /**
155  * Call glGetPerfMonitorGroupsAMD() with zero for groupSize.
156  *
157  * Verify that it doesn't write any group IDs.
158  */
159 static void
test_number_of_groups_zero_size_array(void)160 test_number_of_groups_zero_size_array(void)
161 {
162 	bool pass = true;
163 	unsigned groups[2] = {0xd0d0d0d0, 0xd1d1d1d1};
164 	int num_groups = -1;
165 
166 	glGetPerfMonitorGroupsAMD(&num_groups, 0, groups);
167 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
168 
169 	/* num_groups must have changed */
170 	pass = num_groups >= 0 && pass;
171 
172 	/* The groups array should not have changed. */
173 	pass = groups[0] == 0xd0d0d0d0 && pass;
174 	pass = groups[1] == 0xd1d1d1d1 && pass;
175 	report(pass);
176 }
177 
178 /**
179  * Call glGetPerfMonitorGroupsAMD() with a groups array bigger than groupSize.
180  *
181  * Verify that it fills the correct number of array slots with group IDs.
182  */
183 static void
test_number_of_groups_partial_array(void)184 test_number_of_groups_partial_array(void)
185 {
186 	bool pass = true;
187 	unsigned groups[] = {0xdddddddd, 0xdddddddd, 0xdddddddd, 0xdddddddd};
188 
189 	/* Artificially low array size */
190 	const int groups_array_size = 2;
191 	int num_groups = -1;
192 	int i;
193 
194 	/* This should return the number of groups.  It should not attempt to
195 	 * write any groups since the pointer is NULL.
196 	 */
197 	glGetPerfMonitorGroupsAMD(&num_groups, groups_array_size, groups);
198 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
199 
200 	/* num_groups must have changed */
201 	pass = num_groups >= 0 && pass;
202 
203 	/* The first few elements should have changed. */
204 	for (i = 0; i < MIN2(num_groups, groups_array_size); i++) {
205 		pass = groups[i] != 0xdddddddd && pass;
206 	}
207 
208 	/* Catalyst 13.10 on a Radeon 6870 appears to have a bug where this
209 	 * returns 3 elements instead of 2.  According to the spec,
210 	 * "The number of entries that will be returned in <groups> is
211 	 *  determined by <groupSize>."
212 	 *
213 	 * Technically, it does not say that N elements will be returned if
214 	 * groupSize is N, but that's the only reasonable assumption.
215 	 */
216 
217 	/* The rest should remain untouched. */
218 	for (; i < ARRAY_SIZE(groups); i++) {
219 		pass = groups[i] == 0xdddddddd && pass;
220 	}
221 
222 	report(pass);
223 }
224 
225 /******************************************************************************/
226 
227 /**
228  * Call glGetPerfMonitorCountersAMD() with an invalid group ID.
229  *
230  * Verify that it produces INVALID_VALUE.
231  */
232 static void
test_get_counters_invalid_group(unsigned invalid_group)233 test_get_counters_invalid_group(unsigned invalid_group)
234 {
235 	glGetPerfMonitorCountersAMD(invalid_group, NULL, NULL, 0, NULL);
236 	report(piglit_check_gl_error(GL_INVALID_VALUE));
237 }
238 
239 /**
240  * Call glGetPerfMonitorCountersAMD() with a bunch of NULL pointers.
241  *
242  * Verify that it doesn't crash attempting to write numCounters,
243  * maxActiveCounters, or the counters list.
244  */
245 static void
test_get_counters_null_pointers(unsigned valid_group)246 test_get_counters_null_pointers(unsigned valid_group)
247 {
248 	glGetPerfMonitorCountersAMD(valid_group, NULL, NULL, 0, NULL);
249 	report(piglit_check_gl_error(GL_NO_ERROR));
250 }
251 
252 /**
253  * Call glGetPerfMonitorCountersAMD() with NULL for the array but non-zero size.
254  *
255  * Verify that it returns the number of groups but doesn't try to write any
256  * group IDs and crash.
257  */
258 static void
test_get_counters_null_pointer_non_zero_size(unsigned valid_group)259 test_get_counters_null_pointer_non_zero_size(unsigned valid_group)
260 {
261 	glGetPerfMonitorCountersAMD(valid_group, NULL, NULL, 777, NULL);
262 	report(piglit_check_gl_error(GL_NO_ERROR));
263 }
264 
265 /**
266  * Call glGetPerfMonitorCountersAMD() with zero for countersSize.
267  *
268  * Verify that it doesn't write any IDs, but does return other data.
269  */
270 static void
test_get_counters_zero_size_array(unsigned valid_group)271 test_get_counters_zero_size_array(unsigned valid_group)
272 {
273 	bool pass = true;
274 	unsigned counters[2] = {0xd0d0d0d0, 0xd1d1d1d1};
275 	int num_counters = -1;
276 	int max_active_counters = -1;
277 
278 	glGetPerfMonitorCountersAMD(valid_group, &num_counters,
279 				    &max_active_counters,
280 				    0, counters);
281 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
282 
283 	/* Expect a positive number of counters. */
284 	pass = num_counters >= 0 && pass;
285 
286 	/* Expect a positive maximum active counters. */
287 	pass = max_active_counters >= 0 && pass;
288 
289 	/* The counters array should not have changed. */
290 	pass = counters[0] == 0xd0d0d0d0 && pass;
291 	pass = counters[1] == 0xd1d1d1d1 && pass;
292 	report(pass);
293 }
294 
295 /**
296  * Call glGetPerfMonitorGroupsAMD() with a groups array bigger than groupSize.
297  *
298  * Verify that it fills the correct number of array slots with group IDs.
299  */
300 static void
test_get_counters_partial_array(unsigned valid_group)301 test_get_counters_partial_array(unsigned valid_group)
302 {
303 	bool pass = true;
304 	unsigned counters[] = {0xdddddddd, 0xdddddddd, 0xdddddddd, 0xdddddddd};
305 
306 	/* Artificially low array size */
307 	const int counters_array_size = 2;
308 	int num_counters = -1;
309 	int i;
310 
311 	/* This should return the number of groups.  It should not attempt to
312 	 * write any groups since the pointer is NULL.
313 	 */
314 	glGetPerfMonitorCountersAMD(valid_group, &num_counters, NULL,
315 				    counters_array_size, counters);
316 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
317 
318 	/* num_counters must have changed */
319 	pass = num_counters >= 0 && pass;
320 
321 	/* The first few elements should have changed. */
322 	for (i = 0; i < MIN2(num_counters, counters_array_size); i++) {
323 		pass = counters[i] != 0xdddddddd && pass;
324 	}
325 
326 	/* The rest should remain untouched. */
327 	for (; i < ARRAY_SIZE(counters); i++) {
328 		pass = counters[i] == 0xdddddddd && pass;
329 	}
330 
331 	report(pass);
332 }
333 
334 /******************************************************************************/
335 
336 /**
337  * Call glGetPerfMonitorGroupStringAMD() with an invalid group ID.
338  *
339  * Verify that it produces INVALID_VALUE.
340  */
341 static void
test_group_string_invalid_group(unsigned invalid_group)342 test_group_string_invalid_group(unsigned invalid_group)
343 {
344 	glGetPerfMonitorGroupStringAMD(invalid_group, 0, NULL, NULL);
345 	report(piglit_check_gl_error(GL_INVALID_VALUE));
346 }
347 
348 /**
349  * Call glGetPerfMonitorGroupStringAMD() with a NULL length pointer.
350  *
351  * Verify that it doesn't crash.
352  */
353 static void
test_group_string_null_length(unsigned valid_group)354 test_group_string_null_length(unsigned valid_group)
355 {
356 	glGetPerfMonitorGroupStringAMD(valid_group, 0, NULL, NULL);
357 	report(piglit_check_gl_error(GL_NO_ERROR));
358 }
359 
360 /**
361  * Call glGetPerfMonitorGroupStringAMD() with a single character buffer.
362  *
363  * Verify that length is correct and no buffer overflows occur.
364  */
365 static void
test_group_string_single_character_buffer(unsigned valid_group)366 test_group_string_single_character_buffer(unsigned valid_group)
367 {
368 	bool pass = true;
369 	char name[3] = "```";
370 	GLsizei length = 0xd0d0d0d0;
371 
372 	glGetPerfMonitorGroupStringAMD(valid_group, 1, &length, name);
373 	pass = piglit_check_gl_error(GL_NO_ERROR);
374 
375 	/* Verify buffer contents: only the first character should change. */
376 	pass = name[0] != '`' && pass;
377 	pass = name[1] == '`' && pass;
378 	pass = name[2] == '`' && pass;
379 
380 	/* length is the number of characters written excluding the null
381 	 * terminator.
382 	 */
383 	if (name[0] == '\0') {
384 		pass = length == 0 && pass;
385 	} else {
386 		/* AMD Catalyst 13.10 (Radeon 6870) does not write a null
387 		 * terminator.  Instead, it writes the first part of the name.
388 		 */
389 		pass = length == 1 && pass;
390 	}
391 
392 	report(pass);
393 }
394 
395 /**
396  * Call glGetPerfMonitorGroupStringAMD() with a small buffer.
397  *
398  * Verify that a name is returned, length is valid, and no overflows occur.
399  */
400 static void
test_group_string_small_buffer(unsigned valid_group)401 test_group_string_small_buffer(unsigned valid_group)
402 {
403 	bool pass = true;
404 	char name[3] = "```";
405 	GLsizei length = 0xd0d0d0d0;
406 	int i;
407 
408 	glGetPerfMonitorGroupStringAMD(valid_group, 3, &length, name);
409 
410 	pass = length <= 3 && pass;
411 
412 	/* Verify buffer contents: accept no null terminator. */
413 	for (i = 0; i < length; i++)
414 		pass = name[i] != '`' && pass;
415 
416 	if (length < 3) {
417 		pass = name[length] == '\0';
418 		for (i = length + 1; i < 3; i++)
419 			pass = name[i] == '`' && pass;
420 	}
421 
422 	report(pass);
423 }
424 
425 /**
426  * Call glGetPerfMonitorGroupStringAMD() with an appropriately sized buffer.
427  *
428  * Verify that a name is returned, length is valid, and no overflows occur.
429  */
430 static void
test_group_string_normal_buffer(unsigned valid_group)431 test_group_string_normal_buffer(unsigned valid_group)
432 {
433 	bool pass = true;
434 	char *name;
435 	GLsizei length = 0xd0d0d0d0;
436 	int i;
437 
438 	/* Get the length; bail if unwritten to avoid huge allocations. */
439 	glGetPerfMonitorGroupStringAMD(valid_group, 0, &length, NULL);
440 	pass = pass && piglit_check_gl_error(GL_NO_ERROR);
441 	if (length == 0xd0d0d0d0)
442 		report(false);
443 
444 	name = malloc(length + 1);
445 	assert(name != NULL);
446 
447 	/* Fill the buffer with a known character (` marks) */
448 	memset(name, '`', length + 1);
449 
450 	/* Get the name; everything will fit. */
451 	glGetPerfMonitorGroupStringAMD(valid_group, length + 1, NULL, name);
452 	pass = pass && piglit_check_gl_error(GL_NO_ERROR);
453 
454 	/* Indexes in the interval [0, length) must have been written, or
455 	 * else length is wrong.
456 	 */
457 	for (i = 0; i < length; i++)
458 		pass = name[i] != '`' && pass;
459 
460 	/* The last character must be the null terminator. */
461 	pass = name[length] == '\0' && pass;
462 
463 	report(pass);
464 }
465 
466 /******************************************************************************/
467 
468 /**
469  * Call glGetPerfMonitorCounterStringAMD() with an invalid group ID.
470  *
471  * Verify that it produces INVALID_VALUE.
472  */
473 static void
test_counter_string_invalid_group(unsigned invalid_group)474 test_counter_string_invalid_group(unsigned invalid_group)
475 {
476 	glGetPerfMonitorCounterStringAMD(invalid_group, 0, 0, NULL, NULL);
477 	report(piglit_check_gl_error(GL_INVALID_VALUE));
478 }
479 
480 /**
481  * Call glGetPerfMonitorCounterStringAMD() with an invalid counter ID.
482  *
483  * Verify that it produces INVALID_VALUE.
484  */
485 static void
test_counter_string_invalid_counter(unsigned group,unsigned invalid_counter)486 test_counter_string_invalid_counter(unsigned group, unsigned invalid_counter)
487 {
488 	glGetPerfMonitorCounterStringAMD(group, invalid_counter, 0, NULL, NULL);
489 	report(piglit_check_gl_error(GL_INVALID_VALUE));
490 }
491 
492 /**
493  * Call glGetPerfMonitorCounterStringAMD() with a NULL length pointer.
494  *
495  * Verify that it doesn't crash.
496  */
497 static void
test_counter_string_null_length(unsigned group,unsigned counter)498 test_counter_string_null_length(unsigned group, unsigned counter)
499 {
500 	glGetPerfMonitorCounterStringAMD(group, counter, 0, NULL, NULL);
501 	report(piglit_check_gl_error(GL_NO_ERROR));
502 }
503 
504 /**
505  * Call glGetPerfMonitorCounterStringAMD() with a single character buffer.
506  *
507  * Verify that length is correct and no buffer overflows occur.
508  */
509 static void
test_counter_string_single_character_buffer(unsigned group,unsigned counter)510 test_counter_string_single_character_buffer(unsigned group, unsigned counter)
511 {
512 	bool pass = true;
513 	char name[3] = "```";
514 	GLsizei length = 0xd0d0d0d0;
515 
516 	glGetPerfMonitorCounterStringAMD(group, counter, 1, &length, name);
517 	pass = piglit_check_gl_error(GL_NO_ERROR);
518 
519 	/* Verify buffer contents */
520 	pass = name[0] != '`' && pass;
521 	pass = name[1] == '`' && pass;
522 	pass = name[2] == '`' && pass;
523 
524 	/* length is the number of characters written excluding the null
525 	 * terminator.
526 	 */
527 	if (name[0] == '\0') {
528 		pass = length == 0 && pass;
529 	} else {
530 		/* AMD Catalyst 13.10 (Radeon 6870) does not write a null
531 		 * terminator.  Instead, it writes the first part of the name.
532 		 */
533 		pass = length == 1 && pass;
534 	}
535 
536 	report(pass);
537 }
538 
539 /**
540  * Call glGetPerfMonitorCounterStringAMD() with a small buffer.
541  *
542  * Verify that a name is returned, length is valid, and no overflows occur.
543  */
544 static void
test_counter_string_small_buffer(unsigned group,unsigned counter)545 test_counter_string_small_buffer(unsigned group, unsigned counter)
546 {
547 	bool pass = true;
548 	char name[3] = "```";
549 	GLsizei length = 0xd0d0d0d0;
550 	int i;
551 
552 	glGetPerfMonitorCounterStringAMD(group, counter, 3, &length, name);
553 
554 	pass = length <= 3 && pass;
555 
556 	/* Verify buffer contents: accept no null terminator. */
557 	for (i = 0; i < length; i++)
558 		pass = name[i] != '`' && pass;
559 
560 	if (length < 3) {
561 		pass = name[length] == '\0';
562 		for (i = length + 1; i < 3; i++)
563 			pass = name[i] == '`' && pass;
564 	}
565 
566 	report(pass);
567 }
568 
569 /**
570  * Call glGetPerfMonitorCounterStringAMD() with an appropriately sized buffer.
571  *
572  * Verify that a name is returned, length is valid, and no overflows occur.
573  */
574 static void
test_counter_string_normal_buffer(unsigned group,unsigned counter)575 test_counter_string_normal_buffer(unsigned group, unsigned counter)
576 {
577 	bool pass = true;
578 	char *name;
579 	GLsizei length = 0xd0d0d0d0;
580 	int i;
581 
582 	/* Get the length; bail if unwritten to avoid huge allocations. */
583 	glGetPerfMonitorCounterStringAMD(group, counter, 0, &length, NULL);
584 	pass = pass && piglit_check_gl_error(GL_NO_ERROR);
585 	if (length == 0xd0d0d0d0)
586 		report(false);
587 
588 	name = malloc(length + 1);
589 	assert(name != NULL);
590 
591 	/* Fill the buffer with a known character (` marks) */
592 	memset(name, '`', length + 1);
593 
594 	/* Get the name; everything will fit. */
595 	glGetPerfMonitorCounterStringAMD(group, counter, length + 1, NULL, name);
596 	pass = pass && piglit_check_gl_error(GL_NO_ERROR);
597 
598 	/* Indexes in the interval [0, length) must have been written, or
599 	 * else length is wrong.
600 	 */
601 	for (i = 0; i < length; i++)
602 		pass = name[i] != '`' && pass;
603 
604 	/* The last character must be the null terminator. */
605 	pass = name[length] == '\0' && pass;
606 
607 	report(pass);
608 }
609 
610 /******************************************************************************/
611 
612 /**
613  * Call glGetPerfMonitorCounterInfoAMD() with an invalid group ID.
614  *
615  * Verify that it produces INVALID_VALUE.
616  */
617 static void
test_counter_info_invalid_group(unsigned invalid_group)618 test_counter_info_invalid_group(unsigned invalid_group)
619 {
620 	GLenum type;
621 	glGetPerfMonitorCounterInfoAMD(invalid_group, 0, GL_COUNTER_TYPE_AMD,
622 				       &type);
623 	report(piglit_check_gl_error(GL_INVALID_VALUE));
624 }
625 
626 /**
627  * Call glGetPerfMonitorCounterInfoAMD() with an invalid counter ID.
628  *
629  * Verify that it produces INVALID_VALUE.
630  */
631 static void
test_counter_info_invalid_counter(unsigned group,unsigned invalid_counter)632 test_counter_info_invalid_counter(unsigned group, unsigned invalid_counter)
633 {
634 	GLenum type;
635 	glGetPerfMonitorCounterInfoAMD(group, invalid_counter,
636 				       GL_COUNTER_TYPE_AMD, &type);
637 	report(piglit_check_gl_error(GL_INVALID_VALUE));
638 }
639 
640 /**
641  * Call glGetPerfMonitorCounterInfoAMD() on every group/counter and verify that:
642  * - All counters must have a valid type.
643  * - Percentage counters must have a range of [0.0f, 100.0f]
644  * - Counter ranges should return a minimum strictly less than the maximum.
645  * - The counter range query doesn't return too much data.
646  */
647 static void
test_counter_info(unsigned * groups,int num_groups)648 test_counter_info(unsigned *groups, int num_groups)
649 {
650 	int i;
651 	int j;
652 
653 	for (i = 0; i < num_groups; i++) {
654 		unsigned *counters;
655 		int num_counters;
656 		get_counters(groups[i], &counters, &num_counters);
657 
658 		for (j = 0; j < num_counters; j++) {
659 			GLenum type = GL_NONE;
660 			uint64_t data[3];
661 			uint64_t min_u, max_u;
662 			float min_f, max_f;
663 			uint32_t unchanged;
664 			bool is_unsigned = false;
665 
666 			glGetPerfMonitorCounterInfoAMD(groups[i], counters[j],
667 						       GL_COUNTER_TYPE_AMD,
668 						       &type);
669 
670 			/* Get the range */
671 			memset(data, 0xff, sizeof(uint64_t) * 3);
672 			glGetPerfMonitorCounterInfoAMD(groups[i], counters[j],
673 						       GL_COUNTER_RANGE_AMD,
674 						       data);
675 
676 			/* Validate the type and use it to interpret the
677 			 * minimum/maximum information.
678 			 */
679 			switch (type) {
680 			case GL_UNSIGNED_INT:
681 				min_u = ((uint32_t *) data)[0];
682 				max_u = ((uint32_t *) data)[1];
683 				unchanged = ((uint32_t *) data)[2];
684 				is_unsigned = true;
685 				break;
686 			case GL_UNSIGNED_INT64_AMD:
687 				min_u = data[0];
688 				max_u = data[1];
689 				unchanged = ((uint32_t *) data)[4];
690 				is_unsigned = true;
691 				break;
692 			case GL_PERCENTAGE_AMD:
693 			case GL_FLOAT:
694 				min_f = ((float *) data)[0];
695 				max_f = ((float *) data)[1];
696 				unchanged = ((uint32_t *) data)[2];
697 				break;
698 			default:
699 				printf("Group %u/Counter %u has an invalid type: %x\n", groups[i], counters[j], type);
700 				report(false);
701 			}
702 
703 			/* Make sure it didn't write too much data. */
704 			if (unchanged != 0xffffffff) {
705 				printf("COUNTER_RANGE_AMD query for group %u/Counter %u wrote too much data to the buffer.\n", groups[i], counters[j]);
706 				report(false);
707 			}
708 
709 			/* "If type value returned is PERCENTAGE_AMD, then this
710 			 *  describes a float value that is in the range [0.0 ..
711 			 *  100.0]."  So we can check this.
712 			 */
713 			if (type == GL_PERCENTAGE_AMD) {
714 				if (min_f != 0.0f || max_f != 100.0f) {
715 					printf("Group %u/Counter %u's minimum (%f) and maximum (%f) must be 0.0f and 100.0f, respectively.\n", groups[i], counters[j], min_f, max_f);
716 					report(false);
717 				}
718 			} else if (is_unsigned) {
719 				/* The spec doesn't explicitly state it, but it
720 				 * makes sense for the minimum to be strictly
721 				 * less than the maximum.  Do a service to
722 				 * driver authors and validate that.
723 				 */
724 				if (min_u >= max_u) {
725 					printf("Group %u/Counter %u's minimum (%" PRIu64 ") is >= the maximum (%" PRIu64 ").\n", groups[i], counters[j], min_u, max_u);
726 					report(false);
727 				}
728 			} else if (type == GL_FLOAT) {
729 				if (min_f >= max_f) {
730 					printf("Group %u/Counter %u's minimum (%f) is >= the maximum (%f).\n", groups[i], counters[j], min_f, max_f);
731 					report(false);
732 				}
733 			}
734 		}
735 
736 		free(counters);
737 	}
738 	report(true);
739 }
740 
741 /******************************************************************************/
742 
743 
744 /**
745  * Call glBeginPerfMonitorAMD() on an invalid monitor ID.
746  * (Should be run before any Gen tests to ensure this ID is invalid.)
747  *
748  * XXX: This isn't actually specified, but it seems like it ought to be.
749  */
750 void
test_begin_invalid_monitor(void)751 test_begin_invalid_monitor(void)
752 {
753 	glBeginPerfMonitorAMD(777);
754 	report(piglit_check_gl_error(GL_INVALID_VALUE));
755 }
756 
757 /**
758  * Call glEndPerfMonitorAMD() on an invalid monitor ID.
759  * (Should be run before any Gen tests to ensure this ID is invalid.)
760  *
761  * XXX: This isn't actually specified, but it seems like it ought to be.
762  *
763  * AMD Catalyst 13.10 (Radeon 6870) instead produces INVALID_OPERATION,
764  * presumably because the (invalid) monitor hasn't been started.  (See
765  * test_end_without_begin.)  So we allow either here.
766  */
767 void
test_end_invalid_monitor(void)768 test_end_invalid_monitor(void)
769 {
770 	GLenum error;
771 	glEndPerfMonitorAMD(777);
772 	error = glGetError();
773 	report(error == GL_INVALID_VALUE || error == GL_INVALID_OPERATION);
774 }
775 
776 /**
777  * Call glGetPerfMonitorCounterDataAMD() with an invalid monitor ID.
778  *
779  * XXX: This isn't actually specified, but it seems like it ought to be.
780  */
781 static void
test_get_counter_data_invalid_monitor(void)782 test_get_counter_data_invalid_monitor(void)
783 {
784 	unsigned value;
785 	glGetPerfMonitorCounterDataAMD(777, GL_PERFMON_RESULT_AVAILABLE_AMD,
786 				       0, &value, NULL);
787 	report(piglit_check_gl_error(GL_INVALID_VALUE));
788 }
789 
790 /**
791  * Call glSelectPerfMonitorCountersAMD() with an invalid monitor ID.
792  *
793  * "If <monitor> is not a valid monitor created by GenPerfMonitorsAMD, then
794  *  INVALID_VALUE will be generated."
795  */
796 static void
test_select_counters_invalid_monitor(void)797 test_select_counters_invalid_monitor(void)
798 {
799 	unsigned junk;
800 	glSelectPerfMonitorCountersAMD(777, false, 0, 0, &junk);
801 	report(piglit_check_gl_error(GL_INVALID_VALUE));
802 }
803 
804 /**
805  * Call glDeletePerfMonitorsAMD() on an invalid monitor ID.
806  * (Should be run before any Gen tests to ensure this ID is invalid.)
807  *
808  * "If a monitor ID in the list <monitors> does not reference a previously
809  *  generated performance monitor, an INVALID_VALUE error is generated."
810  *
811  * AMD Catalyst 13.10 (Radeon 6870) fails this test, producing NO_ERROR.
812  */
813 static void
test_delete_monitor_invalid(void)814 test_delete_monitor_invalid(void)
815 {
816 	unsigned monitor = 777;
817 	glDeletePerfMonitorsAMD(1, &monitor);
818 	report(piglit_check_gl_error(GL_INVALID_VALUE));
819 }
820 
821 /**
822  * Mean tests for glGetPerfMonitorCounterDataAMD()'s data return mechanism.
823  *
824  * AMD Catalyst 13.10 (Radeon 6870) fails this test.  It does not set
825  * bytes_written, yet writes 0 for each of these queries.  It apparently
826  * interprets these fields as only relevant to the PERFMON_RESULT_AMD query.
827  */
828 static void
test_get_counter_data_byte_size(void)829 test_get_counter_data_byte_size(void)
830 {
831 	bool pass = true;
832 	unsigned monitor;
833 	unsigned value;
834 	GLsizei bytes_written;
835 
836 	glGenPerfMonitorsAMD(1, &monitor);
837 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
838 
839 	/* "It is an INVALID_OPERATION error far <data> to be NULL." */
840 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
841 				       0, NULL, NULL);
842 	pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
843 
844 	/* "The argument <dataSize> specifies the number of bytes available in
845 	 *  the <data> buffer for writing."
846 	 *
847 	 * It would be easy to accidentally treat this as 4-byte units, so
848 	 * be mean and try < sizeof(int) sizes.
849 	 */
850 
851 	/* dataSize = 0: Nothing should be written. */
852 	value = bytes_written = 0xd0d0d0d0;
853 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
854 				       0, &value, &bytes_written);
855 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
856 	pass = value == 0xd0d0d0d0 && pass;
857 	pass = bytes_written == 0 && pass;
858 
859 	/* dataSize = 1: Unclear.  Accept nothing or 1 byte written. */
860 	value = bytes_written = 0xd0d0d0d0;
861 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
862 				       1, &value, &bytes_written);
863 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
864 	pass = value == 0xd0d0d0d0 && pass;
865 	if (bytes_written == 1) {
866 		pass = value == 0xd0d0d000 && pass;
867 	} else if (bytes_written == 0) {
868 		pass = value == 0xd0d0d0d0 && pass;
869 	} else {
870 		pass = false;
871 	}
872 
873 	glDeletePerfMonitorsAMD(1, &monitor);
874 	report(pass);
875 }
876 
877 static void
test_gen_initial_state(void)878 test_gen_initial_state(void)
879 {
880 	bool pass = true;
881 	unsigned monitor;
882 	unsigned value;
883 
884 	glGenPerfMonitorsAMD(1, &monitor);
885 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
886 
887 	/* "The value of the PERFMON_RESULT_AVAILABLE_AMD, PERMON_RESULT_AMD,
888 	 *  and PERFMON_RESULT_SIZE queries will all initially be 0."
889 	 */
890 	value = 0xd0d0d0d0;
891 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
892 				       4, &value, NULL);
893 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
894 	pass = value == 0 && pass;
895 
896 	/* AMD Catalyst 13.10 (Radeon 6870) actually does write 0 for the
897 	 * PERFMON_RESULT query even though it isn't available.  This
898 	 * matches the spec, but is strange.
899 	 */
900 	value = 0xd0d0d0d0;
901 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AMD,
902 				       4, &value, NULL);
903 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
904 	pass = value == 0 && pass;
905 
906 	value = 0xd0d0d0d0;
907 	glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD,
908 				       4, &value, NULL);
909 	pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
910 	pass = value == 0 && pass;
911 
912 	glDeletePerfMonitorsAMD(1, &monitor);
913 	report(pass);
914 }
915 
916 /**
917  * "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is
918  *  called when a performance monitor is not currently started."
919  */
920 void
test_end_without_begin(void)921 test_end_without_begin(void)
922 {
923 	unsigned monitor;
924 	glGenPerfMonitorsAMD(1, &monitor);
925 	glEndPerfMonitorAMD(monitor);
926 	glDeletePerfMonitorsAMD(1, &monitor);
927 	report(piglit_check_gl_error(GL_INVALID_OPERATION));
928 }
929 
930 /**
931  * "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
932  *  called when a performance monitor is already active."
933  */
934 void
test_double_begin(void)935 test_double_begin(void)
936 {
937 	GLenum error;
938 	bool pass;
939 	unsigned monitor;
940 	glGenPerfMonitorsAMD(1, &monitor);
941 	glBeginPerfMonitorAMD(monitor);
942 
943 	error = glGetError();
944 	if (error != GL_NO_ERROR) {
945 		glDeletePerfMonitorsAMD(1, &monitor);
946 		/* Monitoring couldn't start for some reason; bail. */
947 		if (error == GL_INVALID_OPERATION)
948 			return;
949 		/* We weren't expecting this other error. */
950 		report(false);
951 	}
952 
953 	/* Double begin */
954 	glBeginPerfMonitorAMD(monitor);
955 	pass = piglit_check_gl_error(GL_INVALID_OPERATION);
956 
957 	glDeletePerfMonitorsAMD(1, &monitor);
958 	report(pass);
959 }
960 
961 /******************************************************************************/
962 
963 /**
964  * Call glSelectPerfMonitorCountersAMD() with an invalid group ID.
965  *
966  * "If <group> is not a valid group, the INVALID_VALUE error will be generated."
967  */
968 static void
test_select_counters_invalid_group(unsigned invalid_group)969 test_select_counters_invalid_group(unsigned invalid_group)
970 {
971 	unsigned monitor;
972 	unsigned junk;
973 	bool pass;
974 	glGenPerfMonitorsAMD(1, &monitor);
975 	glSelectPerfMonitorCountersAMD(monitor, false, invalid_group, 0, &junk);
976 	pass = piglit_check_gl_error(GL_INVALID_VALUE);
977 	glDeletePerfMonitorsAMD(1, &monitor);
978 	report(pass);
979 }
980 
981 
982 /**
983  * Call glSelectPerfMonitorCountersAMD() with numCounters < 0.
984  *
985  * "If <numCounters> is less than 0, an INVALID_VALUE error will be generated."
986  */
987 static void
test_select_counters_invalid_num_counters(unsigned group)988 test_select_counters_invalid_num_counters(unsigned group)
989 {
990 	unsigned monitor;
991 	unsigned junk;
992 	bool pass;
993 	glGenPerfMonitorsAMD(1, &monitor);
994 	glSelectPerfMonitorCountersAMD(monitor, false, group, -1, &junk);
995 	pass = piglit_check_gl_error(GL_INVALID_VALUE);
996 	glDeletePerfMonitorsAMD(1, &monitor);
997 	report(pass);
998 }
999 
1000 /******************************************************************************/
1001 
1002 enum piglit_result
piglit_display(void)1003 piglit_display(void)
1004 {
1005 	return PIGLIT_FAIL;
1006 }
1007 
1008 /**
1009  * The main test program.
1010  */
1011 void
piglit_init(int argc,char ** argv)1012 piglit_init(int argc, char **argv)
1013 {
1014 	unsigned *groups;
1015 	int num_groups;
1016 	unsigned *g0_counters;
1017 	int num_g0_counters;
1018 	unsigned invalid_group;
1019 	unsigned invalid_counter;
1020 
1021 	piglit_require_extension("GL_AMD_performance_monitor");
1022 
1023 	/* Basic glGetPerfMonitorGroupsAMD() tests */
1024 	test_number_of_groups_null_num_groups_pointer();
1025 	test_number_of_groups_null_groups_pointer();
1026 	test_number_of_groups_zero_size_array();
1027 	test_number_of_groups_partial_array();
1028 
1029 	get_groups(&groups, &num_groups);
1030 	invalid_group = find_invalid_group(groups, num_groups);
1031 
1032 	test_get_counters_invalid_group(invalid_group);
1033 	test_group_string_invalid_group(invalid_group);
1034 	test_counter_string_invalid_group(invalid_group);
1035 	test_counter_info_invalid_group(invalid_group);
1036 
1037 	test_begin_invalid_monitor();
1038 	test_end_invalid_monitor();
1039 	test_delete_monitor_invalid();
1040 	test_get_counter_data_invalid_monitor();
1041 	test_select_counters_invalid_monitor();
1042 	test_get_counter_data_byte_size();
1043 	test_gen_initial_state();
1044 	test_end_without_begin();
1045 	test_double_begin();
1046 
1047 	test_select_counters_invalid_group(invalid_group);
1048 
1049 	/* If there are no groups, the rest of the tests can't run.  Bail. */
1050 	if (num_groups == 0)
1051 		exit(0);
1052 
1053 	test_get_counters_null_pointers(groups[0]);
1054 	test_get_counters_null_pointer_non_zero_size(groups[0]);
1055 	test_get_counters_zero_size_array(groups[0]);
1056 	test_get_counters_partial_array(groups[0]);
1057 	test_group_string_null_length(groups[0]);
1058 	test_group_string_single_character_buffer(groups[0]);
1059 	test_group_string_small_buffer(groups[0]);
1060 	test_group_string_normal_buffer(groups[0]);
1061 
1062 	test_counter_info(groups, num_groups);
1063 
1064 	test_select_counters_invalid_num_counters(groups[0]);
1065 
1066 	get_counters(groups[0], &g0_counters, &num_g0_counters);
1067 	invalid_counter = find_invalid_counter(g0_counters, num_g0_counters);
1068 
1069 	test_counter_string_invalid_counter(groups[0], invalid_counter);
1070 	test_counter_info_invalid_counter(groups[0], invalid_counter);
1071 
1072 	/* If there are no counters, the rest of the tests can't run.  Bail. */
1073 	if (num_g0_counters == 0)
1074 		exit(0);
1075 
1076 	test_counter_string_null_length(groups[0], g0_counters[0]);
1077 	test_counter_string_single_character_buffer(groups[0], g0_counters[0]);
1078 	test_counter_string_small_buffer(groups[0], g0_counters[0]);
1079 	test_counter_string_normal_buffer(groups[0], g0_counters[0]);
1080 
1081 	exit(0);
1082 }
1083