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