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
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * OTHER DEALINGS IN THE SOFTWARE.
23
 */
24
 
25
 
26
#include "glheader.h"
27
#include "context.h"
28
#include "enums.h"
29
#include "hash.h"
30
#include "imports.h"
31
#include "queryobj.h"
32
#include "mtypes.h"
33
#include "main/dispatch.h"
34
 
35
 
36
/**
37
 * Allocate a new query object.  This is a fallback routine called via
38
 * ctx->Driver.NewQueryObject().
39
 * \param ctx - rendering context
40
 * \param id - the new object's ID
41
 * \return pointer to new query_object object or NULL if out of memory.
42
 */
43
static struct gl_query_object *
44
_mesa_new_query_object(struct gl_context *ctx, GLuint id)
45
{
46
   struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
47
   (void) ctx;
48
   if (q) {
49
      q->Id = id;
50
      q->Result = 0;
51
      q->Active = GL_FALSE;
52
 
53
      /* This is to satisfy the language of the specification: "In the initial
54
       * state of a query object, the result is available" (OpenGL 3.1 §
55
       * 2.13).
56
       */
57
      q->Ready = GL_TRUE;
58
 
59
      /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
60
       * used, but no object is associated with them until the first time they
61
       * are used by BeginQuery." Since our implementation actually does
62
       * allocate an object at this point, use a flag to indicate that this
63
       * object has not yet been bound so should not be considered a query.
64
       */
65
      q->EverBound = GL_FALSE;
66
   }
67
   return q;
68
}
69
 
70
 
71
/**
72
 * Begin a query.  Software driver fallback.
73
 * Called via ctx->Driver.BeginQuery().
74
 */
75
static void
76
_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
77
{
78
   ctx->NewState |= _NEW_DEPTH; /* for swrast */
79
}
80
 
81
 
82
/**
83
 * End a query.  Software driver fallback.
84
 * Called via ctx->Driver.EndQuery().
85
 */
86
static void
87
_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
88
{
89
   ctx->NewState |= _NEW_DEPTH; /* for swrast */
90
   q->Ready = GL_TRUE;
91
}
92
 
93
 
94
/**
95
 * Wait for query to complete.  Software driver fallback.
96
 * Called via ctx->Driver.WaitQuery().
97
 */
98
static void
99
_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
100
{
101
   /* For software drivers, _mesa_end_query() should have completed the query.
102
    * For real hardware, implement a proper WaitQuery() driver function,
103
    * which may require issuing a flush.
104
    */
105
   assert(q->Ready);
106
}
107
 
108
 
109
/**
110
 * Check if a query results are ready.  Software driver fallback.
111
 * Called via ctx->Driver.CheckQuery().
112
 */
113
static void
114
_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
115
{
116
   /* No-op for sw rendering.
117
    * HW drivers may need to flush at this time.
118
    */
119
}
120
 
121
 
122
/**
123
 * Delete a query object.  Called via ctx->Driver.DeleteQuery().
124
 * Not removed from hash table here.
125
 */
126
static void
127
_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
128
{
129
   free(q->Label);
130
   free(q);
131
}
132
 
133
 
134
void
135
_mesa_init_query_object_functions(struct dd_function_table *driver)
136
{
137
   driver->NewQueryObject = _mesa_new_query_object;
138
   driver->DeleteQuery = _mesa_delete_query;
139
   driver->BeginQuery = _mesa_begin_query;
140
   driver->EndQuery = _mesa_end_query;
141
   driver->WaitQuery = _mesa_wait_query;
142
   driver->CheckQuery = _mesa_check_query;
143
}
144
 
145
static struct gl_query_object **
146
get_pipe_stats_binding_point(struct gl_context *ctx,
147
                             GLenum target)
148
{
149
   const int which = target - GL_VERTICES_SUBMITTED_ARB;
150
   assert(which < MAX_PIPELINE_STATISTICS);
151
 
152
   if (!_mesa_is_desktop_gl(ctx) ||
153
       !ctx->Extensions.ARB_pipeline_statistics_query)
154
      return NULL;
155
 
156
   return &ctx->Query.pipeline_stats[which];
157
}
158
 
159
/**
160
 * Return pointer to the query object binding point for the given target and
161
 * index.
162
 * \return NULL if invalid target, else the address of binding point
163
 */
