2
* Copyright © 2012 Intel Corporation
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:
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
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.
25
* \file performance_monitor.c
26
* Core Mesa support for the AMD_performance_monitor extension.
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.
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.
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"
50
#include "state_tracker/st_cb_bitmap.h"
51
#include "state_tracker/st_context.h"
52
#include "state_tracker/st_debug.h"
54
#include "pipe/p_context.h"
55
#include "pipe/p_screen.h"
58
_mesa_init_performance_monitors(struct gl_context *ctx)
60
ctx->PerfMonitor.Monitors = _mesa_NewHashTable();
61
ctx->PerfMonitor.NumGroups = 0;
62
ctx->PerfMonitor.Groups = NULL;
67
init_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
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;
76
st_flush_bitmap_cache(st_context(ctx));
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];
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");
91
num_active_counters += m->ActiveGroups[gid];
93
max_batch_counters += m->ActiveGroups[gid];
96
if (!num_active_counters)
99
m->active_counters = CALLOC(num_active_counters,
100
sizeof(*m->active_counters));
101
if (!m->active_counters)
104
if (max_batch_counters) {
105
batch = CALLOC(max_batch_counters, sizeof(*batch));
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];
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];
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;
125
cntr->query = pipe->create_query(pipe, c->query_type, 0);
129
++m->num_active_counters;
133
/* Create the batch query. */
134
if (num_batch_counters) {
135
m->batch_query = pipe->create_batch_query(pipe, num_batch_counters,
137
m->batch_result = CALLOC(num_batch_counters, sizeof(m->batch_result->batch[0]));
138
if (!m->batch_query || !m->batch_result)
151
do_reset_perf_monitor(struct gl_perf_monitor_object *m,
152
struct pipe_context *pipe)
156
for (i = 0; i < m->num_active_counters; ++i) {
157
struct pipe_query *query = m->active_counters[i].query;
159
pipe->destroy_query(pipe, query);
161
FREE(m->active_counters);
162
m->active_counters = NULL;
163
m->num_active_counters = 0;
165
if (m->batch_query) {
166
pipe->destroy_query(pipe, m->batch_query);
167
m->batch_query = NULL;
169
FREE(m->batch_result);
170
m->batch_result = NULL;
174
delete_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
176
struct pipe_context *pipe = st_context(ctx)->pipe;
178
do_reset_perf_monitor(m, pipe);
183
begin_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
185
struct pipe_context *pipe = st_context(ctx)->pipe;
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))
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))
202
if (m->batch_query && !pipe->begin_query(pipe, m->batch_query))
208
/* Failed to start the monitoring session. */
209
do_reset_perf_monitor(m, pipe);
214
end_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
216
struct pipe_context *pipe = st_context(ctx)->pipe;
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;
223
pipe->end_query(pipe, query);
227
pipe->end_query(pipe, m->batch_query);
231
reset_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m)
233
struct pipe_context *pipe = st_context(ctx)->pipe;
236
end_perf_monitor(ctx, m);
238
do_reset_perf_monitor(m, pipe);
241
begin_perf_monitor(ctx, m);
245
is_perf_monitor_result_available(struct gl_context *ctx,
246
struct gl_perf_monitor_object *m)
248
struct pipe_context *pipe = st_context(ctx)->pipe;
251
if (!m->num_active_counters)
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. */
265
if (m->batch_query &&
266
!pipe->get_query_result(pipe, m->batch_query, FALSE, m->batch_result))
273
get_perf_monitor_result(struct gl_context *ctx,
274
struct gl_perf_monitor_object *m,
279
struct pipe_context *pipe = st_context(ctx)->pipe;
282
/* Copy data to the supplied array (data).
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.
288
bool have_batch_query = false;
291
have_batch_query = pipe->get_query_result(pipe, m->batch_query, TRUE,
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 };
302
gid = cntr->group_id;
303
type = ctx->PerfMonitor.Groups[gid].Counters[cid].Type;
306
if (!pipe->get_query_result(pipe, cntr->query, TRUE, &result))
309
if (!have_batch_query)
311
result.batch[0] = m->batch_result->batch[cntr->batch_index];
314
data[offset++] = gid;
315
data[offset++] = cid;
317
case GL_UNSIGNED_INT64_AMD:
318
memcpy(&data[offset], &result.u64, sizeof(uint64_t));
319
offset += sizeof(uint64_t) / sizeof(GLuint);
321
case GL_UNSIGNED_INT:
322
memcpy(&data[offset], &result.u32, sizeof(uint32_t));
323
offset += sizeof(uint32_t) / sizeof(GLuint);
326
case GL_PERCENTAGE_AMD:
327
memcpy(&data[offset], &result.f, sizeof(GLfloat));
328
offset += sizeof(GLfloat) / sizeof(GLuint);
334
*bytesWritten = offset * sizeof(GLuint);
338
_mesa_free_perfomance_monitor_groups(struct gl_context *ctx)
340
struct gl_perf_monitor_state *perfmon = &ctx->PerfMonitor;
343
for (gid = 0; gid < perfmon->NumGroups; gid++) {
344
FREE((void *)perfmon->Groups[gid].Counters);
346
FREE((void *)perfmon->Groups);
350
init_groups(struct gl_context *ctx)
352
if (likely(ctx->PerfMonitor.Groups))
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;
361
/* Get the number of available queries. */
362
num_counters = screen->get_driver_query_info(screen, 0, NULL);
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));
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;
375
if (!screen->get_driver_query_group_info(screen, gid, &group_info))
378
g->Name = group_info.name;
379
g->MaxActiveCounters = group_info.max_active_queries;
381
if (group_info.num_queries)
382
counters = CALLOC(group_info.num_queries, sizeof(*counters));
385
g->Counters = counters;
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;
391
if (!screen->get_driver_query_info(screen, cid, &info))
393
if (info.group_id != gid)
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:
403
c->Maximum.u64 = info.max_value.u64 ? info.max_value.u64 : UINT64_MAX;
404
c->Type = GL_UNSIGNED_INT64_AMD;
406
case PIPE_DRIVER_QUERY_TYPE_UINT:
408
c->Maximum.u32 = info.max_value.u32 ? info.max_value.u32 : UINT32_MAX;
409
c->Type = GL_UNSIGNED_INT;
411
case PIPE_DRIVER_QUERY_TYPE_FLOAT:
413
c->Maximum.f = info.max_value.f ? info.max_value.f : FLT_MAX;
416
case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE:
418
c->Maximum.f = 100.0f;
419
c->Type = GL_PERCENTAGE_AMD;
422
unreachable("Invalid driver query type!");
425
c->query_type = info.query_type;
426
c->flags = info.flags;
427
if (c->flags & PIPE_DRIVER_QUERY_FLAG_BATCH)
432
perfmon->NumGroups++;
434
perfmon->Groups = groups;
439
for (gid = 0; gid < num_groups; gid++) {
440
FREE((void *)groups[gid].Counters);
445
static struct gl_perf_monitor_object *
446
new_performance_monitor(struct gl_context *ctx, GLuint index)
449
struct gl_perf_monitor_object *m = CALLOC_STRUCT(gl_perf_monitor_object);
459
rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
462
ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
464
if (m->ActiveGroups == NULL || m->ActiveCounters == NULL)
467
for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) {
468
const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i];
470
m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD,
471
BITSET_WORDS(g->NumCounters));
472
if (m->ActiveCounters[i] == NULL)
479
ralloc_free(m->ActiveGroups);
480
ralloc_free(m->ActiveCounters);
481
delete_perf_monitor(ctx, m);
486
free_performance_monitor(void *data, void *user)
488
struct gl_perf_monitor_object *m = data;
489
struct gl_context *ctx = user;
491
ralloc_free(m->ActiveGroups);
492
ralloc_free(m->ActiveCounters);
493
delete_perf_monitor(ctx, m);
497
_mesa_free_performance_monitors(struct gl_context *ctx)
499
_mesa_HashDeleteAll(ctx->PerfMonitor.Monitors,
500
free_performance_monitor, ctx);
501
_mesa_DeleteHashTable(ctx->PerfMonitor.Monitors);
504
static inline struct gl_perf_monitor_object *
505
lookup_monitor(struct gl_context *ctx, GLuint id)
507
return (struct gl_perf_monitor_object *)
508
_mesa_HashLookup(ctx->PerfMonitor.Monitors, id);
511
static inline const struct gl_perf_monitor_group *
512
get_group(const struct gl_context *ctx, GLuint id)
514
if (id >= ctx->PerfMonitor.NumGroups)
517
return &ctx->PerfMonitor.Groups[id];
520
static inline const struct gl_perf_monitor_counter *
521
get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
523
if (id >= group_obj->NumCounters)
526
return &group_obj->Counters[id];
529
/*****************************************************************************/
532
_mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
535
GET_CURRENT_CONTEXT(ctx);
538
if (numGroups != NULL)
539
*numGroups = ctx->PerfMonitor.NumGroups;
541
if (groupsSize > 0 && groups != NULL) {
543
unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
545
/* We just use the index in the Groups array as the ID. */
546
for (i = 0; i < n; i++)
552
_mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
553
GLint *maxActiveCounters,
554
GLsizei countersSize, GLuint *counters)
556
GET_CURRENT_CONTEXT(ctx);
557
const struct gl_perf_monitor_group *group_obj;
561
group_obj = get_group(ctx, group);
562
if (group_obj == NULL) {
563
_mesa_error(ctx, GL_INVALID_VALUE,
564
"glGetPerfMonitorCountersAMD(invalid group)");
568
if (maxActiveCounters != NULL)
569
*maxActiveCounters = group_obj->MaxActiveCounters;
571
if (numCounters != NULL)
572
*numCounters = group_obj->NumCounters;
574
if (counters != NULL) {
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. */
585
_mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
586
GLsizei *length, GLchar *groupString)
588
GET_CURRENT_CONTEXT(ctx);
589
const struct gl_perf_monitor_group *group_obj;
593
group_obj = get_group(ctx, group);
594
if (group_obj == NULL) {
595
_mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
600
/* Return the number of characters that would be required to hold the
601
* group string, excluding the null terminator.
604
*length = strlen(group_obj->Name);
607
*length = MIN2(strlen(group_obj->Name), bufSize);
608
if (groupString != NULL)
609
strncpy(groupString, group_obj->Name, bufSize);
614
_mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
615
GLsizei bufSize, GLsizei *length,
616
GLchar *counterString)
618
GET_CURRENT_CONTEXT(ctx);
620
const struct gl_perf_monitor_group *group_obj;
621
const struct gl_perf_monitor_counter *counter_obj;
625
group_obj = get_group(ctx, group);
627
if (group_obj == NULL) {
628
_mesa_error(ctx, GL_INVALID_VALUE,
629
"glGetPerfMonitorCounterStringAMD(invalid group)");
633
counter_obj = get_counter(group_obj, counter);
635
if (counter_obj == NULL) {
636
_mesa_error(ctx, GL_INVALID_VALUE,
637
"glGetPerfMonitorCounterStringAMD(invalid counter)");
642
/* Return the number of characters that would be required to hold the
643
* counter string, excluding the null terminator.
646
*length = strlen(counter_obj->Name);
649
*length = MIN2(strlen(counter_obj->Name), bufSize);
650
if (counterString != NULL)
651
strncpy(counterString, counter_obj->Name, bufSize);
656
_mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
659
GET_CURRENT_CONTEXT(ctx);
661
const struct gl_perf_monitor_group *group_obj;
662
const struct gl_perf_monitor_counter *counter_obj;
666
group_obj = get_group(ctx, group);
668
if (group_obj == NULL) {
669
_mesa_error(ctx, GL_INVALID_VALUE,
670
"glGetPerfMonitorCounterInfoAMD(invalid group)");
674
counter_obj = get_counter(group_obj, counter);
676
if (counter_obj == NULL) {
677
_mesa_error(ctx, GL_INVALID_VALUE,
678
"glGetPerfMonitorCounterInfoAMD(invalid counter)");
683
case GL_COUNTER_TYPE_AMD:
684
*((GLenum *) data) = counter_obj->Type;
687
case GL_COUNTER_RANGE_AMD:
688
switch (counter_obj->Type) {
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;
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;
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;
709
assert(!"Should not get here: invalid counter type");
714
_mesa_error(ctx, GL_INVALID_ENUM,
715
"glGetPerfMonitorCounterInfoAMD(pname)");
721
_mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
723
GET_CURRENT_CONTEXT(ctx);
725
if (MESA_VERBOSE & VERBOSE_API)
726
_mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
731
_mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
735
if (monitors == NULL)
738
if (_mesa_HashFindFreeKeys(ctx->PerfMonitor.Monitors, monitors, n)) {
740
for (i = 0; i < n; i++) {
741
struct gl_perf_monitor_object *m =
742
new_performance_monitor(ctx, monitors[i]);
744
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
747
_mesa_HashInsert(ctx->PerfMonitor.Monitors, monitors[i], m, true);
750
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
756
_mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
759
GET_CURRENT_CONTEXT(ctx);
761
if (MESA_VERBOSE & VERBOSE_API)
762
_mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
765
_mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
769
if (monitors == NULL)
772
for (i = 0; i < n; i++) {
773
struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
776
/* Give the driver a chance to stop the monitor if it's active. */
778
reset_perf_monitor(ctx, m);
782
_mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
783
ralloc_free(m->ActiveGroups);
784
ralloc_free(m->ActiveCounters);
785
delete_perf_monitor(ctx, m);
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."
791
_mesa_error(ctx, GL_INVALID_VALUE,
792
"glDeletePerfMonitorsAMD(invalid monitor)");
798
_mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
799
GLuint group, GLint numCounters,
802
GET_CURRENT_CONTEXT(ctx);
804
struct gl_perf_monitor_object *m;
805
const struct gl_perf_monitor_group *group_obj;
807
m = lookup_monitor(ctx, monitor);
809
/* "INVALID_VALUE error will be generated if the <monitor> parameter to
810
* SelectPerfMonitorCountersAMD does not reference a monitor created by
811
* GenPerfMonitorsAMD."
814
_mesa_error(ctx, GL_INVALID_VALUE,
815
"glSelectPerfMonitorCountersAMD(invalid monitor)");
819
group_obj = get_group(ctx, group);
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."
826
if (group_obj == NULL) {
827
_mesa_error(ctx, GL_INVALID_VALUE,
828
"glSelectPerfMonitorCountersAMD(invalid group)");
832
/* "INVALID_VALUE error will be generated if the <numCounters> parameter to
833
* SelectPerfMonitorCountersAMD is less than 0."
835
if (numCounters < 0) {
836
_mesa_error(ctx, GL_INVALID_VALUE,
837
"glSelectPerfMonitorCountersAMD(numCounters < 0)");
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."
845
reset_perf_monitor(ctx, m);
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)");
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]);
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]);
876
_mesa_BeginPerfMonitorAMD(GLuint monitor)
878
GET_CURRENT_CONTEXT(ctx);
880
struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
883
_mesa_error(ctx, GL_INVALID_VALUE,
884
"glBeginPerfMonitorAMD(invalid monitor)");
888
/* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
889
* called when a performance monitor is already active."
892
_mesa_error(ctx, GL_INVALID_OPERATION,
893
"glBeginPerfMonitor(already active)");
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.
900
if (begin_perf_monitor(ctx, m)) {
904
_mesa_error(ctx, GL_INVALID_OPERATION,
905
"glBeginPerfMonitor(driver unable to begin monitoring)");
910
_mesa_EndPerfMonitorAMD(GLuint monitor)
912
GET_CURRENT_CONTEXT(ctx);
914
struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
917
_mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
921
/* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
922
* when a performance monitor is not currently started."
925
_mesa_error(ctx, GL_INVALID_OPERATION, "glEndPerfMonitor(not active)");
929
end_perf_monitor(ctx, m);
936
* Return the number of bytes needed to store a monitor's result.
939
perf_monitor_result_size(const struct gl_context *ctx,
940
const struct gl_perf_monitor_object *m)
942
unsigned group, counter;
945
for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
946
const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
948
BITSET_FOREACH_SET(counter, m->ActiveCounters[group], g->NumCounters) {
949
const struct gl_perf_monitor_counter *c = &g->Counters[counter];
951
size += sizeof(uint32_t); /* Group ID */
952
size += sizeof(uint32_t); /* Counter ID */
953
size += _mesa_perf_monitor_counter_size(c);
960
_mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
961
GLsizei dataSize, GLuint *data,
964
GET_CURRENT_CONTEXT(ctx);
966
struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
967
bool result_available;
970
_mesa_error(ctx, GL_INVALID_VALUE,
971
"glGetPerfMonitorCounterDataAMD(invalid monitor)");
975
/* "It is an INVALID_OPERATION error for <data> to be NULL." */
977
_mesa_error(ctx, GL_INVALID_OPERATION,
978
"glGetPerfMonitorCounterDataAMD(data == NULL)");
982
/* We need at least enough room for a single value. */
983
if (dataSize < sizeof(GLuint)) {
984
if (bytesWritten != NULL)
989
/* If the monitor has never ended, there is no result. */
990
result_available = m->Ended &&
991
is_perf_monitor_result_available(ctx, m);
993
/* AMD appears to return 0 for all queries unless a result is available. */
994
if (!result_available) {
996
if (bytesWritten != NULL)
997
*bytesWritten = sizeof(GLuint);
1002
case GL_PERFMON_RESULT_AVAILABLE_AMD:
1004
if (bytesWritten != NULL)
1005
*bytesWritten = sizeof(GLuint);
1007
case GL_PERFMON_RESULT_SIZE_AMD:
1008
*data = perf_monitor_result_size(ctx, m);
1009
if (bytesWritten != NULL)
1010
*bytesWritten = sizeof(GLuint);
1012
case GL_PERFMON_RESULT_AMD:
1013
get_perf_monitor_result(ctx, m, dataSize, data, bytesWritten);
1016
_mesa_error(ctx, GL_INVALID_ENUM,
1017
"glGetPerfMonitorCounterDataAMD(pname)");
1022
* Returns how many bytes a counter's value takes up.
1025
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
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);
1036
assert(!"Should not get here: invalid counter type");