~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/mesa/main/performance_monitor.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2012 Intel Corporation
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 
 * copy of this software and associated documentation files (the "Software"),
6
 
 * to deal in the Software without restriction, including without limitation
7
 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
 * and/or sell copies of the Software, and to permit persons to whom the
9
 
 * Software is furnished to do so, subject to the following conditions:
10
 
 *
11
 
 * The above copyright notice and this permission notice (including the next
12
 
 * paragraph) shall be included in all copies or substantial portions of the
13
 
 * Software.
14
 
 *
15
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18
 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 
 * DEALINGS IN THE SOFTWARE.
22
 
 */
23
 
 
24
 
/**
25
 
 * \file performance_monitor.c
26
 
 * Core Mesa support for the AMD_performance_monitor extension.
27
 
 *
28
 
 * In order to implement this extension, start by defining two enums:
29
 
 * one for Groups, and one for Counters.  These will be used as indexes into
30
 
 * arrays, so they should start at 0 and increment from there.
31
 
 *
32
 
 * Counter IDs need to be globally unique.  That is, you can't have counter 7
33
 
 * in group A and counter 7 in group B.  A global enum of all available
34
 
 * counters is a convenient way to guarantee this.
35
 
 */
36
 
 
37
 
#include <stdbool.h>
38
 
#include "glheader.h"
39
 
#include "context.h"
40
 
#include "enums.h"
41
 
#include "hash.h"
42
 
#include "macros.h"
43
 
#include "mtypes.h"
44
 
#include "performance_monitor.h"
45
 
#include "util/bitset.h"
46
 
#include "util/ralloc.h"
47
 
#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
58
 
_mesa_init_performance_monitors(struct gl_context *ctx)
59
 
{
60
 
   ctx->PerfMonitor.Monitors = _mesa_NewHashTable();
61
 
   ctx->PerfMonitor.NumGroups = 0;
62
 
   ctx->PerfMonitor.Groups = NULL;
63
 
}
64
 
 
65
 
 
66
 
static bool
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
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
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
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
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
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
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
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
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
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 *
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
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
497
 
_mesa_free_performance_monitors(struct gl_context *ctx)
498
 
{
499
 
   _mesa_HashDeleteAll(ctx->PerfMonitor.Monitors,
500
 
                       free_performance_monitor, ctx);
501
 
   _mesa_DeleteHashTable(ctx->PerfMonitor.Monitors);
502
 
}
503
 
 
504
 
static inline struct gl_perf_monitor_object *
505
 
lookup_monitor(struct gl_context *ctx, GLuint id)
506
 
{
507
 
   return (struct gl_perf_monitor_object *)
508
 
      _mesa_HashLookup(ctx->PerfMonitor.Monitors, id);
509
 
}
510
 
 
511
 
static inline const struct gl_perf_monitor_group *
512
 
get_group(const struct gl_context *ctx, GLuint id)
513
 
{
514
 
   if (id >= ctx->PerfMonitor.NumGroups)
515
 
      return NULL;
516
 
 
517
 
   return &ctx->PerfMonitor.Groups[id];
518
 
}
519
 
 
520
 
static inline const struct gl_perf_monitor_counter *
521
 
get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
522
 
{
523
 
   if (id >= group_obj->NumCounters)
524
 
      return NULL;
525
 
 
526
 
   return &group_obj->Counters[id];
527
 
}
528
 
 
529
 
/*****************************************************************************/
530
 
 
531
 
void GLAPIENTRY
532
 
_mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
533
 
                              GLuint *groups)
534
 
{
535
 
   GET_CURRENT_CONTEXT(ctx);
536
 
   init_groups(ctx);
537
 
 
538
 
   if (numGroups != NULL)
539
 
      *numGroups = ctx->PerfMonitor.NumGroups;
540
 
 
541
 
   if (groupsSize > 0 && groups != NULL) {
542
 
      unsigned i;
543
 
      unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
544
 
 
545
 
      /* We just use the index in the Groups array as the ID. */
546
 
      for (i = 0; i < n; i++)
547
 
         groups[i] = i;
548
 
   }
549
 
}
550
 
 
551
 
void GLAPIENTRY
552
 
_mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
553
 
                                GLint *maxActiveCounters,
554
 
                                GLsizei countersSize, GLuint *counters)
555
 
