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