1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2012-2017 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_query.c 26bf215546Sopenharmony_ci * Core Mesa support for the INTEL_performance_query extension. 27bf215546Sopenharmony_ci */ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <stdbool.h> 30bf215546Sopenharmony_ci#include "glheader.h" 31bf215546Sopenharmony_ci#include "context.h" 32bf215546Sopenharmony_ci#include "enums.h" 33bf215546Sopenharmony_ci#include "hash.h" 34bf215546Sopenharmony_ci#include "macros.h" 35bf215546Sopenharmony_ci#include "mtypes.h" 36bf215546Sopenharmony_ci#include "performance_query.h" 37bf215546Sopenharmony_ci#include "util/ralloc.h" 38bf215546Sopenharmony_ci#include "api_exec_decl.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "pipe/p_context.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci#include "state_tracker/st_cb_flush.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_civoid 45bf215546Sopenharmony_ci_mesa_init_performance_queries(struct gl_context *ctx) 46bf215546Sopenharmony_ci{ 47bf215546Sopenharmony_ci ctx->PerfQuery.Objects = _mesa_NewHashTable(); 48bf215546Sopenharmony_ci} 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_cistatic void 51bf215546Sopenharmony_cifree_performance_query(void *data, void *user) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci struct gl_perf_query_object *m = data; 54bf215546Sopenharmony_ci struct gl_context *ctx = user; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci /* Don't confuse the implementation by deleting an active query. We can 57bf215546Sopenharmony_ci * toggle Active/Used to false because we're tearing down the GL context 58bf215546Sopenharmony_ci * and it's already idle (see _mesa_free_context_data). 59bf215546Sopenharmony_ci */ 60bf215546Sopenharmony_ci m->Active = false; 61bf215546Sopenharmony_ci m->Used = false; 62bf215546Sopenharmony_ci ctx->pipe->delete_intel_perf_query(ctx->pipe, (struct pipe_query *)m); 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_civoid 66bf215546Sopenharmony_ci_mesa_free_performance_queries(struct gl_context *ctx) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci _mesa_HashDeleteAll(ctx->PerfQuery.Objects, 69bf215546Sopenharmony_ci free_performance_query, ctx); 70bf215546Sopenharmony_ci _mesa_DeleteHashTable(ctx->PerfQuery.Objects); 71bf215546Sopenharmony_ci} 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_cistatic inline struct gl_perf_query_object * 74bf215546Sopenharmony_cilookup_object(struct gl_context *ctx, GLuint id) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci return _mesa_HashLookup(ctx->PerfQuery.Objects, id); 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_cistatic GLuint 80bf215546Sopenharmony_ciinit_performance_query_info(struct gl_context *ctx) 81bf215546Sopenharmony_ci{ 82bf215546Sopenharmony_ci return ctx->pipe->init_intel_perf_query_info(ctx->pipe); 83bf215546Sopenharmony_ci} 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci/* For INTEL_performance_query, query id 0 is reserved to be invalid. */ 86bf215546Sopenharmony_cistatic inline unsigned 87bf215546Sopenharmony_ciqueryid_to_index(GLuint queryid) 88bf215546Sopenharmony_ci{ 89bf215546Sopenharmony_ci return queryid - 1; 90bf215546Sopenharmony_ci} 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_cistatic inline GLuint 93bf215546Sopenharmony_ciindex_to_queryid(unsigned index) 94bf215546Sopenharmony_ci{ 95bf215546Sopenharmony_ci return index + 1; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic inline bool 99bf215546Sopenharmony_ciqueryid_valid(const struct gl_context *ctx, unsigned numQueries, GLuint queryid) 100bf215546Sopenharmony_ci{ 101bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 102bf215546Sopenharmony_ci * 103bf215546Sopenharmony_ci * "Performance counter ids values start with 1. Performance counter id 0 104bf215546Sopenharmony_ci * is reserved as an invalid counter." 105bf215546Sopenharmony_ci */ 106bf215546Sopenharmony_ci return queryid != 0 && queryid_to_index(queryid) < numQueries; 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic inline GLuint 110bf215546Sopenharmony_cicounterid_to_index(GLuint counterid) 111bf215546Sopenharmony_ci{ 112bf215546Sopenharmony_ci return counterid - 1; 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic void 116bf215546Sopenharmony_cioutput_clipped_string(GLchar *stringRet, 117bf215546Sopenharmony_ci GLuint stringMaxLen, 118bf215546Sopenharmony_ci const char *string) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci if (!stringRet) 121bf215546Sopenharmony_ci return; 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci strncpy(stringRet, string ? string : "", stringMaxLen); 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci /* No specification given about whether returned strings needs 126bf215546Sopenharmony_ci * to be zero-terminated. Zero-terminate the string always as we 127bf215546Sopenharmony_ci * don't otherwise communicate the length of the returned 128bf215546Sopenharmony_ci * string. 129bf215546Sopenharmony_ci */ 130bf215546Sopenharmony_ci if (stringMaxLen > 0) 131bf215546Sopenharmony_ci stringRet[stringMaxLen - 1] = '\0'; 132bf215546Sopenharmony_ci} 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci/*****************************************************************************/ 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ciextern void GLAPIENTRY 137bf215546Sopenharmony_ci_mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci unsigned numQueries; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 144bf215546Sopenharmony_ci * 145bf215546Sopenharmony_ci * "If queryId pointer is equal to 0, INVALID_VALUE error is generated." 146bf215546Sopenharmony_ci */ 147bf215546Sopenharmony_ci if (!queryId) { 148bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 149bf215546Sopenharmony_ci "glGetFirstPerfQueryIdINTEL(queryId == NULL)"); 150bf215546Sopenharmony_ci return; 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci numQueries = init_performance_query_info(ctx); 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 156bf215546Sopenharmony_ci * 157bf215546Sopenharmony_ci * "If the given hardware platform doesn't support any performance 158bf215546Sopenharmony_ci * queries, then the value of 0 is returned and INVALID_OPERATION error 159bf215546Sopenharmony_ci * is raised." 160bf215546Sopenharmony_ci */ 161bf215546Sopenharmony_ci if (numQueries == 0) { 162bf215546Sopenharmony_ci *queryId = 0; 163bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 164bf215546Sopenharmony_ci "glGetFirstPerfQueryIdINTEL(no queries supported)"); 165bf215546Sopenharmony_ci return; 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci *queryId = index_to_queryid(0); 169bf215546Sopenharmony_ci} 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ciextern void GLAPIENTRY 172bf215546Sopenharmony_ci_mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId) 173bf215546Sopenharmony_ci{ 174bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci unsigned numQueries; 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 179bf215546Sopenharmony_ci * 180bf215546Sopenharmony_ci * "The result is passed in location pointed by nextQueryId. If query 181bf215546Sopenharmony_ci * identified by queryId is the last query available the value of 0 is 182bf215546Sopenharmony_ci * returned. If the specified performance query identifier is invalid 183bf215546Sopenharmony_ci * then INVALID_VALUE error is generated. If nextQueryId pointer is 184bf215546Sopenharmony_ci * equal to 0, an INVALID_VALUE error is generated. Whenever error is 185bf215546Sopenharmony_ci * generated, the value of 0 is returned." 186bf215546Sopenharmony_ci */ 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci if (!nextQueryId) { 189bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 190bf215546Sopenharmony_ci "glGetNextPerfQueryIdINTEL(nextQueryId == NULL)"); 191bf215546Sopenharmony_ci return; 192bf215546Sopenharmony_ci } 193bf215546Sopenharmony_ci 194bf215546Sopenharmony_ci numQueries = init_performance_query_info(ctx); 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (!queryid_valid(ctx, numQueries, queryId)) { 197bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 198bf215546Sopenharmony_ci "glGetNextPerfQueryIdINTEL(invalid query)"); 199bf215546Sopenharmony_ci return; 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci if (queryid_valid(ctx, numQueries, ++queryId)) 203bf215546Sopenharmony_ci *nextQueryId = queryId; 204bf215546Sopenharmony_ci else 205bf215546Sopenharmony_ci *nextQueryId = 0; 206bf215546Sopenharmony_ci} 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ciextern void GLAPIENTRY 209bf215546Sopenharmony_ci_mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId) 210bf215546Sopenharmony_ci{ 211bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci unsigned numQueries; 214bf215546Sopenharmony_ci unsigned i; 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 217bf215546Sopenharmony_ci * 218bf215546Sopenharmony_ci * "If queryName does not reference a valid query name, an INVALID_VALUE 219bf215546Sopenharmony_ci * error is generated." 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_ci if (!queryName) { 222bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 223bf215546Sopenharmony_ci "glGetPerfQueryIdByNameINTEL(queryName == NULL)"); 224bf215546Sopenharmony_ci return; 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci /* The specification does not state that this produces an error but 228bf215546Sopenharmony_ci * to be consistent with glGetFirstPerfQueryIdINTEL we generate an 229bf215546Sopenharmony_ci * INVALID_VALUE error 230bf215546Sopenharmony_ci */ 231bf215546Sopenharmony_ci if (!queryId) { 232bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 233bf215546Sopenharmony_ci "glGetPerfQueryIdByNameINTEL(queryId == NULL)"); 234bf215546Sopenharmony_ci return; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci numQueries = init_performance_query_info(ctx); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci for (i = 0; i < numQueries; ++i) { 240bf215546Sopenharmony_ci const GLchar *name; 241bf215546Sopenharmony_ci GLuint ignore; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci ctx->pipe->get_intel_perf_query_info(ctx->pipe, i, &name, 244bf215546Sopenharmony_ci &ignore, &ignore, &ignore); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci if (strcmp(name, queryName) == 0) { 247bf215546Sopenharmony_ci *queryId = index_to_queryid(i); 248bf215546Sopenharmony_ci return; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 253bf215546Sopenharmony_ci "glGetPerfQueryIdByNameINTEL(invalid query name)"); 254bf215546Sopenharmony_ci} 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ciextern void GLAPIENTRY 257bf215546Sopenharmony_ci_mesa_GetPerfQueryInfoINTEL(GLuint queryId, 258bf215546Sopenharmony_ci GLuint nameLength, GLchar *name, 259bf215546Sopenharmony_ci GLuint *dataSize, 260bf215546Sopenharmony_ci GLuint *numCounters, 261bf215546Sopenharmony_ci GLuint *numActive, 262bf215546Sopenharmony_ci GLuint *capsMask) 263bf215546Sopenharmony_ci{ 264bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci unsigned numQueries = init_performance_query_info(ctx); 267bf215546Sopenharmony_ci unsigned queryIndex = queryid_to_index(queryId); 268bf215546Sopenharmony_ci const char *queryName; 269bf215546Sopenharmony_ci GLuint queryDataSize; 270bf215546Sopenharmony_ci GLuint queryNumCounters; 271bf215546Sopenharmony_ci GLuint queryNumActive; 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci if (!queryid_valid(ctx, numQueries, queryId)) { 274bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 275bf215546Sopenharmony_ci * 276bf215546Sopenharmony_ci * "If queryId does not reference a valid query type, an 277bf215546Sopenharmony_ci * INVALID_VALUE error is generated." 278bf215546Sopenharmony_ci */ 279bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 280bf215546Sopenharmony_ci "glGetPerfQueryInfoINTEL(invalid query)"); 281bf215546Sopenharmony_ci return; 282bf215546Sopenharmony_ci } 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci ctx->pipe->get_intel_perf_query_info(ctx->pipe, queryIndex, &queryName, 285bf215546Sopenharmony_ci &queryDataSize, &queryNumCounters, 286bf215546Sopenharmony_ci &queryNumActive); 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci output_clipped_string(name, nameLength, queryName); 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci if (dataSize) 291bf215546Sopenharmony_ci *dataSize = queryDataSize; 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci if (numCounters) 294bf215546Sopenharmony_ci *numCounters = queryNumCounters; 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 297bf215546Sopenharmony_ci * 298bf215546Sopenharmony_ci * "-- the actual number of already created query instances in 299bf215546Sopenharmony_ci * maxInstances location" 300bf215546Sopenharmony_ci * 301bf215546Sopenharmony_ci * 1) Typo in the specification, should be noActiveInstances. 302bf215546Sopenharmony_ci * 2) Another typo in the specification, maxInstances parameter is not listed 303bf215546Sopenharmony_ci * in the declaration of this function in the list of new functions. 304bf215546Sopenharmony_ci */ 305bf215546Sopenharmony_ci if (numActive) 306bf215546Sopenharmony_ci *numActive = queryNumActive; 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci /* Assume for now that all queries are per-context */ 309bf215546Sopenharmony_ci if (capsMask) 310bf215546Sopenharmony_ci *capsMask = GL_PERFQUERY_SINGLE_CONTEXT_INTEL; 311bf215546Sopenharmony_ci} 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_cistatic uint32_t 314bf215546Sopenharmony_cipipe_counter_type_enum_to_gl_type(enum pipe_perf_counter_type type) 315bf215546Sopenharmony_ci{ 316bf215546Sopenharmony_ci switch (type) { 317bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_EVENT: return GL_PERFQUERY_COUNTER_EVENT_INTEL; 318bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_DURATION_NORM: return GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL; 319bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_DURATION_RAW: return GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL; 320bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_THROUGHPUT: return GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL; 321bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_RAW: return GL_PERFQUERY_COUNTER_RAW_INTEL; 322bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_TYPE_TIMESTAMP: return GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL; 323bf215546Sopenharmony_ci default: 324bf215546Sopenharmony_ci unreachable("Unknown counter type"); 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci} 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_cistatic uint32_t 329bf215546Sopenharmony_cipipe_counter_data_type_to_gl_type(enum pipe_perf_counter_data_type type) 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci switch (type) { 332bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_DATA_TYPE_BOOL32: return GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL; 333bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_DATA_TYPE_UINT32: return GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL; 334bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_DATA_TYPE_UINT64: return GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL; 335bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_DATA_TYPE_FLOAT: return GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL; 336bf215546Sopenharmony_ci case PIPE_PERF_COUNTER_DATA_TYPE_DOUBLE: return GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL; 337bf215546Sopenharmony_ci default: 338bf215546Sopenharmony_ci unreachable("Unknown counter data type"); 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci} 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_cistatic void 343bf215546Sopenharmony_ciget_perf_counter_info(struct gl_context *ctx, 344bf215546Sopenharmony_ci unsigned query_index, 345bf215546Sopenharmony_ci unsigned counter_index, 346bf215546Sopenharmony_ci const char **name, 347bf215546Sopenharmony_ci const char **desc, 348bf215546Sopenharmony_ci GLuint *offset, 349bf215546Sopenharmony_ci GLuint *data_size, 350bf215546Sopenharmony_ci GLuint *type_enum, 351bf215546Sopenharmony_ci GLuint *data_type_enum, 352bf215546Sopenharmony_ci GLuint64 *raw_max) 353bf215546Sopenharmony_ci{ 354bf215546Sopenharmony_ci struct pipe_context *pipe = ctx->pipe; 355bf215546Sopenharmony_ci uint32_t pipe_type_enum; 356bf215546Sopenharmony_ci uint32_t pipe_data_type_enum; 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci pipe->get_intel_perf_query_counter_info(pipe, query_index, counter_index, 359bf215546Sopenharmony_ci name, desc, offset, data_size, 360bf215546Sopenharmony_ci &pipe_type_enum, &pipe_data_type_enum, raw_max); 361bf215546Sopenharmony_ci *type_enum = pipe_counter_type_enum_to_gl_type(pipe_type_enum); 362bf215546Sopenharmony_ci *data_type_enum = pipe_counter_data_type_to_gl_type(pipe_data_type_enum); 363bf215546Sopenharmony_ci} 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ciextern void GLAPIENTRY 366bf215546Sopenharmony_ci_mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId, 367bf215546Sopenharmony_ci GLuint nameLength, GLchar *name, 368bf215546Sopenharmony_ci GLuint descLength, GLchar *desc, 369bf215546Sopenharmony_ci GLuint *offset, 370bf215546Sopenharmony_ci GLuint *dataSize, 371bf215546Sopenharmony_ci GLuint *typeEnum, 372bf215546Sopenharmony_ci GLuint *dataTypeEnum, 373bf215546Sopenharmony_ci GLuint64 *rawCounterMaxValue) 374bf215546Sopenharmony_ci{ 375bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci unsigned numQueries = init_performance_query_info(ctx); 378bf215546Sopenharmony_ci unsigned queryIndex = queryid_to_index(queryId); 379bf215546Sopenharmony_ci const char *queryName; 380bf215546Sopenharmony_ci GLuint queryDataSize; 381bf215546Sopenharmony_ci GLuint queryNumCounters; 382bf215546Sopenharmony_ci GLuint queryNumActive; 383bf215546Sopenharmony_ci unsigned counterIndex; 384bf215546Sopenharmony_ci const char *counterName; 385bf215546Sopenharmony_ci const char *counterDesc; 386bf215546Sopenharmony_ci GLuint counterOffset; 387bf215546Sopenharmony_ci GLuint counterDataSize; 388bf215546Sopenharmony_ci GLuint counterTypeEnum; 389bf215546Sopenharmony_ci GLuint counterDataTypeEnum; 390bf215546Sopenharmony_ci GLuint64 counterRawMax; 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci if (!queryid_valid(ctx, numQueries, queryId)) { 393bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 394bf215546Sopenharmony_ci * 395bf215546Sopenharmony_ci * "If the pair of queryId and counterId does not reference a valid 396bf215546Sopenharmony_ci * counter, an INVALID_VALUE error is generated." 397bf215546Sopenharmony_ci */ 398bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 399bf215546Sopenharmony_ci "glGetPerfCounterInfoINTEL(invalid queryId)"); 400bf215546Sopenharmony_ci return; 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci ctx->pipe->get_intel_perf_query_info(ctx->pipe, queryIndex, &queryName, 404bf215546Sopenharmony_ci &queryDataSize, &queryNumCounters, 405bf215546Sopenharmony_ci &queryNumActive); 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci counterIndex = counterid_to_index(counterId); 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci if (counterIndex >= queryNumCounters) { 410bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 411bf215546Sopenharmony_ci "glGetPerfCounterInfoINTEL(invalid counterId)"); 412bf215546Sopenharmony_ci return; 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci get_perf_counter_info(ctx, queryIndex, counterIndex, 416bf215546Sopenharmony_ci &counterName, 417bf215546Sopenharmony_ci &counterDesc, 418bf215546Sopenharmony_ci &counterOffset, 419bf215546Sopenharmony_ci &counterDataSize, 420bf215546Sopenharmony_ci &counterTypeEnum, 421bf215546Sopenharmony_ci &counterDataTypeEnum, 422bf215546Sopenharmony_ci &counterRawMax); 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci output_clipped_string(name, nameLength, counterName); 425bf215546Sopenharmony_ci output_clipped_string(desc, descLength, counterDesc); 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci if (offset) 428bf215546Sopenharmony_ci *offset = counterOffset; 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci if (dataSize) 431bf215546Sopenharmony_ci *dataSize = counterDataSize; 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci if (typeEnum) 434bf215546Sopenharmony_ci *typeEnum = counterTypeEnum; 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci if (dataTypeEnum) 437bf215546Sopenharmony_ci *dataTypeEnum = counterDataTypeEnum; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci if (rawCounterMaxValue) 440bf215546Sopenharmony_ci *rawCounterMaxValue = counterRawMax; 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci if (rawCounterMaxValue) { 443bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 444bf215546Sopenharmony_ci * 445bf215546Sopenharmony_ci * "for some raw counters for which the maximal value is 446bf215546Sopenharmony_ci * deterministic, the maximal value of the counter in 1 second is 447bf215546Sopenharmony_ci * returned in the location pointed by rawCounterMaxValue, otherwise, 448bf215546Sopenharmony_ci * the location is written with the value of 0." 449bf215546Sopenharmony_ci * 450bf215546Sopenharmony_ci * Since it's very useful to be able to report a maximum value for 451bf215546Sopenharmony_ci * more that just counters using the _COUNTER_RAW_INTEL or 452bf215546Sopenharmony_ci * _COUNTER_DURATION_RAW_INTEL enums (e.g. for a _THROUGHPUT tools 453bf215546Sopenharmony_ci * want to be able to visualize the absolute throughput with respect 454bf215546Sopenharmony_ci * to the theoretical maximum that's possible) and there doesn't seem 455bf215546Sopenharmony_ci * to be any reason not to allow _THROUGHPUT counters to also be 456bf215546Sopenharmony_ci * considerer "raw" here, we always leave it up to the backend to 457bf215546Sopenharmony_ci * decide when it's appropriate to report a maximum counter value or 0 458bf215546Sopenharmony_ci * if not. 459bf215546Sopenharmony_ci */ 460bf215546Sopenharmony_ci *rawCounterMaxValue = counterRawMax; 461bf215546Sopenharmony_ci } 462bf215546Sopenharmony_ci} 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ciextern void GLAPIENTRY 465bf215546Sopenharmony_ci_mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle) 466bf215546Sopenharmony_ci{ 467bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci unsigned numQueries = init_performance_query_info(ctx); 470bf215546Sopenharmony_ci GLuint id; 471bf215546Sopenharmony_ci struct gl_perf_query_object *obj; 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 474bf215546Sopenharmony_ci * 475bf215546Sopenharmony_ci * "If queryId does not reference a valid query type, an INVALID_VALUE 476bf215546Sopenharmony_ci * error is generated." 477bf215546Sopenharmony_ci */ 478bf215546Sopenharmony_ci if (!queryid_valid(ctx, numQueries, queryId)) { 479bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 480bf215546Sopenharmony_ci "glCreatePerfQueryINTEL(invalid queryId)"); 481bf215546Sopenharmony_ci return; 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci /* This is not specified in the extension, but is the only sane thing to 485bf215546Sopenharmony_ci * do. 486bf215546Sopenharmony_ci */ 487bf215546Sopenharmony_ci if (queryHandle == NULL) { 488bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 489bf215546Sopenharmony_ci "glCreatePerfQueryINTEL(queryHandle == NULL)"); 490bf215546Sopenharmony_ci return; 491bf215546Sopenharmony_ci } 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci id = _mesa_HashFindFreeKeyBlock(ctx->PerfQuery.Objects, 1); 494bf215546Sopenharmony_ci if (!id) { 495bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 496bf215546Sopenharmony_ci * 497bf215546Sopenharmony_ci * "If the query instance cannot be created due to exceeding the 498bf215546Sopenharmony_ci * number of allowed instances or driver fails query creation due to 499bf215546Sopenharmony_ci * an insufficient memory reason, an OUT_OF_MEMORY error is 500bf215546Sopenharmony_ci * generated, and the location pointed by queryHandle returns NULL." 501bf215546Sopenharmony_ci */ 502bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 503bf215546Sopenharmony_ci return; 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci obj = (struct gl_perf_query_object *)ctx->pipe->new_intel_perf_query_obj(ctx->pipe, 507bf215546Sopenharmony_ci queryid_to_index(queryId)); 508bf215546Sopenharmony_ci if (obj == NULL) { 509bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 510bf215546Sopenharmony_ci return; 511bf215546Sopenharmony_ci } 512bf215546Sopenharmony_ci 513bf215546Sopenharmony_ci obj->Id = id; 514bf215546Sopenharmony_ci obj->Active = false; 515bf215546Sopenharmony_ci obj->Ready = false; 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci _mesa_HashInsert(ctx->PerfQuery.Objects, id, obj, true); 518bf215546Sopenharmony_ci *queryHandle = id; 519bf215546Sopenharmony_ci} 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_ciextern void GLAPIENTRY 522bf215546Sopenharmony_ci_mesa_DeletePerfQueryINTEL(GLuint queryHandle) 523bf215546Sopenharmony_ci{ 524bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci struct gl_perf_query_object *obj = lookup_object(ctx, queryHandle); 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 529bf215546Sopenharmony_ci * 530bf215546Sopenharmony_ci * "If a query handle doesn't reference a previously created performance 531bf215546Sopenharmony_ci * query instance, an INVALID_VALUE error is generated." 532bf215546Sopenharmony_ci */ 533bf215546Sopenharmony_ci if (obj == NULL) { 534bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 535bf215546Sopenharmony_ci "glDeletePerfQueryINTEL(invalid queryHandle)"); 536bf215546Sopenharmony_ci return; 537bf215546Sopenharmony_ci } 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_ci /* To avoid complications in the backend we never ask the backend to 540bf215546Sopenharmony_ci * delete an active query or a query object while we are still 541bf215546Sopenharmony_ci * waiting for data. 542bf215546Sopenharmony_ci */ 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci if (obj->Active) 545bf215546Sopenharmony_ci _mesa_EndPerfQueryINTEL(queryHandle); 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci if (obj->Used && !obj->Ready) { 548bf215546Sopenharmony_ci ctx->pipe->wait_intel_perf_query(ctx->pipe, (struct pipe_query *)obj); 549bf215546Sopenharmony_ci obj->Ready = true; 550bf215546Sopenharmony_ci } 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci _mesa_HashRemove(ctx->PerfQuery.Objects, queryHandle); 553bf215546Sopenharmony_ci ctx->pipe->delete_intel_perf_query(ctx->pipe, (struct pipe_query *)obj); 554bf215546Sopenharmony_ci} 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_ciextern void GLAPIENTRY 557bf215546Sopenharmony_ci_mesa_BeginPerfQueryINTEL(GLuint queryHandle) 558bf215546Sopenharmony_ci{ 559bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci struct gl_perf_query_object *obj = lookup_object(ctx, queryHandle); 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 564bf215546Sopenharmony_ci * 565bf215546Sopenharmony_ci * "If a query handle doesn't reference a previously created performance 566bf215546Sopenharmony_ci * query instance, an INVALID_VALUE error is generated." 567bf215546Sopenharmony_ci */ 568bf215546Sopenharmony_ci if (obj == NULL) { 569bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 570bf215546Sopenharmony_ci "glBeginPerfQueryINTEL(invalid queryHandle)"); 571bf215546Sopenharmony_ci return; 572bf215546Sopenharmony_ci } 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 575bf215546Sopenharmony_ci * 576bf215546Sopenharmony_ci * "Note that some query types, they cannot be collected in the same 577bf215546Sopenharmony_ci * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if 578bf215546Sopenharmony_ci * they refer to queries of such different types. In such case 579bf215546Sopenharmony_ci * INVALID_OPERATION error is generated." 580bf215546Sopenharmony_ci * 581bf215546Sopenharmony_ci * We also generate an INVALID_OPERATION error if the driver can't begin 582bf215546Sopenharmony_ci * a query for its own reasons, and for nesting the same query. 583bf215546Sopenharmony_ci */ 584bf215546Sopenharmony_ci if (obj->Active) { 585bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 586bf215546Sopenharmony_ci "glBeginPerfQueryINTEL(already active)"); 587bf215546Sopenharmony_ci return; 588bf215546Sopenharmony_ci } 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci /* To avoid complications in the backend we never ask the backend to 591bf215546Sopenharmony_ci * reuse a query object and begin a new query while we are still 592bf215546Sopenharmony_ci * waiting for data on that object. 593bf215546Sopenharmony_ci */ 594bf215546Sopenharmony_ci if (obj->Used && !obj->Ready) { 595bf215546Sopenharmony_ci ctx->pipe->wait_intel_perf_query(ctx->pipe, (struct pipe_query *)obj); 596bf215546Sopenharmony_ci obj->Ready = true; 597bf215546Sopenharmony_ci } 598bf215546Sopenharmony_ci 599bf215546Sopenharmony_ci if (ctx->pipe->begin_intel_perf_query(ctx->pipe, (struct pipe_query *)obj)) { 600bf215546Sopenharmony_ci obj->Used = true; 601bf215546Sopenharmony_ci obj->Active = true; 602bf215546Sopenharmony_ci obj->Ready = false; 603bf215546Sopenharmony_ci } else { 604bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 605bf215546Sopenharmony_ci "glBeginPerfQueryINTEL(driver unable to begin query)"); 606bf215546Sopenharmony_ci } 607bf215546Sopenharmony_ci} 608bf215546Sopenharmony_ci 609bf215546Sopenharmony_ciextern void GLAPIENTRY 610bf215546Sopenharmony_ci_mesa_EndPerfQueryINTEL(GLuint queryHandle) 611bf215546Sopenharmony_ci{ 612bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci struct gl_perf_query_object *obj = lookup_object(ctx, queryHandle); 615bf215546Sopenharmony_ci 616bf215546Sopenharmony_ci /* Not explicitly covered in the spec, but for consistency... */ 617bf215546Sopenharmony_ci if (obj == NULL) { 618bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 619bf215546Sopenharmony_ci "glEndPerfQueryINTEL(invalid queryHandle)"); 620bf215546Sopenharmony_ci return; 621bf215546Sopenharmony_ci } 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 624bf215546Sopenharmony_ci * 625bf215546Sopenharmony_ci * "If a performance query is not currently started, an 626bf215546Sopenharmony_ci * INVALID_OPERATION error will be generated." 627bf215546Sopenharmony_ci */ 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci if (!obj->Active) { 630bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 631bf215546Sopenharmony_ci "glEndPerfQueryINTEL(not active)"); 632bf215546Sopenharmony_ci return; 633bf215546Sopenharmony_ci } 634bf215546Sopenharmony_ci 635bf215546Sopenharmony_ci ctx->pipe->end_intel_perf_query(ctx->pipe, (struct pipe_query *)obj); 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci obj->Active = false; 638bf215546Sopenharmony_ci obj->Ready = false; 639bf215546Sopenharmony_ci} 640bf215546Sopenharmony_ci 641bf215546Sopenharmony_ciextern void GLAPIENTRY 642bf215546Sopenharmony_ci_mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags, 643bf215546Sopenharmony_ci GLsizei dataSize, void *data, GLuint *bytesWritten) 644bf215546Sopenharmony_ci{ 645bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci struct gl_perf_query_object *obj = lookup_object(ctx, queryHandle); 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci /* Not explicitly covered in the spec, but for consistency... */ 650bf215546Sopenharmony_ci if (obj == NULL) { 651bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 652bf215546Sopenharmony_ci "glEndPerfQueryINTEL(invalid queryHandle)"); 653bf215546Sopenharmony_ci return; 654bf215546Sopenharmony_ci } 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci /* The GL_INTEL_performance_query spec says: 657bf215546Sopenharmony_ci * 658bf215546Sopenharmony_ci * "If bytesWritten or data pointers are NULL then an INVALID_VALUE 659bf215546Sopenharmony_ci * error is generated." 660bf215546Sopenharmony_ci */ 661bf215546Sopenharmony_ci if (!bytesWritten || !data) { 662bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 663bf215546Sopenharmony_ci "glGetPerfQueryDataINTEL(bytesWritten or data is NULL)"); 664bf215546Sopenharmony_ci return; 665bf215546Sopenharmony_ci } 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_ci /* Just for good measure in case a lazy application is only 668bf215546Sopenharmony_ci * checking this and not checking for errors... 669bf215546Sopenharmony_ci */ 670bf215546Sopenharmony_ci *bytesWritten = 0; 671bf215546Sopenharmony_ci 672bf215546Sopenharmony_ci /* Not explicitly covered in the spec but a query that was never started 673bf215546Sopenharmony_ci * cannot return any data. 674bf215546Sopenharmony_ci */ 675bf215546Sopenharmony_ci if (!obj->Used) { 676bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 677bf215546Sopenharmony_ci "glGetPerfQueryDataINTEL(query never began)"); 678bf215546Sopenharmony_ci return; 679bf215546Sopenharmony_ci } 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci /* Not explicitly covered in the spec but to be consistent with 682bf215546Sopenharmony_ci * EndPerfQuery which validates that an application only ends an 683bf215546Sopenharmony_ci * active query we also validate that an application doesn't try 684bf215546Sopenharmony_ci * and get the data for a still active query... 685bf215546Sopenharmony_ci */ 686bf215546Sopenharmony_ci if (obj->Active) { 687bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 688bf215546Sopenharmony_ci "glGetPerfQueryDataINTEL(query still active)"); 689bf215546Sopenharmony_ci return; 690bf215546Sopenharmony_ci } 691bf215546Sopenharmony_ci 692bf215546Sopenharmony_ci if (!obj->Ready) 693bf215546Sopenharmony_ci obj->Ready = ctx->pipe->is_intel_perf_query_ready(ctx->pipe, 694bf215546Sopenharmony_ci (struct pipe_query *)obj); 695bf215546Sopenharmony_ci 696bf215546Sopenharmony_ci if (!obj->Ready) { 697bf215546Sopenharmony_ci if (flags == GL_PERFQUERY_FLUSH_INTEL) { 698bf215546Sopenharmony_ci st_glFlush(ctx, 0); 699bf215546Sopenharmony_ci } else if (flags == GL_PERFQUERY_WAIT_INTEL) { 700bf215546Sopenharmony_ci ctx->pipe->wait_intel_perf_query(ctx->pipe, (struct pipe_query *)obj); 701bf215546Sopenharmony_ci obj->Ready = true; 702bf215546Sopenharmony_ci } 703bf215546Sopenharmony_ci } 704bf215546Sopenharmony_ci 705bf215546Sopenharmony_ci if (obj->Ready) { 706bf215546Sopenharmony_ci if (!ctx->pipe->get_intel_perf_query_data(ctx->pipe, (struct pipe_query *)obj, 707bf215546Sopenharmony_ci dataSize, data, bytesWritten)) { 708bf215546Sopenharmony_ci memset(data, 0, dataSize); 709bf215546Sopenharmony_ci *bytesWritten = 0; 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 712bf215546Sopenharmony_ci "glGetPerfQueryDataINTEL(deferred begin query failure)"); 713bf215546Sopenharmony_ci } 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci} 716