164
static struct gl_query_object **
165
get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
166
{
167
   switch (target) {
168
   case GL_SAMPLES_PASSED_ARB:
169
      if (ctx->Extensions.ARB_occlusion_query)
170
         return &ctx->Query.CurrentOcclusionObject;
171
      else
172
         return NULL;
173
   case GL_ANY_SAMPLES_PASSED:
174
      if (ctx->Extensions.ARB_occlusion_query2)
175
         return &ctx->Query.CurrentOcclusionObject;
176
      else
177
         return NULL;
178
   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
179
      if (ctx->Extensions.ARB_ES3_compatibility
180
          || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
181
         return &ctx->Query.CurrentOcclusionObject;
182
      else
183
         return NULL;
184
   case GL_TIME_ELAPSED_EXT:
185
      if (ctx->Extensions.EXT_timer_query)
186
         return &ctx->Query.CurrentTimerObject;
187
      else
188
         return NULL;
189
   case GL_PRIMITIVES_GENERATED:
190
      if (ctx->Extensions.EXT_transform_feedback)
191
         return &ctx->Query.PrimitivesGenerated[index];
192
      else
193
         return NULL;
194
   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
195
      if (ctx->Extensions.EXT_transform_feedback)
196
         return &ctx->Query.PrimitivesWritten[index];
197
      else
198
         return NULL;
199
 
200
   case GL_VERTICES_SUBMITTED_ARB:
201
   case GL_PRIMITIVES_SUBMITTED_ARB:
202
   case GL_VERTEX_SHADER_INVOCATIONS_ARB:
203
   case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
204
   case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
205
   case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
206
         return get_pipe_stats_binding_point(ctx, target);
207
 
208
   case GL_GEOMETRY_SHADER_INVOCATIONS:
209
      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
210
      target = GL_VERTICES_SUBMITTED_ARB + MAX_PIPELINE_STATISTICS - 1;
211
      /* fallthrough */
212
   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
213
      if (_mesa_has_geometry_shaders(ctx))
214
         return get_pipe_stats_binding_point(ctx, target);
215
      else
216
         return NULL;
217
 
218
   case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
219
   case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
220
      if (ctx->Extensions.ARB_tessellation_shader)
221
         return get_pipe_stats_binding_point(ctx, target);
222
      else
223
         return NULL;
224
 
225
   case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
226
      if (_mesa_has_compute_shaders(ctx))
227
         return get_pipe_stats_binding_point(ctx, target);
228
      else
229
         return NULL;
230
 
231
   default:
232
      return NULL;
233
   }
234
}
235
 
236
/**
237
 * Create $n query objects and store them in *ids. Make them of type $target
238
 * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
239
 */
240
static void
241
create_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
242
               bool dsa)
243
{
244
   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
245
   GLuint first;
246
 
247
   if (MESA_VERBOSE & VERBOSE_API)
248
      _mesa_debug(ctx, "%s(%d)\n", func, n);
249
 
250
   if (n < 0) {
251
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
252
      return;
253
   }
254
 
255
   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
256
   if (first) {
257
      GLsizei i;
258
      for (i = 0; i < n; i++) {
259
         struct gl_query_object *q
260
            = ctx->Driver.NewQueryObject(ctx, first + i);
261
         if (!q) {
262
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
263
            return;
264
         } else if (dsa) {
265
            /* Do the equivalent of binding the buffer with a target */
266
            q->Target = target;
267
            q->EverBound = GL_TRUE;
268
         }
269
         ids[i] = first + i;
270
         _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
271
      }
272
   }
273
}
274
 
275
void GLAPIENTRY
276
_mesa_GenQueries(GLsizei n, GLuint *ids)
277
{
278
   GET_CURRENT_CONTEXT(ctx);
279
   create_queries(ctx, 0, n, ids, false);
280
}
281
 
282
void GLAPIENTRY
283
_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
284
{
285
   GET_CURRENT_CONTEXT(ctx);
286
 
287
   if (!ctx->Extensions.ARB_direct_state_access) {
288
      _mesa_error(ctx, GL_INVALID_OPERATION,
289
                  "glCreateQueries(GL_ARB_direct_state_access "
290
                  "is not supported)");
291
      return;
292
   }
293
 
294
   switch (target) {
295
   case GL_SAMPLES_PASSED:
296
   case GL_ANY_SAMPLES_PASSED:
297
   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
298
   case GL_TIME_ELAPSED:
299
   case GL_TIMESTAMP:
300
   case GL_PRIMITIVES_GENERATED:
301
   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
302
      break;
303
   default:
304
      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
305
                  _mesa_lookup_enum_by_nr(target));
306
      return;
307
   }
