As with AMD_performance_monitor, 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 query, while a few sanity check
all counters in all queries.

Signed-off-by: Petri Latvala <petri.latv...@intel.com>
---
 tests/all.py                                       |   6 +
 tests/spec/CMakeLists.txt                          |   1 +
 .../spec/intel_performance_query/CMakeLists.gl.txt |  14 +
 tests/spec/intel_performance_query/CMakeLists.txt  |   1 +
 tests/spec/intel_performance_query/api.c           | 808 +++++++++++++++++++++
 tests/spec/intel_performance_query/measure.c       | 294 ++++++++
 tests/spec/intel_performance_query/minmax.c        |  58 ++
 7 files changed, 1182 insertions(+)
 create mode 100644 tests/spec/intel_performance_query/CMakeLists.gl.txt
 create mode 100644 tests/spec/intel_performance_query/CMakeLists.txt
 create mode 100644 tests/spec/intel_performance_query/api.c
 create mode 100644 tests/spec/intel_performance_query/measure.c
 create mode 100644 tests/spec/intel_performance_query/minmax.c

diff --git a/tests/all.py b/tests/all.py
index 1e1aa3d..ba1eb56 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -1425,6 +1425,12 @@ 
import_glsl_parser_tests(spec['AMD_shader_trinary_minmax'],
                         os.path.join(testsDir, 'spec', 
'amd_shader_trinary_minmax'),
                         [''])
 
+# Group INTEL_performance_query
+spec['INTEL_performance_query'] = Group()
+profile.test_list['spec/INTEL_performance_query/api'] = 
PlainExecTest('intel_performance_query_api -auto')
+profile.test_list['spec/INTEL_performance_query/measure'] = 
PlainExecTest('intel_performance_query_measure -auto')
+profile.test_list['spec/INTEL_performance_query/minmax'] = 
PlainExecTest('intel_performance_query_minmax')
+
 # Group ARB_point_sprite
 arb_point_sprite = Group()
 spec['ARB_point_sprite'] = arb_point_sprite
diff --git a/tests/spec/CMakeLists.txt b/tests/spec/CMakeLists.txt
index 0a513c1..037653e 100644
--- a/tests/spec/CMakeLists.txt
+++ b/tests/spec/CMakeLists.txt
@@ -100,3 +100,4 @@ add_subdirectory (ext_image_dma_buf_import)
 add_subdirectory (arb_blend_func_extended)
 add_subdirectory (ext_unpack_subimage)
 add_subdirectory (arb_vertex_array_object)
