[Piglit] [PATCH] Add tests for the GL_AMD_performance_monitor extension.
Kenneth Graunke
kenneth at whitecape.org
Thu Mar 28 01:01:34 PDT 2013
On 03/27/2013 12:12 AM, Ken Phillis Jr wrote:
> I read over the patch, and I noticed a few things.
>
> 1) Which platform did you test on? My guess is Linux.
Linux with the AMD Catalyst driver, and Linux with my branch of Mesa
that implements this.
> 2) Where are the dynamic entry points for this extension? These tests
> will fail on windows without this implemented.
Gah...I was wondering about that, but since it worked I presumed that
piglit-dispatch somehow already had support for this extension's entry
points. But you're right, it doesn't. It only worked due to libGL ABI
bugs. :(
I'll write a patch to add the new entry points to piglit-dispatch.
Thanks for catching that!
> Anyways, From here, I think the extension looks really good... Only
> bit would be to fix #2 listed above.
Excellent, thank you.
> On Wed, Mar 27, 2013 at 12:21 AM, Kenneth Graunke <kenneth at whitecape.org> wrote:
>> One of the challenging aspects of testing this extension is that it
>> defines an implementation-specific set of groups and counters. Many of
>> the tests here arbitrarily operate on the counters in the first group,
>> while a few sanity check all counters in all groups.
>>
>> All tests pass on AMD's Catalyst 12.06 driver on a Radeon 3650, except
>> for: test_number_of_groups_partial_array, test_delete_monitor_invalid,
>> and test_get_counter_data_byte_size. I believe the first two are
>> legitimate bugs in AMD's implementation, and the latter is a
>> disagreement about the associativity of text within a paragraph. Still,
>> these are minor details and I believe the tests are valid.
>>
>> Signed-off-by: Kenneth Graunke <kenneth at whitecape.org>
>> ---
>> tests/all.tests | 5 +
>> tests/spec/CMakeLists.txt | 1 +
>> .../spec/amd_performance_monitor/CMakeLists.gl.txt | 13 +
>> tests/spec/amd_performance_monitor/CMakeLists.txt | 1 +
>> tests/spec/amd_performance_monitor/api.c | 1080 ++++++++++++++++++++
>> tests/spec/amd_performance_monitor/measure.c | 387 +++++++
>> 6 files changed, 1487 insertions(+)
>> create mode 100644 tests/spec/amd_performance_monitor/CMakeLists.gl.txt
>> create mode 100644 tests/spec/amd_performance_monitor/CMakeLists.txt
>> create mode 100644 tests/spec/amd_performance_monitor/api.c
>> create mode 100644 tests/spec/amd_performance_monitor/measure.c
>>
>> diff --git a/tests/all.tests b/tests/all.tests
>> index 911cd61..f8a40e2 100644
>> --- a/tests/all.tests
>> +++ b/tests/all.tests
>> @@ -863,6 +863,11 @@ add_shader_test_dir(spec['glsl-es-3.00'],
>> recursive=True)
>> add_concurrent_test(spec['glsl-es-3.00']['execution'], 'varying-struct-centroid_gles3')
>>
>> +# AMD_performance_monitor
>> +profile.test_list['AMD_performance_monitor/api'] =
>> + PlainExecTest('amd_performance_monitor_api -auto')
>> +profile.test_list['AMD_performance_monitor/measure'] =
>> + PlainExecTest('amd_performance_monitor_measure -auto')
>>
>> # Group AMD_conservative_depth
>> spec['AMD_conservative_depth'] = Group()
>> diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
>> index 18b1d37..a1492cc 100644
>> --- a/tests/spec/CMakeLists.txt
>> +++ b/tests/spec/CMakeLists.txt
>> @@ -1,3 +1,4 @@
>> +add_subdirectory (amd_performance_monitor)
>> add_subdirectory (arb_color_buffer_float)
>> add_subdirectory (arb_debug_output)
>> add_subdirectory (arb_draw_instanced)
>> diff --git a/tests/spec/amd_performance_monitor/CMakeLists.gl.txt b/tests/spec/amd_performance_monitor/CMakeLists.gl.txt
>> new file mode 100644
>> index 0000000..5ddc12d
>> --- /dev/null
>> +++ b/tests/spec/amd_performance_monitor/CMakeLists.gl.txt
>> @@ -0,0 +1,13 @@
>> +include_directories(
>> + ${GLEXT_INCLUDE_DIR}
>> + ${OPENGL_INCLUDE_PATH}
>> +)
>> +
>> +link_libraries (
>> + piglitutil_${piglit_target_api}
>> + ${OPENGL_gl_LIBRARY}
>> + ${OPENGL_glu_LIBRARY}
>> +)
>> +
>> +piglit_add_executable (amd_performance_monitor_api api.c)
>> +piglit_add_executable (amd_performance_monitor_measure measure.c)
>> diff --git a/tests/spec/amd_performance_monitor/CMakeLists.txt b/tests/spec/amd_performance_monitor/CMakeLists.txt
>> new file mode 100644
>> index 0000000..144a306
>> --- /dev/null
>> +++ b/tests/spec/amd_performance_monitor/CMakeLists.txt
>> @@ -0,0 +1 @@
>> +piglit_include_target_api()
>> diff --git a/tests/spec/amd_performance_monitor/api.c b/tests/spec/amd_performance_monitor/api.c
>> new file mode 100644
>> index 0000000..81a2641
>> --- /dev/null
>> +++ b/tests/spec/amd_performance_monitor/api.c
>> @@ -0,0 +1,1080 @@
>> +/*
>> + * Copyright © 2013 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + */
>> +
>> +/**
>> + * \file api.c
>> + *
>> + * Basic AMD_performance_monitor infrastructure tests. These test the
>> + * mechanism to retrieve counter and group information, string processing,
>> + * and various error conditions. They do not actually activate monitoring.
>> + */
>> +
>> +#define __STDC_FORMAT_MACROS
>> +#include <inttypes.h>
>> +#include "piglit-util-gl-common.h"
>> +
>> +PIGLIT_GL_TEST_CONFIG_BEGIN
>> +
>> + config.supports_gl_compat_version = 10;
>> + config.window_visual = PIGLIT_GL_VISUAL_RGB;
>> +
>> +PIGLIT_GL_TEST_CONFIG_END
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Get a list of group IDs.
>> + */
>> +static void
>> +get_groups(unsigned **groups, int *num_groups)
>> +{
>> + glGetPerfMonitorGroupsAMD(num_groups, 0, NULL);
>> + *groups = calloc(*num_groups, sizeof(unsigned));
>> + glGetPerfMonitorGroupsAMD(NULL, *num_groups, *groups);
>> +}
>> +
>> +/**
>> + * Get a list of counter IDs in a given group.
>> + */
>> +static void
>> +get_counters(unsigned group, unsigned **counters, int *num_counters)
>> +{
>> + glGetPerfMonitorCountersAMD(group, num_counters, NULL, 0, NULL);
>> + *counters = calloc(*num_counters, sizeof(unsigned));
>> + glGetPerfMonitorCountersAMD(group, NULL, NULL, *num_counters, *counters);
>> +}
>> +
>> +/**
>> + * Return true if x is in xs.
>> + */
>> +static bool
>> +in_list(int x, unsigned *xs, int elts)
>> +{
>> + int i;
>> + for (i = 0; i < elts; i++) {
>> + if (x == xs[i])
>> + return true;
>> + }
>> + return false;
>> +}
>> +
>> +/**
>> + * Find an invalid group ID.
>> + */
>> +static unsigned
>> +find_invalid_group(unsigned *groups, int num_groups)
>> +{
>> + unsigned invalid_group = ~0;
>> +
>> + /* Most implementations probably use small consecutive integers, so
>> + * start at ~0 and work backwards. Hopefully we shouldn't loop.
>> + */
>> + while (in_list(invalid_group, groups, num_groups))
>> + --invalid_group;
>> +
>> + return invalid_group;
>> +}
>> +
>> +/**
>> + * Find an invalid counter ID.
>> + */
>> +static unsigned
>> +find_invalid_counter(unsigned *counters, int num_counters)
>> +{
>> + unsigned invalid_counter = ~0;
>> +
>> + /* Most implementations probably use small consecutive integers, so
>> + * start at ~0 and work backwards. Hopefully we shouldn't loop.
>> + */
>> + while (in_list(invalid_counter, counters, num_counters))
>> + --invalid_counter;
>> +
>> + return invalid_counter;
>> +}
>> +
>> +#define report(pass) \
>> + piglit_report_subtest_result((pass) ? PIGLIT_PASS : PIGLIT_FAIL, __func__); \
>> + return
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupsAMD() with a NULL numGroups pointer.
>> + *
>> + * Verify that it doesn't attempt to write the number of groups and crash.
>> + */
>> +static void
>> +test_number_of_groups_null_num_groups_pointer(void)
>> +{
>> + glGetPerfMonitorGroupsAMD(NULL, 0, NULL);
>> + report(piglit_check_gl_error(GL_NO_ERROR));
>> +}
>> +
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupsAMD() with NULL for groups but non-zero groupSize.
>> + *
>> + * Verify that it returns the number of groups but doesn't try to write any
>> + * group IDs and crash.
>> + */
>> +static void
>> +test_number_of_groups_null_groups_pointer(void)
>> +{
>> + bool pass = true;
>> + int num_groups = -1;
>> +
>> + glGetPerfMonitorGroupsAMD(&num_groups, 777, NULL);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = num_groups >= 0 && pass;
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupsAMD() with zero for groupSize.
>> + *
>> + * Verify that it doesn't write any group IDs.
>> + */
>> +static void
>> +test_number_of_groups_zero_size_array(void)
>> +{
>> + bool pass = true;
>> + unsigned groups[2] = {0xd0d0d0d0, 0xd1d1d1d1};
>> + int num_groups = -1;
>> +
>> + glGetPerfMonitorGroupsAMD(&num_groups, 0, groups);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* num_groups must have changed */
>> + pass = num_groups >= 0 && pass;
>> +
>> + /* The groups array should not have changed. */
>> + pass = groups[0] == 0xd0d0d0d0 && pass;
>> + pass = groups[1] == 0xd1d1d1d1 && pass;
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupsAMD() with a groups array bigger than groupSize.
>> + *
>> + * Verify that it fills the correct number of array slots with group IDs.
>> + */
>> +static void
>> +test_number_of_groups_partial_array(void)
>> +{
>> + bool pass = true;
>> + unsigned groups[] = {0xdddddddd, 0xdddddddd, 0xdddddddd, 0xdddddddd};
>> +
>> + /* Artificially low array size */
>> + const int groups_array_size = 2;
>> + int num_groups = -1;
>> + int i;
>> +
>> + /* This should return the number of groups. It should not attempt to
>> + * write any groups since the pointer is NULL.
>> + */
>> + glGetPerfMonitorGroupsAMD(&num_groups, groups_array_size, groups);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* num_groups must have changed */
>> + pass = num_groups >= 0 && pass;
>> +
>> + /* The first few elements should have changed. */
>> + for (i = 0; i < MIN2(num_groups, groups_array_size); i++) {
>> + pass = groups[i] != 0xdddddddd && pass;
>> + }
>> +
>> + /* Catalyst 12.6 on a Radeon 3650 appears to have a bug where this
>> + * returns 3 elements instead of 2. According to the spec,
>> + * "The number of entries that will be returned in <groups> is
>> + * determined by <groupSize>."
>> + *
>> + * Technically, it does not say that N elements will be returned if
>> + * groupSize is N, but that's the only reasonable assumption.
>> + */
>> +
>> + /* The rest should remain untouched. */
>> + for (; i < ARRAY_SIZE(groups); i++) {
>> + pass = groups[i] == 0xdddddddd && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glGetPerfMonitorCountersAMD() with an invalid group ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_get_counters_invalid_group(unsigned invalid_group)
>> +{
>> + glGetPerfMonitorCountersAMD(invalid_group, NULL, NULL, 0, NULL);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCountersAMD() with a bunch of NULL pointers.
>> + *
>> + * Verify that it doesn't crash attempting to write numCounters,
>> + * maxActiveCounters, or the counters list.
>> + */
>> +static void
>> +test_get_counters_null_pointers(unsigned valid_group)
>> +{
>> + glGetPerfMonitorCountersAMD(valid_group, NULL, NULL, 0, NULL);
>> + report(piglit_check_gl_error(GL_NO_ERROR));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCountersAMD() with NULL for the array but non-zero size.
>> + *
>> + * Verify that it returns the number of groups but doesn't try to write any
>> + * group IDs and crash.
>> + */
>> +static void
>> +test_get_counters_null_pointer_non_zero_size(unsigned valid_group)
>> +{
>> + glGetPerfMonitorCountersAMD(valid_group, NULL, NULL, 777, NULL);
>> + report(piglit_check_gl_error(GL_NO_ERROR));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCountersAMD() with zero for countersSize.
>> + *
>> + * Verify that it doesn't write any IDs, but does return other data.
>> + */
>> +static void
>> +test_get_counters_zero_size_array(unsigned valid_group)
>> +{
>> + bool pass = true;
>> + unsigned counters[2] = {0xd0d0d0d0, 0xd1d1d1d1};
>> + int num_counters = -1;
>> + int max_active_counters = -1;
>> +
>> + glGetPerfMonitorCountersAMD(valid_group, &num_counters,
>> + &max_active_counters,
>> + 0, counters);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* Expect a positive number of counters. */
>> + pass = num_counters >= 0 && pass;
>> +
>> + /* Expect a positive maximum active counters. */
>> + pass = max_active_counters >= 0 && pass;
>> +
>> + /* The counters array should not have changed. */
>> + pass = counters[0] == 0xd0d0d0d0 && pass;
>> + pass = counters[1] == 0xd1d1d1d1 && pass;
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupsAMD() with a groups array bigger than groupSize.
>> + *
>> + * Verify that it fills the correct number of array slots with group IDs.
>> + */
>> +static void
>> +test_get_counters_partial_array(unsigned valid_group)
>> +{
>> + bool pass = true;
>> + unsigned counters[] = {0xdddddddd, 0xdddddddd, 0xdddddddd, 0xdddddddd};
>> +
>> + /* Artificially low array size */
>> + const int counters_array_size = 2;
>> + int num_counters = -1;
>> + int i;
>> +
>> + /* This should return the number of groups. It should not attempt to
>> + * write any groups since the pointer is NULL.
>> + */
>> + glGetPerfMonitorCountersAMD(valid_group, &num_counters, NULL,
>> + counters_array_size, counters);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* num_counters must have changed */
>> + pass = num_counters >= 0 && pass;
>> +
>> + /* The first few elements should have changed. */
>> + for (i = 0; i < MIN2(num_counters, counters_array_size); i++) {
>> + pass = counters[i] != 0xdddddddd && pass;
>> + }
>> +
>> + /* The rest should remain untouched. */
>> + for (; i < ARRAY_SIZE(counters); i++) {
>> + pass = counters[i] == 0xdddddddd && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupStringAMD() with an invalid group ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_group_string_invalid_group(unsigned invalid_group)
>> +{
>> + glGetPerfMonitorGroupStringAMD(invalid_group, 0, NULL, NULL);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupStringAMD() with a NULL length pointer.
>> + *
>> + * Verify that it doesn't crash.
>> + */
>> +static void
>> +test_group_string_null_length(unsigned valid_group)
>> +{
>> + glGetPerfMonitorGroupStringAMD(valid_group, 0, NULL, NULL);
>> + report(piglit_check_gl_error(GL_NO_ERROR));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupStringAMD() with a single character buffer.
>> + *
>> + * Verify that length is correct and no buffer overflows occur.
>> + */
>> +static void
>> +test_group_string_single_character_buffer(unsigned valid_group)
>> +{
>> + bool pass = true;
>> + char name[3] = "```";
>> + GLsizei length = 0xd0d0d0d0;
>> +
>> + glGetPerfMonitorGroupStringAMD(valid_group, 1, &length, name);
>> + pass = piglit_check_gl_error(GL_NO_ERROR);
>> +
>> + /* Verify buffer contents: only the first character should change. */
>> + pass = name[0] != '`' && pass;
>> + pass = name[1] == '`' && pass;
>> + pass = name[2] == '`' && pass;
>> +
>> + /* length is the number of characters written excluding the null
>> + * terminator.
>> + */
>> + if (name[0] == '\0') {
>> + pass = length == 0 && pass;
>> + } else {
>> + /* AMD Catalyst 12.06 (Radeon 3650) does not write a null
>> + * terminator. Instead, it writes the first part of the name.
>> + */
>> + pass = length == 1 && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupStringAMD() with a small buffer.
>> + *
>> + * Verify that a name is returned, length is valid, and no overflows occur.
>> + */
>> +static void
>> +test_group_string_small_buffer(unsigned valid_group)
>> +{
>> + bool pass = true;
>> + char name[3] = "```";
>> + GLsizei length = 0xd0d0d0d0;
>> + int i;
>> +
>> + glGetPerfMonitorGroupStringAMD(valid_group, 3, &length, name);
>> +
>> + pass = length <= 3 && pass;
>> +
>> + /* Verify buffer contents: accept no null terminator. */
>> + for (i = 0; i < length; i++)
>> + pass = name[i] != '`' && pass;
>> +
>> + if (length < 3) {
>> + pass = name[length] == '\0';
>> + for (i = length + 1; i < 3; i++)
>> + pass = name[i] == '`' && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorGroupStringAMD() with an appropriately sized buffer.
>> + *
>> + * Verify that a name is returned, length is valid, and no overflows occur.
>> + */
>> +static void
>> +test_group_string_normal_buffer(unsigned valid_group)
>> +{
>> + bool pass = true;
>> + char *name;
>> + GLsizei length = 0xd0d0d0d0;
>> + int i;
>> +
>> + /* Get the length; bail if unwritten to avoid huge allocations. */
>> + glGetPerfMonitorGroupStringAMD(valid_group, 0, &length, NULL);
>> + pass = pass && piglit_check_gl_error(GL_NO_ERROR);
>> + if (length == 0xd0d0d0d0)
>> + report(false);
>> +
>> + name = malloc(length + 1);
>> + assert(name != NULL);
>> +
>> + /* Fill the buffer with a known character (` marks) */
>> + memset(name, '`', length + 1);
>> +
>> + /* Get the name; everything will fit. */
>> + glGetPerfMonitorGroupStringAMD(valid_group, length + 1, NULL, name);
>> + pass = pass && piglit_check_gl_error(GL_NO_ERROR);
>> +
>> + /* Indexes in the interval [0, length) must have been written, or
>> + * else length is wrong.
>> + */
>> + for (i = 0; i < length; i++)
>> + pass = name[i] != '`' && pass;
>> +
>> + /* The last character must be the null terminator. */
>> + pass = name[length] == '\0' && pass;
>> +
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with an invalid group ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_counter_string_invalid_group(unsigned invalid_group)
>> +{
>> + glGetPerfMonitorCounterStringAMD(invalid_group, 0, 0, NULL, NULL);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with an invalid counter ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_counter_string_invalid_counter(unsigned group, unsigned invalid_counter)
>> +{
>> + glGetPerfMonitorCounterStringAMD(group, invalid_counter, 0, NULL, NULL);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with a NULL length pointer.
>> + *
>> + * Verify that it doesn't crash.
>> + */
>> +static void
>> +test_counter_string_null_length(unsigned group, unsigned counter)
>> +{
>> + glGetPerfMonitorCounterStringAMD(group, counter, 0, NULL, NULL);
>> + report(piglit_check_gl_error(GL_NO_ERROR));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with a single character buffer.
>> + *
>> + * Verify that length is correct and no buffer overflows occur.
>> + */
>> +static void
>> +test_counter_string_single_character_buffer(unsigned group, unsigned counter)
>> +{
>> + bool pass = true;
>> + char name[3] = "```";
>> + GLsizei length = 0xd0d0d0d0;
>> +
>> + glGetPerfMonitorCounterStringAMD(group, counter, 1, &length, name);
>> + pass = piglit_check_gl_error(GL_NO_ERROR);
>> +
>> + /* Verify buffer contents */
>> + pass = name[0] != '`' && pass;
>> + pass = name[1] == '`' && pass;
>> + pass = name[2] == '`' && pass;
>> +
>> + /* length is the number of characters written excluding the null
>> + * terminator.
>> + */
>> + if (name[0] == '\0') {
>> + pass = length == 0 && pass;
>> + } else {
>> + /* AMD Catalyst 12.06 (Radeon 3650) does not write a null
>> + * terminator. Instead, it writes the first part of the name.
>> + */
>> + pass = length == 1 && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with a small buffer.
>> + *
>> + * Verify that a name is returned, length is valid, and no overflows occur.
>> + */
>> +static void
>> +test_counter_string_small_buffer(unsigned group, unsigned counter)
>> +{
>> + bool pass = true;
>> + char name[3] = "```";
>> + GLsizei length = 0xd0d0d0d0;
>> + int i;
>> +
>> + glGetPerfMonitorCounterStringAMD(group, counter, 3, &length, name);
>> +
>> + pass = length <= 3 && pass;
>> +
>> + /* Verify buffer contents: accept no null terminator. */
>> + for (i = 0; i < length; i++)
>> + pass = name[i] != '`' && pass;
>> +
>> + if (length < 3) {
>> + pass = name[length] == '\0';
>> + for (i = length + 1; i < 3; i++)
>> + pass = name[i] == '`' && pass;
>> + }
>> +
>> + report(pass);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterStringAMD() with an appropriately sized buffer.
>> + *
>> + * Verify that a name is returned, length is valid, and no overflows occur.
>> + */
>> +static void
>> +test_counter_string_normal_buffer(unsigned group, unsigned counter)
>> +{
>> + bool pass = true;
>> + char *name;
>> + GLsizei length = 0xd0d0d0d0;
>> + int i;
>> +
>> + /* Get the length; bail if unwritten to avoid huge allocations. */
>> + glGetPerfMonitorCounterStringAMD(group, counter, 0, &length, NULL);
>> + pass = pass && piglit_check_gl_error(GL_NO_ERROR);
>> + if (length == 0xd0d0d0d0)
>> + report(false);
>> +
>> + name = malloc(length + 1);
>> + assert(name != NULL);
>> +
>> + /* Fill the buffer with a known character (` marks) */
>> + memset(name, '`', length + 1);
>> +
>> + /* Get the name; everything will fit. */
>> + glGetPerfMonitorCounterStringAMD(group, counter, length + 1, NULL, name);
>> + pass = pass && piglit_check_gl_error(GL_NO_ERROR);
>> +
>> + /* Indexes in the interval [0, length) must have been written, or
>> + * else length is wrong.
>> + */
>> + for (i = 0; i < length; i++)
>> + pass = name[i] != '`' && pass;
>> +
>> + /* The last character must be the null terminator. */
>> + pass = name[length] == '\0' && pass;
>> +
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterInfoAMD() with an invalid group ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_counter_info_invalid_group(unsigned invalid_group)
>> +{
>> + GLenum type;
>> + glGetPerfMonitorCounterInfoAMD(invalid_group, 0, GL_COUNTER_TYPE_AMD,
>> + &type);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterInfoAMD() with an invalid counter ID.
>> + *
>> + * Verify that it produces INVALID_VALUE.
>> + */
>> +static void
>> +test_counter_info_invalid_counter(unsigned group, unsigned invalid_counter)
>> +{
>> + GLenum type;
>> + glGetPerfMonitorCounterInfoAMD(group, invalid_counter,
>> + GL_COUNTER_TYPE_AMD, &type);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterInfoAMD() on every group/counter and verify that:
>> + * - All counters must have a valid type.
>> + * - Percentage counters must have a range of [0.0f, 100.0f]
>> + * - Counter ranges should return a minimum strictly less than the maximum.
>> + * - The counter range query doesn't return too much data.
>> + */
>> +static void
>> +test_counter_info(unsigned *groups, int num_groups)
>> +{
>> + int i;
>> + int j;
>> +
>> + for (i = 0; i < num_groups; i++) {
>> + unsigned *counters;
>> + int num_counters;
>> + get_counters(groups[i], &counters, &num_counters);
>> +
>> + for (j = 0; j < num_counters; j++) {
>> + GLenum type = GL_NONE;
>> + uint64_t data[3];
>> + uint64_t min_u, max_u;
>> + float min_f, max_f;
>> + uint32_t unchanged;
>> + bool is_unsigned = false;
>> +
>> + glGetPerfMonitorCounterInfoAMD(groups[i], counters[j],
>> + GL_COUNTER_TYPE_AMD,
>> + &type);
>> +
>> + /* Get the range */
>> + memset(data, 0xff, sizeof(uint64_t) * 3);
>> + glGetPerfMonitorCounterInfoAMD(groups[i], counters[j],
>> + GL_COUNTER_RANGE_AMD,
>> + data);
>> +
>> + /* Validate the type and use it to interpret the
>> + * minimum/maximum information.
>> + */
>> + switch (type) {
>> + case GL_UNSIGNED_INT:
>> + min_u = ((uint32_t *) data)[0];
>> + max_u = ((uint32_t *) data)[1];
>> + unchanged = ((uint32_t *) data)[2];
>> + is_unsigned = true;
>> + break;
>> + case GL_UNSIGNED_INT64_AMD:
>> + min_u = data[0];
>> + max_u = data[1];
>> + unchanged = ((uint32_t *) data)[4];
>> + is_unsigned = true;
>> + break;
>> + case GL_PERCENTAGE_AMD:
>> + case GL_FLOAT:
>> + min_f = ((float *) data)[0];
>> + max_f = ((float *) data)[1];
>> + unchanged = ((uint32_t *) data)[2];
>> + break;
>> + default:
>> + printf("Group %u/Counter %u has an invalid type: %x\n", groups[i], counters[j], type);
>> + report(false);
>> + }
>> +
>> + /* Make sure it didn't write too much data. */
>> + if (unchanged != 0xffffffff) {
>> + printf("COUNTER_RANGE_AMD query for group %u/Counter %u wrote too much data to the buffer.\n", groups[i], counters[j]);
>> + report(false);
>> + }
>> +
>> + /* "If type value returned is PERCENTAGE_AMD, then this
>> + * describes a float value that is in the range [0.0 ..
>> + * 100.0]." So we can check this.
>> + */
>> + if (type == GL_PERCENTAGE_AMD) {
>> + if (min_f != 0.0f || max_f != 100.0f) {
>> + 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);
>> + report(false);
>> + }
>> + } else if (is_unsigned) {
>> + /* The spec doesn't explicitly state it, but it
>> + * makes sense for the minimum to be strictly
>> + * less than the maximum. Do a service to
>> + * driver authors and validate that.
>> + */
>> + if (min_u >= max_u) {
>> + printf("Group %u/Counter %u's minimum (%" PRIu64 ") is >= the maximum (%" PRIu64 ").\n", groups[i], counters[j], min_u, max_u);
>> + report(false);
>> + }
>> + } else if (type == GL_FLOAT) {
>> + if (min_f >= max_f) {
>> + printf("Group %u/Counter %u's minimum (%f) is >= the maximum (%f).\n", groups[i], counters[j], min_f, max_f);
>> + report(false);
>> + }
>> + }
>> + }
>> +
>> + free(counters);
>> + }
>> + report(true);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +
>> +/**
>> + * Call glBeginPerfMonitorAMD() on an invalid monitor ID.
>> + * (Should be run before any Gen tests to ensure this ID is invalid.)
>> + *
>> + * XXX: This isn't actually specified, but it seems like it ought to be.
>> + */
>> +void
>> +test_begin_invalid_monitor(void)
>> +{
>> + glBeginPerfMonitorAMD(777);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glEndPerfMonitorAMD() on an invalid monitor ID.
>> + * (Should be run before any Gen tests to ensure this ID is invalid.)
>> + *
>> + * XXX: This isn't actually specified, but it seems like it ought to be.
>> + *
>> + * AMD Catalyst 12.6 (Radeon 3650) instead produces INVALID_OPERATION,
>> + * presumably because the (invalid) monitor hasn't been started. (See
>> + * test_end_without_begin.) So we allow either here.
>> + */
>> +void
>> +test_end_invalid_monitor(void)
>> +{
>> + GLenum error;
>> + glEndPerfMonitorAMD(777);
>> + error = glGetError();
>> + report(error == GL_INVALID_VALUE || error == GL_INVALID_OPERATION);
>> +}
>> +
>> +/**
>> + * Call glGetPerfMonitorCounterDataAMD() with an invalid monitor ID.
>> + *
>> + * XXX: This isn't actually specified, but it seems like it ought to be.
>> + */
>> +static void
>> +test_get_counter_data_invalid_monitor(void)
>> +{
>> + unsigned value;
>> + glGetPerfMonitorCounterDataAMD(777, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + 0, &value, NULL);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glSelectPerfMonitorCountersAMD() with an invalid monitor ID.
>> + *
>> + * "If <monitor> is not a valid monitor created by GenPerfMonitorsAMD, then
>> + * INVALID_VALUE will be generated."
>> + */
>> +static void
>> +test_select_counters_invalid_monitor(void)
>> +{
>> + unsigned junk;
>> + glSelectPerfMonitorCountersAMD(777, false, 0, 0, &junk);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Call glDeletePerfMonitorsAMD() on an invalid monitor ID.
>> + * (Should be run before any Gen tests to ensure this ID is invalid.)
>> + *
>> + * "If a monitor ID in the list <monitors> does not reference a previously
>> + * generated performance monitor, an INVALID_VALUE error is generated."
>> + *
>> + * AMD Catalyst 12.6 (Radeon 3650) fails this test, producing NO_ERROR.
>> + */
>> +static void
>> +test_delete_monitor_invalid(void)
>> +{
>> + unsigned monitor = 777;
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(piglit_check_gl_error(GL_INVALID_VALUE));
>> +}
>> +
>> +/**
>> + * Mean tests for glGetPerfMonitorCounterDataAMD()'s data return mechanism.
>> + *
>> + * AMD Catalyst 12.6 (Radeon 3650) fails this test. It does not set
>> + * bytes_written, yet writes 0 for each of these queries. It apparently
>> + * interprets these fields as only relevant to the PERFMON_RESULT_AMD query.
>> + */
>> +static void
>> +test_get_counter_data_byte_size(void)
>> +{
>> + bool pass = true;
>> + unsigned monitor;
>> + unsigned value;
>> + GLsizei bytes_written;
>> +
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* "It is an INVALID_OPERATION error far <data> to be NULL." */
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + 0, NULL, NULL);
>> + pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
>> +
>> + /* "The argument <dataSize> specifies the number of bytes available in
>> + * the <data> buffer for writing."
>> + *
>> + * It would be easy to accidentally treat this as 4-byte units, so
>> + * be mean and try < sizeof(int) sizes.
>> + */
>> +
>> + /* dataSize = 0: Nothing should be written. */
>> + value = bytes_written = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + 0, &value, &bytes_written);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = value == 0xd0d0d0d0 && pass;
>> + pass = bytes_written == 0 && pass;
>> +
>> + /* dataSize = 1: Unclear. Accept nothing or 1 byte written. */
>> + value = bytes_written = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + 1, &value, &bytes_written);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = value == 0xd0d0d0d0 && pass;
>> + if (bytes_written == 1) {
>> + pass = value == 0xd0d0d000 && pass;
>> + } else if (bytes_written == 0) {
>> + pass = value == 0xd0d0d0d0 && pass;
>> + } else {
>> + pass = false;
>> + }
>> +
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(pass);
>> +}
>> +
>> +static void
>> +test_gen_initial_state(void)
>> +{
>> + bool pass = true;
>> + unsigned monitor;
>> + unsigned value;
>> +
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> +
>> + /* "The value of the PERFMON_RESULT_AVAILABLE_AMD, PERMON_RESULT_AMD,
>> + * and PERFMON_RESULT_SIZE queries will all initially be 0."
>> + */
>> + value = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + 4, &value, NULL);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = value == 0 && pass;
>> +
>> + /* AMD Catalyst 12.6 (Radeon 3650) actually does write 0 for the
>> + * PERFMON_RESULT query even though it isn't available. This
>> + * matches the spec, but is strange.
>> + */
>> + value = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AMD,
>> + 4, &value, NULL);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = value == 0 && pass;
>> +
>> + value = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD,
>> + 4, &value, NULL);
>> + pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
>> + pass = value == 0 && pass;
>> +
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(pass);
>> +}
>> +
>> +/**
>> + * "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is
>> + * called when a performance monitor is not currently started."
>> + */
>> +void
>> +test_end_without_begin(void)
>> +{
>> + unsigned monitor;
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + glEndPerfMonitorAMD(monitor);
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(piglit_check_gl_error(GL_INVALID_OPERATION));
>> +}
>> +
>> +/**
>> + * "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
>> + * called when a performance monitor is already active."
>> + */
>> +void
>> +test_double_begin(void)
>> +{
>> + GLenum error;
>> + bool pass;
>> + unsigned monitor;
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + glBeginPerfMonitorAMD(monitor);
>> +
>> + error = glGetError();
>> + if (error != GL_NO_ERROR) {
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + /* Monitoring couldn't start for some reason; bail. */
>> + if (error == GL_INVALID_OPERATION)
>> + return;
>> + /* We weren't expecting this other error. */
>> + report(false);
>> + }
>> +
>> + /* Double begin */
>> + glBeginPerfMonitorAMD(monitor);
>> + pass = piglit_check_gl_error(GL_INVALID_OPERATION);
>> +
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Call glSelectPerfMonitorCountersAMD() with an invalid group ID.
>> + *
>> + * "If <group> is not a valid group, the INVALID_VALUE error will be generated."
>> + */
>> +static void
>> +test_select_counters_invalid_group(unsigned invalid_group)
>> +{
>> + unsigned monitor;
>> + unsigned junk;
>> + bool pass;
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + glSelectPerfMonitorCountersAMD(monitor, false, invalid_group, 0, &junk);
>> + pass = piglit_check_gl_error(GL_INVALID_VALUE);
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(pass);
>> +}
>> +
>> +
>> +/**
>> + * Call glSelectPerfMonitorCountersAMD() with numCounters < 0.
>> + *
>> + * "If <numCounters> is less than 0, an INVALID_VALUE error will be generated."
>> + */
>> +static void
>> +test_select_counters_invalid_num_counters(unsigned group)
>> +{
>> + unsigned monitor;
>> + unsigned junk;
>> + bool pass;
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + glSelectPerfMonitorCountersAMD(monitor, false, group, -1, &junk);
>> + pass = piglit_check_gl_error(GL_INVALID_VALUE);
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + report(pass);
>> +}
>> +
>> +/******************************************************************************/
>> +
>> +enum piglit_result
>> +piglit_display(void)
>> +{
>> + return PIGLIT_FAIL;
>> +}
>> +
>> +/**
>> + * The main test program.
>> + */
>> +void
>> +piglit_init(int argc, char **argv)
>> +{
>> + unsigned *groups;
>> + int num_groups;
>> + unsigned *g0_counters;
>> + int num_g0_counters;
>> + unsigned invalid_group;
>> + unsigned invalid_counter;
>> +
>> + piglit_require_extension("GL_AMD_performance_monitor");
>> +
>> + /* Basic glGetPerfMonitorGroupsAMD() tests */
>> + test_number_of_groups_null_num_groups_pointer();
>> + test_number_of_groups_null_groups_pointer();
>> + test_number_of_groups_zero_size_array();
>> + test_number_of_groups_partial_array();
>> +
>> + get_groups(&groups, &num_groups);
>> + invalid_group = find_invalid_group(groups, num_groups);
>> +
>> + test_get_counters_invalid_group(invalid_group);
>> + test_group_string_invalid_group(invalid_group);
>> + test_counter_string_invalid_group(invalid_group);
>> + test_counter_info_invalid_group(invalid_group);
>> +
>> + test_begin_invalid_monitor();
>> + test_end_invalid_monitor();
>> + test_delete_monitor_invalid();
>> + test_get_counter_data_invalid_monitor();
>> + test_select_counters_invalid_monitor();
>> + test_get_counter_data_byte_size();
>> + test_gen_initial_state();
>> + test_end_without_begin();
>> + test_double_begin();
>> +
>> + test_select_counters_invalid_group(invalid_group);
>> +
>> + /* If there are no groups, the rest of the tests can't run. Bail. */
>> + if (num_groups == 0)
>> + exit(0);
>> +
>> + test_get_counters_null_pointers(groups[0]);
>> + test_get_counters_null_pointer_non_zero_size(groups[0]);
>> + test_get_counters_zero_size_array(groups[0]);
>> + test_get_counters_partial_array(groups[0]);
>> + test_group_string_null_length(groups[0]);
>> + test_group_string_single_character_buffer(groups[0]);
>> + test_group_string_small_buffer(groups[0]);
>> + test_group_string_normal_buffer(groups[0]);
>> +
>> + test_counter_info(groups, num_groups);
>> +
>> + test_select_counters_invalid_num_counters(groups[0]);
>> +
>> + get_counters(groups[0], &g0_counters, &num_g0_counters);
>> + invalid_counter = find_invalid_counter(g0_counters, num_g0_counters);
>> +
>> + test_counter_string_invalid_counter(groups[0], invalid_counter);
>> + test_counter_info_invalid_counter(groups[0], invalid_counter);
>> +
>> + /* If there are no counters, the rest of the tests can't run. Bail. */
>> + if (num_g0_counters == 0)
>> + exit(0);
>> +
>> + test_counter_string_null_length(groups[0], g0_counters[0]);
>> + test_counter_string_single_character_buffer(groups[0], g0_counters[0]);
>> + test_counter_string_small_buffer(groups[0], g0_counters[0]);
>> + test_counter_string_normal_buffer(groups[0], g0_counters[0]);
>> +
>> + exit(0);
>> +}
>> diff --git a/tests/spec/amd_performance_monitor/measure.c b/tests/spec/amd_performance_monitor/measure.c
>> new file mode 100644
>> index 0000000..e89ff00
>> --- /dev/null
>> +++ b/tests/spec/amd_performance_monitor/measure.c
>> @@ -0,0 +1,387 @@
>> +/*
>> + * Copyright © 2013 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + */
>> +
>> +/**
>> + * \file measure.c
>> + *
>> + * Some AMD_performance_monitor tests that actually measure things.
>> + */
>> +
>> +#define __STDC_FORMAT_MACROS
>> +#include <inttypes.h>
>> +#include "piglit-util-gl-common.h"
>> +
>> +PIGLIT_GL_TEST_CONFIG_BEGIN
>> +
>> + config.supports_gl_compat_version = 10;
>> + config.window_visual = PIGLIT_GL_VISUAL_RGB;
>> +
>> +PIGLIT_GL_TEST_CONFIG_END
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Get a list of group IDs.
>> + */
>> +static void
>> +get_groups(unsigned **groups, int *num_groups)
>> +{
>> + glGetPerfMonitorGroupsAMD(num_groups, 0, NULL);
>> + *groups = calloc(*num_groups, sizeof(unsigned));
>> + glGetPerfMonitorGroupsAMD(NULL, *num_groups, *groups);
>> +}
>> +
>> +/**
>> + * Get a list of counter IDs in a given group.
>> + */
>> +static void
>> +get_counters(unsigned group, unsigned **counters, int *num_counters,
>> + int *max_active_counters)
>> +{
>> + glGetPerfMonitorCountersAMD(group, num_counters, NULL, 0, NULL);
>> + *counters = calloc(*num_counters, sizeof(unsigned));
>> + glGetPerfMonitorCountersAMD(group, NULL, max_active_counters,
>> + *num_counters, *counters);
>> +}
>> +
>> +#define verify(x) \
>> + if (!(x)) { \
>> + piglit_report_subtest_result(PIGLIT_FAIL, test_name); \
>> + return; \
>> + }
>> +
>> +/******************************************************************************/
>> +
>> +/**
>> + * Poll until PERFMON_RESULT_AVAILABLE returns 1; glFinish() on each iteration.
>> + *
>> + * Only loop for 5 times to guard against implementations that never finish.
>> + */
>> +static bool
>> +wait_until_available(unsigned monitor)
>> +{
>> + int i;
>> + unsigned available = 0;
>> + for (i = 0; !available && i < 5; i++) {
>> + glFinish();
>> + glGetPerfMonitorCounterDataAMD(monitor,
>> + GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + sizeof(unsigned), &available,
>> + NULL);
>> + }
>> + return available;
>> +}
>> +
>> +/**
>> + * Basic functional test: enable all the counters in the first group
>> + * (up to the maximum that can be active at a time), begin monitoring,
>> + * end monitoring, make sure results are available, sanity check the
>> + * result size, and get the results.
>> + */
>> +static void
>> +test_basic_measurement(unsigned group)
>> +{
>> + unsigned monitor;
>> + unsigned *counters;
>> + int num_counters;
>> + int max_active_counters;
>> + unsigned usable_counters;
>> + unsigned result_size = 0;
>> + GLsizei bytes_written = 0;
>> + unsigned *data;
>> +
>> + uint32_t *p;
>> + unsigned value;
>> +
>> + const char *test_name;
>> +
>> + /**
>> + * Test #1: Basic Measurement.
>> + *
>> + * Enable all the counters in the first group (up to the maximum that
>> + * can be active at a time), begin monitoring, end monitoring, make
>> + * sure results are available, sanity check the result size, and get
>> + * the results.
>> + */
>> + test_name = "basic measurement";
>> +
>> + get_counters(group, &counters, &num_counters,
>> + &max_active_counters);
>> + verify(max_active_counters >= 0);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + usable_counters = MIN2(num_counters, max_active_counters);
>> +
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Enable counters 0 .. usable_counters from the list. */
>> + glSelectPerfMonitorCountersAMD(monitor, true, group, usable_counters,
>> + counters);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Start monitoring */
>> + glBeginPerfMonitorAMD(monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Drawing...meh */
>> + glFinish();
>> +
>> + /* End monitoring */
>> + glEndPerfMonitorAMD(monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Wait for the result to be available. */
>> + verify(wait_until_available(monitor));
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Get the result size. */
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD,
>> + sizeof(unsigned), &result_size, NULL);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Make sure the size is in bytes. */
>> + verify(result_size % sizeof(unsigned) == 0);
>> +
>> + /* The format is <Group ID, Group, Value>. The first two are
>> + * uint32_ts. Value is either a float, uint32_t, or uint64_t.
>> + * As a sanity check, make sure the result size is within
>> + * reasonable limits. Don't bother checking the actual types
>> + * since that's a bunch of work.
>> + */
>> + verify(result_size >= 3 * sizeof(uint32_t) * usable_counters)
>> + verify(result_size <=
>> + (2 * sizeof(uint32_t) + sizeof(uint64_t)) * usable_counters);
>> +
>> + /* Get the results. */
>> + data = calloc(1, result_size);
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AMD,
>> + result_size, data, &bytes_written);
>> +
>> + verify(bytes_written == result_size);
>> +
>> + piglit_report_subtest_result(PIGLIT_PASS, test_name);
>> +
>> + /**
>> + * Test #2: Verify counter results against specified range.
>> + */
>> + p = data;
>> + while ((char *) p < ((char *) data) + bytes_written) {
>> + uint32_t group_id = p[0];
>> + uint32_t counter_id = p[1];
>> +
>> + /* Counter values */
>> + uint32_t u32 = p[2];
>> + float f = ((float *) p)[2];
>> + uint64_t u64 = ((uint64_t *) p)[1];
>> +
>> + /* Query results */
>> + GLenum counter_type = GL_NONE;
>> + uint64_t range[2];
>> +
>> + /* There's only one group, so it better match */
>> + verify(group_id == group);
>> +
>> + /* Getting the counter data also validates the counter ID
>> + * without having to walk through the whole list of counters.
>> + */
>> + glGetPerfMonitorCounterInfoAMD(group_id, counter_id,
>> + GL_COUNTER_TYPE_AMD,
>> + &counter_type);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + glGetPerfMonitorCounterInfoAMD(group_id, counter_id,
>> + GL_COUNTER_RANGE_AMD,
>> + range);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Make sure it falls within the proper range */
>> + switch (counter_type) {
>> + case GL_UNSIGNED_INT: {
>> + uint32_t min = ((uint32_t *) range)[0];
>> + uint32_t max = ((uint32_t *) range)[1];
>> + verify(u32 >= min);
>> + verify(u32 <= max);
>> + break;
>> + }
>> + case GL_UNSIGNED_INT64_AMD: {
>> + verify(u64 >= range[0]);
>> + verify(u64 <= range[1]);
>> + break;
>> + }
>> + case GL_PERCENTAGE_AMD:
>> + case GL_FLOAT: {
>> + float min = ((float *) range)[0];
>> + float max = ((float *) range)[1];
>> + verify(f >= min);
>> + verify(f <= max);
>> + break;
>> + }
>> + }
>> +
>> + p += (counter_type == GL_UNSIGNED_INT64_AMD) ? 4 : 3;
>> + }
>> + verify(result_size == ((char *) p - (char *) data));
>> +
>> + free(data);
>> +
>> + /**
>> + * Test #3: Changing the set of active counters resets queries.
>> + *
>> + * "When SelectPerfMonitorCountersAMD is called on a monitor, any
>> + * outstanding results for that monitor become invalidated and the
>> + * result queries PERFMON_RESULT_SIZE_AMD and
>> + * PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
>> + */
>> + test_name = "selecting counters resets queries";
>> +
>> + /* Turn off the first counter. */
>> + glSelectPerfMonitorCountersAMD(monitor, false, group, 1, counters);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Results should no longer be available. All queries should
>> + * return 0.
>> + */
>> + value = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + sizeof(unsigned), &value, NULL);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> + verify(value == 0);
>> +
>> + value = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD,
>> + sizeof(unsigned), &value, NULL);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> + verify(value == 0);
>> +
>> + piglit_report_subtest_result(PIGLIT_PASS, test_name);
>> +
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> +}
>> +
>> +
>> +/**
>> + * Make sure that calling SelectPerfMonitorCountersAMD on an active monitor
>> + * is possible, resets active queries, and restarts monitoring (so it remains
>> + * active).
>> + *
>> + * This is not actually specified, but matches the behavior of AMD's driver.
>> + * Being an AMD extension, other implementations should probably match theirs.
>> + */
>> +static void
>> +test_change_counters_while_active(unsigned group)
>> +{
>> + unsigned monitor;
>> + unsigned *counters;
>> + int num_counters;
>> + int max_active_counters;
>> + unsigned usable_counters;
>> + unsigned data;
>> + const char *test_name = "change counters while active";
>> +
>> + get_counters(group, &counters, &num_counters,
>> + &max_active_counters);
>> + verify(max_active_counters >= 0);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + usable_counters = MIN2(num_counters, max_active_counters);
>> +
>> + if (usable_counters == 0)
>> + return; /* skip */
>> +
>> + glGenPerfMonitorsAMD(1, &monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Enable counters 0 .. usable_counters from the list. */
>> + glSelectPerfMonitorCountersAMD(monitor, true, group, usable_counters,
>> + counters);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Start monitoring */
>> + glBeginPerfMonitorAMD(monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Turn off the first counter. The specification is unclear whether
>> + * or not this should be allowed while monitoring is active, but it
>> + * apparently is (Catalyst 12.06 on a Radeon 3650).
>> + */
>> + glSelectPerfMonitorCountersAMD(monitor, false, group, 1, counters);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + /* Verify that all queries have been reset to 0 */
>> + data = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_AVAILABLE_AMD,
>> + sizeof(unsigned), &data, NULL);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> + verify(data == 0);
>> +
>> + data = 0xd0d0d0d0;
>> + glGetPerfMonitorCounterDataAMD(monitor, GL_PERFMON_RESULT_SIZE_AMD,
>> + sizeof(unsigned), &data, NULL);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> + verify(data == 0);
>> +
>> + /* The spec doesn't explicitly mention whether or not monitoring
>> + * is still active, but apparently it is.
>> + */
>> + glEndPerfMonitorAMD(monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + glDeletePerfMonitorsAMD(1, &monitor);
>> + verify(piglit_check_gl_error(GL_NO_ERROR));
>> +
>> + piglit_report_subtest_result(PIGLIT_PASS, test_name);
>> +}
>> +
>> +
>> +/******************************************************************************/
>> +
>> +enum piglit_result
>> +piglit_display(void)
>> +{
>> + return PIGLIT_FAIL;
>> +}
>> +
>> +/**
>> + * The main test program.
>> + */
>> +void
>> +piglit_init(int argc, char **argv)
>> +{
>> + unsigned *groups;
>> + int num_groups;
>> +
>> + piglit_require_extension("GL_AMD_performance_monitor");
>> +
>> + /* Basic glGetPerfMonitorGroupsAMD() tests */
>> + get_groups(&groups, &num_groups);
>> +
>> + /* If there are no groups, the rest of the tests can't run. Bail. */
>> + if (num_groups == 0)
>> + exit(0);
>> +
>> + test_basic_measurement(groups[0]);
>> + test_change_counters_while_active(groups[0]);
>> +
>> + exit(0);
>> +}
>> --
>> 1.8.2
>>
>> _______________________________________________
>> Piglit mailing list
>> Piglit at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/piglit
More information about the Piglit
mailing list