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(void * data,void * user)104 free_performance_monitor(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    GET_CURRENT_CONTEXT(ctx);
342 
343    if (MESA_VERBOSE & VERBOSE_API)
344       _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
345 
346    init_groups(ctx);
347 
348    if (n < 0) {
349       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
350       return;
351    }
352 
353    if (monitors == NULL)
354       return;
355 
356    if (_mesa_HashFindFreeKeys(ctx->PerfMonitor.Monitors, monitors, n)) {
357       GLsizei i;
358       for (i = 0; i < n; i++) {
359          struct gl_perf_monitor_object *m =
360             new_performance_monitor(ctx, monitors[i]);
361          if (!m) {
362             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
363             return;
364          }
365          _mesa_HashInsert(ctx->PerfMonitor.Monitors, monitors[i], m, true);
366       }
367    } else {
368       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
369       return;
370    }
371 }
372 
373 void GLAPIENTRY
_mesa_DeletePerfMonitorsAMD(GLsizei n,GLuint * monitors)374 _mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
375 {
376    GLint i;
377    GET_CURRENT_CONTEXT(ctx);
378 
379    if (MESA_VERBOSE & VERBOSE_API)
380       _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
381 
382    if (n < 0) {
383       _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
384       return;
385    }
386 
387    if (monitors == NULL)
388       return;
389 
390    for (i = 0; i < n; i++) {
391       struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
392 
393       if (m) {
394          /* Give the driver a chance to stop the monitor if it's active. */
395          if (m->Active) {
396             ctx->Driver.ResetPerfMonitor(ctx, m);
397             m->Ended = false;
398          }
399 
400          _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
401          ralloc_free(m->ActiveGroups);
402          ralloc_free(m->ActiveCounters);
403          ctx->Driver.DeletePerfMonitor(ctx, m);
404       } else {
405          /* "INVALID_VALUE error will be generated if any of the monitor IDs
406           *  in the <monitors> parameter to DeletePerfMonitorsAMD do not
407           *  reference a valid generated monitor ID."
408           */
409          _mesa_error(ctx, GL_INVALID_VALUE,
410                      "glDeletePerfMonitorsAMD(invalid monitor)");
411       }
412    }
413 }
414 
415 void GLAPIENTRY
_mesa_SelectPerfMonitorCountersAMD(GLuint monitor,GLboolean enable,GLuint group,GLint numCounters,GLuint * counterList)416 _mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
417                                    GLuint group, GLint numCounters,
418                                    GLuint *counterList)
419 {
420    GET_CURRENT_CONTEXT(ctx);
421    int i;
422    struct gl_perf_monitor_object *m;
423    const struct gl_perf_monitor_group *group_obj;
424 
425    m = lookup_monitor(ctx, monitor);
426 
427    /* "INVALID_VALUE error will be generated if the <monitor> parameter to
428     *  SelectPerfMonitorCountersAMD does not reference a monitor created by
429     *  GenPerfMonitorsAMD."
430     */
431    if (m == NULL) {
432       _mesa_error(ctx, GL_INVALID_VALUE,
433                   "glSelectPerfMonitorCountersAMD(invalid monitor)");
434       return;
435    }
436 
437    group_obj = get_group(ctx, group);
438 
439    /* "INVALID_VALUE error will be generated if the <group> parameter to
440     *  GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
441     *  GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
442     *  SelectPerfMonitorCountersAMD does not reference a valid group ID."
443     */
444    if (group_obj == NULL) {
445       _mesa_error(ctx, GL_INVALID_VALUE,
446                   "glSelectPerfMonitorCountersAMD(invalid group)");
447       return;
448    }
449 
450    /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
451     *  SelectPerfMonitorCountersAMD is less than 0."
452     */
453    if (numCounters < 0) {
454       _mesa_error(ctx, GL_INVALID_VALUE,
455                   "glSelectPerfMonitorCountersAMD(numCounters < 0)");
456       return;
457    }
458 
459    /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
460     *  results for that monitor become invalidated and the result queries
461     *  PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
462     */
463    ctx->Driver.ResetPerfMonitor(ctx, m);
464 
465    /* Sanity check the counter ID list. */
466    for (i = 0; i < numCounters; i++) {
467       if (counterList[i] >= group_obj->NumCounters) {
468          _mesa_error(ctx, GL_INVALID_VALUE,
469                      "glSelectPerfMonitorCountersAMD(invalid counter ID)");
470          return;
471       }
472    }
473 
474    if (enable) {
475       /* Enable the counters */
476       for (i = 0; i < numCounters; i++) {
477          if (!BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
478             ++m->ActiveGroups[group];
479             BITSET_SET(m->ActiveCounters[group], counterList[i]);
480          }
481       }
482    } else {
483       /* Disable the counters */
484       for (i = 0; i < numCounters; i++) {
485          if (BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
486             --m->ActiveGroups[group];
487             BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
488          }
489       }
490    }
491 }
492 
493 void GLAPIENTRY
_mesa_BeginPerfMonitorAMD(GLuint monitor)494 _mesa_BeginPerfMonitorAMD(GLuint monitor)
495 {
496    GET_CURRENT_CONTEXT(ctx);
497 
498    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
499 
500    if (m == NULL) {
501       _mesa_error(ctx, GL_INVALID_VALUE,
502                   "glBeginPerfMonitorAMD(invalid monitor)");
503       return;
504    }
505 
506    /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
507     *  called when a performance monitor is already active."
508     */
509    if (m->Active) {
510       _mesa_error(ctx, GL_INVALID_OPERATION,
511                   "glBeginPerfMonitor(already active)");
512       return;
513    }
514 
515    /* The driver is free to return false if it can't begin monitoring for
516     * any reason.  This translates into an INVALID_OPERATION error.
517     */
518    if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
519       m->Active = true;
520       m->Ended = false;
521    } else {
522       _mesa_error(ctx, GL_INVALID_OPERATION,
523                   "glBeginPerfMonitor(driver unable to begin monitoring)");
524    }
525 }
526 
527 void GLAPIENTRY
_mesa_EndPerfMonitorAMD(GLuint monitor)528 _mesa_EndPerfMonitorAMD(GLuint monitor)
529 {
530    GET_CURRENT_CONTEXT(ctx);
531 
532    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
533 
534    if (m == NULL) {
535       _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
536       return;
537    }
538 
539    /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
540     *  when a performance monitor is not currently started."
541     */
542    if (!m->Active) {
543       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndPerfMonitor(not active)");
544       return;
545    }
546 
547    ctx->Driver.EndPerfMonitor(ctx, m);
548 
549    m->Active = false;
550    m->Ended = true;
551 }
552 
553 /**
554  * Return the number of bytes needed to store a monitor's result.
555  */
556 static unsigned
perf_monitor_result_size(const struct gl_context * ctx,const struct gl_perf_monitor_object * m)557 perf_monitor_result_size(const struct gl_context *ctx,
558                          const struct gl_perf_monitor_object *m)
559 {
560    unsigned group, counter;
561    unsigned size = 0;
562 
563    for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
564       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
565 
566       BITSET_FOREACH_SET(counter, m->ActiveCounters[group], g->NumCounters) {
567          const struct gl_perf_monitor_counter *c = &g->Counters[counter];
568 
569          size += sizeof(uint32_t); /* Group ID */
570          size += sizeof(uint32_t); /* Counter ID */
571          size += _mesa_perf_monitor_counter_size(c);
572       }
573    }
574    return size;
575 }
576 
577 void GLAPIENTRY
_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor,GLenum pname,GLsizei dataSize,GLuint * data,GLint * bytesWritten)578 _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
579                                    GLsizei dataSize, GLuint *data,
580                                    GLint *bytesWritten)
581 {
582    GET_CURRENT_CONTEXT(ctx);
583 
584    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
585    bool result_available;
586 
587    if (m == NULL) {
588       _mesa_error(ctx, GL_INVALID_VALUE,
589                   "glGetPerfMonitorCounterDataAMD(invalid monitor)");
590       return;
591    }
592 
593    /* "It is an INVALID_OPERATION error for <data> to be NULL." */
594    if (data == NULL) {
595       _mesa_error(ctx, GL_INVALID_OPERATION,
596                   "glGetPerfMonitorCounterDataAMD(data == NULL)");
597       return;
598    }
599 
600    /* We need at least enough room for a single value. */
601    if (dataSize < sizeof(GLuint)) {
602       if (bytesWritten != NULL)
603          *bytesWritten = 0;
604       return;
605    }
606 
607    /* If the monitor has never ended, there is no result. */
608    result_available = m->Ended &&
609       ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
610 
611    /* AMD appears to return 0 for all queries unless a result is available. */
612    if (!result_available) {
613       *data = 0;
614       if (bytesWritten != NULL)
615          *bytesWritten = sizeof(GLuint);
616       return;
617    }
618 
619    switch (pname) {
620    case GL_PERFMON_RESULT_AVAILABLE_AMD:
621       *data = 1;
622       if (bytesWritten != NULL)
623          *bytesWritten = sizeof(GLuint);
624       break;
625    case GL_PERFMON_RESULT_SIZE_AMD:
626       *data = perf_monitor_result_size(ctx, m);
627       if (bytesWritten != NULL)
628          *bytesWritten = sizeof(GLuint);
629       break;
630    case GL_PERFMON_RESULT_AMD:
631       ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, bytesWritten);
632       break;
633    default:
634       _mesa_error(ctx, GL_INVALID_ENUM,
635                   "glGetPerfMonitorCounterDataAMD(pname)");
636    }
637 }
638 
639 /**
640  * Returns how many bytes a counter's value takes up.
641  */
642 unsigned
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter * c)643 _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
644 {
645    switch (c->Type) {
646    case GL_FLOAT:
647    case GL_PERCENTAGE_AMD:
648       return sizeof(GLfloat);
649    case GL_UNSIGNED_INT:
650       return sizeof(GLuint);
651    case GL_UNSIGNED_INT64_AMD:
652       return sizeof(uint64_t);
653    default:
654       assert(!"Should not get here: invalid counter type");
655       return 0;
656    }
657 }
658