| Name |
| |
| AMD_query_buffer_object |
| |
| Name Strings |
| |
| GL_AMD_query_buffer_object |
| |
| Contact |
| |
| Daniel Rakos (daniel.rakos 'at' amd.com) |
| |
| Contributors |
| |
| Daniel Rakos, AMD |
| Graham Sellers, AMD |
| Christophe Riccio, AMD |
| |
| Status |
| |
| Shipping in Catalyst 12.6 |
| |
| Version |
| |
| Last Modified Date: 03/07/2016 |
| Author Revision: 6 |
| |
| Number |
| |
| 420 |
| |
| Dependencies |
| |
| OpenGL 1.5 is required. |
| |
| This extension is written against the OpenGL 4.2 (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 to a transform feedback buffer may |
| be retrieved from the GL through query objects. The current value of a |
| query object may be retrieved by the application through the OpenGL API. |
| 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 current value of a query |
| result may be retrieved into a buffer object instead of client memory. |
| This allows the query result 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 |
| CPU-GPU synchronization event. |
| |
| The result of any query object type supported by the GL implementation |
| may be retrieved 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_AMD 0x9194 |
| |
| Accepted by the <target> parameters of BindBuffer, BufferData, |
| BufferSubData, MapBuffer, UnmapBuffer, MapBufferRange, GetBufferSubData, |
| GetBufferParameteriv |
| and GetBufferPointerv: |
| |
| QUERY_BUFFER_AMD 0x9192 |
| |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv, |
| and GetDoublev: |
| |
| QUERY_BUFFER_BINDING_AMD 0x9193 |
| |
| Additions to Chapter 2 of the OpenGL 4.2 (core) Specification (OpenGL Operation) |
| |
| Modify Section 2.9, Buffer Objects |
| |
| Add to Table 2.8: Buffer object binding targets (p. 43) |
| |
| +---------------------+--------------------------+-------------------------+ |
| | Target name | Purpose | Described in section(s) | |
| +---------------------+--------------------------+-------------------------+ |
| | QUERY_BUFFER_AMD | Query result buffer | 6.1.7 | |
| +---------------------+--------------------------+-------------------------+ |
| |
| Additions to Chapter 3 of the OpenGL 3.2 (core) Specification (Rasterization) |
| |
| None. |
| |
| Additions to Chapter 4 of the OpenGL 3.2 (core) Specification (Per-Fragment Operations and the Frame Buffer) |
| |
| None. |
| |
| Additions to Chapter 5 of the OpenGL 3.2 (core) Specification (Special Functions) |
| |
| None. |
| |
| Additions to Chapter 6 of the OpenGL 3.2 (core) Specification (State and State Requests) |
| |
| Modify Section 6.1.7, Asynchronous Queries |
| |
| Add new paragraph before the third paragraph on p. 358 |
| |
| Initially, zero is bound for the QUERY_BUFFER_AMD, indicating that |
| <params> is a pointer into client memory. However, if a non-zero buffer |
| object is bound as the current query result buffer, then <params> is |
| treated as an offset into the designated buffer object. |
| |
| Replace last sentence of the third paragraph on p. 358 |
| beginning with "The state of a query object can be queried with ..." |
| |
| pname must be QUERY_RESULT, QUERY_RESULT_NO_WAIT_AMD |
| or QUERY_RESULT_AVAILABLE. |
| |
| Add new paragraph before the last paragraph on p. 358 |
| |
| If <pname> is QUERY_RESULT_NO_WAIT_AMD, 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 the AGL/GLX/WGL Specifications |
| |
| None. |
| |
| GLX Protocol |
| |
| None. |
| |
| Errors |
| |
| INVALID_OPERATION is generated by GetQueryObjectiv, GetQueryObjectuiv, |
| GetQueryObjecti64v, or GetQueryObjectui64v if the command would cause data |
| to be written beyond the bounds of the buffer currently currently bound |
| to the QUERY_BUFFER_AMD target. |
| |
| New State |
| |
| Append to Table 6.41, "Query Object State" |
| |
| +----------------------------+-------+-------------------+---------------+-------------------------------------------+-------+ |
| | Get Value | Type | Get Command | Initial Value | Description | Sec. | |
| +----------------------------+-------+-------------------+---------------+-------------------------------------------+-------+ |
| | QUERY_BUFFER_BINDING_AMD | Z+ | GetIntegeriv | 0 | Query result buffer binding. | 6.1.7 | |
| +----------------------------+-------+-------------------+---------------+-------------------------------------------+-------+ |
| |
| 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_AMD, queryBuffer); |
| glBufferData(GL_QUERY_BUFFER_AMD, 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_AMD, 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_AMD, queryBuffer); |
| glBufferData(GL_QUERY_BUFFER_AMD, 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_AMD, queryBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_AVAILABLE, BUFFER_OFFSET(0)); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT_AMD, 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_AMD |
| |
| // 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_AMD, queryBuffer); |
| GLuint defaultValue = 42; |
| glBufferData(GL_QUERY_BUFFER_AMD, 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_AMD, queryBuffer); |
| glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT_AMD, 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_AMD, 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_AMD 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_AMD 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_AMD be accepted by GetQueryObjectiv, |
| GetQueryObjectuiv, GetQueryObjecti64v and GetQueryObjectui64v in case |
| there is no buffer bound to QUERY_BUFFER_AMD? |
| |
| 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_AMD? |
| |
| 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_AMD, |
| 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 rage 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 in software for query types that cannot be |
| supported in 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_AMD |
| 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 default 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, leave the current value |
| untouched. |
| |
| 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 leaved untouched. |
| |
| |
| Revision History |
| |
| Rev. Date Author Changes |
| ---- -------- -------- --------------------------------------------- |
| |
| 6 03/07/2016 drakos Fixed typo in example #4 |
| 5 06/01/2012 gsellers Minor cleanup. Shipped and ready for posting. |
| 4 03/21/2012 drakos Removed undefined behavior when using |
| QUERY_RESULT_NO_WAIT and added issue #8 |
| based on Graham's comments |
| 3 03/12/2012 drakos Assigned enums |
| 2 03/07/2012 drakos Clarified issues #4 and #5 |
| Added issue #7 based on Christophe's comments |
| 1 02/28/2012 drakos Initial revision |