{
556
 
   GET_CURRENT_CONTEXT(ctx);
557
 
   const struct gl_perf_monitor_group *group_obj;
558
 
 
559
 
   init_groups(ctx);
560
 
 
561
 
   group_obj = get_group(ctx, group);
562
 
   if (group_obj == NULL) {
563
 
      _mesa_error(ctx, GL_INVALID_VALUE,
564
 
                  "glGetPerfMonitorCountersAMD(invalid group)");
565
 
      return;
566
 
   }
567
 
 
568
 
   if (maxActiveCounters != NULL)
569
 
      *maxActiveCounters = group_obj->MaxActiveCounters;
570
 
 
571
 
   if (numCounters != NULL)
572
 
      *numCounters = group_obj->NumCounters;
573
 
 
574
 
   if (counters != NULL) {
575
 
      unsigned i;
576
 
      unsigned n = MIN2(group_obj->NumCounters, (GLuint) countersSize);
577
 
      for (i = 0; i < n; i++) {
578
 
         /* We just use the index in the Counters array as the ID. */
579
 
         counters[i] = i;
580
 
      }
581
 
   }
582
 
}
583
 
 
584
 
void GLAPIENTRY
585
 
_mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
586
 
                                   GLsizei *length, GLchar *groupString)
587
 
{
588
 
   GET_CURRENT_CONTEXT(ctx);
589
 
   const struct gl_perf_monitor_group *group_obj;
590
 
 
591
 
   init_groups(ctx);
592
 
 
593
 
   group_obj = get_group(ctx, group);
594
 
   if (group_obj == NULL) {
595
 
      _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
596
 
      return;
597
 
   }
598
 
 
599
 
   if (bufSize == 0) {
600
 
      /* Return the number of characters that would be required to hold the
601
 
       * group string, excluding the null terminator.
602
 
       */
603
 
      if (length != NULL)
604
 
         *length = strlen(group_obj->Name);
605
 
   } else {
606
 
      if (length != NULL)
607
 
         *length = MIN2(strlen(group_obj->Name), bufSize);
608
 
      if (groupString != NULL)
609
 
         strncpy(groupString, group_obj->Name, bufSize);
610
 
   }
611
 
}
612
 
 
613
 
void GLAPIENTRY
614
 
_mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
615
 
                                     GLsizei bufSize, GLsizei *length,
616
 
                                     GLchar *counterString)
617
 
{
618
 
   GET_CURRENT_CONTEXT(ctx);
619
 
 
620
 
   const struct gl_perf_monitor_group *group_obj;
621
 
   const struct gl_perf_monitor_counter *counter_obj;
622
 
 
623
 
   init_groups(ctx);
624
 
 
625
 
   group_obj = get_group(ctx, group);
626
 
 
627
 
   if (group_obj == NULL) {
628
 
      _mesa_error(ctx, GL_INVALID_VALUE,
629
 
                  "glGetPerfMonitorCounterStringAMD(invalid group)");
630
 
      return;
631
 
   }
632
 
 
633
 
   counter_obj = get_counter(group_obj, counter);
634
 
 
635
 
   if (counter_obj == NULL) {
636
 
      _mesa_error(ctx, GL_INVALID_VALUE,
637
 
                  "glGetPerfMonitorCounterStringAMD(invalid counter)");
638
 
      return;
639
 
   }
640
 
 
641
 
   if (bufSize == 0) {
642
 
      /* Return the number of characters that would be required to hold the
643
 
       * counter string, excluding the null terminator.
644
 
       */
645
 
      if (length != NULL)
646
 
         *length = strlen(counter_obj->Name);
647
 
   } else {
648
 
      if (length != NULL)
649
 
         *length = MIN2(strlen(counter_obj->Name), bufSize);
650
 
      if (counterString != NULL)
651
 
         strncpy(counterString, counter_obj->Name, bufSize);
652
 
   }
653
 
}
654
 
 
655
 
void GLAPIENTRY
656
 
_mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
657
 
                                   GLvoid *data)
658
 
