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