+add_subdirectory (intel_performance_query)
diff --git a/tests/spec/intel_performance_query/CMakeLists.gl.txt 
b/tests/spec/intel_performance_query/CMakeLists.gl.txt
new file mode 100644
index 0000000..7d10e0b
--- /dev/null
+++ b/tests/spec/intel_performance_query/CMakeLists.gl.txt
@@ -0,0 +1,14 @@
+include_directories(
+       ${GLEXT_INCLUDE_DIR}
+       ${OPENGL_INCLUDE_PATH}
+)
+
+link_libraries (
+       piglitutil_${piglit_target_api}
+       ${OPENGL_gl_LIBRARY}
+       ${OPENGL_glu_LIBRARY}
+)
+
+piglit_add_executable (intel_performance_query_api api.c)
+piglit_add_executable (intel_performance_query_minmax minmax.c)
+piglit_add_executable (intel_performance_query_measure measure.c)
diff --git a/tests/spec/intel_performance_query/CMakeLists.txt 
b/tests/spec/intel_performance_query/CMakeLists.txt
new file mode 100644
index 0000000..144a306
--- /dev/null
+++ b/tests/spec/intel_performance_query/CMakeLists.txt
@@ -0,0 +1 @@
+piglit_include_target_api()
diff --git a/tests/spec/intel_performance_query/api.c 
b/tests/spec/intel_performance_query/api.c
new file mode 100644
index 0000000..afb7fcb
--- /dev/null
+++ b/tests/spec/intel_performance_query/api.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright © 2014 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 INTEL_performance_query infrastructure tests.  These test the
+ * mechanism to retrieve counter and query 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 = 30;
+       config.supports_gl_es_version = 20;
+       config.window_visual = PIGLIT_GL_VISUAL_RGB;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/******************************************************************************/
+
+/**
+ * Get a list of query IDs.
+ */
+static void
+get_queries(GLuint ** queries, unsigned *num_queries)
+{
+       GLuint queryid;
+       unsigned i;
+
+       /* Enumerate all query ids first to get their count */
+       *num_queries = 0;
+       for (glGetFirstPerfQueryIdINTEL(&queryid);
+            queryid != 0;
+            glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+               ++(*num_queries);
+       }
+
+       *queries = calloc(*num_queries, sizeof(unsigned));
+
+       /* And now collect them */
+       i = 0;
+       for (glGetFirstPerfQueryIdINTEL(&queryid);
+            queryid != 0;
+            glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+               (*queries)[i++] = queryid;
+       }
+}
+
+/**
+ * Get a list of counter IDs in a given query.
+ */
+static void
+get_counters(GLuint query, GLuint ** counters, unsigned *num_counters)
+{
+       unsigned i;
+
+       glGetPerfQueryInfoINTEL(query, 0, NULL, NULL,
+                               num_counters, NULL, NULL);
+
+       /* Counters start from 1 and are continuous */
+       *counters = calloc(*num_counters, sizeof(unsigned));
+       for (i = 0; i < *num_counters; ++i) {
+               (*counters)[i] = i + 1;
+       }
+}
+
+/**
+ * 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 query ID.
+ */
+static GLuint
+find_invalid_query(unsigned *queries, int num_queries)
+{
+       unsigned invalid_query = ~0;
+
+       /* Most implementations probably use small consecutive integers, so
+        * start at ~0 and work backwards.  Hopefully we shouldn't loop.
+        */
+       while (in_list(invalid_query, queries, num_queries))
+               --invalid_query;
+
+       return invalid_query;
+}
+
+/**
+ * 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) \
+       do { \
+               piglit_report_subtest_result((pass) ? \
+               PIGLIT_PASS : PIGLIT_FAIL, __FUNCTION__); \
+               return; \
+       } while (0)
+
+/******************************************************************************/
+
+/** Call glGetFirstPerfQueryIdINTEL() with a NULL queryId pointer.
+ *
+ * Verify that it doesn't attempt to write the query id and crash.
+ */
+static void
+test_first_query_null_queryid_pointer(void)
+{
+       glGetFirstPerfQueryIdINTEL(NULL);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetNextPerfQueryIdINTEL() with a NULL nextQueryId.
+ *
+ * Verify that it doesn't attempt to write the query id and crash.
+ */
+static void
+test_next_query_null_nextqueryid_pointer(unsigned validquery)
+{
+       glGetNextPerfQueryIdINTEL(validquery, NULL);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetNextPerfQueryIdINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_next_query_invalid_queryid(unsigned invalidquery)
+{
+       unsigned dummy;
+
+       glGetNextPerfQueryIdINTEL(invalidquery, &dummy);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfQueryIdByNameINTEL() with a NULL query id pointer.
+ *
+ * Verify that it doesn't attempt to write a query id and crash.
+ */
+static void
+test_get_query_by_name_null_queryid_pointer(const char *validname)
+{
+       glGetPerfQueryIdByNameINTEL(validname, NULL);
+       /* The specification does not say that this should produce an error. */
+}
+
+/** Call glGetPerfQueryIdByNameINTEL() with a NULL name pointer.
+ *
+ * Verify that it doesn't attempt to read the name and crash.
+ */
+static void
+test_get_query_by_name_null_name_pointer(void)
+{
+       unsigned dummy;
+
+       glGetPerfQueryIdByNameINTEL(NULL, &dummy);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfQueryIdByNameINTEL() with an invalid name.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_query_by_name_invalid_name(const char *invalidname)
+{
+       unsigned dummy;
+
+       glGetPerfQueryIdByNameINTEL(invalidname, &dummy);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfQueryInfoINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_query_info_invalid_queryid(unsigned invalidquery)
+{
+       char name[256];
+       GLuint datasize;
+       GLuint counters;
+       GLuint instances;
+       GLuint caps;
+
+       glGetPerfQueryInfoINTEL(invalidquery,
+                               sizeof(name), name,
+                               &datasize, &counters, &instances, &caps);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfQueryInfoINTEL() with NULL pointers.
+ *
+ * Verify that it doesn't attempt to write data to them and crash.
+ * Verify that it doesn't produce an error.
+ */
+static void
+test_get_perf_query_info_null_pointers(unsigned validquery)
+{
+       glGetPerfQueryInfoINTEL(validquery, 0, NULL, NULL, NULL, NULL, NULL);
+       report(piglit_check_gl_error(GL_NO_ERROR));
+}
+
+/** Call glGetPerfQueryInfoINTEL() with a single character buffer.
+ *
+ * Verify that length is correct, the string is zero-terminated,
+ * and no buffer overflows occur.
+ */
+static void
+test_get_perf_query_info_single_character_buffer(unsigned validquery)
+{
+       char name[3] = "```";
+       bool pass = true;
+
+       glGetPerfQueryInfoINTEL(validquery, 1, name, NULL, NULL, NULL, NULL);
+       pass = piglit_check_gl_error(GL_NO_ERROR);
+
+       /* Verify buffer contents: only the first character should change,
+        * and it should be the terminator.
+        */
+       pass = name[0] == '\0' && pass;
+       pass = name[1] == '`' && pass;
+       pass = name[2] == '`' && pass;
+
+       report(pass);
+}
+
+/******************************************************************************/
+
+/** Call glGetPerfCounterInfoINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_counter_info_invalid_queryid(unsigned invalidquery)
+{
+       char name[256];
+       char desc[1024];
+       GLuint offset;
+       GLuint datasize;
+       GLuint type;
+       GLuint datatype;
+       GLuint64 maxvalue;
+
+       /* 1 is a valid counter ID */
+       glGetPerfCounterInfoINTEL(invalidquery, 1,
+                                 sizeof(name), name,
+                                 sizeof(desc), desc,
+                                 &offset, &datasize, &type,
+                                 &datatype, &maxvalue);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with a valid query id but invalid
+ * counter id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_get_perf_counter_info_invalid_counterid(unsigned validquery,
+                                            unsigned invalidcounter)
+{
+       char name[256];
+       char desc[1024];
+       GLuint offset;
+       GLuint datasize;
+       GLuint type;
+       GLuint datatype;
+       GLuint64 maxvalue;
+
+       glGetPerfCounterInfoINTEL(validquery, invalidcounter,
+                                 sizeof(name), name,
+                                 sizeof(desc), desc,
+                                 &offset, &datasize, &type,
+                                 &datatype, &maxvalue);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with NULL pointers.
+ *
+ * Verify that it doesn't attempt to write data to them and crash.
+ * Verify that it doesn't produce an error.
+ */
+static void
+test_get_perf_counter_info_null_pointers(unsigned validquery,
+                                        unsigned validcounter)
+{
+       glGetPerfCounterInfoINTEL(validquery, validcounter,
+                                 0, NULL,
+                                 0, NULL, NULL, NULL, NULL, NULL, NULL);
+       report(piglit_check_gl_error(GL_NO_ERROR));
+}
+
+/** Call glGetPerfCounterInfoINTEL() with single character buffers.
+ *
+ * Verify that length is correct, the string is zero-terminated,
+ * and no buffer overflows occur.
+ */
+static void
+test_get_perf_counter_info_single_character_buffer(unsigned validquery,
+                                                  unsigned validcounter)
+{
+       char name[3] = "```";
+       char desc[3] = "```";
+       bool pass = true;
+
+       glGetPerfCounterInfoINTEL(validquery, validcounter,
+                                 1, name,
+                                 1, desc, NULL, NULL, NULL, NULL, NULL);
+       pass = piglit_check_gl_error(GL_NO_ERROR);
+
+       /* Verify buffer contents: only the first character should change,
+        * and it should be the terminator.
+        */
+       pass = name[0] == '\0' && pass;
+       pass = name[1] == '`' && pass;
+       pass = name[2] == '`' && pass;
+
+       pass = desc[0] == '\0' && pass;
+       pass = desc[1] == '`' && pass;
+       pass = desc[2] == '`' && pass;
+
+       report(pass);
+}
+
+/**
+ * Call glGetPerfQueryInfoINTEL() on every query and verify that all
+ * queries have a valid capsMask value.
+ */
+static void
+test_query_info(unsigned *queries, unsigned num_queries)
+{
+       int i;
+
+       for (i = 0; i < num_queries; ++i) {
+               char name[256];
+               GLuint datasize;
+               GLuint counters;
+               GLuint instances;
+               GLuint caps;
+
+               glGetPerfQueryInfoINTEL(queries[i],
+                                       sizeof(name), name,
+                                       &datasize, &counters,
+                                       &instances, &caps);
+
+               if (caps != GL_PERFQUERY_SINGLE_CONTEXT_INTEL &&
+                   caps != GL_PERFQUERY_GLOBAL_CONTEXT_INTEL) {
+                       printf("Query %u has an invalid capability mask: %x\n",
+                              queries[i], caps);
+                       report(false);
+                       break;
+               }
+       }
+
+       report(true);
+}
+
+/**
+ * Call glGetPerfCounterInfoINTEL() on every query/counter pair and verify that
+ * all counters have a valid type and datatype.
+ */
+static void
+test_counter_info(unsigned *queries, unsigned num_queries)
+{
+       int i;
+       int j;
+
+       for (i = 0; i < num_queries; ++i) {
+               unsigned *counters;
+               unsigned num_counters;
+               get_counters(queries[i], &counters, &num_counters);
+
+               if (!piglit_automatic) {
+                       char queryname[256];
+
+                       glGetPerfQueryInfoINTEL(queries[i], sizeof(queryname),
+                                               queryname, NULL, NULL, NULL,
+                                               NULL);
+                       printf("Query %u [%s]:\n", queries[i], queryname);
+               }
+
+               for (j = 0; j < num_counters; ++j) {
+                       char name[256];
+                       char desc[1024];
+                       GLuint offset;
+                       GLuint datasize;
+                       GLuint type;
+                       GLuint datatype;
+                       GLuint64 maxvalue;
+
+                       memset(name, 0, sizeof(name));
+                       memset(desc, 0, sizeof(desc));
+
+                       glGetPerfCounterInfoINTEL(queries[i], counters[j],
+                                                 sizeof(name), name,
+                                                 sizeof(desc), desc,
+                                                 &offset, &datasize, &type,
+                                                 &datatype, &maxvalue);
+
+                       if (!piglit_automatic)
+                               printf(" Counter %u [%s]: %s\n", counters[j],
+                                      name, desc);
+
+                       switch (datatype) {
+                       default:
+                               printf("Query %u/Counter %u has an invalid 
datatype: %x\n",
+                                      queries[i], counters[j], datatype);
+                               report(false);
+                               break;
+                       case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+                       case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+                       case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+                       case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+                       case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+                               break;
+                       }
+
+                       switch (type) {
+                       default:
+                               printf("Query %u/Counter %u has an invalid 
type: %x\n",
+                                      queries[i], counters[j], type);
+                               report(false);
+                               break;
+                       case GL_PERFQUERY_COUNTER_EVENT_INTEL:
+                       case GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL:
+                       case GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL:
+                       case GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL:
+                       case GL_PERFQUERY_COUNTER_RAW_INTEL:
+                       case GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL:
+                               break;
+                       }
+               }
+               free(counters);
+       }
+
+       report(true);
+}
+
+/******************************************************************************/
+
+/**
+ * Call glBeginPerfQueryINTEL() on an invalid query handle.
+ * (Should be run before any Gen tests to ensure this handle is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+void
+test_begin_invalid_query_handle(void)
+{
+       glBeginPerfQueryINTEL(777);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glEndPerfQueryINTEL() on an invalid query handle.
+ * (Should be run before any Gen tests to ensure this ID is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE or INVALID_OPERATION.
+ * XXX: Only INVALID_OPERATION is actually specified, assume
+ * INVALID_VALUE can also be generated.
+ */
+void
+test_end_invalid_query_handle(void)
+{
+       GLenum error;
+       glEndPerfQueryINTEL(777);
+       error = glGetError();
+       report(error == GL_INVALID_VALUE || error == GL_INVALID_OPERATION);
+}
+
+/**
+ * Call glCreatePerfQueryINTEL() with an invalid query id.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_create_perf_query_invalid_query(unsigned invalidquery)
+{
+       GLuint handle;
+       glCreatePerfQueryINTEL(invalidquery, &handle);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glCreatePerfQueryINTEL() with a NULL queryhandle pointer.
+ *
+ * Verify that it doesn't attempt to write a handle and crash,
+ * and produces INVALID_VALUE.
+ * XXX: This isn't actually specified, but it seems like it ought to be.
+ */
+static void
+test_create_perf_query_null_handle_pointer(unsigned validquery)
+{
+       glCreatePerfQueryINTEL(validquery, NULL);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glDeletePerfQueryINTEL() with an invalid query handle.
+ *
+ * Verify that it produces INVALID_VALUE.
+ */
+static void
+test_delete_perf_query_invalid_handle(void)
+{
+       glDeletePerfQueryINTEL(777);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with an invalid query handle.
+ * (Should be run before any Gen tests to ensure this ID is invalid.)
+ *
+ * Verify that it produces INVALID_VALUE.
+ * XXX: This isn't actually specified, but it seems like it ought to be.
+ */
+static void
+test_get_query_data_invalid_query_handle(void)
+{
+       char data[1024];
+       GLuint bytes;
+       glGetPerfQueryDataINTEL(777, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+                               sizeof(data), data, &bytes);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with a NULL data pointer.
+ *
+ * Verify that it doesn't attempt to write data and crash, and
+ * produces INVALID_VALUE.
+ */
+static void
+test_get_query_data_null_data_pointer(void)
+{
+       GLuint query;
+       GLuint handle;
+       GLuint bytes;
+
+       glGetFirstPerfQueryIdINTEL(&query);
+       glCreatePerfQueryINTEL(query, &handle);
+
+       glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+                               128, NULL, &bytes);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL() with a NULL byteswritten pointer.
+ *
+ * Verify that it doesn't attempt to write data and crash, and
+ * produces INVALID_VALUE.
+ */
+static void
+test_get_query_data_null_byteswritten_pointer(void)
+{
+       GLuint query;
+       GLuint handle;
+       char data[1024];
+
+       glGetFirstPerfQueryIdINTEL(&query);
+       glCreatePerfQueryINTEL(query, &handle);
+
+       glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+                               sizeof(data), data, NULL);
+       report(piglit_check_gl_error(GL_INVALID_VALUE));
+}
+
+/**
+ * Call glGetPerfQueryDataINTEL on a query handle that hasn't been started.
+ *
+ * Verify that no data is written in such case.
+ */
+static void
+test_initial_state(void)
+{
+       bool pass = true;
+       unsigned query;
+       unsigned handle;
+       unsigned bytes = 0xd0d0d0d0;
+       char data[1024];
+
+       glGetFirstPerfQueryIdINTEL(&query);
+       glCreatePerfQueryINTEL(query, &handle);
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+       memset(data, '`', sizeof(data));
+
+       glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_DONOT_FLUSH_INTEL,
+                               sizeof(data), data, &bytes);
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+       pass = bytes == 0 && pass;
+       pass = data[0] == '`' && pass;
+
+       glDeletePerfQueryINTEL(handle);
+       report(pass);
+}
+
+/**
+ * "If a performance query is not currently started, an
+ * INVALID_OPERATION error will be generated."
+ */
+static void
+test_end_without_begin(void)
+{
+       bool pass = true;
+       unsigned query;
+       unsigned handle;
+
+       glGetFirstPerfQueryIdINTEL(&query);
+       glCreatePerfQueryINTEL(query, &handle);
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+       glEndPerfQueryINTEL(handle);
+       report(piglit_check_gl_error(GL_INVALID_OPERATION));
+
+       glDeletePerfQueryINTEL(handle);
+}
+
+/**
+ * "Note that some query types, they cannot be collected in the same
+ * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if
+ * they refer to queries of such different types. In such case
+ * INVALID_OPERATION error is generated."
+ *
+ * Impossible to know for sure which different queries cannot be used
+ * at the same time.  Assume that the same query cannot be started
+ * twice, so verify that calling Begin twice on the same query
+ * produces INVALID_OPERATION.
+ */
+static void
+test_double_begin(void)
+{
+       bool pass = true;
+       unsigned query;
+       unsigned handle;
+       GLenum error;
+
+       glGetFirstPerfQueryIdINTEL(&query);
+       glCreatePerfQueryINTEL(query, &handle);
+       pass = piglit_check_gl_error(GL_NO_ERROR) && pass;
+
+       glBeginPerfQueryINTEL(handle);
+
+       error = glGetError();
+       if (error != GL_NO_ERROR) {
+               glDeletePerfQueryINTEL(handle);
+               /* Query couldn't start for some reason; bail. */
+               if (error == GL_INVALID_OPERATION)
+                       return;
+               /* We weren't expecting this other error. */
+               report(false);
+       }
+
+       /* Double begin */
+       glBeginPerfQueryINTEL(handle);
+       pass = piglit_check_gl_error(GL_INVALID_OPERATION) && pass;
+
+       glDeletePerfQueryINTEL(handle);
+       report(pass);
+}
+
+/******************************************************************************/
+
+enum piglit_result
+piglit_display(void)
+{
+       return PIGLIT_FAIL;
+}
+
+/**
+ * The main test program.
+ */
+void
+piglit_init(int argc, char **argv)
+{
+       unsigned *queries;
+       unsigned num_queries;
+       unsigned *counters;
+       unsigned num_counters;
+       unsigned invalid_query;
+       unsigned valid_query;
+       unsigned invalid_counter;
+       unsigned valid_counter;
+       char valid_name[256];
+
+       piglit_require_extension("GL_INTEL_performance_query");
+
+       test_first_query_null_queryid_pointer();
+
+       get_queries(&queries, &num_queries);
+
+       /* If there are no valid queries, the rest of the tests can't run.
+        * Bail.
+        */
+       if (num_queries == 0)
+               exit(0);
+
+       invalid_query = find_invalid_query(queries, num_queries);
+       valid_query = queries[0];
+
+       test_next_query_null_nextqueryid_pointer(valid_query);
+       test_next_query_invalid_queryid(invalid_query);
+
+       glGetPerfQueryInfoINTEL(valid_query, sizeof(valid_name), valid_name,
+                               NULL, NULL, NULL, NULL);
+
+       test_get_query_by_name_null_queryid_pointer(valid_name);
+       test_get_query_by_name_null_name_pointer();
+       test_get_query_by_name_invalid_name
+               ("We assume this is an invalid name of a query");
+       test_get_perf_query_info_invalid_queryid(invalid_query);
+       test_get_perf_query_info_null_pointers(valid_query);
+       test_get_perf_query_info_single_character_buffer(valid_query);
+       test_get_perf_counter_info_invalid_queryid(invalid_query);
+
+       get_counters(valid_query, &counters, &num_counters);
+
+       /* If there are no counters, the rest of the tests can't run.
+        * Bail.
+        */
+       if (num_counters == 0)
+               exit(0);
+
+       invalid_counter = find_invalid_counter(counters, num_counters);
+       valid_counter = counters[0];
+
+       test_get_perf_counter_info_invalid_counterid(valid_query,
+                                                    invalid_counter);
+       test_get_perf_counter_info_null_pointers(valid_query, valid_counter);
+       test_get_perf_counter_info_single_character_buffer(valid_query,
+                                                          valid_counter);
+       test_query_info(queries, num_queries);
+       test_counter_info(queries, num_queries);
+       test_begin_invalid_query_handle();
+       test_end_invalid_query_handle();
+       test_create_perf_query_invalid_query(invalid_query);
+       test_create_perf_query_null_handle_pointer(valid_query);
+       test_delete_perf_query_invalid_handle();
+       test_get_query_data_invalid_query_handle();
+       test_get_query_data_null_data_pointer();
+       test_get_query_data_null_byteswritten_pointer();
+       test_initial_state();
+       test_end_without_begin();
+       test_double_begin();
+
+       free(counters);
+       free(queries);
+
+       exit(0);
+}
diff --git a/tests/spec/intel_performance_query/measure.c 
b/tests/spec/intel_performance_query/measure.c
new file mode 100644
index 0000000..e11b5f7
--- /dev/null
+++ b/tests/spec/intel_performance_query/measure.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright © 2014 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 INTEL_performance_query 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 = 30;
+       config.supports_gl_es_version = 20;
+       config.window_visual = PIGLIT_GL_VISUAL_RGB;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/******************************************************************************/
+
+/**
+ * Get a list of query IDs.
+ */
+static void
+get_queries(unsigned **queries, unsigned *num_queries)
+{
+       unsigned queryid;
+       unsigned i;
+
+       /* Enumerate all query ids first to get their count */
+       *num_queries = 0;
+       for (glGetFirstPerfQueryIdINTEL(&queryid);
+            queryid != 0;
+            glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+               ++(*num_queries);
+       }
+
+       *queries = calloc(*num_queries, sizeof(unsigned));
+
+       /* And now collect them */
+       i = 0;
+       for (glGetFirstPerfQueryIdINTEL(&queryid);
+            queryid != 0;
+            glGetNextPerfQueryIdINTEL(queryid, &queryid)) {
+               (*queries)[i++] = queryid;
+       }
+}
+
+/**
+ * Get a list of counter IDs in a given query.
+ */
+static void
+get_counters(unsigned query, unsigned **counters, unsigned *num_counters)
+{
+       unsigned i;
+
+       glGetPerfQueryInfoINTEL(query, 0, NULL, NULL,
+                               num_counters, NULL, NULL);
+
+       /* Counters start from 1 and are continuous */
+       *counters = calloc(*num_counters, sizeof(unsigned));
+       for (i = 0; i < *num_counters; ++i) {
+               (*counters)[i] = i + 1;
+       }
+}
+
+/**
+ * Get the size of a counter value of a given datatype enum in bytes.
+ */
+static unsigned
+value_size(GLuint datatype)
+{
+       switch (datatype) {
+       default:
+               /* Return 0 so the caller can report correct data to piglit. */
+               return 0;
+       case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+       case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+       case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+               return sizeof(uint32_t);
+       case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+       case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+               return sizeof(uint64_t);
+       }
+}
+
+#define verify(x)                                              \
+  if (!(x)) {                                                  \
+    piglit_report_subtest_result(PIGLIT_FAIL, "%s", test_name); \
+    return;                                                     \
+  }
+
+/******************************************************************************/
+
+/**
+ * Basic functional test: create a query of the first query (this
+ * terminology is too overloaded) begin monitoring, end monitoring,
+ * make sure results are available, sanity check the result size, and
+ * get the results.
+ */
+static void
+test_basic_measurement(unsigned query)
+{
+       unsigned handle;
+       unsigned *counters;
+       unsigned num_counters;
+       unsigned result_size = 0;
+       GLuint bytes_written = 0;
+       char *data;
+       unsigned i;
+
+       const char *test_name;
+
+       /**
+       * Test #1: Initialization
+       *
+       * Begin monitoring, end monitoring.
+       */
+       test_name = "initialization";
+
+       get_counters(query, &counters, &num_counters);
+       verify(num_counters > 0);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+
+       glCreatePerfQueryINTEL(query, &handle);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+
+       /* Start monitoring */
+       glBeginPerfQueryINTEL(handle);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+
+       /* Drawing...meh */
+       piglit_draw_triangle(0.0, 0.0, 1.0, 1.0, 0.5, 0.5);
+
+       /* End monitoring */
+       glEndPerfQueryINTEL(handle);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+
+       piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+       /**
+       * Test #2: Receiving results
+       *
+       * Grab the data and sanity check its size as much as possible.
+       */
+
+       test_name = "result retrieval";
+
+       /* Get the result size. */
+       glGetPerfQueryInfoINTEL(query, 0, NULL, &result_size, NULL, NULL,
+                               NULL);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+
+       /* Get the results. */
+
+       /* Allocate more than the query info says, in case the
+        * implementation lied about the size.
+        */
+       data = calloc(1, result_size + 32);
+       /* Pass GL_PERFQUERY_WAIT_INTEL which will make the function
+        * return only when results are available.
+        */
+       glGetPerfQueryDataINTEL(handle, GL_PERFQUERY_WAIT_INTEL,
+                               result_size + 32, data, &bytes_written);
+       verify(piglit_check_gl_error(GL_NO_ERROR));
+       verify(bytes_written == result_size);
+
+       piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+       /**
+       * Test #3: Data
+       *
+       * Check that the data sizes and offsets are correct.
+       */
+       test_name = "data";
+
+       /* Counter values are one of float, double, uint32_t, uint64_t or
+        * bool32_t. Now, the specification implicitly allows counters to
+        * alias and extra data to exist between values (GetPerfCounterInfo
+        * gives counter data offset in bytes) so we don't have many sanity
+        * checks on the result_size the spec would restrict.
+        */
+       verify(result_size >= sizeof(uint32_t));
+       verify(result_size % sizeof(uint32_t) == 0);
+
+       for (i = 0; i < num_counters; ++i) {
+               char name[256];
+               GLuint offset;
+               GLuint size;
+               GLuint datatype;
+               glGetPerfCounterInfoINTEL(query, counters[i],
+                                         sizeof(name), name,
+                                         0, NULL,
+                                         &offset, &size,
+                                         NULL, &datatype, NULL);
+               verify(piglit_check_gl_error(GL_NO_ERROR));
+               verify(offset + size <= result_size);
+               /* This tests that the datatype enum is valid */
+               verify(value_size(datatype) != 0);
+               /* In theory, the specification allows counter values to be
+                * _multiple_ values of the reported data type.
+                */
+               verify(size >= value_size(datatype));
+               verify(size % value_size(datatype) == 0);
+
+               /* Print the counter value for manual inspection. */
+               if (!piglit_automatic) {
+                       char *p;
+
+                       p = data + offset;
+                       printf("%u [%s]: ", i, name);
+                       switch (datatype) {
+                       case GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL:
+                               printf("%" PRIu32 "\n", *((uint32_t *) p));
+                               break;
+                       case GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL:
+                               printf("%" PRIu64 "\n", *((uint64_t *) p));
+                               break;
+                       case GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL:
+                               printf("%f\n", *((float *) p));
+                               break;
+                       case GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL:
+                               printf("%f\n", *((double *) p));
+                               break;
+                       case GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL:
+                               printf("%" PRIu32 "\n", *((uint32_t *) p));
+                               break;
+                       default:
+                               verify(!"not reached, should have already 
checked for validity");
+                               break;
+                       }
+               }
+       }
+
+       piglit_report_subtest_result(PIGLIT_PASS, "%s", test_name);
+
+       free(data);
+
+       glDeletePerfQueryINTEL(handle);
+}
+
+
+/******************************************************************************/
+
+enum piglit_result
+piglit_display(void)
+{
+       return PIGLIT_FAIL;
+}
+
+/**
+ * The main test program.
+ */
+void
+piglit_init(int argc, char **argv)
+{
+       unsigned *queries;
+       unsigned num_queries;
+
+       piglit_require_extension("GL_INTEL_performance_query");
+
+       get_queries(&queries, &num_queries);
+
+       /* If there are no queries, the rest of the tests can't run.  Bail. */
+       if (num_queries == 0)
+               exit(0);
+
+       test_basic_measurement(queries[0]);
+
+       exit(0);
+}
diff --git a/tests/spec/intel_performance_query/minmax.c 
b/tests/spec/intel_performance_query/minmax.c
new file mode 100644
index 0000000..8258fb6
--- /dev/null
+++ b/tests/spec/intel_performance_query/minmax.c
@@ -0,0 +1,58 @@
+/* Copyright © 2014 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.
+ */
+
+#include "piglit-util-gl-common.h"
+#include "minmax-test.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+       config.supports_gl_compat_version = 30;
+       config.supports_gl_es_version = 20;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+enum piglit_result
+piglit_display(void)
+{
+       return PIGLIT_FAIL;
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+       GLboolean extended;
+
+       piglit_require_extension("GL_INTEL_performance_query");
+       piglit_print_minmax_header();
+
+       piglit_test_min_int(GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL, 256);
+       piglit_test_min_int(GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL, 256);
+       piglit_test_min_int(GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL, 1024);
+
+       /* No value tested for this */
+       glGetBooleanv(GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL, &extended);
+
+       if (!piglit_check_gl_error(GL_NO_ERROR))
+               piglit_report_result(PIGLIT_FAIL);
+
+       piglit_report_result(piglit_minmax_pass ? PIGLIT_PASS : PIGLIT_FAIL);
+}
-- 
1.9.0

_______________________________________________
Piglit mailing list
Piglit@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/piglit

Reply via email to