1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * \file performance_monitor.c
26  * Core Mesa support for the AMD_performance_monitor extension.
27  *
28  * In order to implement this extension, start by defining two enums:
29  * one for Groups, and one for Counters.  These will be used as indexes into
30  * arrays, so they should start at 0 and increment from there.
31  *
32  * Counter IDs need to be globally unique.  That is, you can't have counter 7
33  * in group A and counter 7 in group B.  A global enum of all available
34  * counters is a convenient way to guarantee this.
35  */
36 
37 #include <stdbool.h>
38 #include "glheader.h"
39 #include "context.h"
40 #include "enums.h"
41 #include "hash.h"
42 #include "macros.h"
43 #include "mtypes.h"
44 #include "performance_monitor.h"
45 #include "util/bitset.h"
46 #include "util/ralloc.h"
47 
48 void
_mesa_init_performance_monitors(struct gl_context * ctx)49 _mesa_init_performance_monitors(struct gl_context *ctx)
50 {
51    ctx->PerfMonitor.Monitors = _mesa_NewHashTable();
52    ctx->PerfMonitor.NumGroups = 0;
53    ctx->PerfMonitor.Groups = NULL;
54 }
55 
56 static inline void
init_groups(struct gl_context * ctx)57 init_groups(struct gl_context *ctx)
58 {
59    if (unlikely(!ctx->PerfMonitor.Groups))
60       ctx->Driver.InitPerfMonitorGroups(ctx);
61 }
62 
63 static struct gl_perf_monitor_object *
new_performance_monitor(struct gl_context * ctx,GLuint index)64 new_performance_monitor(struct gl_context *ctx, GLuint index)
65 {
66    unsigned i;
67    struct gl_perf_monitor_object *m = ctx->Driver.NewPerfMonitor(ctx);
68 
69    if (m == NULL)
70       return NULL;
71 
72    m->Name = index;
73 
74    m->Active = false;
75 
76    m->ActiveGroups =
77       rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
78 
79    m->ActiveCounters =
80       ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
81 
82    if (m->ActiveGroups == NULL || m->ActiveCounters == NULL)
83       goto fail;
84 
85    for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) {
86       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i];
87 
88       m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD,
89                                            BITSET_WORDS(g->NumCounters));
90       if (m->ActiveCounters[i] == NULL)
91          goto fail;
92    }
93 
94    return m;
95 
96 fail:
97    ralloc_free(m->ActiveGroups);
98    ralloc_free(m->ActiveCounters);
99    ctx->Driver.DeletePerfMonitor(ctx, m);
100    return NULL;
101 }
102 
103 static void
free_performance_monitor(GLuint key,void * data,void * user)104 free_performance_monitor(GLuint key, void *data, void *user)
105 {
106    struct gl_perf_monitor_object *m = data;
107    struct gl_context *ctx = user;
108 
109    ralloc_free(m->ActiveGroups);
110    ralloc_free(m->ActiveCounters);
111    ctx->Driver.DeletePerfMonitor(ctx, m);
112 }
113 
114 void
_mesa_free_performance_monitors(struct gl_context * ctx)115 _mesa_free_performance_monitors(struct gl_context *ctx)
116 {
117    _mesa_HashDeleteAll(ctx->PerfMonitor.Monitors,
118                        free_performance_monitor, ctx);
119    _mesa_DeleteHashTable(ctx->PerfMonitor.Monitors);
120 }
121 
122 static inline struct gl_perf_monitor_object *
lookup_monitor(struct gl_context * ctx,GLuint id)123 lookup_monitor(struct gl_context *ctx, GLuint id)
124 {
125    return (struct gl_perf_monitor_object *)
126       _mesa_HashLookup(ctx->PerfMonitor.Monitors, id);
127 }
128 
129 static inline const struct gl_perf_monitor_group *
get_group(const struct gl_context * ctx,GLuint id)130 get_group(const struct gl_context *ctx, GLuint id)
131 {
132    if (id >= ctx->PerfMonitor.NumGroups)
133       return NULL;
134 
135    return &ctx->PerfMonitor.Groups[id];
136 }
137 
138 static inline const struct gl_perf_monitor_counter *
get_counter(const struct gl_perf_monitor_group * group_obj,GLuint id)139 get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
140 {
141    if (id >= group_obj->NumCounters)
142       return NULL;
143 
144    return &group_obj->Counters[id];
145 }
146 
147 /*****************************************************************************/
148 
149 void GLAPIENTRY
_mesa_GetPerfMonitorGroupsAMD(GLint * numGroups,GLsizei groupsSize,GLuint * groups)150 _mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
151                               GLuint *groups)
152 {
153    GET_CURRENT_CONTEXT(ctx);
154    init_groups(ctx);
155 
156    if (numGroups != NULL)
157       *numGroups = ctx->PerfMonitor.NumGroups;
158 
159    if (groupsSize > 0 && groups != NULL) {
160       unsigned i;
161       unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
162 
163       /* We just use the index in the Groups array as the ID. */
164       for (i = 0; i < n; i++)
165          groups[i] = i;
166    }
167 }
168 
169 void GLAPIENTRY
_mesa_GetPerfMonitorCountersAMD(GLuint group,GLint * numCounters,GLint * maxActiveCounters,GLsizei countersSize,GLuint * counters)170 _mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
171                                 GLint *maxActiveCounters,
172                                 GLsizei countersSize, GLuint *counters)
173 {
174    GET_CURRENT_CONTEXT(ctx);
175    const struct gl_perf_monitor_group *group_obj;
176 
177    init_groups(ctx);
178 
179    group_obj = get_group(ctx, group);
180    if (group_obj == NULL) {
181       _mesa_error(ctx, GL_INVALID_VALUE,
182                   "glGetPerfMonitorCountersAMD(invalid group)");
183       return;
184    }
185 
186    if (maxActiveCounters != NULL)
187       *maxActiveCounters = group_obj->MaxActiveCounters;
188 
189    if (numCounters != NULL)
190       *numCounters = group_obj->NumCounters;
191 
192    if (counters != NULL) {
193       unsigned i;
194       unsigned n = MIN2(group_obj->NumCounters, (GLuint) countersSize);
195       for (i = 0; i < n; i++) {
196          /* We just use the index in the Counters array as the ID. */
197          counters[i] = i;
198       }
199    }
200 }
201 
202 void GLAPIENTRY
_mesa_GetPerfMonitorGroupStringAMD(GLuint group,GLsizei bufSize,GLsizei * length,GLchar * groupString)203 _mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
204                                    GLsizei *length, GLchar *groupString)
205 {
206    GET_CURRENT_CONTEXT(ctx);
207    const struct gl_perf_monitor_group *group_obj;
208 
209    init_groups(ctx);
210 
211    group_obj = get_group(ctx, group);
212    if (group_obj == NULL) {
213       _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
214       return;
215    }
216 
217    if (bufSize == 0) {
218       /* Return the number of characters that would be required to hold the
219        * group string, excluding the null terminator.
220        */
221       if (length != NULL)
222          *length = strlen(group_obj->Name);
223    } else {
224       if (length != NULL)
225          *length = MIN2(strlen(group_obj->Name), bufSize);
226       if (groupString != NULL)
227          strncpy(groupString, group_obj->Name, bufSize);
228    }
229 }
230 
231 void GLAPIENTRY
_mesa_GetPerfMonitorCounterStringAMD(GLuint group,GLuint counter,GLsizei bufSize,GLsizei * length,GLchar * counterString)232 _mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
233                                      GLsizei bufSize, GLsizei *length,
234                                      GLchar *counterString)
235 {
236    GET_CURRENT_CONTEXT(ctx);
237 
238    const struct gl_perf_monitor_group *group_obj;
239    const struct gl_perf_monitor_counter *counter_obj;
240 
241    init_groups(ctx);
242 
243    group_obj = get_group(ctx, group);
244 
245    if (group_obj == NULL) {
246       _mesa_error(ctx, GL_INVALID_VALUE,
247                   "glGetPerfMonitorCounterStringAMD(invalid group)");
248       return;
249    }
250 
251    counter_obj = get_counter(group_obj, counter);
252 
253    if (counter_obj == NULL) {
254       _mesa_error(ctx, GL_INVALID_VALUE,
255                   "glGetPerfMonitorCounterStringAMD(invalid counter)");
256       return;
257    }
258 
259    if (bufSize == 0) {
260       /* Return the number of characters that would be required to hold the
261        * counter string, excluding the null terminator.
262        */
263       if (length != NULL)
264          *length = strlen(counter_obj->Name);
265    } else {
266       if (length != NULL)
267          *length = MIN2(strlen(counter_obj->Name), bufSize);
268       if (counterString != NULL)
269          strncpy(counterString, counter_obj->Name, bufSize);
270    }
271 }
272 
273 void GLAPIENTRY
_mesa_GetPerfMonitorCounterInfoAMD(GLuint group,GLuint counter,GLenum pname,GLvoid * data)274 _mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
275                                    GLvoid *data)
276 {
277    GET_CURRENT_CONTEXT(ctx);
278 
279    const struct gl_perf_monitor_group *group_obj;
280    const struct gl_perf_monitor_counter *counter_obj;
281 
282    init_groups(ctx);
283 
284    group_obj = get_group(ctx, group);
285 
286    if (group_obj == NULL) {
287       _mesa_error(ctx, GL_INVALID_VALUE,
288                   "glGetPerfMonitorCounterInfoAMD(invalid group)");
289       return;
290    }
291 
292    counter_obj = get_counter(group_obj, counter);
293 
294    if (counter_obj == NULL) {
295       _mesa_error(ctx, GL_INVALID_VALUE,
296                   "glGetPerfMonitorCounterInfoAMD(invalid counter)");
297       return;
298    }
299 
300    switch (pname) {
301    case GL_COUNTER_TYPE_AMD:
302       *((GLenum *) data) = counter_obj->Type;
303       break;
304 
305    case GL_COUNTER_RANGE_AMD:
306       switch (counter_obj->Type) {
307       case GL_FLOAT:
308       case GL_PERCENTAGE_AMD: {
309          float *f_data = data;
310          f_data[0] = counter_obj->Minimum.f;
311          f_data[1] = counter_obj->Maximum.f;
312          break;
313       }
314       case GL_UNSIGNED_INT: {
315          uint32_t *u32_data = data;
316          u32_data[0] = counter_obj->Minimum.u32;
317          u32_data[1] = counter_obj->Maximum.u32;
318          break;
319       }
320       case GL_UNSIGNED_INT64_AMD: {
321          uint64_t *u64_data = data;
322          u64_data[0] = counter_obj->Minimum.u64;
323          u64_data[1] = counter_obj->Maximum.u64;
324          break;
325       }
326       default:
327          assert(!"Should not get here: invalid counter type");
328       }
329       break;
330 
331    default:
332       _mesa_error(ctx, GL_INVALID_ENUM,
333                   "glGetPerfMonitorCounterInfoAMD(pname)");
334       return;
335    }
336 }
337 
338 void GLAPIENTRY
_mesa_GenPerfMonitorsAMD(GLsizei n,GLuint * monitors)339 _mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
340 {
341    GLuint first;
342    GET_CURRENT_CONTEXT(ctx);
343 
344    if (MESA_VERBOSE & VERBOSE_API)
345       _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
346 
347    init_groups(ctx);
348 
349    if (n < 0) {
350       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
351       return;
352    }
353 
354    if (monitors == NULL)
355       return;
356 
357    /* We don't actually need them to be contiguous, but this is what
358     * the rest of Mesa does, so we may as well.
359     */
360    first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, n);
361    if (first) {
362       GLsizei i;
363       for (i = 0; i < n; i++) {
364          struct gl_perf_monitor_object *m =
365             new_performance_monitor(ctx, first + i);
366          if (!m) {
367             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
368             return;
369          }
370          monitors[i] = first + i;
371          _mesa_HashInsert(ctx->PerfMonitor.Monitors, first + i, m);
372       }
373    } else {
374       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
375       return;
376    }
377 }
378 
379 void GLAPIENTRY
_mesa_DeletePerfMonitorsAMD(GLsizei n,GLuint * monitors)380 _mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
381 {
382    GLint i;
383    GET_CURRENT_CONTEXT(ctx);
384 
385    if (MESA_VERBOSE & VERBOSE_API)
386       _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
387 
388    if (n < 0) {
389       _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
390       return;
391    }
392 
393    if (monitors == NULL)
394       return;
395 
396    for (i = 0; i < n; i++) {
397       struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
398 
399       if (m) {
400          /* Give the driver a chance to stop the monitor if it's active. */
401          if (m->Active) {
402             ctx->Driver.ResetPerfMonitor(ctx, m);
403             m->Ended = false;
404          }
405 
406          _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
407          ralloc_free(m->ActiveGroups);
408          ralloc_free(m->ActiveCounters);
409          ctx->Driver.DeletePerfMonitor(ctx, m);
410       } else {
411          /* "INVALID_VALUE error will be generated if any of the monitor IDs
412           *  in the <monitors> parameter to DeletePerfMonitorsAMD do not
413           *  reference a valid generated monitor ID."
414           */
415          _mesa_error(ctx, GL_INVALID_VALUE,
416                      "glDeletePerfMonitorsAMD(invalid monitor)");
417       }
418    }
419 }
420 
421 void GLAPIENTRY
_mesa_SelectPerfMonitorCountersAMD(GLuint monitor,GLboolean enable,GLuint group,GLint numCounters,GLuint * counterList)422 _mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
423                                    GLuint group, GLint numCounters,
424                                    GLuint *counterList)
425 {
426    GET_CURRENT_CONTEXT(ctx);
427    int i;
428    struct gl_perf_monitor_object *m;
429    const struct gl_perf_monitor_group *group_obj;
430 
431    m = lookup_monitor(ctx, monitor);
432 
433    /* "INVALID_VALUE error will be generated if the <monitor> parameter to
434     *  SelectPerfMonitorCountersAMD does not reference a monitor created by
435     *  GenPerfMonitorsAMD."
436     */
437    if (m == NULL) {
438       _mesa_error(ctx, GL_INVALID_VALUE,
439                   "glSelectPerfMonitorCountersAMD(invalid monitor)");
440       return;
441    }
442 
443    group_obj = get_group(ctx, group);
444 
445    /* "INVALID_VALUE error will be generated if the <group> parameter to
446     *  GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
447     *  GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
448     *  SelectPerfMonitorCountersAMD does not reference a valid group ID."
449     */
450    if (group_obj == NULL) {
451       _mesa_error(ctx, GL_INVALID_VALUE,
452                   "glSelectPerfMonitorCountersAMD(invalid group)");
453       return;
454    }
455 
456    /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
457     *  SelectPerfMonitorCountersAMD is less than 0."
458     */
459    if (numCounters < 0) {
460       _mesa_error(ctx, GL_INVALID_VALUE,
461                   "glSelectPerfMonitorCountersAMD(numCounters < 0)");
462       return;
463    }
464 
465    /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
466     *  results for that monitor become invalidated and the result queries
467     *  PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
468     */
469    ctx->Driver.ResetPerfMonitor(ctx, m);
470 
471    /* Sanity check the counter ID list. */
472    for (i = 0; i < numCounters; i++) {
473       if (counterList[i] >= group_obj->NumCounters) {
474          _mesa_error(ctx, GL_INVALID_VALUE,
475                      "glSelectPerfMonitorCountersAMD(invalid counter ID)");
476          return;
477       }
478    }
479 
480    if (enable) {
481       /* Enable the counters */
482       for (i = 0; i < numCounters; i++) {
483          if (!BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
484             ++m->ActiveGroups[group];
485             BITSET_SET(m->ActiveCounters[group], counterList[i]);
486          }
487       }
488    } else {
489       /* Disable the counters */
490       for (i = 0; i < numCounters; i++) {
491          if (BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
492             --m->ActiveGroups[group];
493             BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
494          }
495       }
496    }
497 }
498 
499 void GLAPIENTRY
_mesa_BeginPerfMonitorAMD(GLuint monitor)500 _mesa_BeginPerfMonitorAMD(GLuint monitor)
501 {
502    GET_CURRENT_CONTEXT(ctx);
503 
504    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
505 
506    if (m == NULL) {
507       _mesa_error(ctx, GL_INVALID_VALUE,
508                   "glBeginPerfMonitorAMD(invalid monitor)");
509       return;
510    }
511 
512    /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
513     *  called when a performance monitor is already active."
514     */
515    if (m->Active) {
516       _mesa_error(ctx, GL_INVALID_OPERATION,
517                   "glBeginPerfMonitor(already active)");
518       return;
519    }
520 
521    /* The driver is free to return false if it can't begin monitoring for
522     * any reason.  This translates into an INVALID_OPERATION error.
523     */
524    if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
525       m->Active = true;
526       m->Ended = false;
527    } else {
528       _mesa_error(ctx, GL_INVALID_OPERATION,
529                   "glBeginPerfMonitor(driver unable to begin monitoring)");
530    }
531 }
532 
533 void GLAPIENTRY
_mesa_EndPerfMonitorAMD(GLuint monitor)534 _mesa_EndPerfMonitorAMD(GLuint monitor)
535 {
536    GET_CURRENT_CONTEXT(ctx);
537 
538    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
539 
540    if (m == NULL) {
541       _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
542       return;
543    }
544 
545    /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
546     *  when a performance monitor is not currently started."
547     */
548    if (!m->Active) {
549       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndPerfMonitor(not active)");
550       return;
551    }
552 
553    ctx->Driver.EndPerfMonitor(ctx, m);
554 
555    m->Active = false;
556    m->Ended = true;
557 }
558 
559 /**
560  * Return the number of bytes needed to store a monitor's result.
561  */
562 static unsigned
perf_monitor_result_size(const struct gl_context * ctx,const struct gl_perf_monitor_object * m)563 perf_monitor_result_size(const struct gl_context *ctx,
564                          const struct gl_perf_monitor_object *m)
565 {
566    unsigned group, counter;
567    unsigned size = 0;
568 
569    for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
570       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
571 
572       BITSET_FOREACH_SET(counter, m->ActiveCounters[group], g->NumCounters) {
573          const struct gl_perf_monitor_counter *c = &g->Counters[counter];
574 
575          size += sizeof(uint32_t); /* Group ID */
576          size += sizeof(uint32_t); /* Counter ID */
577          size += _mesa_perf_monitor_counter_size(c);
578       }
579    }
580    return size;
581 }
582 
583 void GLAPIENTRY
_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor,GLenum pname,GLsizei dataSize,GLuint * data,GLint * bytesWritten)584 _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
585                                    GLsizei dataSize, GLuint *data,
586                                    GLint *bytesWritten)
587 {
588    GET_CURRENT_CONTEXT(ctx);
589 
590    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
591    bool result_available;
592 
593    if (m == NULL) {
594       _mesa_error(ctx, GL_INVALID_VALUE,
595                   "glGetPerfMonitorCounterDataAMD(invalid monitor)");
596       return;
597    }
598 
599    /* "It is an INVALID_OPERATION error for <data> to be NULL." */
600    if (data == NULL) {
601       _mesa_error(ctx, GL_INVALID_OPERATION,
602                   "glGetPerfMonitorCounterDataAMD(data == NULL)");
603       return;
604    }
605 
606    /* We need at least enough room for a single value. */
607    if (dataSize < sizeof(GLuint)) {
608       if (bytesWritten != NULL)
609          *bytesWritten = 0;
610       return;
611    }
612 
613    /* If the monitor has never ended, there is no result. */
614    result_available = m->Ended &&
615       ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
616 
617    /* AMD appears to return 0 for all queries unless a result is available. */
618    if (!result_available) {
619       *data = 0;
620       if (bytesWritten != NULL)
621          *bytesWritten = sizeof(GLuint);
622       return;
623    }
624 
625    switch (pname) {
626    case GL_PERFMON_RESULT_AVAILABLE_AMD:
627       *data = 1;
628       if (bytesWritten != NULL)
629          *bytesWritten = sizeof(GLuint);
630       break;
631    case GL_PERFMON_RESULT_SIZE_AMD:
632       *data = perf_monitor_result_size(ctx, m);
633       if (bytesWritten != NULL)
634          *bytesWritten = sizeof(GLuint);
635       break;
636    case GL_PERFMON_RESULT_AMD:
637       ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, bytesWritten);
638       break;
639    default:
640       _mesa_error(ctx, GL_INVALID_ENUM,
641                   "glGetPerfMonitorCounterDataAMD(pname)");
642    }
643 }
644 
645 /**
646  * Returns how many bytes a counter's value takes up.
647  */
648 unsigned
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter * c)649 _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
650 {
651    switch (c->Type) {
652    case GL_FLOAT:
653    case GL_PERCENTAGE_AMD:
654       return sizeof(GLfloat);
655    case GL_UNSIGNED_INT:
656       return sizeof(GLuint);
657    case GL_UNSIGNED_INT64_AMD:
658       return sizeof(uint64_t);
659    default:
660       assert(!"Should not get here: invalid counter type");
661       return 0;
662    }
663 }
664