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