Query Object

From OpenGL.org
Jump to: navigation, search
Query Object
Core in version 4.4
Core since version 1.5
ARB extension ARB_occlusion_query

Query Objects are OpenGL Objects that are used for asynchronous queries of certain kinds of information.

Management

Query objects follow the general OpenGL Object paradigm. They have glGenQueries and glDeleteQueries. However, unlike most other OpenGL Objects, there is no general glBindQuery or similar function.

Many kinds of query operations require a scope. The scope of the query is bound by a pair of begin/end functions, such that the query returns some information generated through the execution of the commands within that scope.

Like textures, query objects have different types, represented by the target​ parameter taken by the query object functions. Query objects represent a single integer value, generated by some OpenGL process, which can be queried asynchronously. The different types determine what the value being queried means and where it comes from:

  • GL_SAMPLES_PASSED​​: The number of samples that pass the depth test for all rendering commands within the scope of the query.
  • GL_ANY_SAMPLES_PASSED​​: GL_FALSE​ if none of the scoped rendering commands generate samples that pass the depth test; otherwise, the value is GL_TRUE​. This requires OpenGL 3.3 or ARB_occlusion_query2.
  • GL_ANY_SAMPLES_PASSED_CONSERVATIVE​​: As GL_ANY_SAMPLES_PASSED​, except that the implementation may use a less accurate algorithm, which may be faster, but at the cost of more more false positives. This requires OpenGL 4.3 or ARB_ES3_compatibility.
  • GL_PRIMITIVES_GENERATED​: Records the number of primitives sent to a particular Geometry Shader output stream (or by stream 0 if no GS is active) by the scoped rendering commands. This requires OpenGL 3.0; multiple streams requires 4.0 or ARB_transform_feedback3.
  • GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​: Records the number of primitives written by a Geometry Shader stream to a Transform Feedback object (or by stream 0 if no GS is active) by the scoped rendering commands. This requires OpenGL 3.0; multiple streams requires 4.0 or ARB_transform_feedback3.
  • GL_TIME_ELAPSED​​: Records the time that it takes for the GPU to execute all of the scoped commands. The timer starts when all commands before the scope have completed, and the timer ends when the last scoped command has completed.
  • GL_TIMESTAMP​: Records the current time of the GPU.

Query scope

The result of query objects is usually based on data created from multiple rendering commands. As such, the commands that the query operates over is denoted by a begin/end pair of functions:

glBeginQuery(GLenum target​, GLuint id​);
glEndQuery(GLenum target​);

The only target​ not accepted by these functions is GL_TIMESTAMP​.

Some targets are indexed, meaning that the target has some number of slots for query operations. These kinds of targets can use glBeginQueryIndexed and glEndQueryIndexed, which take an index that the function will begin a query on. glBeginQuery is defined as calling glBeginQueryIndexed with an index​ of 0.

What the index represents depends on the target​ type. Targets that allow for a non-zero index are:

  • GL_PRIMITIVES_GENERATED​​: The index represents a vertex stream output from the Geometry Shader. The maximum index is GL_MAX_VERTEX_STREAMS​. Requires OpenGL 4.0 or ARB_transform_feedback3.
  • GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​: The index represents a vertex stream output from the Geometry Shader. The maximum index is GL_MAX_VERTEX_STREAMS​. Requires OpenGL 4.0 or ARB_transform_feedback3.

Query retrieval

To retrieve information from the query object, the following function is used:

glGetQueryObject[ui64v](GLuint id​, GLenum pname​, type * params​);

The id​ is the query object to retrieve information about. pname​ is the type of information to retrieve. The data queried will be written into params​.

Query objects provide the following different types of information:

GL_QUERY_RESULT_AVAILABLE​
The purpose of query objects is to represent asynchronous queries of values. Thus, even after a query's scope has ended, the queried value may not be immediately available. This query is used to ask the query object if the result is actually available. This will write GL_FALSE​ if the query has not completed, and GL_TRUE​ otherwise.
GL_QUERY_RESULT​
This returns the actual result of the query. If the query's internal integer value is too large for the bitdepth the function call asked for (ie: the query stores the integer with 48-bits, but the user uses the the 32-bit integer version of the function), then the value returned will be the value that is closest to the actual value of the query.
Note that if you query the result before GL_QUERY_RESULT_AVAILABLE​ returns GL_TRUE​, then you will be effectively turning an asynchronous query into a synchronous one. That is, the function will stall the CPU until the result is available.
GL_QUERY_RESULT_NO_WAIT​ (requires OpenGL 4.4/ARB_query_buffer_object)
This is a combination of the above two values. If the query result is available, this returns the query result as though with GL_QUERY_RESULT​. If the query result is not available, then nothing is written, and whatever value was in params​ will be unchanged.

Query buffer object

Query Object
Core in version 4.4
Core since version 4.4
Core ARB extension ARB_query_buffer_object
Vendor extension AMD_query_buffer_object

The results queried from a query object can be fed into a Buffer Object. This allows users to help feed query results back into internal OpenGL operations. This is useful for querying the number of primitives generated by the Geometry Shader into an indirect rendering call. It can also be used in tandem with Image Load Store and other buffer reading mechanisms.

To do this, a buffer must first be bound to GL_QUERY_BUFFER​ with glBindBuffer. When a non-zero buffer object is bound to this binding point, the behavior of glGetQueryObject changes. The params​ field is interpreted, not as a pointer to memory but as a numerical byte offset into the buffer bound to GL_QUERY_BUFFER​.

The size of the value written is determined by the version of glGetQueryObject being called.

The write works with the standard, in-order Memory Model that the rest of OpenGL uses. However, there is a barrier that is needed to order writes between incoherent accesses to the buffer and this API.

