xref: /aosp_15_r20/external/mesa3d/src/mesa/main/performance_monitor.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "util/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 #include "util/u_memory.h"
48 #include "api_exec_decl.h"
49 
50 #include "state_tracker/st_cb_bitmap.h"
51 #include "state_tracker/st_context.h"
52 #include "state_tracker/st_debug.h"
53 
54 #include "pipe/p_context.h"
55 #include "pipe/p_screen.h"
56 
57 void
_mesa_init_performance_monitors(struct gl_context * ctx)58 _mesa_init_performance_monitors(struct gl_context *ctx)
59 {
60    _mesa_InitHashTable(&ctx->PerfMonitor.Monitors);
61    ctx->PerfMonitor.NumGroups = 0;
62    ctx->PerfMonitor.Groups = NULL;
63 }
64 
65 
66 static bool
init_perf_monitor(struct gl_context * ctx,struct gl_perf_monitor_object * m)67 init_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
68 {
69    struct pipe_context *pipe = ctx->pipe;
70    unsigned *batch = NULL;
71    unsigned num_active_counters = 0;
72    unsigned max_batch_counters = 0;
73    unsigned num_batch_counters = 0;
74    int gid, cid;
75 
76    st_flush_bitmap_cache(st_context(ctx));
77 
78    /* Determine the number of active counters. */
79    for (gid = 0; gid < ctx->PerfMonitor.NumGroups; gid++) {
80       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[gid];
81 
82       if (m->ActiveGroups[gid] > g->MaxActiveCounters) {
83          /* Maximum number of counters reached. Cannot start the session. */
84          if (ST_DEBUG & DEBUG_MESA) {
85             debug_printf("Maximum number of counters reached. "
86                          "Cannot start the session!\n");
87          }
88          return false;
89       }
90 
91       num_active_counters += m->ActiveGroups[gid];
92       if (g->has_batch)
93          max_batch_counters += m->ActiveGroups[gid];
94    }
95 
96    if (!num_active_counters)
97       return true;
98 
99    m->active_counters = CALLOC(num_active_counters,
100                                  sizeof(*m->active_counters));
101    if (!m->active_counters)
102       return false;
103 
104    if (max_batch_counters) {
105       batch = CALLOC(max_batch_counters, sizeof(*batch));
106       if (!batch)
107          return false;
108    }
109 
110    /* Create a query for each active counter. */
111    for (gid = 0; gid < ctx->PerfMonitor.NumGroups; gid++) {
112       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[gid];
113 
114       BITSET_FOREACH_SET(cid, m->ActiveCounters[gid], g->NumCounters) {
115          const struct gl_perf_monitor_counter *c = &g->Counters[cid];
116          struct gl_perf_counter_object *cntr =
117             &m->active_counters[m->num_active_counters];
118 
119          cntr->id       = cid;
120          cntr->group_id = gid;
121          if (c->flags & PIPE_DRIVER_QUERY_FLAG_BATCH) {
122             cntr->batch_index = num_batch_counters;
123             batch[num_batch_counters++] = c->query_type;
124          } else {
125             cntr->query = pipe->create_query(pipe, c->query_type, 0);
126             if (!cntr->query)
127                goto fail;
128          }
129          ++m->num_active_counters;
130       }
131    }
132 
133    /* Create the batch query. */
134    if (num_batch_counters) {
135       m->batch_query = pipe->create_batch_query(pipe, num_batch_counters,
136                                                   batch);
137       m->batch_result = CALLOC(num_batch_counters, sizeof(m->batch_result->batch[0]));
138       if (!m->batch_query || !m->batch_result)
139          goto fail;
140    }
141 
142    FREE(batch);
143    return true;
144 
145 fail:
146    FREE(batch);
147    return false;
148 }
149 
150 static void
do_reset_perf_monitor(struct gl_perf_monitor_object * m,struct pipe_context * pipe)151 do_reset_perf_monitor(struct gl_perf_monitor_object *m,
152                    struct pipe_context *pipe)
153 {
154    unsigned i;
155 
156    for (i = 0; i < m->num_active_counters; ++i) {
157       struct pipe_query *query = m->active_counters[i].query;
158       if (query)
159          pipe->destroy_query(pipe, query);
160    }
161    FREE(m->active_counters);
162    m->active_counters = NULL;
163    m->num_active_counters = 0;
164 
165    if (m->batch_query) {
166       pipe->destroy_query(pipe, m->batch_query);
167       m->batch_query = NULL;
168    }
169    FREE(m->batch_result);
170    m->batch_result = NULL;
171 }
172 
173 static void
delete_perf_monitor(struct gl_context * ctx,struct gl_perf_monitor_object * m)174 delete_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
175 {
176    struct pipe_context *pipe = st_context(ctx)->pipe;
177 
178    do_reset_perf_monitor(m, pipe);
179    FREE(m);
180 }
181 
182 static GLboolean
begin_perf_monitor(struct gl_context * ctx,struct gl_perf_monitor_object * m)183 begin_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
184 {
185    struct pipe_context *pipe = st_context(ctx)->pipe;
186    unsigned i;
187 
188    if (!m->num_active_counters) {
189       /* Create a query for each active counter before starting
190        * a new monitoring session. */
191       if (!init_perf_monitor(ctx, m))
192          goto fail;
193    }
194 
195    /* Start the query for each active counter. */
196    for (i = 0; i < m->num_active_counters; ++i) {
197       struct pipe_query *query = m->active_counters[i].query;
198       if (query && !pipe->begin_query(pipe, query))
199           goto fail;
200    }
201 
202    if (m->batch_query && !pipe->begin_query(pipe, m->batch_query))
203       goto fail;
204 
205    return true;
206 
207 fail:
208    /* Failed to start the monitoring session. */
209    do_reset_perf_monitor(m, pipe);
210    return false;
211 }
212 
213 static void
end_perf_monitor(struct gl_context * ctx,struct gl_perf_monitor_object * m)214 end_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
215 {
216    struct pipe_context *pipe = st_context(ctx)->pipe;
217    unsigned i;
218 
219    /* Stop the query for each active counter. */
220    for (i = 0; i < m->num_active_counters; ++i) {
221       struct pipe_query *query = m->active_counters[i].query;
222       if (query)
223          pipe->end_query(pipe, query);
224    }
225 
226    if (m->batch_query)
227       pipe->end_query(pipe, m->batch_query);
228 }
229 
230 static void
reset_perf_monitor(struct gl_context * ctx,struct gl_perf_monitor_object * m)231 reset_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
232 {
233    struct pipe_context *pipe = st_context(ctx)->pipe;
234 
235    if (!m->Ended)
236       end_perf_monitor(ctx, m);
237 
238    do_reset_perf_monitor(m, pipe);
239 
240    if (m->Active)
241       begin_perf_monitor(ctx, m);
242 }
243 
244 static GLboolean
is_perf_monitor_result_available(struct gl_context * ctx,struct gl_perf_monitor_object * m)245 is_perf_monitor_result_available(struct gl_context *ctx,
246                                  struct gl_perf_monitor_object *m)
247 {
248    struct pipe_context *pipe = st_context(ctx)->pipe;
249    unsigned i;
250 
251    if (!m->num_active_counters)
252       return false;
253 
254    /* The result of a monitoring session is only available if the query of
255     * each active counter is idle. */
256    for (i = 0; i < m->num_active_counters; ++i) {
257       struct pipe_query *query = m->active_counters[i].query;
258       union pipe_query_result result;
259       if (query && !pipe->get_query_result(pipe, query, false, &result)) {
260          /* The query is busy. */
261          return false;
262       }
263    }
264 
265    if (m->batch_query &&
266        !pipe->get_query_result(pipe, m->batch_query, false, m->batch_result))
267       return false;
268 
269    return true;
270 }
271 
272 static void
get_perf_monitor_result(struct gl_context * ctx,struct gl_perf_monitor_object * m,GLsizei dataSize,GLuint * data,GLint * bytesWritten)273 get_perf_monitor_result(struct gl_context *ctx,
274                         struct gl_perf_monitor_object *m,
275                         GLsizei dataSize,
276                         GLuint *data,
277                         GLint *bytesWritten)
278 {
279    struct pipe_context *pipe = st_context(ctx)->pipe;
280    unsigned i;
281 
282    /* Copy data to the supplied array (data).
283     *
284     * The output data format is: <group ID, counter ID, value> for each
285     * active counter. The API allows counters to appear in any order.
286     */
287    GLsizei offset = 0;
288    bool have_batch_query = false;
289 
290    if (m->batch_query)
291       have_batch_query = pipe->get_query_result(pipe, m->batch_query, true,
292                                                 m->batch_result);
293 
294    /* Read query results for each active counter. */
295    for (i = 0; i < m->num_active_counters; ++i) {
296       struct gl_perf_counter_object *cntr = &m->active_counters[i];
297       union pipe_query_result result = { 0 };
298       int gid, cid;
299       GLenum type;
300 
301       cid  = cntr->id;
302       gid  = cntr->group_id;
303       type = ctx->PerfMonitor.Groups[gid].Counters[cid].Type;
304 
305       if (cntr->query) {
306          if (!pipe->get_query_result(pipe, cntr->query, true, &result))
307             continue;
308       } else {
309          if (!have_batch_query)
310             continue;
311          result.batch[0] = m->batch_result->batch[cntr->batch_index];
312       }
313 
314       data[offset++] = gid;
315       data[offset++] = cid;
316       switch (type) {
317       case GL_UNSIGNED_INT64_AMD:
318          memcpy(&data[offset], &result.u64, sizeof(uint64_t));
319          offset += sizeof(uint64_t) / sizeof(GLuint);
320          break;
321       case GL_UNSIGNED_INT:
322          memcpy(&data[offset], &result.u32, sizeof(uint32_t));
323          offset += sizeof(uint32_t) / sizeof(GLuint);
324          break;
325       case GL_FLOAT:
326       case GL_PERCENTAGE_AMD:
327          memcpy(&data[offset], &result.f, sizeof(GLfloat));
328          offset += sizeof(GLfloat) / sizeof(GLuint);
329          break;
330       }
331    }
332 
333    if (bytesWritten)
334       *bytesWritten = offset * sizeof(GLuint);
335 }
336 
337 void
_mesa_free_perfomance_monitor_groups(struct gl_context * ctx)338 _mesa_free_perfomance_monitor_groups(struct gl_context *ctx)
339 {
340    struct gl_perf_monitor_state *perfmon = &ctx->PerfMonitor;
341    int gid;
342 
343    for (gid = 0; gid < perfmon->NumGroups; gid++) {
344       FREE((void *)perfmon->Groups[gid].Counters);
345    }
346    FREE((void *)perfmon->Groups);
347 }
348 
349 static inline void
init_groups(struct gl_context * ctx)350 init_groups(struct gl_context *ctx)
351 {
352    if (likely(ctx->PerfMonitor.Groups))
353       return;
354 
355    struct gl_perf_monitor_state *perfmon = &ctx->PerfMonitor;
356    struct pipe_screen *screen = ctx->pipe->screen;
357    struct gl_perf_monitor_group *groups = NULL;
358    int num_counters, num_groups;
359    int gid, cid;
360 
361    /* Get the number of available queries. */
362    num_counters = screen->get_driver_query_info(screen, 0, NULL);
363 
364    /* Get the number of available groups. */
365    num_groups = screen->get_driver_query_group_info(screen, 0, NULL);
366    groups = CALLOC(num_groups, sizeof(*groups));
367    if (!groups)
368       return;
369 
370    for (gid = 0; gid < num_groups; gid++) {
371       struct gl_perf_monitor_group *g = &groups[perfmon->NumGroups];
372       struct pipe_driver_query_group_info group_info;
373       struct gl_perf_monitor_counter *counters = NULL;
374 
375       if (!screen->get_driver_query_group_info(screen, gid, &group_info))
376          continue;
377 
378       g->Name = group_info.name;
379       g->MaxActiveCounters = group_info.max_active_queries;
380 
381       if (group_info.num_queries)
382          counters = CALLOC(group_info.num_queries, sizeof(*counters));
383       if (!counters)
384          goto fail;
385       g->Counters = counters;
386 
387       for (cid = 0; cid < num_counters; cid++) {
388          struct gl_perf_monitor_counter *c = &counters[g->NumCounters];
389          struct pipe_driver_query_info info;
390 
391          if (!screen->get_driver_query_info(screen, cid, &info))
392             continue;
393          if (info.group_id != gid)
394             continue;
395 
396          c->Name = info.name;
397          switch (info.type) {
398             case PIPE_DRIVER_QUERY_TYPE_UINT64:
399             case PIPE_DRIVER_QUERY_TYPE_BYTES:
400             case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS:
401             case PIPE_DRIVER_QUERY_TYPE_HZ:
402                c->Minimum.u64 = 0;
403                c->Maximum.u64 = info.max_value.u64 ? info.max_value.u64 : UINT64_MAX;
404                c->Type = GL_UNSIGNED_INT64_AMD;
405                break;
406             case PIPE_DRIVER_QUERY_TYPE_UINT:
407                c->Minimum.u32 = 0;
408                c->Maximum.u32 = info.max_value.u32 ? info.max_value.u32 : UINT32_MAX;
409                c->Type = GL_UNSIGNED_INT;
410                break;
411             case PIPE_DRIVER_QUERY_TYPE_FLOAT:
412                c->Minimum.f = 0.0;
413                c->Maximum.f = info.max_value.f ? info.max_value.f : FLT_MAX;
414                c->Type = GL_FLOAT;
415                break;
416             case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
417                c->Minimum.f = 0.0f;
418                c->Maximum.f = 100.0f;
419                c->Type = GL_PERCENTAGE_AMD;
420                break;
421             default:
422                unreachable("Invalid driver query type!");
423          }
424 
425          c->query_type = info.query_type;
426          c->flags = info.flags;
427          if (c->flags & PIPE_DRIVER_QUERY_FLAG_BATCH)
428             g->has_batch = true;
429 
430          g->NumCounters++;
431       }
432       perfmon->NumGroups++;
433    }
434    perfmon->Groups = groups;
435 
436    return;
437 
438 fail:
439    for (gid = 0; gid < num_groups; gid++) {
440       FREE((void *)groups[gid].Counters);
441    }
442    FREE(groups);
443 }
444 
445 static struct gl_perf_monitor_object *
new_performance_monitor(struct gl_context * ctx,GLuint index)446 new_performance_monitor(struct gl_context *ctx, GLuint index)
447 {
448    unsigned i;
449    struct gl_perf_monitor_object *m = CALLOC_STRUCT(gl_perf_monitor_object);
450 
451    if (m == NULL)
452       return NULL;
453 
454    m->Name = index;
455 
456    m->Active = false;
457 
458    m->ActiveGroups =
459       rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
460 
461    m->ActiveCounters =
462       ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
463 
464    if (m->ActiveGroups == NULL || m->ActiveCounters == NULL)
465       goto fail;
466 
467    for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) {
468       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i];
469 
470       m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD,
471                                            BITSET_WORDS(g->NumCounters));
472       if (m->ActiveCounters[i] == NULL)
473          goto fail;
474    }
475 
476    return m;
477 
478 fail:
479    ralloc_free(m->ActiveGroups);
480    ralloc_free(m->ActiveCounters);
481    delete_perf_monitor(ctx, m);
482    return NULL;
483 }
484 
485 static void
free_performance_monitor(void * data,void * user)486 free_performance_monitor(void *data, void *user)
487 {
488    struct gl_perf_monitor_object *m = data;
489    struct gl_context *ctx = user;
490 
491    ralloc_free(m->ActiveGroups);
492    ralloc_free(m->ActiveCounters);
493    delete_perf_monitor(ctx, m);
494 }
495 
496 void
_mesa_free_performance_monitors(struct gl_context * ctx)497 _mesa_free_performance_monitors(struct gl_context *ctx)
498 {
499    _mesa_DeinitHashTable(&ctx->PerfMonitor.Monitors, free_performance_monitor,
500                          ctx);
501 }
502 
503 static inline struct gl_perf_monitor_object *
lookup_monitor(struct gl_context * ctx,GLuint id)504 lookup_monitor(struct gl_context *ctx, GLuint id)
505 {
506    return (struct gl_perf_monitor_object *)
507       _mesa_HashLookup(&ctx->PerfMonitor.Monitors, id);
508 }
509 
510 static inline const struct gl_perf_monitor_group *
get_group(const struct gl_context * ctx,GLuint id)511 get_group(const struct gl_context *ctx, GLuint id)
512 {
513    if (id >= ctx->PerfMonitor.NumGroups)
514       return NULL;
515 
516    return &ctx->PerfMonitor.Groups[id];
517 }
518 
519 static inline const struct gl_perf_monitor_counter *
get_counter(const struct gl_perf_monitor_group * group_obj,GLuint id)520 get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
521 {
522    if (id >= group_obj->NumCounters)
523       return NULL;
524 
525    return &group_obj->Counters[id];
526 }
527 
528 /*****************************************************************************/
529 
530 void GLAPIENTRY
_mesa_GetPerfMonitorGroupsAMD(GLint * numGroups,GLsizei groupsSize,GLuint * groups)531 _mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
532                               GLuint *groups)
533 {
534    GET_CURRENT_CONTEXT(ctx);
535    init_groups(ctx);
536 
537    if (numGroups != NULL)
538       *numGroups = ctx->PerfMonitor.NumGroups;
539 
540    if (groupsSize > 0 && groups != NULL) {
541       unsigned i;
542       unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
543 
544       /* We just use the index in the Groups array as the ID. */
545       for (i = 0; i < n; i++)
546          groups[i] = i;
547    }
548 }
549 
550 void GLAPIENTRY
_mesa_GetPerfMonitorCountersAMD(GLuint group,GLint * numCounters,GLint * maxActiveCounters,GLsizei countersSize,GLuint * counters)551 _mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
552                                 GLint *maxActiveCounters,
553                                 GLsizei countersSize, GLuint *counters)
554 {
555    GET_CURRENT_CONTEXT(ctx);
556    const struct gl_perf_monitor_group *group_obj;
557 
558    init_groups(ctx);
559 
560    group_obj = get_group(ctx, group);
561    if (group_obj == NULL) {
562       _mesa_error(ctx, GL_INVALID_VALUE,
563                   "glGetPerfMonitorCountersAMD(invalid group)");
564       return;
565    }
566 
567    if (maxActiveCounters != NULL)
568       *maxActiveCounters = group_obj->MaxActiveCounters;
569 
570    if (numCounters != NULL)
571       *numCounters = group_obj->NumCounters;
572 
573    if (counters != NULL) {
574       unsigned i;
575       unsigned n = MIN2(group_obj->NumCounters, (GLuint) countersSize);
576       for (i = 0; i < n; i++) {
577          /* We just use the index in the Counters array as the ID. */
578          counters[i] = i;
579       }
580    }
581 }
582 
583 void GLAPIENTRY
_mesa_GetPerfMonitorGroupStringAMD(GLuint group,GLsizei bufSize,GLsizei * length,GLchar * groupString)584 _mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
585                                    GLsizei *length, GLchar *groupString)
586 {
587    GET_CURRENT_CONTEXT(ctx);
588    const struct gl_perf_monitor_group *group_obj;
589 
590    init_groups(ctx);
591 
592    group_obj = get_group(ctx, group);
593    if (group_obj == NULL) {
594       _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
595       return;
596    }
597 
598    if (bufSize == 0) {
599       /* Return the number of characters that would be required to hold the
600        * group string, excluding the null terminator.
601        */
602       if (length != NULL)
603          *length = strlen(group_obj->Name);
604    } else {
605       if (length != NULL)
606          *length = MIN2(strlen(group_obj->Name), bufSize);
607       if (groupString != NULL)
608          strncpy(groupString, group_obj->Name, bufSize);
609    }
610 }
611 
612 void GLAPIENTRY
_mesa_GetPerfMonitorCounterStringAMD(GLuint group,GLuint counter,GLsizei bufSize,GLsizei * length,GLchar * counterString)613 _mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
614                                      GLsizei bufSize, GLsizei *length,
615                                      GLchar *counterString)
616 {
617    GET_CURRENT_CONTEXT(ctx);
618 
619    const struct gl_perf_monitor_group *group_obj;
620    const struct gl_perf_monitor_counter *counter_obj;
621 
622    init_groups(ctx);
623 
624    group_obj = get_group(ctx, group);
625 
626    if (group_obj == NULL) {
627       _mesa_error(ctx, GL_INVALID_VALUE,
628                   "glGetPerfMonitorCounterStringAMD(invalid group)");
629       return;
630    }
631 
632    counter_obj = get_counter(group_obj, counter);
633 
634    if (counter_obj == NULL) {
635       _mesa_error(ctx, GL_INVALID_VALUE,
636                   "glGetPerfMonitorCounterStringAMD(invalid counter)");
637       return;
638    }
639 
640    if (bufSize == 0) {
641       /* Return the number of characters that would be required to hold the
642        * counter string, excluding the null terminator.
643        */
644       if (length != NULL)
645          *length = strlen(counter_obj->Name);
646    } else {
647       if (length != NULL)
648          *length = MIN2(strlen(counter_obj->Name), bufSize);
649       if (counterString != NULL)
650          strncpy(counterString, counter_obj->Name, bufSize);
651    }
652 }
653 
654 void GLAPIENTRY
_mesa_GetPerfMonitorCounterInfoAMD(GLuint group,GLuint counter,GLenum pname,GLvoid * data)655 _mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
656                                    GLvoid *data)
657 {
658    GET_CURRENT_CONTEXT(ctx);
659 
660    const struct gl_perf_monitor_group *group_obj;
661    const struct gl_perf_monitor_counter *counter_obj;
662 
663    init_groups(ctx);
664 
665    group_obj = get_group(ctx, group);
666 
667    if (group_obj == NULL) {
668       _mesa_error(ctx, GL_INVALID_VALUE,
669                   "glGetPerfMonitorCounterInfoAMD(invalid group)");
670       return;
671    }
672 
673    counter_obj = get_counter(group_obj, counter);
674 
675    if (counter_obj == NULL) {
676       _mesa_error(ctx, GL_INVALID_VALUE,
677                   "glGetPerfMonitorCounterInfoAMD(invalid counter)");
678       return;
679    }
680 
681    switch (pname) {
682    case GL_COUNTER_TYPE_AMD:
683       *((GLenum *) data) = counter_obj->Type;
684       break;
685 
686    case GL_COUNTER_RANGE_AMD:
687       switch (counter_obj->Type) {
688       case GL_FLOAT:
689       case GL_PERCENTAGE_AMD: {
690          float *f_data = data;
691          f_data[0] = counter_obj->Minimum.f;
692          f_data[1] = counter_obj->Maximum.f;
693          break;
694       }
695       case GL_UNSIGNED_INT: {
696          uint32_t *u32_data = data;
697          u32_data[0] = counter_obj->Minimum.u32;
698          u32_data[1] = counter_obj->Maximum.u32;
699          break;
700       }
701       case GL_UNSIGNED_INT64_AMD: {
702          uint64_t *u64_data = data;
703          u64_data[0] = counter_obj->Minimum.u64;
704          u64_data[1] = counter_obj->Maximum.u64;
705          break;
706       }
707       default:
708          assert(!"Should not get here: invalid counter type");
709       }
710       break;
711 
712    default:
713       _mesa_error(ctx, GL_INVALID_ENUM,
714                   "glGetPerfMonitorCounterInfoAMD(pname)");
715       return;
716    }
717 }
718 
719 void GLAPIENTRY
_mesa_GenPerfMonitorsAMD(GLsizei n,GLuint * monitors)720 _mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
721 {
722    GET_CURRENT_CONTEXT(ctx);
723 
724    if (MESA_VERBOSE & VERBOSE_API)
725       _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
726 
727    init_groups(ctx);
728 
729    if (n < 0) {
730       _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
731       return;
732    }
733 
734    if (monitors == NULL)
735       return;
736 
737    if (_mesa_HashFindFreeKeys(&ctx->PerfMonitor.Monitors, monitors, n)) {
738       GLsizei i;
739       for (i = 0; i < n; i++) {
740          struct gl_perf_monitor_object *m =
741             new_performance_monitor(ctx, monitors[i]);
742          if (!m) {
743             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
744             return;
745          }
746          _mesa_HashInsert(&ctx->PerfMonitor.Monitors, monitors[i], m);
747       }
748    } else {
749       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
750       return;
751    }
752 }
753 
754 void GLAPIENTRY
_mesa_DeletePerfMonitorsAMD(GLsizei n,GLuint * monitors)755 _mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
756 {
757    GLint i;
758    GET_CURRENT_CONTEXT(ctx);
759 
760    if (MESA_VERBOSE & VERBOSE_API)
761       _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
762 
763    if (n < 0) {
764       _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
765       return;
766    }
767 
768    if (monitors == NULL)
769       return;
770 
771    for (i = 0; i < n; i++) {
772       struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
773 
774       if (m) {
775          /* Give the driver a chance to stop the monitor if it's active. */
776          if (m->Active) {
777             reset_perf_monitor(ctx, m);
778             m->Ended = false;
779          }
780 
781          _mesa_HashRemove(&ctx->PerfMonitor.Monitors, monitors[i]);
782          ralloc_free(m->ActiveGroups);
783          ralloc_free(m->ActiveCounters);
784          delete_perf_monitor(ctx, m);
785       } else {
786          /* "INVALID_VALUE error will be generated if any of the monitor IDs
787           *  in the <monitors> parameter to DeletePerfMonitorsAMD do not
788           *  reference a valid generated monitor ID."
789           */
790          _mesa_error(ctx, GL_INVALID_VALUE,
791                      "glDeletePerfMonitorsAMD(invalid monitor)");
792       }
793    }
794 }
795 
796 void GLAPIENTRY
_mesa_SelectPerfMonitorCountersAMD(GLuint monitor,GLboolean enable,GLuint group,GLint numCounters,GLuint * counterList)797 _mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
798                                    GLuint group, GLint numCounters,
799                                    GLuint *counterList)
800 {
801    GET_CURRENT_CONTEXT(ctx);
802    int i;
803    struct gl_perf_monitor_object *m;
804    const struct gl_perf_monitor_group *group_obj;
805 
806    m = lookup_monitor(ctx, monitor);
807 
808    /* "INVALID_VALUE error will be generated if the <monitor> parameter to
809     *  SelectPerfMonitorCountersAMD does not reference a monitor created by
810     *  GenPerfMonitorsAMD."
811     */
812    if (m == NULL) {
813       _mesa_error(ctx, GL_INVALID_VALUE,
814                   "glSelectPerfMonitorCountersAMD(invalid monitor)");
815       return;
816    }
817 
818    group_obj = get_group(ctx, group);
819 
820    /* "INVALID_VALUE error will be generated if the <group> parameter to
821     *  GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
822     *  GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
823     *  SelectPerfMonitorCountersAMD does not reference a valid group ID."
824     */
825    if (group_obj == NULL) {
826       _mesa_error(ctx, GL_INVALID_VALUE,
827                   "glSelectPerfMonitorCountersAMD(invalid group)");
828       return;
829    }
830 
831    /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
832     *  SelectPerfMonitorCountersAMD is less than 0."
833     */
834    if (numCounters < 0) {
835       _mesa_error(ctx, GL_INVALID_VALUE,
836                   "glSelectPerfMonitorCountersAMD(numCounters < 0)");
837       return;
838    }
839 
840    /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
841     *  results for that monitor become invalidated and the result queries
842     *  PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
843     */
844    reset_perf_monitor(ctx, m);
845 
846    /* Sanity check the counter ID list. */
847    for (i = 0; i < numCounters; i++) {
848       if (counterList[i] >= group_obj->NumCounters) {
849          _mesa_error(ctx, GL_INVALID_VALUE,
850                      "glSelectPerfMonitorCountersAMD(invalid counter ID)");
851          return;
852       }
853    }
854 
855    if (enable) {
856       /* Enable the counters */
857       for (i = 0; i < numCounters; i++) {
858          if (!BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
859             ++m->ActiveGroups[group];
860             BITSET_SET(m->ActiveCounters[group], counterList[i]);
861          }
862       }
863    } else {
864       /* Disable the counters */
865       for (i = 0; i < numCounters; i++) {
866          if (BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
867             --m->ActiveGroups[group];
868             BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
869          }
870       }
871    }
872 }
873 
874 void GLAPIENTRY
_mesa_BeginPerfMonitorAMD(GLuint monitor)875 _mesa_BeginPerfMonitorAMD(GLuint monitor)
876 {
877    GET_CURRENT_CONTEXT(ctx);
878 
879    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
880 
881    if (m == NULL) {
882       _mesa_error(ctx, GL_INVALID_VALUE,
883                   "glBeginPerfMonitorAMD(invalid monitor)");
884       return;
885    }
886 
887    /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
888     *  called when a performance monitor is already active."
889     */
890    if (m->Active) {
891       _mesa_error(ctx, GL_INVALID_OPERATION,
892                   "glBeginPerfMonitor(already active)");
893       return;
894    }
895 
896    /* The driver is free to return false if it can't begin monitoring for
897     * any reason.  This translates into an INVALID_OPERATION error.
898     */
899    if (begin_perf_monitor(ctx, m)) {
900       m->Active = true;
901       m->Ended = false;
902    } else {
903       _mesa_error(ctx, GL_INVALID_OPERATION,
904                   "glBeginPerfMonitor(driver unable to begin monitoring)");
905    }
906 }
907 
908 void GLAPIENTRY
_mesa_EndPerfMonitorAMD(GLuint monitor)909 _mesa_EndPerfMonitorAMD(GLuint monitor)
910 {
911    GET_CURRENT_CONTEXT(ctx);
912 
913    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
914 
915    if (m == NULL) {
916       _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
917       return;
918    }
919 
920    /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
921     *  when a performance monitor is not currently started."
922     */
923    if (!m->Active) {
924       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndPerfMonitor(not active)");
925       return;
926    }
927 
928    end_perf_monitor(ctx, m);
929 
930    m->Active = false;
931    m->Ended = true;
932 }
933 
934 /**
935  * Return the number of bytes needed to store a monitor's result.
936  */
937 static unsigned
perf_monitor_result_size(const struct gl_context * ctx,const struct gl_perf_monitor_object * m)938 perf_monitor_result_size(const struct gl_context *ctx,
939                          const struct gl_perf_monitor_object *m)
940 {
941    unsigned group, counter;
942    unsigned size = 0;
943 
944    for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
945       const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
946 
947       BITSET_FOREACH_SET(counter, m->ActiveCounters[group], g->NumCounters) {
948          const struct gl_perf_monitor_counter *c = &g->Counters[counter];
949 
950          size += sizeof(uint32_t); /* Group ID */
951          size += sizeof(uint32_t); /* Counter ID */
952          size += _mesa_perf_monitor_counter_size(c);
953       }
954    }
955    return size;
956 }
957 
958 void GLAPIENTRY
_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor,GLenum pname,GLsizei dataSize,GLuint * data,GLint * bytesWritten)959 _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
960                                    GLsizei dataSize, GLuint *data,
961                                    GLint *bytesWritten)
962 {
963    GET_CURRENT_CONTEXT(ctx);
964 
965    struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
966    bool result_available;
967 
968    if (m == NULL) {
969       _mesa_error(ctx, GL_INVALID_VALUE,
970                   "glGetPerfMonitorCounterDataAMD(invalid monitor)");
971       return;
972    }
973 
974    /* "It is an INVALID_OPERATION error for <data> to be NULL." */
975    if (data == NULL) {
976       _mesa_error(ctx, GL_INVALID_OPERATION,
977                   "glGetPerfMonitorCounterDataAMD(data == NULL)");
978       return;
979    }
980 
981    /* We need at least enough room for a single value. */
982    if (dataSize < sizeof(GLuint)) {
983       if (bytesWritten != NULL)
984          *bytesWritten = 0;
985       return;
986    }
987 
988    /* If the monitor has never ended, there is no result. */
989    result_available = m->Ended &&
990       is_perf_monitor_result_available(ctx, m);
991 
992    /* AMD appears to return 0 for all queries unless a result is available. */
993    if (!result_available) {
994       *data = 0;
995       if (bytesWritten != NULL)
996          *bytesWritten = sizeof(GLuint);
997       return;
998    }
999 
1000    switch (pname) {
1001    case GL_PERFMON_RESULT_AVAILABLE_AMD:
1002       *data = 1;
1003       if (bytesWritten != NULL)
1004          *bytesWritten = sizeof(GLuint);
1005       break;
1006    case GL_PERFMON_RESULT_SIZE_AMD:
1007       *data = perf_monitor_result_size(ctx, m);
1008       if (bytesWritten != NULL)
1009          *bytesWritten = sizeof(GLuint);
1010       break;
1011    case GL_PERFMON_RESULT_AMD:
1012       get_perf_monitor_result(ctx, m, dataSize, data, bytesWritten);
1013       break;
1014    default:
1015       _mesa_error(ctx, GL_INVALID_ENUM,
1016                   "glGetPerfMonitorCounterDataAMD(pname)");
1017    }
1018 }
1019 
1020 /**
1021  * Returns how many bytes a counter's value takes up.
1022  */
1023 unsigned
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter * c)1024 _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
1025 {
1026    switch (c->Type) {
1027    case GL_FLOAT:
1028    case GL_PERCENTAGE_AMD:
1029       return sizeof(GLfloat);
1030    case GL_UNSIGNED_INT:
1031       return sizeof(GLuint);
1032    case GL_UNSIGNED_INT64_AMD:
1033       return sizeof(uint64_t);
1034    default:
1035       assert(!"Should not get here: invalid counter type");
1036       return 0;
1037    }
1038 }
1039