[Mesa-dev] [PATCH 1/3] mesa: Add core support for the GL_AMD_performance_monitor extension.

Ian Romanick idr at freedesktop.org
Fri Sep 20 14:53:52 PDT 2013


On 09/20/2013 04:42 PM, Kenneth Graunke wrote:
> On 09/20/2013 07:55 AM, Brian Paul wrote:
>> On Thu, Sep 19, 2013 at 5:27 PM, Kenneth Graunke <kenneth at whitecape.org> wrote:
> [snip]
>>> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
>>> index 6d700ec..70dba6e 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;
>>
>> GLuint?
>>
> 
> I chose 'unsigned' over 'GLuint' here since it's only used internally,
> and never exposed by the API.  But I can switch if you prefer that.
> 
>>> +
>>> +   /**
>>> +    * 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;
>>
>> GLbitfield?
> 
> The type here is actually BITSET_WORD (from bitset.h), which is a
> #define for GLuint.  Including bitset.h from mtypes.h led to all kinds
> of problems, so I just used GLuint.
> 
> It seems like we could do something better, but I'm not sure what.

Could we make BITSET_WORD be uint32_t?  I suspect that's a type from
before we had our own inttypes.h...

>>> +};
>>> +
>>> +
>>> +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.
>>> +    */
>>> +   GLint MaxActiveCounters;
>>
>> GLuint?
> 
> That would make sense, but for some reason the AMD_performance_monitor
> extension exposes this value as a GLint:
> 
> void GetPerfMonitorCountersAMD(uint group, int *numCounters,
>                                int *maxActiveCounters, sizei countersSize,
>                                uint *counters)
> 
> I figured it should probably match...
> 
>>> +
>>> +   /** Array of counters within this group. */
>>> +   const struct gl_perf_monitor_counter *Counters;
>>> +   GLint 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;
>>> +   GLint NumGroups;
>>
>> GLuint?
> 
> Likewise, the extension exposes this as a GLint:
> 
> void GetPerfMonitorGroupsAMD(int *numGroups, sizei groupsSize,
>                              uint *groups)
> 
> I don't know why...GLuint would have made more sense.  Of course, nobody
> is going to have enough groups for it to make a difference :)
> 
>>
>>> +
>>> +   /** 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)
>>> @@ -3153,6 +3236,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;
>>> @@ -3618,6 +3702,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..0782219
>>> --- /dev/null
>>> +++ b/src/mesa/main/performance_monitor.c
>>> @@ -0,0 +1,606 @@
>>> +/*
>>> + * 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 *
>>> +_mesa_new_performance_monitor(struct gl_context *ctx, GLuint index)
> 
> I've removed the _mesa_ prefix on this function in response to your
> later comments, as it's static.
> 
>>> +{
>>> +   int i;
>>
>> If NumGroups is changed to unsigned (above), this should be unsigned too.
>>
>>
>>> +   struct gl_perf_monitor_object *m = ctx->Driver.NewPerfMonitor(ctx);
>>
>> Check for m=NULL and raise GL_OUT_OF_MEMORY?
> 
> Good catch.  I've added:
> 
>    if (m == NULL)
>       return NULL;
> 
> The caller already detected a NULL return value and raises
> GL_OUT_OF_MEMORY.  We just would have crashed first. :)
> 
>>> +
>>> +   m->ActiveGroups =
>>> +      rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
>>> +
>>> +   m->ActiveCounters =
>>> +      ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
>>
>> NULL ptr checks?
> 
> Right...I've added:
> 
>    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));
> 
> and:
>    if (m->ActiveCounters[i] == NULL)
>       goto fail;
> 
>>> +   }
>>> +
>>> +   return m;
> 
> and finally:
> 
> 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) {
>>> +      int i;
>>> +      int 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) {
>>> +      int i;
>>> +      for (i = 0; i < MIN2(group_obj->NumCounters, countersSize); i++) {
>>
>> If MIN2 gets evaluated for each iteration, maybe put it in an 'n' var
>> like above.
> 
> Good call.  Changed.
> 
>>> +         /* 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);
>>
>> I think you need to replace bufSize there with the value you put in *length.
> 
> It shouldn't matter.  The names should all be proper NULL-terminated C
> strings, so the strncpy will automatically stop at
> strlen(group_obj->Name).  Passing bufSize to strncpy catches the case
> where the buffer is smaller than the group name.
> 
> If the caller supplies a length pointer, we'll write the actual number
> of bytes copied, which is the minimum of the actual string length and
> the buffer size.
> 
> I'm pretty sure I hit all of these cases in Piglit's
> tests/spec/amd_performance_monitor/api.c test.
> 
>>
>>> +   }
>>> +}
>>> +
>>> +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);
>>
>> bufSize issue again.
>>
> [snip]
>>> +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 should either set m->Active to true or raise an error:
>>> +    * "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
>>> +    *  unable to begin monitoring with the currently selected counters."
>>> +    */
>>> +   ctx->Driver.BeginPerfMonitor(ctx, m);
>>
>> Set m->Active = true here?  We set it to false in the End function below.
> 
> See the above comment.  The spec allows drivers to arbitrarily refuse to
> start monitoring due to unknown constraints.  It's sort of a cop-out;
> the extension is general, and each GPU has weird restrictions on
> performance counters that would be hard to expose.
> 
> So the driver needs to set m->Active or raise an error.
> 
> In contrast, it should always be possible to /stop/ counting, so I made
> the core code set m->Active = false.  I could move that to the driver
> for consistency, I suppose.  Do you have a preference?
> 
>>
>>> +}
>>> +
>>> +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(already inactive)");
>>
>> "glEndPerfMonitor(not active)"
> 
> I like that better.  Changed.
> 
>>
>>> +      return;
>>> +   }
>>> +
>>> +   ctx->Driver.EndPerfMonitor(ctx, m);
>>> +
>>> +   m->Active = false;
>>> +}
>>> +
>>> +/**
>>> + * Return the number of bytes needed to store a monitor's result.
>>> + */
>>> +static unsigned
>>> +_mesa_perf_monitor_result_size(const struct gl_context *ctx,
>>> +                               const struct gl_perf_monitor_object *m)
>>
>> I don't usually put _mesa_ on static functions like this.  I think ctx
>> could be const-qualified too.
> 
> Oops, right.  I've removed the _mesa_ prefix.  ctx was already const
> qualified.
> 
>>
>>> +{
>>> +   unsigned size = 0;
>>> +   int group, counter;
>>
>> unsigned group, counter vars to avoid MSVC signed/unsigned comparison
>> warnings below.
>>
>>
>>> +
>>> +   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 = _mesa_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;
>>> +   }
>>> +}
>>> +
>>> +/*
>>> +void
>>> +_mesa_init_perf_monitors(struct gl_context *ctx,
>>> +                         const struct gl_perf_monitor_counter *counters,
>>> +                         unsigned num_counters,
>>> +                         const struct gl_perf_monitor_group *groups,
>>> +                         unsigned num_groups)
>>> +{
>>> +   ctx->PerfMonitor.Groups = groups;
>>> +   ctx->PerfMonitor.NumGroups = num_groups;
>>> +   ctx->PerfMonitor.Counters = counters;
>>> +   ctx->PerfMonitor.NumCounters = num_counters;
>>> +}
>>> +*/
>>> 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
>>
>>
>>
>> Reviewed-by: Brian Paul <brianp at vmware.com>
> 
> Thanks Brian!
> 
> --Ken
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> 



More information about the mesa-dev mailing list