308
 
309
   create_queries(ctx, target, n, ids, true);
310
}
311
 
312
 
313
void GLAPIENTRY
314
_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
315
{
316
   GLint i;
317
   GET_CURRENT_CONTEXT(ctx);
318
   FLUSH_VERTICES(ctx, 0);
319
 
320
   if (MESA_VERBOSE & VERBOSE_API)
321
      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
322
 
323
   if (n < 0) {
324
      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
325
      return;
326
   }
327
 
328
   for (i = 0; i < n; i++) {
329
      if (ids[i] > 0) {
330
         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
331
         if (q) {
332
            if (q->Active) {
333
               struct gl_query_object **bindpt;
334
               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
335
               assert(bindpt); /* Should be non-null for active q. */
336
               if (bindpt) {
337
                  *bindpt = NULL;
338
               }
339
               q->Active = GL_FALSE;
340
               ctx->Driver.EndQuery(ctx, q);
341
            }
342
            _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
343
            ctx->Driver.DeleteQuery(ctx, q);
344
         }
345
      }
346
   }
347
}
348
 
349
 
350
GLboolean GLAPIENTRY
351
_mesa_IsQuery(GLuint id)
352
{
353
   struct gl_query_object *q;
354
 
355
   GET_CURRENT_CONTEXT(ctx);
356
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
357
 
358
   if (MESA_VERBOSE & VERBOSE_API)
359
      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
360
 
361
   if (id == 0)
362
      return GL_FALSE;
363
 
364
   q = _mesa_lookup_query_object(ctx, id);
365
   if (q == NULL)
366
      return GL_FALSE;
367
 
368
   return q->EverBound;
369
}
370
 
371
static GLboolean
372
query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
373
{
374
   switch (target) {
375
   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
376
   case GL_PRIMITIVES_GENERATED:
377
      if (index >= ctx->Const.MaxVertexStreams) {
378
         _mesa_error(ctx, GL_INVALID_VALUE,
379
                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
380
         return GL_FALSE;
381
      }
382
      break;
383
   default:
384
      if (index > 0) {
385
         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
386
         return GL_FALSE;
387
      }
388
   }
389
   return GL_TRUE;
390
}
391
 
392
void GLAPIENTRY
393
_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
394
{
395
   struct gl_query_object *q, **bindpt;
396
   GET_CURRENT_CONTEXT(ctx);
397
 
398
   if (MESA_VERBOSE & VERBOSE_API)
399
      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
400
                  _mesa_lookup_enum_by_nr(target), index, id);
401
 
402
   if (!query_error_check_index(ctx, target, index))
403
      return;
404
 
405
   FLUSH_VERTICES(ctx, 0);
406
 
407
   bindpt = get_query_binding_point(ctx, target, index);
408
   if (!bindpt) {
409
      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
410
      return;
411
   }
412
 
413
   /* From the GL_ARB_occlusion_query spec:
414
    *
415
    *     "If BeginQueryARB is called while another query is already in
416
    *      progress with the same target, an INVALID_OPERATION error is
417
    *      generated."
418
    */
419
   if (*bindpt) {
420
      _mesa_error(ctx, GL_INVALID_OPERATION,
421
                  "glBeginQuery{Indexed}(target=%s is active)",
422
                  _mesa_lookup_enum_by_nr(target));
423
      return;
424
   }
425
 
426
   if (id == 0) {
427
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
428
      return;
429
   }
430
 
431
   q = _mesa_lookup_query_object(ctx, id);
432
   if (!q) {
433
      if (ctx->API != API_OPENGL_COMPAT) {
434
         _mesa_error(ctx, GL_INVALID_OPERATION,
435
                     "glBeginQuery{Indexed}(non-gen name)");
436
         return;
437
      } else {
438
         /* create new object */
439
         q = ctx->Driver.NewQueryObject(ctx, id);
440
         if (!q) {
441
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
442
            return;
443
         }
444
         _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
445
      }
446
   }
447
   else {
448
      /* pre-existing object */
449
      if (q->Active) {
450
         _mesa_error(ctx, GL_INVALID_OPERATION,
451
                     "glBeginQuery{Indexed}(query already active)");
452
         return;
453
      }
454
 
455
      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
456
       * spec states:
457
       *
458
       *     "BeginQuery generates an INVALID_OPERATION error if any of the
459
       *      following conditions hold: [...] id is the name of an
460
       *      existing query object whose type does not match target; [...]
461
       *
462
       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
463
       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
464
       */
465
      if (q->EverBound && q->Target != target) {
466
         _mesa_error(ctx, GL_INVALID_OPERATION,
467
                     "glBeginQuery{Indexed}(target mismatch)");
468
         return;
469
      }
470
   }
471
 
472
   /* This possibly changes the target of a buffer allocated by
473
    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
474
    * the following:
475
    *
476
    * "CreateQueries adds a , so strictly speaking the 
477
    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
478
    * isn't a selector, so we decided not to change it."
479
    *
480
    * Updating the target of the query object should be acceptable, so let's
481
    * do that.
482
    */
483
 
484
   q->Target = target;
485
   q->Active = GL_TRUE;
486
   q->Result = 0;
487
   q->Ready = GL_FALSE;
488
   q->EverBound = GL_TRUE;
489
   q->Stream = index;
490
 
491
   /* XXX should probably refcount query objects */
492
   *bindpt = q;
493
 
494
   ctx->Driver.BeginQuery(ctx, q);
495
}
496
 