{
659
 
   GET_CURRENT_CONTEXT(ctx);
660
 
 
661
 
   const struct gl_perf_monitor_group *group_obj;
662
 
   const struct gl_perf_monitor_counter *counter_obj;
663
 
 
664
 
   init_groups(ctx);
665
 
 
666
 
   group_obj = get_group(ctx, group);
667
 
 
668
 
   if (group_obj == NULL) {
669
 
      _mesa_error(ctx, GL_INVALID_VALUE,
670
 
                  "glGetPerfMonitorCounterInfoAMD(invalid group)");
671
 
      return;
672
 
   }
673
 
 
674
 
   counter_obj = get_counter(group_obj, counter);
675
 
 
676
 
   if (counter_obj == NULL) {
677
 
      _mesa_error(ctx, GL_INVALID_VALUE,
678
 
                  "glGetPerfMonitorCounterInfoAMD(invalid counter)");
679
 
      return;
680
 
   }
681
 
 
682
 
   switch (pname) {
683
 
   case GL_COUNTER_TYPE_AMD:
684
 
      *((GLenum *) data) = counter_obj->Type;
685
 
      break;
686
 
 
687
 
   case GL_COUNTER_RANGE_AMD:
688
 
      switch (counter_obj->Type) {
689
 
      case GL_FLOAT:
690
 
      case GL_PERCENTAGE_AMD: {
691
 
         float *f_data = data;
692
 
         f_data[0] = counter_obj->Minimum.f;
693
 
         f_data[1] = counter_obj->Maximum.f;
694
 
         break;
695
 
      }
696
 
      case GL_UNSIGNED_INT: {
697
 
         uint32_t *u32_data = data;
698
 
         u32_data[0] = counter_obj->Minimum.u32;
699
 
         u32_data[1] = counter_obj->Maximum.u32;
700
 
         break;
701
 
      }
702
 
      case GL_UNSIGNED_INT64_AMD: {
703
 
         uint64_t *u64_data = data;
704
 
         u64_data[0] = counter_obj->Minimum.u64;
705
 
         u64_data[1] = counter_obj->Maximum.u64;
706
 
         break;
707
 
      }
708
 
      default:
709
 
         assert(!"Should not get here: invalid counter type");
710
 
      }
711
 
      break;
712
 
 
713
 
   default:
714
 
      _mesa_error(ctx, GL_INVALID_ENUM,
715
 
                  "glGetPerfMonitorCounterInfoAMD(pname)");
716
 
      return;
717
 
   }
718
 
}
719
 
 
720
 
void GLAPIENTRY
721
 
_mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
722
 
{
723
 
   GET_CURRENT_CONTEXT(ctx);
724
 
 
725
 
   if (MESA_VERBOSE & VERBOSE_API)
726
 
      _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
727
 
 
728
 
   init_groups(ctx);
729
 
 
730
 
   if (n < 0) {
731
 
      _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
732
 
      return;
733
 
   }
734
 
 
735
 
   if (monitors == NULL)
736
 
      return;
737
 
 
738
 
   if (_mesa_HashFindFreeKeys(ctx->PerfMonitor.Monitors, monitors, n)) {
739
 
      GLsizei i;
740
 
      for (i = 0; i < n; i++) {
741
 
         struct gl_perf_monitor_object *m =
742
 
            new_performance_monitor(ctx, monitors[i]);
743
 
         if (!m) {
744
 
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
745
 
            return;
746
 
         }
747
 
         _mesa_HashInsert(ctx->PerfMonitor.Monitors, monitors[i], m, true);
748
 
      }
749
 
   } else {
750
 
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
751
 
      return;
752
 
   }
753
 
}
754
 
 
755
 
void GLAPIENTRY
756
 
_mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
757
 
{
758
 
   GLint i;
759
 
   GET_CURRENT_CONTEXT(ctx);
760
 
 
761
 
   if (MESA_VERBOSE & VERBOSE_API)
762
 
      _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
763
 
 
764
 
   if (n < 0) {
765
 
      _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
766
 
      return;
767
 
   }
768
 
 
769
 
   if (monitors == NULL)
770
 
      return;
771
 
 
772
 
   for (i = 0; i < n; i++) {
773
 
      struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
774
 
 
775
 
      if (m) {
776
 
         /* Give the driver a chance to stop the monitor if it's active. */
777
 
         if (m->Active) {
778
 
            reset_perf_monitor(ctx, m);
779
 
            m->Ended = false;
780
 
         }
781
 
 
782
 
         _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
783
 
         ralloc_free(m->ActiveGroups);
784
 
         ralloc_free(m->ActiveCounters);
785
 
         delete_perf_monitor(ctx, m);
786
 
      } else {
787
 
         /* "INVALID_VALUE error will be generated if any of the monitor IDs
788
 
          *  in the <monitors> parameter to DeletePerfMonitorsAMD do not
789
 
          *  reference a valid generated monitor ID."
790
 
          */
791
 
         _mesa_error(ctx, GL_INVALID_VALUE,
792
 
                     "glDeletePerfMonitorsAMD(invalid monitor)");
793
 
      }
794
 
   }
795
 
}
796
 
 
797
 
void GLAPIENTRY
798
 
_mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
799
 
                                   GLuint group, GLint numCounters,
800
 
                                   GLuint *counterList)
801
 