Query precision

All query objects represent a single integer value. However, each type of query object has a different precision for this value. While you can query the integer value at 32 and 64-bit precision, the OpenGL implementation only provides so much precision for these values.

The precision for a query can be acquired by calling glGetQuery with GL_QUERY_COUNTER_BITS​ as the second parameter. OpenGL defines the minimum precision for each query type as follows:

Query type Minimum precision
GL_SAMPLES_PASSED​​ 32*
GL_ANY_SAMPLES_PASSED​​ 1
GL_ANY_SAMPLES_PASSED_CONSERVATIVE​​ 1
GL_PRIMITIVES_GENERATED​ 32
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​ 32
GL_TIME_ELAPSED​​ 30
GL_TIMESTAMP​ 30

* In OpenGL 3.3, the minimum precision required is a function of the maximum viewport width and height. Specifically, the precision is required to be at least enough to hold a counter that is twice the maximum width and height, thus supporting 2x multisampling at the largest buffer size.

Note that implementations are allowed to return 0 for any of these values. This means that the query type contains no actual information, and the implementation does not really support it..

Occlusion queries

Query Object
Core in version 4.4
Core since version 1.5
Core ARB extension ARB_occlusion_query2

Occlusion queries are the collective name for the following query object types: GL_SAMPLES_PASSED​​​, GL_ANY_SAMPLES_PASSED​​​, and GL_ANY_SAMPLES_PASSED_CONSERVATIVE​​​. These represent ways to detect whether an object is visible. They detect whether the scoped rendering commands pass the depth test and if so, how many samples pass.

Note that the sample count and pass/fail are based only on the depth test. The stencil test, alpha test, or fragment shader discard​ is irrelevant with queries. Also, if explicit early depth tests are used, the sample count is bumped before the fragment shader issues discard​. So again, discard​ is irrelevant.

When using Multisampling, the implementation is allowed to decide how to count the individual samples within a pixel area. The implementation may count only the samples within a triangle's area (if the triangle only covers part of a pixel), or it may count all of the samples if the triangle covers any of them in a pixel.

The GL_ANY_SAMPLES_PASSED_CONSERVATIVE​​​ may be faster than GL_ANY_SAMPLES_PASSED​​​. However, it may also be less accurate. If it is, it will only be such that it gives more false positives than the more accurate method.

The result of an occlusion query can be used as the condition for Conditional Rendering.

In general, this feature is used to prevent rendering objects that are complex by rendering a much simpler volume (with a simple shader) in the same place. Write Masks are used to prevent drawing anything or modifying the depth buffer. If samples of that object are visible, then the actual complex object is drawn.

Timer queries

Timer Query
Core in version 4.4
Core since version 3.3
Core ARB extension ARB_timer_query

Timer queries are the collective name for the query types GL_TIMESTAMP​ and GL_TIME_ELAPSED​. These are used for measuring the GPU timings of various operations. All times returned are measured in nanoseconds.

The GL_TIME_ELAPSED​ query is used with a scope to measure how long it takes for the scoped commands to execute on the GPU. The timer starts when the first command starts executing, and the timer ends when the final command is completed.

The GL_TIMESTAMP​ query type is not used with a scope; it is used to record a specific time. Exactly what the time is relative to is implementation-dependent. Instead, they can only be used with this function:

glQueryCounter(GLuint id​, GLenum target​);

This will store into the query object the time when the GPU will have completed all previously issued commands.

Calling glGetInteger64v with GL_TIMESTAMP​ will return the GPU timestamp when all previously given commands have issued, but not necessarily completed. Unlike the actual timer query commands, this command will stall the CPU until the timestamp is returned.

When using the synchronous timestamp, coupled with an asynchronous GL_TIMESTAMP​ query, one can determine the latency between when commands are issued and when they complete.

Primitive queries

Primitive Query
Core in version 4.4
Core since version 3.0

Primitive queries are the collective name for the GL_PRIMITIVES_GENERATED​​​ and GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​​ query object types. These are used for detecting how many primitives were generated during one or more rendering operations. This is primarily used for Transform Feedback, particularly in cases where the number of items to be generated by a geometry and/or Tessellation Shader depends on the data provided.

The primitive counts in these cases are the number of basic primitives. So a triangle strip 5 vertices long is 3 primitives, not one primitive.

GL_PRIMITIVES_GENERATED​​​ provides the number of primitives that are output by a Geometry Shader. If no GS is active, then it is the number of primitives output from the rendering command. Though without a GS or a Tessellatiion Shader, you can easily determine the number of primitives.

GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​ is slightly different. It is the number of primitives that are written to transform feedback buffers. For this count to be incremented, the scoped commands must issue rendering commands while within the boundaries of glBeginTransformFeedback/glEndTransformFeedback. The transform feedback scope and the query scope can overlap, and one can end before the other. Similarly, transform feedback can be paused with glPauseTransformFeedback, and the count will not include primitives generated here.

Note that glDrawTransformFeedback is perfectly capable of rendering from a transform feedback object without having to query the number of vertices. Though this is only core in GL 4.0, it is widely available on 3.x-class hardware.

Multiple streams

Stream Output
Core in version 4.4
Core since version 4.0
Core ARB extension ARB_transform_feedback3

Transform feedback operations can have multiple output streams. As such, primitive queries can be indexed, with each index representing a potential transform feedback output stream.

The definition of the primitive query types does not change. Primitives can still be sent to a stream where no transform feedback buffers are written. In that case, any GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN​ queries active on that stream will not have their count incremented. However, active GL_PRIMITIVES_GENERATED​ queries will.

Reference