| Name |
| |
| ARB_query_buffer_object |
| |
| Name Strings |
| |
| GL_ARB_query_buffer_object |
| |
| Contact |
| |
| Daniel Rakos (daniel.rakos 'at' amd.com) |
| |
| Contributors |
| |
| Daniel Rakos, AMD |
| Graham Sellers, AMD |
| Christophe Riccio, AMD |
| |
| Notice |
| |
| Copyright (c) 2013 The Khronos Group Inc. Copyright terms at |
| http://www.khronos.org/registry/speccopyright.html |
| |
| Status |
| |
| Complete. Approved by the ARB on June 3, 2013. |
| Ratified by the Khronos Board of Promoters on July 19, 2013. |
| |
| Version |
| |
| Last Modified Date: 7 March 2016 |
| Author Revision: 3 |
| |
| Number |
| |
| ARB Extension #148 |
| |
| Dependencies |
| |
| OpenGL 1.5 is required. |
| |
| This extension is written against the OpenGL 4.3 (core) specification. |
| |
| Overview |
| |
| Statistics about the operation of the OpenGL pipeline, such as the number |
| of samples that passed the depth test, the elapsed time between two events |
| or the number of vertices written by transform feedback can be retrieved |
| from the GL through query objects. The result of a query object is |
| acquired by the application through the OpenGL API into a client provided |
| memory location. Should the result returned by the API be required for use |
| in a shader, it must be passed back to the GL via a program uniform or |
| some other mechanism. This requires a round-trip from the GPU to the CPU |
| and back. |
| |
| This extension introduces a mechanism whereby the result of a query object |
| may be retrieved into a buffer object instead of client memory. This allows |
| the query rsult to be made available to a shader without a round-trip to |
| the CPU for example by subsequently using the buffer object as a uniform |
| buffer, texture buffer or other data store visible to the shader. This |
| functionality may also be used to place the results of many query objects |
| into a single, large buffer and then map or otherwise read back the entire |
| buffer at a later point in time, avoiding a per-query object CPU-GPU |
| synchronization event. |
| |
| The extension allows acquiring the result of any query object type |
| supported by the GL implementation into a buffer object. The implementation |
| will determine the most efficient method of copying the query result to the |
| buffer. |
| |
| New Procedures and Functions |
| |
| None. |
| |
| New Tokens |
| |
| Accepted by the <pname> parameter of GetQueryObjectiv, GetQueryObjectuiv, |
| GetQueryObjecti64v and GetQueryObjectui64v: |
| |
| QUERY_RESULT_NO_WAIT 0x9194 |
| |
| Accepted by the <target> parameter of BindBuffer, BufferData, |
| BufferSubData, MapBuffer, UnmapBuffer, MapBufferRange, GetBufferSubData, |
| GetBufferParameteriv, GetBufferParameteri64v, GetBufferPointerv, |
| ClearBufferSubData, and the <readtarget> and <writetarget> parameters of |
| CopyBufferSubData: |
| |
| QUERY_BUFFER 0x9192 |
| |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv, |
| and GetDoublev: |
| |
| QUERY_BUFFER_BINDING 0x9193 |
| |
| Accepted in the <barriers> bitfield in MemoryBarrier: |
| |
| QUERY_BUFFER_BARRIER_BIT 0x00008000 |
| |
| Additions to Chapter 4 of the OpenGL Core Profile Specification, Version 4.3, |
| "Event Model" |
| |
| Modify Section 4.2.1, "Query Object Queries" |
| |
| Add new paragraph after the fist paragraph on p. 44 ending with |
| "... <id> is the name of a query object." |
| |
| Initially, zero is bound to the QUERY_BUFFER binding point, indicating |
| that <params> is a pointer into client memory. However, if a non-zero |
| buffer object is bound as the current query result buffer (see section |
| 6.1), then <params> is treated as an offset into the designated buffer |
| object. |
| |
| Add new paragraph after the third paragraph on p. 44 ending with |
| "... finite amount of time." |
| |
| If <pname> is QUERY_RESULT_NO_WAIT, then the query object's result |
| value is returned as a single integer in <params> if the result is |
| available at the time of the state query. If the result is not available |
| then the destination memory location is not overwritten. |
| |
| Additions to Chapter 6 of the OpenGL Core Profile Specification, Version 4.3, |
| "Buffer Objects" |
| |
| Modify Section 6.1, "Creating and Binding Buffer Objects" |
| |
| Add to Table 6.1: "Buffer object binding targets" |
| |
| +--------------------+--------------------------+-------------------------+ |
| | Target name | Purpose | Described in section(s) | |
| +--------------------+--------------------------+-------------------------+ |
| | QUERY_BUFFER | Query result buffer | 4.2.1 | |
| +--------------------+--------------------------+-------------------------+ |
| |
| Additions to Chapter 7 of the OpenGL Core Profile Specification, Version 4.3, |
| "Programs and Shaders" |
| |
| Modify Section 7.12, "Shader Memory Access" |
| |
| Add to the list of MemoryBarrier <barriers> bullets, p. 138 |
| |
| * QUERY_BUFFER_BARRIER_BIT: Writes of buffer objects via the QUERY_BUFFER |
| binding (see section 4.2.1) after the barrier will reflect data written |
| by shaders prior to the barrier. Additionally, buffer object writes |
| issued after the barrier will wait on the completion of all shader |
| writes initiated prior to the barrier. |
| |
| Additions to the AGL/GLX/WGL Specifications |
| |
| None. |
| |
| GLX Protocol |
| |
| None. |
| |
| Errors |
| |
| Replace second error case for QueryObject* with the following: |
| |
| An INVALID_ENUM error is generated if <pname> is not QUERY_RESULT, |
| QUERY_RESULT_NO_WAIT or QUERY_RESULT_AVAILABLE. |
| |
| Add error case for QueryObject* as follows: |
| |
| An INVALID_OPERATION error is generated if the command would cause data |
| to be written beyond the bounds of the buffer currently bound to the |
| QUERY_BUFFER target. |
| |
| New State |
| |
| Append to Table 23.73, "Miscellaneous" |
| |
| +----------------------+------+--------------+---------------+------------------------------+-------+ |
| | Get Value | Type | Get Command | Initial Value | Description | Sec. | |
| +----------------------+------+--------------+---------------+------------------------------+-------+ |
| | QUERY_BUFFER_BINDING | Z+ | GetIntegeriv | 0 | Query result buffer binding. | 4.2.1 | |
| +----------------------+------+--------------+---------------+------------------------------+-------+ |
| |
| New Implementation Dependent State |
| |
| None. |
| |
| Usage Examples |
| |
| Convenient macro definition for specifying buffer offsets: |
| |
| #define BUFFER_OFFSET(i) ((void*)NULL + (i)) |
| |
| Example 1: Using occlusion query result in shader |
| |
| // Create a buffer object for the query result |
| glGenBuffers(1, &queryBuffer); |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| glBufferData(GL_QUERY_BUFFER, sizeof(GLuint), |
| NULL, GL_DYNAMIC_COPY); |
| |
| // Perform occlusion query |
| glBeginQuery(GL_SAMPLES_PASSED, queryId) |
| ... |
| glEndQuery(GL_SAMPLES_PASSED); |
| |
| // Get query results to buffer object |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT, BUFFER_OFFSET(0)); |
| |
| // Bind query result buffer as uniform buffer |
| glBindBufferBase(GL_UNIFORM_BUFFER, 0, queryBuffer); |
| ... |
| |
| --- Shader --- |
| |
| ... |
| uniform queryResult { |
| uint samplesPassed; |
| }; |
| ... |
| void main() { |
| ... |
| if (samplesPassed > threshold) { |
| // complex processing |
| ... |
| } else { |
| // simplified processing |
| ... |
| } |
| ... |
| } |
| |
| Example 2: Using occlusion query result in shader only if result is available |
| |
| // Create a buffer object for the query result |
| glGenBuffers(1, &queryBuffer); |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| glBufferData(GL_QUERY_BUFFER, 2 * sizeof(GLuint), |
| NULL, GL_DYNAMIC_COPY); |
| |
| // Perform occlusion query |
| glBeginQuery(GL_SAMPLES_PASSED, queryId) |
| ... |
| glEndQuery(GL_SAMPLES_PASSED); |
| |
| // Get query availability and result (if available) to buffer object |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_AVAILABLE, BUFFER_OFFSET(0)); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT, BUFFER_OFFSET(4)); |
| |
| // Bind query result buffer as uniform buffer |
| glBindBufferBase(GL_UNIFORM_BUFFER, 0, queryBuffer); |
| ... |
| |
| --- Shader --- |
| |
| ... |
| uniform queryResult { |
| uint resultAvailable; |
| uint samplesPassed; |
| }; |
| ... |
| void main() { |
| ... |
| if (resultAvailable) { |
| if (samplesPassed > threshold) { |
| // complex processing |
| ... |
| } else { |
| // simplified processing |
| ... |
| } |
| } else { |
| // default processing if no query result is available |
| ... |
| } |
| ... |
| } |
| |
| Example 3: Using a default value and QUERY_RESULT_NO_WAIT |
| |
| // Create a buffer object for the query result |
| // Store a default value in the buffer that will be used |
| // if the query results are not available |
| glGenBuffers(1, &queryBuffer); |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| GLuint defaultValue = 42; |
| glBufferData(GL_QUERY_BUFFER, sizeof(GLuint), |
| &defaultValue, GL_DYNAMIC_COPY); |
| |
| // Perform occlusion query |
| glBeginQuery(GL_SAMPLES_PASSED, queryId) |
| ... |
| glEndQuery(GL_SAMPLES_PASSED); |
| |
| // Get query results to buffer object with no wait |
| // Default value remains untouched if results are not available |
| glBindBuffer(GL_QUERY_BUFFER, queryBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT, BUFFER_OFFSET(0)); |
| ... |
| |
| Example 4: Using transform feedback query result to fill indirect draw buffer |
| |
| // Create a buffer object for the indirect draw command |
| glGenBuffers(1, &drawIndirectBuffer); |
| |
| // Initialize draw command |
| DrawArraysIndirectCommand cmd = { ... }; |
| glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuffer); |
| glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawArraysIndirectCommand), |
| &cmd, GL_DYNAMIC_COPY); |
| |
| // Perform transform feedback query |
| glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryId) |
| ... |
| glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); |
| |
| // Write query result to the primCount field of the indirect draw command |
| glBindBuffer(GL_QUERY_BUFFER, drawIndirectBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT, |
| BUFFER_OFFSET(offsetof(DrawArraysIndirectCommand, primCount))); |
| |
| // Execute the indirect draw command |
| glDrawArraysIndirect(GL_TRIANGLES, BUFFER_OFFSET(0)); |
| ... |
| |
| Issues |
| |
| 1) What is QUERY_RESULT_NO_WAIT useful for? |
| |
| RESOLVED: The application may decide that it does not want to wait for the |
| result of the query object if it's not available at the time. This is not |
| a problem without this extension as the application can always query the |
| availability using QUERY_RESULT_AVAILABLE and decide to actually get the |
| results using QUERY_RESULT only if the result is available. However, when |
| using query buffers, QUERY_RESULT_AVAILABLE and QUERY_RESULT alone cannot |
| provide the same flexibility for shader based decision making as the |
| results are either always available (if QUERY_RESULT was used) or never. |
| QUERY_RESULT_NO_WAIT provides a way to query the result only if it's |
| available. Combined with QUERY_RESULT_AVAILABLE, the shader can decide |
| to use the result or not based on the availability (see usage example 2). |
| |
| 2) Should QUERY_RESULT_NO_WAIT be accepted by GetQueryObject* in case |
| there is no buffer bound to QUERY_BUFFER? |
| |
| RESOLVED: YES, for completeness. |
| |
| 3) Is there any guarantee that GetQueryObject* will not wait for the |
| query results to become available if <pname> is QUERY_RESULT_NO_WAIT? |
| |
| RESOLVED: There is no need to have such guarantee. An implementation may |
| choose to wait for the results even in case of QUERY_RESULT_NO_WAIT, |
| however, that may incur a potential performance hit in case the |
| application expects it to not wait. |
| |
| 4) Should the INVALID_OPERATION error be generated if a GetQueryObject* |
| command would access data outside the range of the bound query buffer? |
| |
| RESOLVED: YES. This requires considering the value of <params> and the |
| size of the type of the written value to determine the maximum addressed |
| byte for the state query command. |
| |
| Note: This follows the precedence of the language introduced by |
| ARB_pixel_buffer_object. |
| |
| 5) Should we support 64 bit versions of the state query commands |
| (GetQueryObjecti64v and GetQueryObjectui64v)? |
| |
| RESOLVED: YES, both for completeness and to support timer queries. In this |
| case a 64 bit integer value is written to the buffer. |
| |
| 6) Should the extension support all query types supported by the current |
| GL implementation? |
| |
| RESOLVED: YES. There is not much value in providing additional capability |
| queries that would allow the application to find out which query object |
| types are supported. Also, the GL implementation can always choose to |
| implement the functionality through a GPU-CPU rount-trip for query types |
| that cannot be resolved to a buffer by the hardware. |
| |
| 7) Is there any precedence that the pointer parameter of a glGet* command |
| is treated as an offset into a bound buffer object? |
| |
| RESOLVED: YES, glGetTexImage accepts an offset into the pixel pack buffer |
| in case a pixel pack buffer is bound. As pixel buffer objects are part of |
| the core specification since version 2.1, no precedence is introduced by |
| this extension. |
| |
| 8) What should be written to the query buffer when QUERY_RESULT_NO_WAIT |
| is used but the results are not available? |
| |
| DISCUSSION: Leaving the written value undefined is an option, however |
| in many cases the application can benefit from having a defined value in |
| the query buffer if the results are not available. The following options |
| were considered to support such use cases: |
| |
| a. Write a predefined fixed value to the buffer. |
| b. Write a user specified value to the buffer. |
| c. Don't write anything to the buffer. |
| |
| The problem with option a. is that it may be difficult to select such |
| a predefined value that would not potentially conflict with a valid |
| value. Option b. could be fine, however it requires new API to specify |
| this default value. Thus, option c. is considered to most preferable. |
| |
| RESOLVED: Nothing, the current value in the specified offset of the |
| query buffer is left untouched. |
| |
| 9) How does ARB_query_buffer_object differ from AMD_query_buffer_object? |
| |
| RESOLVED: This extension introduced a new barrier bit accepted by |
| MemoryBarrier that controls the relative ordering of shader buffer writes |
| and query buffer writes. |
| |
| Revision History |
| |
| Rev. Date Author Changes |
| ---- -------- -------- ---------------------------------------------- |
| |
| 3 03/07/2016 drakos Fixed typo in example #4 |
| 2 04/02/2013 drakos Added missing function names to the list of |
| functions accepting QUERY_BUFFER as parameter |
| 1 03/08/2013 drakos Initial draft based on AMD_query_buffer_object |
| Removed suffixes |
| Updated spec language to GL 4.3 |
| Added QUERY_BUFFER_BARRIER_BIT |