Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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