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