497
 
498
void GLAPIENTRY
499
_mesa_EndQueryIndexed(GLenum target, GLuint index)
500
{
501
   struct gl_query_object *q, **bindpt;
502
   GET_CURRENT_CONTEXT(ctx);
503
 
504
   if (MESA_VERBOSE & VERBOSE_API)
505
      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
506
                  _mesa_lookup_enum_by_nr(target), index);
507
 
508
   if (!query_error_check_index(ctx, target, index))
509
      return;
510
 
511
   FLUSH_VERTICES(ctx, 0);
512
 
513
   bindpt = get_query_binding_point(ctx, target, index);
514
   if (!bindpt) {
515
      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
516
      return;
517
   }
518
 
519
   /* XXX should probably refcount query objects */
520
   q = *bindpt;
521
 
522
   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
523
   if (q && q->Target != target) {
524
      _mesa_error(ctx, GL_INVALID_OPERATION,
525
                  "glEndQuery(target=%s with active query of target %s)",
526
                  _mesa_lookup_enum_by_nr(target),
527
                  _mesa_lookup_enum_by_nr(q->Target));
528
      return;
529
   }
530
 
531
   *bindpt = NULL;
532
 
533
   if (!q || !q->Active) {
534
      _mesa_error(ctx, GL_INVALID_OPERATION,
535
                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
536
      return;
537
   }
538
 
539
   q->Active = GL_FALSE;
540
   ctx->Driver.EndQuery(ctx, q);
541
}
542
 
543
void GLAPIENTRY
544
_mesa_BeginQuery(GLenum target, GLuint id)
545
{
546
   _mesa_BeginQueryIndexed(target, 0, id);
547
}
548
 
549
void GLAPIENTRY
550
_mesa_EndQuery(GLenum target)
551
{
552
   _mesa_EndQueryIndexed(target, 0);
553
}
554
 
555
void GLAPIENTRY
556
_mesa_QueryCounter(GLuint id, GLenum target)
557
{
558
   struct gl_query_object *q;
559
   GET_CURRENT_CONTEXT(ctx);
560
 
561
   if (MESA_VERBOSE & VERBOSE_API)
562
      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
563
                  _mesa_lookup_enum_by_nr(target));
564
 
565
   /* error checking */
566
   if (target != GL_TIMESTAMP) {
567
      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
568
      return;
569
   }
570
 
571
   if (id == 0) {
572
      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
573
      return;
574
   }
575
 
576
   q = _mesa_lookup_query_object(ctx, id);
577
   if (!q) {
578
      /* XXX the Core profile should throw INVALID_OPERATION here */
579
 
580
      /* create new object */
581
      q = ctx->Driver.NewQueryObject(ctx, id);
582
      if (!q) {
583
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
584
         return;
585
      }
586
      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
587
   }
588
   else {
589
      if (q->Target && q->Target != GL_TIMESTAMP) {
590
         _mesa_error(ctx, GL_INVALID_OPERATION,
591
                     "glQueryCounter(id has an invalid target)");
592
         return;
593
      }
594
   }