{
802
 
   GET_CURRENT_CONTEXT(ctx);
803
 
   int i;
804
 
   struct gl_perf_monitor_object *m;
805
 
   const struct gl_perf_monitor_group *group_obj;
806
 
 
807
 
   m = lookup_monitor(ctx, monitor);
808
 
 
809
 
   /* "INVALID_VALUE error will be generated if the <monitor> parameter to
810
 
    *  SelectPerfMonitorCountersAMD does not reference a monitor created by
811
 
    *  GenPerfMonitorsAMD."
812
 
    */
813
 
   if (m == NULL) {
814
 
      _mesa_error(ctx, GL_INVALID_VALUE,
815
 
                  "glSelectPerfMonitorCountersAMD(invalid monitor)");
816
 
      return;
817
 
   }
818
 
 
819
 
   group_obj = get_group(ctx, group);
820
 
 
821
 
   /* "INVALID_VALUE error will be generated if the <group> parameter to
822
 
    *  GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
823
 
    *  GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
824
 
    *  SelectPerfMonitorCountersAMD does not reference a valid group ID."
825
 
    */
826
 
   if (group_obj == NULL) {
827
 
      _mesa_error(ctx, GL_INVALID_VALUE,
828
 
                  "glSelectPerfMonitorCountersAMD(invalid group)");
829
 
      return;
830
 
   }
831
 
 
832
 
   /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
833
 
    *  SelectPerfMonitorCountersAMD is less than 0."
834
 
    */
835
 
   if (numCounters < 0) {
836
 
      _mesa_error(ctx, GL_INVALID_VALUE,
837
 
                  "glSelectPerfMonitorCountersAMD(numCounters < 0)");
838
 
      return;
839
 
   }
840
 
 
841
 
   /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
842
 
    *  results for that monitor become invalidated and the result queries
843
 
    *  PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
844
 
    */
845
 
   reset_perf_monitor(ctx, m);
846
 
 
847
 
   /* Sanity check the counter ID list. */
848
 
   for (i = 0; i < numCounters; i++) {
849
 
      if (counterList[i] >= group_obj->NumCounters) {
850
 
         _mesa_error(ctx, GL_INVALID_VALUE,
851
 
                     "glSelectPerfMonitorCountersAMD(invalid counter ID)");
852
 
         return;
853
 
      }
854
 
   }
855
 
 
856
 
   if (enable) {
857
 
      /* Enable the counters */
858
 
      for (i = 0; i < numCounters; i++) {
859
 
         if (!BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
860
 
            ++m->ActiveGroups[group];
861
 
            BITSET_SET(m->ActiveCounters[group], counterList[i]);
862
 
         }
863
 
      }
864
 
   } else {
865
 
      /* Disable the counters */
866
 
      for (i = 0; i < numCounters; i++) {
867
 
         if (BITSET_TEST(m->ActiveCounters[group], counterList[i])) {
868
 
            --m->ActiveGroups[group];
869
 
            BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
870
 
         }
871
 
      }
872
 
   }
873
 
}
874
 
 
875
 
void GLAPIENTRY
876
 
_mesa_BeginPerfMonitorAMD(GLuint monitor)
877
 
{
878
 
   GET_CURRENT_CONTEXT(ctx);
879
 
 
880
 
   struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
881
 
 
882
 
   if (m == NULL) {
883
 
      _mesa_error(ctx, GL_INVALID_VALUE,
884
 
                  "glBeginPerfMonitorAMD(invalid monitor)");
885
 
      return;
886
 
   }
887
 
 
888
 
   /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
889
 
    *  called when a performance monitor is already active."
890
 
    */
891
 
   if (m->Active) {
892
 
      _mesa_error(ctx, GL_INVALID_OPERATION,
893
 
                  "glBeginPerfMonitor(already active)");
894
 
      return;
895
 
   }
896
 
 
897
 
   /* The driver is free to return false if it can't begin monitoring for
898
 
    * any reason.  This translates into an INVALID_OPERATION error.
899
 
    */
900
 
   if (begin_perf_monitor(ctx, m)) {
901
 
      m->Active = true;
902
 
      m->Ended = false;
903
 
   } else {
904
 
      _mesa_error(ctx, GL_INVALID_OPERATION,
905
 
                  "glBeginPerfMonitor(driver unable to begin monitoring)");
906
 
   }
907
 
}
908
 
 
909
 
void GLAPIENTRY
910
 
_mesa_EndPerfMonitorAMD(GLuint monitor)
911
 
{
912
 
   GET_CURRENT_CONTEXT(ctx);
913
 
 
914
 
   struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
915
 
 
916
 
   if (m == NULL) {
917
 
      _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
918
 
      return;
919
 
   }
920
 
 
921
 
   /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
922
 
    *  when a performance monitor is not currently started."
923
 
    */
924
 
   if (!m->Active) {
925
 
      _mesa_error(ctx, GL_INVALID_OPERATION, "glEndPerfMonitor(not active)");
926
 
      return;
927
 
   }
928
 
 
929
 
   end_perf_monitor(ctx, m);
930
 
 
931
 
   m->Active = false;
932
 
   m->Ended = true;
933
 
}
934
 
 
935
 
