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