i965: Don't treat HW_REGs as barriers if they're immediates.
[mesa.git] / src / mesa / main / performance_monitor.c
1 /*
2 * Copyright © 2012 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_monitor.c
26 * Core Mesa support for the AMD_performance_monitor extension.
27 *
28 * In order to implement this extension, start by defining two enums:
29 * one for Groups, and one for Counters. These will be used as indexes into
30 * arrays, so they should start at 0 and increment from there.
31 *
32 * Counter IDs need to be globally unique. That is, you can't have counter 7
33 * in group A and counter 7 in group B. A global enum of all available
34 * counters is a convenient way to guarantee this.
35 */
36
37 #include <stdbool.h>
38 #include "glheader.h"
39 #include "context.h"
40 #include "enums.h"
41 #include "hash.h"
42 #include "macros.h"
43 #include "mtypes.h"
44 #include "performance_monitor.h"
45 #include "bitset.h"
46 #include "ralloc.h"
47
48 void
49 _mesa_init_performance_monitors(struct gl_context *ctx)
50 {
51 ctx->PerfMonitor.Monitors = _mesa_NewHashTable();
52 ctx->PerfMonitor.NumGroups = 0;
53 ctx->PerfMonitor.Groups = NULL;
54 }
55
56 static struct gl_perf_monitor_object *
57 new_performance_monitor(struct gl_context *ctx, GLuint index)
58 {
59 unsigned i;
60 struct gl_perf_monitor_object *m = ctx->Driver.NewPerfMonitor(ctx);
61
62 if (m == NULL)
63 return NULL;
64
65 m->Name = index;
66
67 m->Active = false;
68
69 m->ActiveGroups =
70 rzalloc_array(NULL, unsigned, ctx->PerfMonitor.NumGroups);
71
72 m->ActiveCounters =
73 ralloc_array(NULL, BITSET_WORD *, ctx->PerfMonitor.NumGroups);
74
75 if (m->ActiveGroups == NULL || m->ActiveCounters == NULL)
76 goto fail;
77
78 for (i = 0; i < ctx->PerfMonitor.NumGroups; i++) {
79 const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[i];
80
81 m->ActiveCounters[i] = rzalloc_array(m->ActiveCounters, BITSET_WORD,
82 BITSET_WORDS(g->NumCounters));
83 if (m->ActiveCounters[i] == NULL)
84 goto fail;
85 }
86
87 return m;
88
89 fail:
90 ralloc_free(m->ActiveGroups);
91 ralloc_free(m->ActiveCounters);
92 ctx->Driver.DeletePerfMonitor(ctx, m);
93 return NULL;
94 }
95
96 static void
97 free_performance_monitor(GLuint key, void *data, void *user)
98 {
99 struct gl_perf_monitor_object *m = data;
100 struct gl_context *ctx = user;
101
102 ralloc_free(m->ActiveGroups);
103 ralloc_free(m->ActiveCounters);
104 ctx->Driver.DeletePerfMonitor(ctx, m);
105 }
106
107 void
108 _mesa_free_performance_monitors(struct gl_context *ctx)
109 {
110 _mesa_HashDeleteAll(ctx->PerfMonitor.Monitors,
111 free_performance_monitor, ctx);
112 _mesa_DeleteHashTable(ctx->PerfMonitor.Monitors);
113 }
114
115 static inline struct gl_perf_monitor_object *
116 lookup_monitor(struct gl_context *ctx, GLuint id)
117 {
118 return (struct gl_perf_monitor_object *)
119 _mesa_HashLookup(ctx->PerfMonitor.Monitors, id);
120 }
121
122 static inline const struct gl_perf_monitor_group *
123 get_group(const struct gl_context *ctx, GLuint id)
124 {
125 if (id >= ctx->PerfMonitor.NumGroups)
126 return NULL;
127
128 return &ctx->PerfMonitor.Groups[id];
129 }
130
131 static inline const struct gl_perf_monitor_counter *
132 get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
133 {
134 if (id >= group_obj->NumCounters)
135 return NULL;
136
137 return &group_obj->Counters[id];
138 }
139
140 /* For INTEL_performance_query, query id 0 is reserved to be invalid. We use
141 * index to Groups array + 1 as the query id. Same applies to counter id.
142 */
143 static inline GLuint
144 queryid_to_index(GLuint queryid)
145 {
146 return queryid - 1;
147 }
148
149 static inline GLuint
150 index_to_queryid(GLuint index)
151 {
152 return index + 1;
153 }
154
155 static inline bool
156 queryid_valid(const struct gl_context *ctx, GLuint queryid)
157 {
158 return get_group(ctx, queryid_to_index(queryid)) != NULL;
159 }
160
161 static inline GLuint
162 counterid_to_index(GLuint counterid)
163 {
164 return counterid - 1;
165 }
166
167 static inline GLuint
168 index_to_counterid(GLuint index)
169 {
170 return index + 1;
171 }
172
173 static inline bool
174 counterid_valid(const struct gl_perf_monitor_group *group_obj,
175 GLuint counterid)
176 {
177 return get_counter(group_obj, counterid_to_index(counterid)) != NULL;
178 }
179
180 /*****************************************************************************/
181
182 void GLAPIENTRY
183 _mesa_GetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize,
184 GLuint *groups)
185 {
186 GET_CURRENT_CONTEXT(ctx);
187
188 if (numGroups != NULL)
189 *numGroups = ctx->PerfMonitor.NumGroups;
190
191 if (groupsSize > 0 && groups != NULL) {
192 unsigned i;
193 unsigned n = MIN2((GLuint) groupsSize, ctx->PerfMonitor.NumGroups);
194
195 /* We just use the index in the Groups array as the ID. */
196 for (i = 0; i < n; i++)
197 groups[i] = i;
198 }
199 }
200
201 void GLAPIENTRY
202 _mesa_GetPerfMonitorCountersAMD(GLuint group, GLint *numCounters,
203 GLint *maxActiveCounters,
204 GLsizei countersSize, GLuint *counters)
205 {
206 GET_CURRENT_CONTEXT(ctx);
207 const struct gl_perf_monitor_group *group_obj = get_group(ctx, group);
208 if (group_obj == NULL) {
209 _mesa_error(ctx, GL_INVALID_VALUE,
210 "glGetPerfMonitorCountersAMD(invalid group)");
211 return;
212 }
213
214 if (maxActiveCounters != NULL)
215 *maxActiveCounters = group_obj->MaxActiveCounters;
216
217 if (numCounters != NULL)
218 *numCounters = group_obj->NumCounters;
219
220 if (counters != NULL) {
221 unsigned i;
222 unsigned n = MIN2(group_obj->NumCounters, (GLuint) countersSize);
223 for (i = 0; i < n; i++) {
224 /* We just use the index in the Counters array as the ID. */
225 counters[i] = i;
226 }
227 }
228 }
229
230 void GLAPIENTRY
231 _mesa_GetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize,
232 GLsizei *length, GLchar *groupString)
233 {
234 GET_CURRENT_CONTEXT(ctx);
235
236 const struct gl_perf_monitor_group *group_obj = get_group(ctx, group);
237
238 if (group_obj == NULL) {
239 _mesa_error(ctx, GL_INVALID_VALUE, "glGetPerfMonitorGroupStringAMD");
240 return;
241 }
242
243 if (bufSize == 0) {
244 /* Return the number of characters that would be required to hold the
245 * group string, excluding the null terminator.
246 */
247 if (length != NULL)
248 *length = strlen(group_obj->Name);
249 } else {
250 if (length != NULL)
251 *length = MIN2(strlen(group_obj->Name), bufSize);
252 if (groupString != NULL)
253 strncpy(groupString, group_obj->Name, bufSize);
254 }
255 }
256
257 void GLAPIENTRY
258 _mesa_GetPerfMonitorCounterStringAMD(GLuint group, GLuint counter,
259 GLsizei bufSize, GLsizei *length,
260 GLchar *counterString)
261 {
262 GET_CURRENT_CONTEXT(ctx);
263
264 const struct gl_perf_monitor_group *group_obj;
265 const struct gl_perf_monitor_counter *counter_obj;
266
267 group_obj = get_group(ctx, group);
268
269 if (group_obj == NULL) {
270 _mesa_error(ctx, GL_INVALID_VALUE,
271 "glGetPerfMonitorCounterStringAMD(invalid group)");
272 return;
273 }
274
275 counter_obj = get_counter(group_obj, counter);
276
277 if (counter_obj == NULL) {
278 _mesa_error(ctx, GL_INVALID_VALUE,
279 "glGetPerfMonitorCounterStringAMD(invalid counter)");
280 return;
281 }
282
283 if (bufSize == 0) {
284 /* Return the number of characters that would be required to hold the
285 * counter string, excluding the null terminator.
286 */
287 if (length != NULL)
288 *length = strlen(counter_obj->Name);
289 } else {
290 if (length != NULL)
291 *length = MIN2(strlen(counter_obj->Name), bufSize);
292 if (counterString != NULL)
293 strncpy(counterString, counter_obj->Name, bufSize);
294 }
295 }
296
297 void GLAPIENTRY
298 _mesa_GetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname,
299 GLvoid *data)
300 {
301 GET_CURRENT_CONTEXT(ctx);
302
303 const struct gl_perf_monitor_group *group_obj;
304 const struct gl_perf_monitor_counter *counter_obj;
305
306 group_obj = get_group(ctx, group);
307
308 if (group_obj == NULL) {
309 _mesa_error(ctx, GL_INVALID_VALUE,
310 "glGetPerfMonitorCounterInfoAMD(invalid group)");
311 return;
312 }
313
314 counter_obj = get_counter(group_obj, counter);
315
316 if (counter_obj == NULL) {
317 _mesa_error(ctx, GL_INVALID_VALUE,
318 "glGetPerfMonitorCounterInfoAMD(invalid counter)");
319 return;
320 }
321
322 switch (pname) {
323 case GL_COUNTER_TYPE_AMD:
324 *((GLenum *) data) = counter_obj->Type;
325 break;
326
327 case GL_COUNTER_RANGE_AMD:
328 switch (counter_obj->Type) {
329 case GL_FLOAT:
330 case GL_PERCENTAGE_AMD: {
331 float *f_data = data;
332 f_data[0] = counter_obj->Minimum.f;
333 f_data[1] = counter_obj->Maximum.f;
334 break;
335 }
336 case GL_UNSIGNED_INT: {
337 uint32_t *u32_data = data;
338 u32_data[0] = counter_obj->Minimum.u32;
339 u32_data[1] = counter_obj->Maximum.u32;
340 break;
341 }
342 case GL_UNSIGNED_INT64_AMD: {
343 uint64_t *u64_data = data;
344 u64_data[0] = counter_obj->Minimum.u64;
345 u64_data[1] = counter_obj->Maximum.u64;
346 break;
347 }
348 default:
349 assert(!"Should not get here: invalid counter type");
350 }
351 break;
352
353 default:
354 _mesa_error(ctx, GL_INVALID_ENUM,
355 "glGetPerfMonitorCounterInfoAMD(pname)");
356 return;
357 }
358 }
359
360 void GLAPIENTRY
361 _mesa_GenPerfMonitorsAMD(GLsizei n, GLuint *monitors)
362 {
363 GLuint first;
364 GET_CURRENT_CONTEXT(ctx);
365
366 if (MESA_VERBOSE & VERBOSE_API)
367 _mesa_debug(ctx, "glGenPerfMonitorsAMD(%d)\n", n);
368
369 if (n < 0) {
370 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPerfMonitorsAMD(n < 0)");
371 return;
372 }
373
374 if (monitors == NULL)
375 return;
376
377 /* We don't actually need them to be contiguous, but this is what
378 * the rest of Mesa does, so we may as well.
379 */
380 first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, n);
381 if (first) {
382 GLsizei i;
383 for (i = 0; i < n; i++) {
384 struct gl_perf_monitor_object *m =
385 new_performance_monitor(ctx, first + i);
386 if (!m) {
387 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
388 return;
389 }
390 monitors[i] = first + i;
391 _mesa_HashInsert(ctx->PerfMonitor.Monitors, first + i, m);
392 }
393 } else {
394 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPerfMonitorsAMD");
395 return;
396 }
397 }
398
399 void GLAPIENTRY
400 _mesa_DeletePerfMonitorsAMD(GLsizei n, GLuint *monitors)
401 {
402 GLint i;
403 GET_CURRENT_CONTEXT(ctx);
404
405 if (MESA_VERBOSE & VERBOSE_API)
406 _mesa_debug(ctx, "glDeletePerfMonitorsAMD(%d)\n", n);
407
408 if (n < 0) {
409 _mesa_error(ctx, GL_INVALID_VALUE, "glDeletePerfMonitorsAMD(n < 0)");
410 return;
411 }
412
413 if (monitors == NULL)
414 return;
415
416 for (i = 0; i < n; i++) {
417 struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitors[i]);
418
419 if (m) {
420 /* Give the driver a chance to stop the monitor if it's active. */
421 if (m->Active) {
422 ctx->Driver.ResetPerfMonitor(ctx, m);
423 m->Ended = false;
424 }
425
426 _mesa_HashRemove(ctx->PerfMonitor.Monitors, monitors[i]);
427 ralloc_free(m->ActiveGroups);
428 ralloc_free(m->ActiveCounters);
429 ctx->Driver.DeletePerfMonitor(ctx, m);
430 } else {
431 /* "INVALID_VALUE error will be generated if any of the monitor IDs
432 * in the <monitors> parameter to DeletePerfMonitorsAMD do not
433 * reference a valid generated monitor ID."
434 */
435 _mesa_error(ctx, GL_INVALID_VALUE,
436 "glDeletePerfMonitorsAMD(invalid monitor)");
437 }
438 }
439 }
440
441 void GLAPIENTRY
442 _mesa_SelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable,
443 GLuint group, GLint numCounters,
444 GLuint *counterList)
445 {
446 GET_CURRENT_CONTEXT(ctx);
447 int i;
448 struct gl_perf_monitor_object *m;
449 const struct gl_perf_monitor_group *group_obj;
450
451 m = lookup_monitor(ctx, monitor);
452
453 /* "INVALID_VALUE error will be generated if the <monitor> parameter to
454 * SelectPerfMonitorCountersAMD does not reference a monitor created by
455 * GenPerfMonitorsAMD."
456 */
457 if (m == NULL) {
458 _mesa_error(ctx, GL_INVALID_VALUE,
459 "glSelectPerfMonitorCountersAMD(invalid monitor)");
460 return;
461 }
462
463 group_obj = get_group(ctx, group);
464
465 /* "INVALID_VALUE error will be generated if the <group> parameter to
466 * GetPerfMonitorCountersAMD, GetPerfMonitorCounterStringAMD,
467 * GetPerfMonitorCounterStringAMD, GetPerfMonitorCounterInfoAMD, or
468 * SelectPerfMonitorCountersAMD does not reference a valid group ID."
469 */
470 if (group_obj == NULL) {
471 _mesa_error(ctx, GL_INVALID_VALUE,
472 "glSelectPerfMonitorCountersAMD(invalid group)");
473 return;
474 }
475
476 /* "INVALID_VALUE error will be generated if the <numCounters> parameter to
477 * SelectPerfMonitorCountersAMD is less than 0."
478 */
479 if (numCounters < 0) {
480 _mesa_error(ctx, GL_INVALID_VALUE,
481 "glSelectPerfMonitorCountersAMD(numCounters < 0)");
482 return;
483 }
484
485 /* "When SelectPerfMonitorCountersAMD is called on a monitor, any outstanding
486 * results for that monitor become invalidated and the result queries
487 * PERFMON_RESULT_SIZE_AMD and PERFMON_RESULT_AVAILABLE_AMD are reset to 0."
488 */
489 ctx->Driver.ResetPerfMonitor(ctx, m);
490
491 /* Sanity check the counter ID list. */
492 for (i = 0; i < numCounters; i++) {
493 if (counterList[i] >= group_obj->NumCounters) {
494 _mesa_error(ctx, GL_INVALID_VALUE,
495 "glSelectPerfMonitorCountersAMD(invalid counter ID)");
496 return;
497 }
498 }
499
500 if (enable) {
501 /* Enable the counters */
502 for (i = 0; i < numCounters; i++) {
503 ++m->ActiveGroups[group];
504 BITSET_SET(m->ActiveCounters[group], counterList[i]);
505 }
506 } else {
507 /* Disable the counters */
508 for (i = 0; i < numCounters; i++) {
509 --m->ActiveGroups[group];
510 BITSET_CLEAR(m->ActiveCounters[group], counterList[i]);
511 }
512 }
513 }
514
515 void GLAPIENTRY
516 _mesa_BeginPerfMonitorAMD(GLuint monitor)
517 {
518 GET_CURRENT_CONTEXT(ctx);
519
520 struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
521
522 if (m == NULL) {
523 _mesa_error(ctx, GL_INVALID_VALUE,
524 "glBeginPerfMonitorAMD(invalid monitor)");
525 return;
526 }
527
528 /* "INVALID_OPERATION error will be generated if BeginPerfMonitorAMD is
529 * called when a performance monitor is already active."
530 */
531 if (m->Active) {
532 _mesa_error(ctx, GL_INVALID_OPERATION,
533 "glBeginPerfMonitor(already active)");
534 return;
535 }
536
537 /* The driver is free to return false if it can't begin monitoring for
538 * any reason. This translates into an INVALID_OPERATION error.
539 */
540 if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
541 m->Active = true;
542 m->Ended = false;
543 } else {
544 _mesa_error(ctx, GL_INVALID_OPERATION,
545 "glBeginPerfMonitor(driver unable to begin monitoring)");
546 }
547 }
548
549 void GLAPIENTRY
550 _mesa_EndPerfMonitorAMD(GLuint monitor)
551 {
552 GET_CURRENT_CONTEXT(ctx);
553
554 struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
555
556 if (m == NULL) {
557 _mesa_error(ctx, GL_INVALID_VALUE, "glEndPerfMonitorAMD(invalid monitor)");
558 return;
559 }
560
561 /* "INVALID_OPERATION error will be generated if EndPerfMonitorAMD is called
562 * when a performance monitor is not currently started."
563 */
564 if (!m->Active) {
565 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginPerfMonitor(not active)");
566 return;
567 }
568
569 ctx->Driver.EndPerfMonitor(ctx, m);
570
571 m->Active = false;
572 m->Ended = true;
573 }
574
575 /**
576 * Return the number of bytes needed to store a monitor's result.
577 */
578 static unsigned
579 perf_monitor_result_size(const struct gl_context *ctx,
580 const struct gl_perf_monitor_object *m)
581 {
582 unsigned group, counter;
583 unsigned size = 0;
584
585 for (group = 0; group < ctx->PerfMonitor.NumGroups; group++) {
586 const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[group];
587 for (counter = 0; counter < g->NumCounters; counter++) {
588 const struct gl_perf_monitor_counter *c = &g->Counters[counter];
589
590 if (!BITSET_TEST(m->ActiveCounters[group], counter))
591 continue;
592
593 size += sizeof(uint32_t); /* Group ID */
594 size += sizeof(uint32_t); /* Counter ID */
595 size += _mesa_perf_monitor_counter_size(c);
596 }
597 }
598 return size;
599 }
600
601 void GLAPIENTRY
602 _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
603 GLsizei dataSize, GLuint *data,
604 GLint *bytesWritten)
605 {
606 GET_CURRENT_CONTEXT(ctx);
607
608 struct gl_perf_monitor_object *m = lookup_monitor(ctx, monitor);
609 bool result_available;
610
611 if (m == NULL) {
612 _mesa_error(ctx, GL_INVALID_VALUE,
613 "glGetPerfMonitorCounterDataAMD(invalid monitor)");
614 return;
615 }
616
617 /* "It is an INVALID_OPERATION error for <data> to be NULL." */
618 if (data == NULL) {
619 _mesa_error(ctx, GL_INVALID_OPERATION,
620 "glGetPerfMonitorCounterDataAMD(data == NULL)");
621 return;
622 }
623
624 /* We need at least enough room for a single value. */
625 if (dataSize < sizeof(GLuint)) {
626 if (bytesWritten != NULL)
627 *bytesWritten = 0;
628 return;
629 }
630
631 /* If the monitor has never ended, there is no result. */
632 result_available = m->Ended &&
633 ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
634
635 /* AMD appears to return 0 for all queries unless a result is available. */
636 if (!result_available) {
637 *data = 0;
638 if (bytesWritten != NULL)
639 *bytesWritten = sizeof(GLuint);
640 return;
641 }
642
643 switch (pname) {
644 case GL_PERFMON_RESULT_AVAILABLE_AMD:
645 *data = 1;
646 if (bytesWritten != NULL)
647 *bytesWritten = sizeof(GLuint);
648 break;
649 case GL_PERFMON_RESULT_SIZE_AMD:
650 *data = perf_monitor_result_size(ctx, m);
651 if (bytesWritten != NULL)
652 *bytesWritten = sizeof(GLuint);
653 break;
654 case GL_PERFMON_RESULT_AMD:
655 ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, bytesWritten);
656 break;
657 default:
658 _mesa_error(ctx, GL_INVALID_ENUM,
659 "glGetPerfMonitorCounterDataAMD(pname)");
660 }
661 }
662
663 /**
664 * Returns how many bytes a counter's value takes up.
665 */
666 unsigned
667 _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
668 {
669 switch (c->Type) {
670 case GL_FLOAT:
671 case GL_PERCENTAGE_AMD:
672 return sizeof(GLfloat);
673 case GL_UNSIGNED_INT:
674 return sizeof(GLuint);
675 case GL_UNSIGNED_INT64_AMD:
676 return sizeof(uint64_t);
677 default:
678 assert(!"Should not get here: invalid counter type");
679 return 0;
680 }
681 }
682
683 extern void GLAPIENTRY
684 _mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId)
685 {
686 GET_CURRENT_CONTEXT(ctx);
687 unsigned numGroups;
688
689 /* The GL_INTEL_performance_query spec says:
690 *
691 * "If queryId pointer is equal to 0, INVALID_VALUE error is generated."
692 */
693 if (!queryId) {
694 _mesa_error(ctx, GL_INVALID_VALUE,
695 "glGetFirstPerfQueryIdINTEL(queryId == NULL)");
696 return;
697 }
698
699 numGroups = ctx->PerfMonitor.NumGroups;
700
701 /* The GL_INTEL_performance_query spec says:
702 *
703 * "If the given hardware platform doesn't support any performance
704 * queries, then the value of 0 is returned and INVALID_OPERATION error
705 * is raised."
706 */
707 if (numGroups == 0) {
708 *queryId = 0;
709 _mesa_error(ctx, GL_INVALID_OPERATION,
710 "glGetFirstPerfQueryIdINTEL(no queries supported)");
711 return;
712 }
713
714 *queryId = index_to_queryid(0);
715 }
716
717 extern void GLAPIENTRY
718 _mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId)
719 {
720 GET_CURRENT_CONTEXT(ctx);
721
722 /* The GL_INTEL_performance_query spec says:
723 *
724 * "The result is passed in location pointed by nextQueryId. If query
725 * identified by queryId is the last query available the value of 0 is
726 * returned. If the specified performance query identifier is invalid
727 * then INVALID_VALUE error is generated. If nextQueryId pointer is
728 * equal to 0, an INVALID_VALUE error is generated. Whenever error is
729 * generated, the value of 0 is returned."
730 */
731
732 if (!nextQueryId) {
733 _mesa_error(ctx, GL_INVALID_VALUE,
734 "glGetNextPerfQueryIdINTEL(nextQueryId == NULL)");
735 return;
736 }
737
738 if (!queryid_valid(ctx, queryId)) {
739 *nextQueryId = 0;
740 _mesa_error(ctx, GL_INVALID_VALUE,
741 "glGetNextPerfQueryIdINTEL(invalid query)");
742 return;
743 }
744
745 ++queryId;
746
747 if (!queryid_valid(ctx, queryId)) {
748 *nextQueryId = 0;
749 } else {
750 *nextQueryId = queryId;
751 }
752 }
753
754 extern void GLAPIENTRY
755 _mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId)
756 {
757 GET_CURRENT_CONTEXT(ctx);
758 unsigned i;
759
760 /* The GL_INTEL_performance_query spec says:
761 *
762 * "If queryName does not reference a valid query name, an INVALID_VALUE
763 * error is generated."
764 */
765 if (!queryName) {
766 _mesa_error(ctx, GL_INVALID_VALUE,
767 "glGetPerfQueryIdByNameINTEL(queryName == NULL)");
768 return;
769 }
770
771 /* The specification does not state that this produces an error. */
772 if (!queryId) {
773 _mesa_warning(ctx, "glGetPerfQueryIdByNameINTEL(queryId == NULL)");
774 return;
775 }
776
777 for (i = 0; i < ctx->PerfMonitor.NumGroups; ++i) {
778 const struct gl_perf_monitor_group *group_obj = get_group(ctx, i);
779 if (strcmp(group_obj->Name, queryName) == 0) {
780 *queryId = index_to_queryid(i);
781 return;
782 }
783 }
784
785 _mesa_error(ctx, GL_INVALID_VALUE,
786 "glGetPerfQueryIdByNameINTEL(invalid query name)");
787 }
788
789 extern void GLAPIENTRY
790 _mesa_GetPerfQueryInfoINTEL(GLuint queryId,
791 GLuint queryNameLength, char *queryName,
792 GLuint *dataSize, GLuint *noCounters,
793 GLuint *noActiveInstances,
794 GLuint *capsMask)
795 {
796 GET_CURRENT_CONTEXT(ctx);
797 unsigned i;
798
799 const struct gl_perf_monitor_group *group_obj =
800 get_group(ctx, queryid_to_index(queryId));
801
802 if (group_obj == NULL) {
803 /* The GL_INTEL_performance_query spec says:
804 *
805 * "If queryId does not reference a valid query type, an
806 * INVALID_VALUE error is generated."
807 */
808 _mesa_error(ctx, GL_INVALID_VALUE,
809 "glGetPerfQueryInfoINTEL(invalid query)");
810 return;
811 }
812
813 if (queryName) {
814 strncpy(queryName, group_obj->Name, queryNameLength);
815
816 /* No specification given about whether the string needs to be
817 * zero-terminated. Zero-terminate the string always as we don't
818 * otherwise communicate the length of the returned string.
819 */
820 if (queryNameLength > 0) {
821 queryName[queryNameLength - 1] = '\0';
822 }
823 }
824
825 if (dataSize) {
826 unsigned size = 0;
827 for (i = 0; i < group_obj->NumCounters; ++i) {
828 /* What we get from the driver is group id (uint32_t) + counter id
829 * (uint32_t) + value.
830 */
831 size += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
832 }
833 *dataSize = size;
834 }
835
836 if (noCounters) {
837 *noCounters = group_obj->NumCounters;
838 }
839
840 /* The GL_INTEL_performance_query spec says:
841 *
842 * "-- the actual number of already created query instances in
843 * maxInstances location"
844 *
845 * 1) Typo in the specification, should be noActiveInstances.
846 * 2) Another typo in the specification, maxInstances parameter is not listed
847 * in the declaration of this function in the list of new functions.
848 */
849 if (noActiveInstances) {
850 *noActiveInstances = _mesa_HashNumEntries(ctx->PerfMonitor.Monitors);
851 }
852
853 if (capsMask) {
854 /* TODO: This information not yet available in the monitor structs. For
855 * now, we hardcode SINGLE_CONTEXT, since that's what the implementation
856 * currently tries very hard to do.
857 */
858 *capsMask = GL_PERFQUERY_SINGLE_CONTEXT_INTEL;
859 }
860 }
861
862 extern void GLAPIENTRY
863 _mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId,
864 GLuint counterNameLength, char *counterName,
865 GLuint counterDescLength, char *counterDesc,
866 GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum,
867 GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue)
868 {
869 GET_CURRENT_CONTEXT(ctx);
870
871 const struct gl_perf_monitor_group *group_obj;
872 const struct gl_perf_monitor_counter *counter_obj;
873 unsigned counterIndex;
874 unsigned i;
875
876 group_obj = get_group(ctx, queryid_to_index(queryId));
877
878 /* The GL_INTEL_performance_query spec says:
879 *
880 * "If the pair of queryId and counterId does not reference a valid
881 * counter, an INVALID_VALUE error is generated."
882 */
883 if (group_obj == NULL) {
884 _mesa_error(ctx, GL_INVALID_VALUE,
885 "glGetPerfCounterInfoINTEL(invalid queryId)");
886 return;
887 }
888
889 counterIndex = counterid_to_index(counterId);
890 counter_obj = get_counter(group_obj, counterIndex);
891
892 if (counter_obj == NULL) {
893 _mesa_error(ctx, GL_INVALID_VALUE,
894 "glGetPerfCounterInfoINTEL(invalid counterId)");
895 return;
896 }
897
898 if (counterName) {
899 strncpy(counterName, counter_obj->Name, counterNameLength);
900
901 /* No specification given about whether the string needs to be
902 * zero-terminated. Zero-terminate the string always as we don't
903 * otherwise communicate the length of the returned string.
904 */
905 if (counterNameLength > 0) {
906 counterName[counterNameLength - 1] = '\0';
907 }
908 }
909
910 if (counterDesc) {
911 /* TODO: No separate description text at the moment. We pass the name
912 * again for the moment.
913 */
914 strncpy(counterDesc, counter_obj->Name, counterDescLength);
915
916 /* No specification given about whether the string needs to be
917 * zero-terminated. Zero-terminate the string always as we don't
918 * otherwise communicate the length of the returned string.
919 */
920 if (counterDescLength > 0) {
921 counterDesc[counterDescLength - 1] = '\0';
922 }
923 }
924
925 if (counterOffset) {
926 unsigned offset = 0;
927 for (i = 0; i < counterIndex; ++i) {
928 /* What we get from the driver is group id (uint32_t) + counter id
929 * (uint32_t) + value.
930 */
931 offset += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
932 }
933 *counterOffset = 2 * sizeof(uint32_t) + offset;
934 }
935
936 if (counterDataSize) {
937 *counterDataSize = _mesa_perf_monitor_counter_size(counter_obj);
938 }
939
940 if (counterTypeEnum) {
941 /* TODO: Different counter types (semantic type, not data type) not
942 * supported as of yet.
943 */
944 *counterTypeEnum = GL_PERFQUERY_COUNTER_RAW_INTEL;
945 }
946
947 if (counterDataTypeEnum) {
948 switch (counter_obj->Type) {
949 case GL_FLOAT:
950 case GL_PERCENTAGE_AMD:
951 *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL;
952 break;
953 case GL_UNSIGNED_INT:
954 *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL;
955 break;
956 case GL_UNSIGNED_INT64_AMD:
957 *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL;
958 break;
959 default:
960 assert(!"Should not get here: invalid counter type");
961 return;
962 }
963 }
964
965 if (rawCounterMaxValue) {
966 /* This value is (implicitly) specified to be used only with
967 * GL_PERFQUERY_COUNTER_RAW_INTEL counters. When semantic types for
968 * counters are added, that needs to be checked.
969 */
970
971 /* The GL_INTEL_performance_query spec says:
972 *
973 * "for some raw counters for which the maximal value is
974 * deterministic, the maximal value of the counter in 1 second is
975 * returned in the location pointed by rawCounterMaxValue, otherwise,
976 * the location is written with the value of 0."
977 *
978 * The maximum value reported by the driver at the moment is not with
979 * these semantics, so write 0 always to be safe.
980 */
981 *rawCounterMaxValue = 0;
982 }
983 }
984
985 extern void GLAPIENTRY
986 _mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle)
987 {
988 GET_CURRENT_CONTEXT(ctx);
989 GLuint first;
990 GLuint group;
991 const struct gl_perf_monitor_group *group_obj;
992 struct gl_perf_monitor_object *m;
993 unsigned i;
994
995 /* This is not specified in the extension, but is the only sane thing to
996 * do.
997 */
998 if (queryHandle == NULL) {
999 _mesa_error(ctx, GL_INVALID_VALUE,
1000 "glCreatePerfQueryINTEL(queryHandle == NULL)");
1001 return;
1002 }
1003
1004 group = queryid_to_index(queryId);
1005 group_obj = get_group(ctx, group);
1006
1007 /* The GL_INTEL_performance_query spec says:
1008 *
1009 * "If queryId does not reference a valid query type, an INVALID_VALUE
1010 * error is generated."
1011 */
1012 if (group_obj == NULL) {
1013 _mesa_error(ctx, GL_INVALID_VALUE,
1014 "glCreatePerfQueryINTEL(invalid queryId)");
1015 return;
1016 }
1017
1018 /* The query object created here is the counterpart of a `monitor' in
1019 * AMD_performance_monitor. This call is equivalent to calling
1020 * GenPerfMonitorsAMD and SelectPerfMonitorCountersAMD with a list of all
1021 * counters in a group.
1022 */
1023
1024 /* We keep the monitor ids contiguous */
1025 first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, 1);
1026 if (!first) {
1027 /* The GL_INTEL_performance_query spec says:
1028 *
1029 * "If the query instance cannot be created due to exceeding the
1030 * number of allowed instances or driver fails query creation due to
1031 * an insufficient memory reason, an OUT_OF_MEMORY error is
1032 * generated, and the location pointed by queryHandle returns NULL."
1033 */
1034 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreatePerfQueryINTEL");
1035 return;
1036 }
1037
1038 m = new_performance_monitor(ctx, first);
1039 _mesa_HashInsert(ctx->PerfMonitor.Monitors, first, m);
1040 *queryHandle = first;
1041
1042 ctx->Driver.ResetPerfMonitor(ctx, m);
1043
1044 for (i = 0; i < group_obj->NumCounters; ++i) {
1045 ++m->ActiveGroups[group];
1046 /* Counters are a continuous range of integers, 0 to NumCounters (excl),
1047 * so i is the counter value to use here.
1048 */
1049 BITSET_SET(m->ActiveCounters[group], i);
1050 }
1051 }
1052
1053 extern void GLAPIENTRY
1054 _mesa_DeletePerfQueryINTEL(GLuint queryHandle)
1055 {
1056 GET_CURRENT_CONTEXT(ctx);
1057 struct gl_perf_monitor_object *m;
1058
1059 /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
1060 * id.
1061 */
1062 m = lookup_monitor(ctx, queryHandle);
1063
1064 /* The GL_INTEL_performance_query spec says:
1065 *
1066 * "If a query handle doesn't reference a previously created performance
1067 * query instance, an INVALID_VALUE error is generated."
1068 */
1069 if (m == NULL) {
1070 _mesa_error(ctx, GL_INVALID_VALUE,
1071 "glDeletePerfQueryINTEL(invalid queryHandle)");
1072 return;
1073 }
1074
1075 /* Let the driver stop the monitor if it's active. */
1076 if (m->Active) {
1077 ctx->Driver.ResetPerfMonitor(ctx, m);
1078 m->Ended = false;
1079 }
1080
1081 _mesa_HashRemove(ctx->PerfMonitor.Monitors, queryHandle);
1082 ralloc_free(m->ActiveGroups);
1083 ralloc_free(m->ActiveCounters);
1084 ctx->Driver.DeletePerfMonitor(ctx, m);
1085 }
1086
1087 extern void GLAPIENTRY
1088 _mesa_BeginPerfQueryINTEL(GLuint queryHandle)
1089 {
1090 GET_CURRENT_CONTEXT(ctx);
1091 struct gl_perf_monitor_object *m;
1092
1093 /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
1094 * id.
1095 */
1096
1097 m = lookup_monitor(ctx, queryHandle);
1098
1099 /* The GL_INTEL_performance_query spec says:
1100 *
1101 * "If a query handle doesn't reference a previously created performance
1102 * query instance, an INVALID_VALUE error is generated."
1103 */
1104 if (m == NULL) {
1105 _mesa_error(ctx, GL_INVALID_VALUE,
1106 "glBeginPerfQueryINTEL(invalid queryHandle)");
1107 return;
1108 }
1109
1110 /* The GL_INTEL_performance_query spec says:
1111 *
1112 * "Note that some query types, they cannot be collected in the same
1113 * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if
1114 * they refer to queries of such different types. In such case
1115 * INVALID_OPERATION error is generated."
1116 *
1117 * We also generate an INVALID_OPERATION error if the driver can't begin
1118 * monitoring for its own reasons, and for nesting the same query.
1119 */
1120 if (m->Active) {
1121 _mesa_error(ctx, GL_INVALID_OPERATION,
1122 "glBeginPerfQueryINTEL(already active)");
1123 return;
1124 }
1125
1126 if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
1127 m->Active = true;
1128 m->Ended = false;
1129 } else {
1130 _mesa_error(ctx, GL_INVALID_OPERATION,
1131 "glBeginPerfQueryINTEL(driver unable to begin monitoring)");
1132 }
1133 }
1134
1135 extern void GLAPIENTRY
1136 _mesa_EndPerfQueryINTEL(GLuint queryHandle)
1137 {
1138 GET_CURRENT_CONTEXT(ctx);
1139 struct gl_perf_monitor_object *m;
1140
1141 /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
1142 * id.
1143 */
1144
1145 m = lookup_monitor(ctx, queryHandle);
1146
1147 /* The GL_INTEL_performance_query spec says:
1148 *
1149 * "If a performance query is not currently started, an
1150 * INVALID_OPERATION error will be generated."
1151 *
1152 * The specification doesn't state that an invalid handle would be an
1153 * INVALID_VALUE error. Regardless, query for such a handle will not be
1154 * started, so we generate an INVALID_OPERATION in that case too.
1155 */
1156 if (m == NULL) {
1157 _mesa_error(ctx, GL_INVALID_OPERATION,
1158 "glEndPerfQueryINTEL(invalid queryHandle)");
1159 return;
1160 }
1161
1162 if (!m->Active) {
1163 _mesa_error(ctx, GL_INVALID_OPERATION,
1164 "glEndPerfQueryINTEL(not active)");
1165 return;
1166 }
1167
1168 ctx->Driver.EndPerfMonitor(ctx, m);
1169
1170 m->Active = false;
1171 m->Ended = true;
1172 }
1173
1174 extern void GLAPIENTRY
1175 _mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags,
1176 GLsizei dataSize, void *data, GLuint *bytesWritten)
1177 {
1178 GET_CURRENT_CONTEXT(ctx);
1179 struct gl_perf_monitor_object *m;
1180 bool result_available;
1181
1182 /* The GL_INTEL_performance_query spec says:
1183 *
1184 * "If bytesWritten or data pointers are NULL then an INVALID_VALUE
1185 * error is generated."
1186 */
1187 if (!bytesWritten || !data) {
1188 _mesa_error(ctx, GL_INVALID_VALUE,
1189 "glGetPerfQueryDataINTEL(bytesWritten or data is NULL)");
1190 return;
1191 }
1192
1193 /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
1194 * id.
1195 */
1196
1197 m = lookup_monitor(ctx, queryHandle);
1198
1199 /* The specification doesn't state that an invalid handle generates an
1200 * error. We could interpret that to mean the case should be handled as
1201 * "measurement not ready for this query", but what should be done if
1202 * `flags' equals PERFQUERY_WAIT_INTEL?
1203 *
1204 * To resolve this, we just generate an INVALID_VALUE from an invalid query
1205 * handle.
1206 */
1207 if (m == NULL) {
1208 _mesa_error(ctx, GL_INVALID_VALUE,
1209 "glGetPerfQueryDataINTEL(invalid queryHandle)");
1210 return;
1211 }
1212
1213 /* We need at least enough room for a single value. */
1214 if (dataSize < sizeof(GLuint)) {
1215 *bytesWritten = 0;
1216 return;
1217 }
1218
1219 /* The GL_INTEL_performance_query spec says:
1220 *
1221 * "The call may end without returning any data if they are not ready
1222 * for reading as the measurement session is still pending (the
1223 * EndPerfQueryINTEL() command processing is not finished by
1224 * hardware). In this case location pointed by the bytesWritten
1225 * parameter will be set to 0."
1226 *
1227 * If EndPerfQueryINTEL() is not called at all, we follow this.
1228 */
1229 if (!m->Ended) {
1230 *bytesWritten = 0;
1231 return;
1232 }
1233
1234 result_available = ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
1235
1236 if (!result_available) {
1237 if (flags == GL_PERFQUERY_FLUSH_INTEL) {
1238 ctx->Driver.Flush(ctx);
1239 } else if (flags == GL_PERFQUERY_WAIT_INTEL) {
1240 /* Assume Finish() is both enough and not too much to wait for
1241 * results. If results are still not available after Finish(), the
1242 * later code automatically bails out with 0 for bytesWritten.
1243 */
1244 ctx->Driver.Finish(ctx);
1245 result_available =
1246 ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
1247 }
1248 }
1249
1250 if (result_available) {
1251 ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, (GLint*)bytesWritten);
1252 } else {
1253 *bytesWritten = 0;
1254 }
1255 }