Series is Reviewed-by: Ian Romanick <[email protected]>
I had one comment (future work) on patch 2. On 09/23/2013 08:56 PM, Kenneth Graunke wrote: > This provides an interface for applications (and OpenGL-based tools) to > access GPU performance counters. Since the exact performance counters > available vary between vendors and hardware generations, the extension > provides an API the application can use to get the names, types, and > minimum/maximum values of all available counters. Counters are also > organized into groups. > > Applications create "performance monitor" objects, select the counters > they want to track, and Begin/End monitoring, much like OpenGL's query > API. Multiple monitors can be in flight simultaneously. > > v2: Pass ctx to all driver hooks (suggested by Christoph), and attempt > to fix overallocation of bitsets (caught by Christoph). Incomplete. > > v3: Significantly rework core data structures. Store counters in groups > rather than in a global list. Use their array index in the group's > counter list as the ID rather than trying to store a globally unique > counter ID. Use bitsets for active counters within a group, and > also track which groups are active so that's easy to query. > > v4: Remove _mesa_ prefix on static functions; detect out of memory > conditions in new_performance_monitor(); make BeginPerfMonitor hook > return a boolean rather than setting m->Active or raising an error. > Switch to GLuint/unsigned for NumGroups, NumCounters, and > MaxActiveCounters (which also means switching a bunch of temporary > variable types). All suggested by Brian Paul. Also, remove > commented out code at the bottom of the block. Finally, fix the > dispatch sanity test (noticed by Ian Romanick). > > Signed-off-by: Kenneth Graunke <[email protected]> > Reviewed-by: Brian Paul <[email protected]> [v3] > --- > src/mapi/glapi/gen/AMD_performance_monitor.xml | 87 ++++ > src/mapi/glapi/gen/Makefile.am | 1 + > src/mapi/glapi/gen/gl_API.xml | 2 + > src/mapi/glapi/gen/gl_genexec.py | 1 + > src/mesa/Makefile.sources | 1 + > src/mesa/SConscript | 1 + > src/mesa/main/context.c | 2 + > src/mesa/main/dd.h | 24 + > src/mesa/main/extensions.c | 1 + > src/mesa/main/mtypes.h | 86 ++++ > src/mesa/main/performance_monitor.c | 609 > +++++++++++++++++++++++++ > src/mesa/main/performance_monitor.h | 85 ++++ > src/mesa/main/tests/dispatch_sanity.cpp | 13 + > 13 files changed, 913 insertions(+) > create mode 100644 src/mapi/glapi/gen/AMD_performance_monitor.xml > create mode 100644 src/mesa/main/performance_monitor.c > create mode 100644 src/mesa/main/performance_monitor.h > > Brian, > > Thanks for the feedback! I agreed with pretty much everything, and I think > I've made all of the requested changes. > > diff --git a/src/mapi/glapi/gen/AMD_performance_monitor.xml > b/src/mapi/glapi/gen/AMD_performance_monitor.xml > new file mode 100644 > index 0000000..b96b263 > --- /dev/null > +++ b/src/mapi/glapi/gen/AMD_performance_monitor.xml > @@ -0,0 +1,87 @@ > +<?xml version="1.0"?> > +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> > + > +<OpenGLAPI> > + > +<category name="GL_AMD_performance_monitor" number="360"> > + > + <function name="GetPerfMonitorGroupsAMD" offset="assign"> > + <param name="numGroups" type="GLint *"/> > + <param name="groupsSize" type="GLsizei"/> > + <param name="groups" type="GLuint *"/> > + </function> > + > + <function name="GetPerfMonitorCountersAMD" offset="assign"> > + <param name="group" type="GLuint"/> > + <param name="numCounters" type="GLint *"/> > + <param name="maxActiveCounters" type="GLint *"/> > + <param name="countersSize" type="GLsizei"/> > + <param name="counters" type="GLuint *"/> > + </function> > + > + <function name="GetPerfMonitorGroupStringAMD" offset="assign"> > + <param name="group" type="GLuint"/> > + <param name="bufSize" type="GLsizei"/> > + <param name="length" type="GLsizei *"/> > + <param name="groupString" type="GLchar *"/> > + </function> > + > + <function name="GetPerfMonitorCounterStringAMD" offset="assign"> > + <param name="group" type="GLuint"/> > + <param name="counter" type="GLuint"/> > + <param name="bufSize" type="GLsizei"/> > + <param name="length" type="GLsizei *"/> > + <param name="counterString" type="GLchar *"/> > + </function> > + > + <function name="GetPerfMonitorCounterInfoAMD" offset="assign"> > + <param name="group" type="GLuint"/> > + <param name="counter" type="GLuint"/> > + <param name="pname" type="GLenum"/> > + <param name="data" type="GLvoid *"/> > + </function> > + > + <function name="GenPerfMonitorsAMD" offset="assign"> > + <param name="n" type="GLsizei"/> > + <param name="monitors" type="GLuint *"/> > + </function> > + > + <function name="DeletePerfMonitorsAMD" offset="assign"> > + <param name="n" type="GLsizei"/> > + <param name="monitors" type="GLuint *"/> > + </function> > + > + <function name="SelectPerfMonitorCountersAMD" offset="assign"> > + <param name="monitor" type="GLuint"/> > + <param name="enable" type="GLboolean"/> > + <param name="group" type="GLuint"/> > + <param name="numCounters" type="GLint"/> > + <param name="counterList" type="GLuint *"/> > + </function> > + > + <function name="BeginPerfMonitorAMD" offset="assign"> > + <param name="monitor" type="GLuint"/> > + </function> > + > + <function name="EndPerfMonitorAMD" offset="assign"> > + <param name="monitor" type="GLuint"/> > + </function> > + > + <function name="GetPerfMonitorCounterDataAMD" offset="assign"> > + <param name="monitor" type="GLuint"/> > + <param name="pname" type="GLenum"/> > + <param name="dataSize" type="GLsizei"/> > + <param name="data" type="GLuint *"/> > + <param name="bytesWritten" type="GLint *"/> > + </function> > + > + <enum name="COUNTER_TYPE_AMD" value="0x8BC0"/> > + <enum name="COUNTER_RANGE_AMD" value="0x8BC1"/> > + <enum name="UNSIGNED_INT64_AMD" value="0x8BC2"/> > + <enum name="PECENTAGE_AMD" value="0x8BC3"/> > + <enum name="PERFMON_RESULT_AVAILABLE_AMD" value="0x8BC4"/> > + <enum name="PERFMON_RESULT_SIZE_AMD" value="0x8BC5"/> > + <enum name="PERFMON_RESULT_AMD" value="0x8BC6"/> > +</category> > + > +</OpenGLAPI> > diff --git a/src/mapi/glapi/gen/Makefile.am b/src/mapi/glapi/gen/Makefile.am > index d4fbd35..9b9b995 100644 > --- a/src/mapi/glapi/gen/Makefile.am > +++ b/src/mapi/glapi/gen/Makefile.am > @@ -115,6 +115,7 @@ API_XML = \ > ARB_texture_storage.xml \ > ARB_vertex_array_object.xml \ > AMD_draw_buffers_blend.xml \ > + AMD_performance_monitor.xml \ > ARB_vertex_type_2_10_10_10_rev.xml \ > APPLE_object_purgeable.xml \ > APPLE_vertex_array_object.xml \ > diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml > index 71aa9a7..f6511e9 100644 > --- a/src/mapi/glapi/gen/gl_API.xml > +++ b/src/mapi/glapi/gen/gl_API.xml > @@ -12890,6 +12890,8 @@ > <enum name="FRAMEBUFFER_SRGB_CAPABLE_EXT" value="0x8DBA"/> > </category> > > +<xi:include href="AMD_performance_monitor.xml" > xmlns:xi="http://www.w3.org/2001/XInclude"/> > + > <category name="GL_APPLE_texture_range" number="367"> > <enum name="TEXTURE_STORAGE_HINT_APPLE" count="1" value="0x85BC"> > <size name="TexParameteriv"/> > diff --git a/src/mapi/glapi/gen/gl_genexec.py > b/src/mapi/glapi/gen/gl_genexec.py > index be82f90..a074c23 100644 > --- a/src/mapi/glapi/gen/gl_genexec.py > +++ b/src/mapi/glapi/gen/gl_genexec.py > @@ -82,6 +82,7 @@ header = """/** > #include "main/matrix.h" > #include "main/multisample.h" > #include "main/objectlabel.h" > +#include "main/performance_monitor.h" > #include "main/pixel.h" > #include "main/pixelstore.h" > #include "main/points.h" > diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources > index 122ea8e..ff242b4 100644 > --- a/src/mesa/Makefile.sources > +++ b/src/mesa/Makefile.sources > @@ -65,6 +65,7 @@ MAIN_FILES = \ > $(SRCDIR)main/objectlabel.c \ > $(SRCDIR)main/pack.c \ > $(SRCDIR)main/pbo.c \ > + $(SRCDIR)main/performance_monitor.c \ > $(SRCDIR)main/pixel.c \ > $(SRCDIR)main/pixelstore.c \ > $(SRCDIR)main/pixeltransfer.c \ > diff --git a/src/mesa/SConscript b/src/mesa/SConscript > index 2cdb79c..9b7712f 100644 > --- a/src/mesa/SConscript > +++ b/src/mesa/SConscript > @@ -97,6 +97,7 @@ main_sources = [ > 'main/objectlabel.c', > 'main/pack.c', > 'main/pbo.c', > + 'main/performance_monitor.c', > 'main/pixel.c', > 'main/pixelstore.c', > 'main/pixeltransfer.c', > diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c > index 58f42cc..310518c 100644 > --- a/src/mesa/main/context.c > +++ b/src/mesa/main/context.c > @@ -105,6 +105,7 @@ > #include "macros.h" > #include "matrix.h" > #include "multisample.h" > +#include "performance_monitor.h" > #include "pixel.h" > #include "pixelstore.h" > #include "points.h" > @@ -764,6 +765,7 @@ init_attrib_groups(struct gl_context *ctx) > _mesa_init_lighting( ctx ); > _mesa_init_matrix( ctx ); > _mesa_init_multisample( ctx ); > + _mesa_init_performance_monitors( ctx ); > _mesa_init_pixel( ctx ); > _mesa_init_pixelstore( ctx ); > _mesa_init_point( ctx ); > diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h > index c1d9b2c..0806e41 100644 > --- a/src/mesa/main/dd.h > +++ b/src/mesa/main/dd.h > @@ -645,6 +645,30 @@ struct dd_function_table { > void (*WaitQuery)(struct gl_context *ctx, struct gl_query_object *q); > /*@}*/ > > + /** > + * \name Performance monitors > + */ > + /*@{*/ > + struct gl_perf_monitor_object * (*NewPerfMonitor)(struct gl_context *ctx); > + void (*DeletePerfMonitor)(struct gl_context *ctx, > + struct gl_perf_monitor_object *m); > + GLboolean (*BeginPerfMonitor)(struct gl_context *ctx, > + struct gl_perf_monitor_object *m); > + > + /** Stop an active performance monitor, discarding results. */ > + void (*ResetPerfMonitor)(struct gl_context *ctx, > + struct gl_perf_monitor_object *m); > + void (*EndPerfMonitor)(struct gl_context *ctx, > + struct gl_perf_monitor_object *m); > + GLboolean (*IsPerfMonitorResultAvailable)(struct gl_context *ctx, > + struct gl_perf_monitor_object > *m); > + void (*GetPerfMonitorResult)(struct gl_context *ctx, > + struct gl_perf_monitor_object *m, > + GLsizei dataSize, > + GLuint *data, > + GLint *bytesWritten); > + /*@}*/ > + > > /** > * \name Vertex Array objects > diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c > index 34615e3..eb93620 100644 > --- a/src/mesa/main/extensions.c > +++ b/src/mesa/main/extensions.c > @@ -291,6 +291,7 @@ static const struct extension extension_table[] = { > { "GL_3DFX_texture_compression_FXT1", > o(TDFX_texture_compression_FXT1), GL, 1999 }, > { "GL_AMD_conservative_depth", > o(ARB_conservative_depth), GL, 2009 }, > { "GL_AMD_draw_buffers_blend", > o(ARB_draw_buffers_blend), GL, 2009 }, > + { "GL_AMD_performance_monitor", > o(AMD_performance_monitor), GL, 2007 }, > { "GL_AMD_seamless_cubemap_per_texture", > o(AMD_seamless_cubemap_per_texture), GL, 2009 }, > { "GL_AMD_shader_stencil_export", > o(ARB_shader_stencil_export), GL, 2009 }, > { "GL_AMD_vertex_shader_layer", > o(AMD_vertex_shader_layer), GL, 2012 }, > diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h > index c88c1c6..59378c7 100644 > --- a/src/mesa/main/mtypes.h > +++ b/src/mesa/main/mtypes.h > @@ -1778,6 +1778,89 @@ struct gl_transform_feedback_state > > > /** > + * A "performance monitor" as described in AMD_performance_monitor. > + */ > +struct gl_perf_monitor_object > +{ > + GLboolean Active; > + > + /** > + * A list of groups with currently active counters. > + * > + * ActiveGroups[g] == n if there are n counters active from group 'g'. > + */ > + unsigned *ActiveGroups; > + > + /** > + * An array of bitsets, subscripted by group ID, then indexed by counter > ID. > + * > + * Checking whether counter 'c' in group 'g' is active can be done via: > + * > + * BITSET_TEST(ActiveCounters[g], c) > + */ > + GLuint **ActiveCounters; > +}; > + > + > +union gl_perf_monitor_counter_value > +{ > + float f; > + uint64_t u64; > + uint32_t u32; > +}; > + > + > +struct gl_perf_monitor_counter > +{ > + /** Human readable name for the counter. */ > + const char *Name; > + > + /** > + * Data type of the counter. Valid values are FLOAT, UNSIGNED_INT, > + * UNSIGNED_INT64_AMD, and PERCENTAGE_AMD. > + */ > + GLenum Type; > + > + /** Minimum counter value. */ > + union gl_perf_monitor_counter_value Minimum; > + > + /** Maximum counter value. */ > + union gl_perf_monitor_counter_value Maximum; > +}; > + > + > +struct gl_perf_monitor_group > +{ > + /** Human readable name for the group. */ > + const char *Name; > + > + /** > + * Maximum number of counters in this group which can be active at the > + * same time. > + */ > + GLuint MaxActiveCounters; > + > + /** Array of counters within this group. */ > + const struct gl_perf_monitor_counter *Counters; > + GLuint NumCounters; > +}; > + > + > +/** > + * Context state for AMD_performance_monitor. > + */ > +struct gl_perf_monitor_state > +{ > + /** Array of performance monitor groups (indexed by group ID) */ > + const struct gl_perf_monitor_group *Groups; > + GLuint NumGroups; > + > + /** The table of all performance monitors. */ > + struct _mesa_HashTable *Monitors; > +}; > + > + > +/** > * Names of the various vertex/fragment program register files, etc. > * > * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c) > @@ -3176,6 +3259,7 @@ struct gl_extensions > GLboolean EXT_vertex_array_bgra; > GLboolean OES_standard_derivatives; > /* vendor extensions */ > + GLboolean AMD_performance_monitor; > GLboolean AMD_seamless_cubemap_per_texture; > GLboolean AMD_vertex_shader_layer; > GLboolean APPLE_object_purgeable; > @@ -3641,6 +3725,8 @@ struct gl_context > > struct gl_transform_feedback_state TransformFeedback; > > + struct gl_perf_monitor_state PerfMonitor; > + > struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */ > struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */ > > diff --git a/src/mesa/main/performance_monitor.c > b/src/mesa/main/performance_monitor.c > new file mode 100644 > index 0000000..8dfa826 > --- /dev/null > +++ b/src/mesa/main/performance_monitor.c > @@ -0,0 +1,609 @@ > +/* > + * Copyright © 2012 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 performance_monitor.c > + * Core Mesa support for the AMD_performance_monitor extension. > + * > + * In order to implement this extension, start by defining two enums: > + * one for Groups, and one for Counters. These will be used as indexes into > + * arrays, so they should start at 0 and increment from there. > + * > + * Counter IDs need to be globally unique. That is, you can't have counter 7 > + * in group A and counter 7 in group B. A global enum of all available > + * counters is a convenient way to guarantee this. > + */ > + > +#include <stdbool.h> > +#include "glheader.h" > +#include "context.h" > +#include "enums.h" > +#include "hash.h" > +#include "macros.h" > +#include "mtypes.h" > +#include "performance_monitor.h" > +#include "bitset.h" > +#include "ralloc.h" > + > +void > +_mesa_init_performance_monitors(struct gl_context *ctx) > +{ > + ctx->PerfMonitor.Monitors = _mesa_NewHashTable(); > + ctx->PerfMonitor.NumGroups = 0; > + ctx->PerfMonitor.Groups = NULL; > +} > + > +static struct gl_perf_monitor_object * > +new_performance_monitor(struct gl_context *ctx, GLuint index) > +{ > + unsigned i; > + struct gl_perf_monitor_object *m = ctx->Driver.NewPerfMonitor(ctx); > + > + if (m == NULL) > + return NULL; > + > + m->ActiveGroups = > + rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups); > + > + m->ActiveCounters = > + ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups); > + > + if (m->ActiveGroups == NULL || m->ActiveCounters == NULL) > + goto fail; > + > + for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) { > + const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i]; > + > + m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD, > + BITSET_WORDS(g->NumCounters)); > + if (m->ActiveCounters[i] == NULL) > + goto fail; > + } > + > + return m; > + > +fail: > + ralloc_free(m->ActiveGroups); > + ralloc_free(m->ActiveCounters); > + ctx->Driver.DeletePerfMonitor(ctx, m); > + return NULL; > +} > + > +static inline struct gl_perf_monitor_object * > +lookup_monitor(struct gl_context *ctx, GLuint id) > +{ > + return (struct gl_perf_monitor_object *) > + _mesa_HashLookup(ctx->PerfMonitor.Monitors, id); > +} > + > +static inline const struct gl_perf_monitor_group * > +get_group(const struct gl_context *ctx, GLuint id) > +{ > + if (id >= ctx->PerfMonitor.NumGroups) > + return NULL; > + > + return &ctx->PerfMonitor.Groups[id]; > +} > + > +static inline const struct gl_perf_monitor_counter * > +get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id) > +{ > + if (id >= group_obj->NumCounters) > + return NULL; > + > + return &group_obj->Counters[id]; > +} > + > +/*****************************************************************************/ > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize, > + GLuint *groups) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + if (numGroups != NULL) > + *numGroups = ctx->PerfMonitor.NumGroups; > + > + if (groupsSize > 0 && groups != NULL) { > + unsigned i; > + unsigned n = MIN2(groupsSize, ctx->PerfMonitor.NumGroups); > + > + /* We just use the index in the Groups array as the ID. */ > + for (i = 0; i < n; i++) > + groups[i] = i; > + } > +} > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters, > + GLint *maxActiveCounters, > + GLsizei countersSize, GLuint *counters) > +{ > + GET_CURRENT_CONTEXT(ctx); > + const struct gl_perf_monitor_group *group_obj = get_group(ctx, group); > + if (group_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCountersAMD(invalid group)"); > + return; > + } > + > + if (maxActiveCounters != NULL) > + *maxActiveCounters = group_obj->MaxActiveCounters; > + > + if (numCounters != NULL) > + *numCounters = group_obj->NumCounters; > + > + if (counters != NULL) { > + unsigned i; > + unsigned n = MIN2(group_obj->NumCounters, countersSize); > + for (i = 0; i < n; i++) { > + /* We just use the index in the Counters array as the ID. */ > + counters[i] = i; > + } > + } > +} > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize, > + GLsizei *length, GLchar *groupString) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + const struct gl_perf_monitor_group *group_obj = get_group(ctx, group); > + > + if (group_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD"); > + return; > + } > + > + if (bufSize == 0) { > + /* Return the number of characters that would be required to hold the > + * group string, excluding the null terminator. > + */ > + if (length != NULL) > + *length = strlen(group_obj->Name); > + } else { > + if (length != NULL) > + *length = MIN2(strlen(group_obj->Name), bufSize); > + if (groupString != NULL) > + strncpy(groupString, group_obj->Name, bufSize); > + } > +} > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter, > + GLsizei bufSize, GLsizei *length, > + GLchar *counterString) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + const struct gl_perf_monitor_group *group_obj; > + const struct gl_perf_monitor_counter *counter_obj; > + > + group_obj = get_group(ctx, group); > + > + if (group_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCounterStringAMD(invalid group)"); > + return; > + } > + > + counter_obj = get_counter(group_obj, counter); > + > + if (counter_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCounterStringAMD(invalid counter)"); > + return; > + } > + > + if (bufSize == 0) { > + /* Return the number of characters that would be required to hold the > + * counter string, excluding the null terminator. > + */ > + if (length != NULL) > + *length = strlen(counter_obj->Name); > + } else { > + if (length != NULL) > + *length = MIN2(strlen(counter_obj->Name), bufSize); > + if (counterString != NULL) > + strncpy(counterString, counter_obj->Name, bufSize); > + } > +} > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum > pname, > + GLvoid *data) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + const struct gl_perf_monitor_group *group_obj; > + const struct gl_perf_monitor_counter *counter_obj; > + > + group_obj = get_group(ctx, group); > + > + if (group_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCounterInfoAMD(invalid group)"); > + return; > + } > + > + counter_obj = get_counter(group_obj, counter); > + > + if (counter_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCounterInfoAMD(invalid counter)"); > + return; > + } > + > + switch (pname) { > + case GL_COUNTER_TYPE_AMD: > + *((GLenum *) data) = counter_obj->Type; > + break; > + > + case GL_COUNTER_RANGE_AMD: > + switch (counter_obj->Type) { > + case GL_FLOAT: > + case GL_PERCENTAGE_AMD: { > + float *f_data = data; > + f_data[0] = counter_obj->Minimum.f; > + f_data[1] = counter_obj->Maximum.f; > + break; > + } > + case GL_UNSIGNED_INT: { > + uint32_t *u32_data = data; > + u32_data[0] = counter_obj->Minimum.u32; > + u32_data[1] = counter_obj->Maximum.u32; > + break; > + } > + case GL_UNSIGNED_INT64_AMD: { > + uint64_t *u64_data = data; > + u64_data[0] = counter_obj->Minimum.u64; > + u64_data[1] = counter_obj->Maximum.u64; > + break; > + } > + default: > + assert(!"Should not get here: invalid counter type"); > + } > + break; > + > + default: > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glGetPerfMonitorCounterInfoAMD(pname)"); > + return; > + } > +} > + > +void GLAPIENTRY > +_mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors) > +{ > + GLuint first; > + GET_CURRENT_CONTEXT(ctx); > + > + if (MESA_VERBOSE & VERBOSE_API) > + _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n); > + > + if (n < 0) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)"); > + return; > + } > + > + if (monitors == NULL) > + return; > + > + /* We don't actually need them to be contiguous, but this is what > + * the rest of Mesa does, so we may as well. > + */ > + first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, n); > + if (first) { > + GLsizei i; > + for (i = 0; i < n; i++) { > + struct gl_perf_monitor_object *m = > + new_performance_monitor(ctx, first + i); > + if (!m) { > + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD"); > + return; > + } > + monitors[i] = first + i; > + _mesa_HashInsert(ctx->PerfMonitor.Monitors, first + i, m); > + } > + } else { > + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD"); > + return; > + } > +} > + > +void GLAPIENTRY > +_mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors) > +{ > + GLint i; > + GET_CURRENT_CONTEXT(ctx); > + > + if (MESA_VERBOSE & VERBOSE_API) > + _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n); > + > + if (n < 0) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)"); > + return; > + } > + > + if (monitors == NULL) > + return; > + > + for (i = 0; i < n; i++) { > + struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]); > + > + if (m) { > + /* Give the driver a chance to stop the monitor if it's active. */ > + if (m->Active) > + ctx->Driver.ResetPerfMonitor(ctx, m); > + > + _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]); > + ralloc_free(m->ActiveGroups); > + ralloc_free(m->ActiveCounters); > + ctx->Driver.DeletePerfMonitor(ctx, m); > + } else { > + /* "INVALID_VALUE error will be generated if any of the monitor IDs > + * in the <monitors> parameter to DeletePerfMonitorsAMD do not > + * reference a valid generated monitor ID." > + */ > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glDeletePerfMonitorsAMD(invalid monitor)"); > + } > + } > +} > + > +void GLAPIENTRY > +_mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable, > + GLuint group, GLint numCounters, > + GLuint *counterList) > +{ > + GET_CURRENT_CONTEXT(ctx); > + unsigned i; > + struct gl_perf_monitor_object *m; > + const struct gl_perf_monitor_group *group_obj; > + > + m = lookup_monitor(ctx, monitor); > + > + /* "INVALID_VALUE error will be generated if the <monitor> parameter to > + * SelectPerfMonitorCountersAMD does not reference a monitor created by > + * GenPerfMonitorsAMD." > + */ > + if (m == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glSelectPerfMonitorCountersAMD(invalid monitor)"); > + return; > + } > + > + group_obj = get_group(ctx, group); > + > + /* "INVALID_VALUE error will be generated if the <group> parameter to > + * GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD, > + * GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or > + * SelectPerfMonitorCountersAMD does not reference a valid group ID." > + */ > + if (group_obj == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glSelectPerfMonitorCountersAMD(invalid group)"); > + return; > + } > + > + /* "INVALID_VALUE error will be generated if the <numCounters> parameter > to > + * SelectPerfMonitorCountersAMD is less than 0." > + */ > + if (numCounters < 0) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glSelectPerfMonitorCountersAMD(numCounters < 0)"); > + return; > + } > + > + /* "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." > + */ > + ctx->Driver.ResetPerfMonitor(ctx, m); > + > + /* Sanity check the counter ID list. */ > + for (i = 0; i < numCounters; i++) { > + if (counterList[i] >= group_obj->NumCounters) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glSelectPerfMonitorCountersAMD(invalid counter ID)"); > + return; > + } > + } > + > + if (enable) { > + /* Enable the counters */ > + for (i = 0; i < numCounters; i++) { > + ++m->ActiveGroups[group]; > + BITSET_SET(m->ActiveCounters[group], counterList[i]); > + } > + } else { > + /* Disable the counters */ > + for (i = 0; i < numCounters; i++) { > + --m->ActiveGroups[group]; > + BITSET_CLEAR(m->ActiveCounters[group], counterList[i]); > + } > + } > +} > + > +void GLAPIENTRY > +_mesa_BeginPerfMonitorAMD(GLuint monitor) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor); > + > + if (m == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glBeginPerfMonitorAMD(invalid monitor)"); > + return; > + } > + > + /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is > + * called when a performance monitor is already active." > + */ > + if (m->Active) { > + _mesa_error(ctx, GL_INVALID_OPERATION, > + "glBeginPerfMonitor(already active)"); > + return; > + } > + > + /* The driver is free to return false if it can't begin monitoring for > + * any reason. This translates into an INVALID_OPERATION error. > + */ > + if (ctx->Driver.BeginPerfMonitor(ctx, m)) { > + m->Active = true; > + } else { > + _mesa_error(ctx, GL_INVALID_OPERATION, > + "glBeginPerfMonitor(driver unable to begin monitoring)"); > + } > +} > + > +void GLAPIENTRY > +_mesa_EndPerfMonitorAMD(GLuint monitor) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor); > + > + if (m == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid > monitor)"); > + return; > + } > + > + /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is > called > + * when a performance monitor is not currently started." > + */ > + if (!m->Active) { > + _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginPerfMonitor(not > active)"); > + return; > + } > + > + ctx->Driver.EndPerfMonitor(ctx, m); > + > + m->Active = false; > +} > + > +/** > + * Return the number of bytes needed to store a monitor's result. > + */ > +static unsigned > +perf_monitor_result_size(const struct gl_context *ctx, > + const struct gl_perf_monitor_object *m) > +{ > + unsigned group, counter; > + unsigned size = 0; > + > + for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) { > + const struct gl_perf_monitor_group *g = > &ctx->PerfMonitor.Groups[group]; > + for (counter = 0; counter < g->NumCounters; counter++) { > + const struct gl_perf_monitor_counter *c = &g->Counters[counter]; > + > + if (!BITSET_TEST(m->ActiveCounters[group], counter)) > + continue; > + > + size += sizeof(uint32_t); /* Group ID */ > + size += sizeof(uint32_t); /* Counter ID */ > + size += _mesa_perf_monitor_counter_size(c); > + } > + } > + return size; > +} > + > +void GLAPIENTRY > +_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, > + GLsizei dataSize, GLuint *data, > + GLint *bytesWritten) > +{ > + GET_CURRENT_CONTEXT(ctx); > + > + struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor); > + > + if (m == NULL) { > + _mesa_error(ctx, GL_INVALID_VALUE, > + "glGetPerfMonitorCounterDataAMD(invalid monitor)"); > + return; > + } > + > + /* "It is an INVALID_OPERATION error for <data> to be NULL." */ > + if (data == NULL) { > + _mesa_error(ctx, GL_INVALID_OPERATION, > + "glGetPerfMonitorCounterDataAMD(data == NULL)"); > + return; > + } > + > + /* We need at least enough room for a single value. */ > + if (dataSize < sizeof(GLuint)) { > + if (bytesWritten != NULL) > + *bytesWritten = 0; > + return; > + } > + > + /* AMD appears to return 0 for all queries unless a result is available. > */ > + if (!ctx->Driver.IsPerfMonitorResultAvailable(ctx, m)) { > + *data = 0; > + if (bytesWritten != NULL) > + *bytesWritten = sizeof(GLuint); > + return; > + } > + > + switch (pname) { > + case GL_PERFMON_RESULT_AVAILABLE_AMD: > + *data = 1; > + if (bytesWritten != NULL) > + *bytesWritten = sizeof(GLuint); > + break; > + case GL_PERFMON_RESULT_SIZE_AMD: > + *data = perf_monitor_result_size(ctx, m); > + if (bytesWritten != NULL) > + *bytesWritten = sizeof(GLuint); > + break; > + case GL_PERFMON_RESULT_AMD: > + ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, bytesWritten); > + break; > + default: > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glGetPerfMonitorCounterDataAMD(pname)"); > + } > +} > + > +/** > + * Returns how many bytes a counter's value takes up. > + */ > +unsigned > +_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c) > +{ > + switch (c->Type) { > + case GL_FLOAT: > + case GL_PERCENTAGE_AMD: > + return sizeof(GLfloat); > + case GL_UNSIGNED_INT: > + return sizeof(GLuint); > + case GL_UNSIGNED_INT64_AMD: > + return sizeof(uint64_t); > + default: > + assert(!"Should not get here: invalid counter type"); > + return 0; > + } > +} > diff --git a/src/mesa/main/performance_monitor.h > b/src/mesa/main/performance_monitor.h > new file mode 100644 > index 0000000..a852a41 > --- /dev/null > +++ b/src/mesa/main/performance_monitor.h > @@ -0,0 +1,85 @@ > +/* > + * Copyright © 2012 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 performance_monitor.h > + * Core Mesa support for the AMD_performance_monitor extension. > + */ > + > +#pragma once > +#ifndef PERFORMANCE_MONITOR_H > +#define PERFORMANCE_MONITOR_H > + > +#include "glheader.h" > + > +extern void > +_mesa_init_performance_monitors(struct gl_context *ctx); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize, > + GLuint *groups); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters, > + GLint *maxActiveCounters, > + GLsizei countersSize, GLuint *counters); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize, > + GLsizei *length, GLchar *groupString); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter, > + GLsizei bufSize, GLsizei *length, > + GLchar *counterString); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum > pname, > + GLvoid *data); > + > +extern void GLAPIENTRY > +_mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors); > + > +extern void GLAPIENTRY > +_mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors); > + > +extern void GLAPIENTRY > +_mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable, > + GLuint group, GLint numCounters, > + GLuint *counterList); > + > +extern void GLAPIENTRY > +_mesa_BeginPerfMonitorAMD(GLuint monitor); > + > +extern void GLAPIENTRY > +_mesa_EndPerfMonitorAMD(GLuint monitor); > + > +extern void GLAPIENTRY > +_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, > + GLsizei dataSize, GLuint *data, > + GLint *bytesWritten); > + > +unsigned > +_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *); > + > +#endif > diff --git a/src/mesa/main/tests/dispatch_sanity.cpp > b/src/mesa/main/tests/dispatch_sanity.cpp > index bea6e96..244173a 100644 > --- a/src/mesa/main/tests/dispatch_sanity.cpp > +++ b/src/mesa/main/tests/dispatch_sanity.cpp > @@ -908,6 +908,19 @@ const struct function gl_core_functions_possible[] = { > { "glObjectLabel", 11, -1 }, > { "glObjectPtrLabel", 11, -1 }, > > + /* GL_AMD_performance_monitor */ > + { "glGetPerfMonitorGroupsAMD", 11, -1 }, > + { "glGetPerfMonitorCountersAMD", 11, -1 }, > + { "glGetPerfMonitorGroupStringAMD", 11, -1 }, > + { "glGetPerfMonitorCounterStringAMD", 11, -1 }, > + { "glGetPerfMonitorCounterInfoAMD", 11, -1 }, > + { "glGenPerfMonitorsAMD", 11, -1 }, > + { "glDeletePerfMonitorsAMD", 11, -1 }, > + { "glSelectPerfMonitorCountersAMD", 11, -1 }, > + { "glBeginPerfMonitorAMD", 11, -1 }, > + { "glEndPerfMonitorAMD", 11, -1 }, > + { "glGetPerfMonitorCounterDataAMD", 11, -1 }, > + > { NULL, 0, -1 } > }; > > _______________________________________________ mesa-dev mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/mesa-dev