/**
936
 
 * Return the number of bytes needed to store a monitor's result.
937
 
 */
938
 
static unsigned
939
 
perf_monitor_result_size(const struct gl_context *ctx,
940
 
                         const struct gl_perf_monitor_object *m)
941
 
{
942
 
   unsigned group, counter;
943
 
   unsigned size = 0;
944
 
 
945
 
   for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
946
 
      const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
947
 
 
948
 
      BITSET_FOREACH_SET(counter, m->ActiveCounters[group], g->NumCounters) {
949
 
         const struct gl_perf_monitor_counter *c = &g->Counters[counter];
950
 
 
951
 
         size += sizeof(uint32_t); /* Group ID */
952
 
         size += sizeof(uint32_t); /* Counter ID */
953
 
         size += _mesa_perf_monitor_counter_size(c);
954
 
      }
955
 
   }
956
 
   return size;
957
 
}
958
 
 
959
 
void GLAPIENTRY
960
 
_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
961
 
                                   GLsizei dataSize, GLuint *data,
962
 
                                   GLint *bytesWritten)
963
 
{
964
 
   GET_CURRENT_CONTEXT(ctx);
965
 
 
966
 
   struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
967
 
   bool result_available;
968
 
 
969
 
   if (m == NULL) {
970
 
      _mesa_error(ctx, GL_INVALID_VALUE,
971
 
                  "glGetPerfMonitorCounterDataAMD(invalid monitor)");
972
 
      return;
973
 
   }
974
 
 
975
 
   /* "It is an INVALID_OPERATION error for <data> to be NULL." */
976
 
   if (data == NULL) {
977
 
      _mesa_error(ctx, GL_INVALID_OPERATION,
978
 
                  "glGetPerfMonitorCounterDataAMD(data == NULL)");
979
 
      return;
980
 
   }
981
 
 
982
 
   /* We need at least enough room for a single value. */
983
 
   if (dataSize < sizeof(GLuint)) {
984
 
      if (bytesWritten != NULL)
985
 
         *bytesWritten = 0;
986
 
      return;
987
 
   }
988
 
 
989
 
   /* If the monitor has never ended, there is no result. */
990
 
   result_available = m->Ended &&
991
 
      is_perf_monitor_result_available(ctx, m);
992
 
 
993
 
   /* AMD appears to return 0 for all queries unless a result is available. */
994
 
   if (!result_available) {
995
 
      *data = 0;
996
 
      if (bytesWritten != NULL)
997
 
         *bytesWritten = sizeof(GLuint);
998
 
      return;
999
 
   }
1000
 
 
1001
 
   switch (pname) {
1002
 
   case GL_PERFMON_RESULT_AVAILABLE_AMD:
1003
 
      *data = 1;
1004
 
      if (bytesWritten != NULL)
1005
 
         *bytesWritten = sizeof(GLuint);
1006
 
      break;
1007
 
   case GL_PERFMON_RESULT_SIZE_AMD:
1008
 
      *data = perf_monitor_result_size(ctx, m);
1009
 
      if (bytesWritten != NULL)
1010
 
         *bytesWritten = sizeof(GLuint);
1011
 
      break;
1012
 
   case GL_PERFMON_RESULT_AMD:
1013
 
      get_perf_monitor_result(ctx, m, dataSize, data, bytesWritten);
1014
 
      break;
1015
 
   default:
1016
 
      _mesa_error(ctx, GL_INVALID_ENUM,
1017
 
                  "glGetPerfMonitorCounterDataAMD(pname)");
1018
 
   }
1019
 
}
1020
 
 
1021
 
/**
1022
 
 * Returns how many bytes a counter's value takes up.
1023
 
 */
1024
 
unsigned
1025
 
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
1026
 
{
1027
 
   switch (c->Type) {
1028
 
   case GL_FLOAT:
1029
 
   case GL_PERCENTAGE_AMD:
1030
 
      return sizeof(GLfloat);
1031
 
   case GL_UNSIGNED_INT:
1032
 
      return sizeof(GLuint);
1033
 
   case GL_UNSIGNED_INT64_AMD:
1034
 
      return sizeof(uint64_t);
1035
 
   default:
1036
 
      assert(!"Should not get here: invalid counter type");
1037
 
      return 0;
1038
 
   }
1039
 
}