595
 
596
   if (q->Active) {
597
      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
598
      return;
599
   }
600
 
601
   /* This possibly changes the target of a buffer allocated by
602
    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
603
    * the following:
604
    *
605
    * "CreateQueries adds a , so strictly speaking the 
606
    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
607
    * isn't a selector, so we decided not to change it."
608
    *
609
    * Updating the target of the query object should be acceptable, so let's
610
    * do that.
611
    */
612
 
613
   q->Target = target;
614
   q->Result = 0;
615
   q->Ready = GL_FALSE;
616
   q->EverBound = GL_TRUE;
617
 
618
   if (ctx->Driver.QueryCounter) {
619
      ctx->Driver.QueryCounter(ctx, q);
620
   } else {
621
      /* QueryCounter is implemented using EndQuery without BeginQuery
622
       * in drivers. This is actually Direct3D and Gallium convention.
623
       */
624
      ctx->Driver.EndQuery(ctx, q);
625
   }
626
}
627
 
628
 
629
void GLAPIENTRY
630
_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
631
                        GLint *params)
632
{
633
   struct gl_query_object *q = NULL, **bindpt = NULL;
634
   GET_CURRENT_CONTEXT(ctx);
635
 
636
   if (MESA_VERBOSE & VERBOSE_API)
637
      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
638
                  _mesa_lookup_enum_by_nr(target),
639
                  index,
640
                  _mesa_lookup_enum_by_nr(pname));
641
 
642
   if (!query_error_check_index(ctx, target, index))
643
      return;
644
 
645
   if (target == GL_TIMESTAMP) {
646
      if (!ctx->Extensions.ARB_timer_query) {
647
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
648
         return;
649
      }
650
   }
651
   else {
652
      bindpt = get_query_binding_point(ctx, target, index);
653
      if (!bindpt) {
654
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
655
         return;
656
      }
657
 
658
      q = *bindpt;
659
   }
660
 
661
   switch (pname) {
662
      case GL_QUERY_COUNTER_BITS_ARB:
663
         switch (target) {
664
         case GL_SAMPLES_PASSED:
665
            *params = ctx->Const.QueryCounterBits.SamplesPassed;
666
            break;
667
         case GL_ANY_SAMPLES_PASSED:
668
            /* The minimum value of this is 1 if it's nonzero, and the value
669
             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
670
             * bits.
671
             */
672
            *params = 1;
673
            break;
674
         case GL_TIME_ELAPSED:
675
            *params = ctx->Const.QueryCounterBits.TimeElapsed;
676
            break;
677
         case GL_TIMESTAMP:
678
            *params = ctx->Const.QueryCounterBits.Timestamp;
679
            break;
680
         case GL_PRIMITIVES_GENERATED:
681
            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
682
            break;
683
         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
684
            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
685
            break;
686
         case GL_VERTICES_SUBMITTED_ARB:
687
            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
688
            break;
689
         case GL_PRIMITIVES_SUBMITTED_ARB:
690
            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
691
            break;
692
         case GL_VERTEX_SHADER_INVOCATIONS_ARB:
693
            *params = ctx->Const.QueryCounterBits.VsInvocations;
694
            break;
695
         case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
696
            *params = ctx->Const.QueryCounterBits.TessPatches;
697
            break;
698
         case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
699
            *params = ctx->Const.QueryCounterBits.TessInvocations;
700
            break;
701
         case GL_GEOMETRY_SHADER_INVOCATIONS:
702
            *params = ctx->Const.QueryCounterBits.GsInvocations;
703
            break;
704
         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
705
            *params = ctx->Const.QueryCounterBits.GsPrimitives;
706
            break;
707
         case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
708
            *params = ctx->Const.QueryCounterBits.FsInvocations;
709
            break;
710
         case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
711
            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
712
            break;
713
         case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
714
            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
715
            break;
716
         case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
717
            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
718
            break;
719
         default:
720
            _mesa_problem(ctx,
721
                          "Unknown target in glGetQueryIndexediv(target = %s)",
722
                          _mesa_lookup_enum_by_nr(target));
723
            *params = 0;
724
            break;
725
         }
726
         break;
727
      case GL_CURRENT_QUERY_ARB:
728
         *params = (q && q->Target == target) ? q->Id : 0;
729
         break;
730
      default:
731
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
732
         return;
733
   }
734
}
735
 
