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