[Piglit] [PATCH] Add tests for the GL_AMD_performance_monitor extension.

Ian Romanick idr at freedesktop.org
Mon Apr 1 11:13:21 PDT 2013


On 03/28/2013 01:01 AM, Kenneth Graunke wrote:
> 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. :(

Does AMD's libGL have the same bug?  If not, let's fix ours.

> 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
>
> _______________________________________________
> Piglit mailing list
> Piglit at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/piglit
>



More information about the Piglit mailing list