736
void GLAPIENTRY
737
_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
738
{
739
   _mesa_GetQueryIndexediv(target, 0, pname, params);
740
}
741
 
742
void GLAPIENTRY
743
_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
744
{
745
   struct gl_query_object *q = NULL;
746
   GET_CURRENT_CONTEXT(ctx);
747
 
748
   if (MESA_VERBOSE & VERBOSE_API)
749
      _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
750
                  _mesa_lookup_enum_by_nr(pname));
751
 
752
   if (id)
753
      q = _mesa_lookup_query_object(ctx, id);
754
 
755
   if (!q || q->Active || !q->EverBound) {
756
      _mesa_error(ctx, GL_INVALID_OPERATION,
757
                  "glGetQueryObjectivARB(id=%d is invalid or active)", id);
758
      return;
759
   }
760
 
761
   switch (pname) {
762
      case GL_QUERY_RESULT_ARB:
763
         if (!q->Ready)
764
            ctx->Driver.WaitQuery(ctx, q);
765
         /* if result is too large for returned type, clamp to max value */
766
         if (q->Target == GL_ANY_SAMPLES_PASSED
767
             || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
768
            if (q->Result)
769
               *params = GL_TRUE;
770
            else
771
               *params = GL_FALSE;
772
         } else {
773
            if (q->Result > 0x7fffffff) {
774
               *params = 0x7fffffff;
775
            }
776
            else {
777
               *params = (GLint)q->Result;
778
            }
779
         }
780
         break;
781
      case GL_QUERY_RESULT_AVAILABLE_ARB:
782
         if (!q->Ready)
783
            ctx->Driver.CheckQuery( ctx, q );
784
         *params = q->Ready;
785
         break;
786
      case GL_QUERY_TARGET:
787
         *params = q->Target;
788
         break;
789
      default:
790
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
791
         return;
792
   }
793
}
794
 
795
 
796
void GLAPIENTRY
797
_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
798
{
799
   struct gl_query_object *q = NULL;
800
   GET_CURRENT_CONTEXT(ctx);
801
 
802
   if (MESA_VERBOSE & VERBOSE_API)
803
      _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
804
                  _mesa_lookup_enum_by_nr(pname));
805
 
806
   if (id)
807
      q = _mesa_lookup_query_object(ctx, id);
808
 
809
   if (!q || q->Active || !q->EverBound) {
810
      _mesa_error(ctx, GL_INVALID_OPERATION,
811
                  "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
812
      return;
813
   }
814
 
815
   switch (pname) {
816
      case GL_QUERY_RESULT_ARB:
817
         if (!q->Ready)
818
            ctx->Driver.WaitQuery(ctx, q);
819
         /* if result is too large for returned type, clamp to max value */
820
         if (q->Target == GL_ANY_SAMPLES_PASSED
821
             || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
822
            if (q->Result)
823
               *params = GL_TRUE;
824
            else
825
               *params = GL_FALSE;
826
         } else {
827
            if (q->Result > 0xffffffff) {
828
               *params = 0xffffffff;
829
            }
830
            else {
831
               *params = (GLuint)q->Result;
832
            }
833
         }
834
         break;
835
      case GL_QUERY_RESULT_AVAILABLE_ARB:
836
         if (!q->Ready)
837
            ctx->Driver.CheckQuery( ctx, q );
838
         *params = q->Ready;
839
         break;
840
      case GL_QUERY_TARGET:
841
         *params = q->Target;
842
         break;
843
      default:
844
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
845
         return;
846
   }
847
}
848
 
849
 
850
/**
851
 * New with GL_EXT_timer_query
852
 */
853
void GLAPIENTRY
854
_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
855
{
856
   struct gl_query_object *q = NULL;
857
   GET_CURRENT_CONTEXT(ctx);
858
 
859
   if (MESA_VERBOSE & VERBOSE_API)
860
      _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
861
                  _mesa_lookup_enum_by_nr(pname));
862
 
863
   if (id)
864
      q = _mesa_lookup_query_object(ctx, id);
865
 
