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

Ken Phillis Jr kphillisjr at gmail.com
Wed Mar 27 00:12:22 PDT 2013


I read over the patch, and I noticed a few things.

1) Which platform did you test on? My guess is Linux.
2) Where are the dynamic entry points for this extension? These tests
will fail on windows without this implemented.

Anyways, From here, I think the extension looks really good... Only
bit would be to fix #2 listed above.

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