• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 void
_mesa_init_performance_queries(struct gl_context * ctx)45 _mesa_init_performance_queries(struct gl_context *ctx)
46 {
47    ctx->PerfQuery.Objects = _mesa_NewHashTable();
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_HashDeleteAll(ctx->PerfQuery.Objects,
69                        free_performance_query, ctx);
70    _mesa_DeleteHashTable(ctx->PerfQuery.Objects);
71 }
72 
73 static inline struct gl_perf_query_object *
lookup_object(struct gl_context * ctx,GLuint id)74 lookup_object(struct gl_context *ctx, GLuint id)
75 {
76    return _mesa_HashLookup(ctx->PerfQuery.Objects, id);
77 }
78 
79 static GLuint
init_performance_query_info(struct gl_context * ctx)80 init_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. */
86 static inline unsigned
queryid_to_index(GLuint queryid)87 queryid_to_index(GLuint queryid)
88 {
89    return queryid - 1;
90 }
91 
92 static inline GLuint
index_to_queryid(unsigned index)93 index_to_queryid(unsigned index)
94 {
95    return index + 1;
96 }
97 
98 static inline bool
queryid_valid(const struct gl_context * ctx,unsigned numQueries,GLuint queryid)99 queryid_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 
109 static inline GLuint
counterid_to_index(GLuint counterid)110 counterid_to_index(GLuint counterid)
111 {
112    return counterid - 1;
113 }
114 
115 static void
output_clipped_string(GLchar * stringRet,GLuint stringMaxLen,const char * string)116 output_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 
136 extern void GLAPIENTRY
_mesa_GetFirstPerfQueryIdINTEL(GLuint * queryId)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 
171 extern void GLAPIENTRY
_mesa_GetNextPerfQueryIdINTEL(GLuint queryId,GLuint * nextQueryId)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 
208 extern void GLAPIENTRY
_mesa_GetPerfQueryIdByNameINTEL(char * queryName,GLuint * queryId)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 
256 extern void GLAPIENTRY
_mesa_GetPerfQueryInfoINTEL(GLuint queryId,GLuint nameLength,GLchar * name,GLuint * dataSize,GLuint * numCounters,GLuint * numActive,GLuint * capsMask)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 
313 static uint32_t
pipe_counter_type_enum_to_gl_type(enum pipe_perf_counter_type type)314 pipe_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 
328 static uint32_t
pipe_counter_data_type_to_gl_type(enum pipe_perf_counter_data_type type)329 pipe_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 
342 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)343 get_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 
365 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)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 
464 extern void GLAPIENTRY
_mesa_CreatePerfQueryINTEL(GLuint queryId,GLuint * queryHandle)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 
521 extern void GLAPIENTRY
_mesa_DeletePerfQueryINTEL(GLuint queryHandle)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 
556 extern void GLAPIENTRY
_mesa_BeginPerfQueryINTEL(GLuint queryHandle)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 
609 extern void GLAPIENTRY
_mesa_EndPerfQueryINTEL(GLuint queryHandle)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 
641 extern void GLAPIENTRY
_mesa_GetPerfQueryDataINTEL(GLuint queryHandle,GLuint flags,GLsizei dataSize,void * data,GLuint * bytesWritten)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