866
   if (!q || q->Active || !q->EverBound) {
867
      _mesa_error(ctx, GL_INVALID_OPERATION,
868
                  "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
869
      return;
870
   }
871
 
872
   switch (pname) {
873
      case GL_QUERY_RESULT_ARB:
874
         if (!q->Ready)
875
            ctx->Driver.WaitQuery(ctx, q);
876
         *params = q->Result;
877
         break;
878
      case GL_QUERY_RESULT_AVAILABLE_ARB:
879
         if (!q->Ready)
880
            ctx->Driver.CheckQuery( ctx, q );
881
         *params = q->Ready;
882
         break;
883
      case GL_QUERY_TARGET:
884
         *params = q->Target;
885
         break;
886
      default:
887
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
888
         return;
889
   }
890
}
891
 
892
 
893
/**
894
 * New with GL_EXT_timer_query
895
 */
896
void GLAPIENTRY
897
_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
898
{
899
   struct gl_query_object *q = NULL;
900
   GET_CURRENT_CONTEXT(ctx);
901
 
902
   if (MESA_VERBOSE & VERBOSE_API)
903
      _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
904
                  _mesa_lookup_enum_by_nr(pname));
905
 
906
   if (id)
907
      q = _mesa_lookup_query_object(ctx, id);
908
 
909
   if (!q || q->Active || !q->EverBound) {
910
      _mesa_error(ctx, GL_INVALID_OPERATION,
911
                  "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
912
      return;
913
   }
914
 
915
   switch (pname) {
916
      case GL_QUERY_RESULT_ARB:
917
         if (!q->Ready)
918
            ctx->Driver.WaitQuery(ctx, q);
919
         *params = q->Result;
920
         break;
921
      case GL_QUERY_RESULT_AVAILABLE_ARB:
922
         if (!q->Ready)
923
            ctx->Driver.CheckQuery( ctx, q );
924
         *params = q->Ready;
925
         break;
926
      case GL_QUERY_TARGET:
927
         *params = q->Target;
928
         break;
929
      default:
930
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
931
         return;
932
   }
933
}
934
 
935
/**
936
 * New with GL_ARB_query_buffer_object
937
 */
938
void GLAPIENTRY
939
_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
940
                             GLintptr offset)
941
{
942
   GET_CURRENT_CONTEXT(ctx);
943
   _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectiv");
944
}
945
 
946
 
947
void GLAPIENTRY
948
_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
949
                              GLintptr offset)
950
{
951
   GET_CURRENT_CONTEXT(ctx);
952
   _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectuiv");
953
}
954
 
955
 
956
void GLAPIENTRY
957
_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
958
                               GLintptr offset)
959
{
960
   GET_CURRENT_CONTEXT(ctx);
961
   _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjecti64v");
962
}
963
 
964
 
965
void GLAPIENTRY
966
_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
967
                                GLintptr offset)
968
{
969
   GET_CURRENT_CONTEXT(ctx);
970
   _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectui64v");
971
}
972
 
973
 
974
/**
975
 * Allocate/init the context state related to query objects.
976
 */
977
void
978
_mesa_init_queryobj(struct gl_context *ctx)
979
{
980
   ctx->Query.QueryObjects = _mesa_NewHashTable();
981
   ctx->Query.CurrentOcclusionObject = NULL;
982
 
983
   ctx->Const.QueryCounterBits.SamplesPassed = 64;
984
   ctx->Const.QueryCounterBits.TimeElapsed = 64;
985
   ctx->Const.QueryCounterBits.Timestamp = 64;
986
   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
987
   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
988
 
989
   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
990
   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
991
   ctx->Const.QueryCounterBits.VsInvocations = 64;
992
   ctx->Const.QueryCounterBits.TessPatches = 64;
993
   ctx->Const.QueryCounterBits.TessInvocations = 64;
994
   ctx->Const.QueryCounterBits.GsInvocations = 64;
995
   ctx->Const.QueryCounterBits.GsPrimitives = 64;
996
   ctx->Const.QueryCounterBits.FsInvocations = 64;
997
   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
998
   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
999
   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
1000
}
1001
 
1002
 
1003
/**
1004
 * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
1005
 */
1006
static void
1007
delete_queryobj_cb(GLuint id, void *data, void *userData)
1008
{
1009
   struct gl_query_object *q= (struct gl_query_object *) data;
1010
   struct gl_context *ctx = (struct gl_context *)userData;
1011
   ctx->Driver.DeleteQuery(ctx, q);
1012
}
1013
 
1014
 
1015
/**
1016
 * Free the context state related to query objects.
1017
 */
1018
void
1019
_mesa_free_queryobj_data(struct gl_context *ctx)
1020
{
1021
   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
1022
   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
1023
}