1Name 2 3 ARB_query_buffer_object 4 5Name Strings 6 7 GL_ARB_query_buffer_object 8 9Contact 10 11 Daniel Rakos (daniel.rakos 'at' amd.com) 12 13Contributors 14 15 Daniel Rakos, AMD 16 Graham Sellers, AMD 17 Christophe Riccio, AMD 18 19Notice 20 21 Copyright (c) 2013 The Khronos Group Inc. Copyright terms at 22 http://www.khronos.org/registry/speccopyright.html 23 24Specification Update Policy 25 26 Khronos-approved extension specifications are updated in response to 27 issues and bugs prioritized by the Khronos OpenGL Working Group. For 28 extensions which have been promoted to a core Specification, fixes will 29 first appear in the latest version of that core Specification, and will 30 eventually be backported to the extension document. This policy is 31 described in more detail at 32 https://www.khronos.org/registry/OpenGL/docs/update_policy.php 33 34Status 35 36 Complete. Approved by the ARB on June 3, 2013. 37 Ratified by the Khronos Board of Promoters on July 19, 2013. 38 39Version 40 41 Last Modified Date: 7 March 2016 42 Author Revision: 3 43 44Number 45 46 ARB Extension #148 47 48Dependencies 49 50 OpenGL 1.5 is required. 51 52 This extension is written against the OpenGL 4.3 (core) specification. 53 54Overview 55 56 Statistics about the operation of the OpenGL pipeline, such as the number 57 of samples that passed the depth test, the elapsed time between two events 58 or the number of vertices written by transform feedback can be retrieved 59 from the GL through query objects. The result of a query object is 60 acquired by the application through the OpenGL API into a client provided 61 memory location. Should the result returned by the API be required for use 62 in a shader, it must be passed back to the GL via a program uniform or 63 some other mechanism. This requires a round-trip from the GPU to the CPU 64 and back. 65 66 This extension introduces a mechanism whereby the result of a query object 67 may be retrieved into a buffer object instead of client memory. This allows 68 the query rsult to be made available to a shader without a round-trip to 69 the CPU for example by subsequently using the buffer object as a uniform 70 buffer, texture buffer or other data store visible to the shader. This 71 functionality may also be used to place the results of many query objects 72 into a single, large buffer and then map or otherwise read back the entire 73 buffer at a later point in time, avoiding a per-query object CPU-GPU 74 synchronization event. 75 76 The extension allows acquiring the result of any query object type 77 supported by the GL implementation into a buffer object. The implementation 78 will determine the most efficient method of copying the query result to the 79 buffer. 80 81New Procedures and Functions 82 83 None. 84 85New Tokens 86 87 Accepted by the <pname> parameter of GetQueryObjectiv, GetQueryObjectuiv, 88 GetQueryObjecti64v and GetQueryObjectui64v: 89 90 QUERY_RESULT_NO_WAIT 0x9194 91 92 Accepted by the <target> parameter of BindBuffer, BufferData, 93 BufferSubData, MapBuffer, UnmapBuffer, MapBufferRange, GetBufferSubData, 94 GetBufferParameteriv, GetBufferParameteri64v, GetBufferPointerv, 95 ClearBufferSubData, and the <readtarget> and <writetarget> parameters of 96 CopyBufferSubData: 97 98 QUERY_BUFFER 0x9192 99 100 Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv, 101 and GetDoublev: 102 103 QUERY_BUFFER_BINDING 0x9193 104 105 Accepted in the <barriers> bitfield in MemoryBarrier: 106 107 QUERY_BUFFER_BARRIER_BIT 0x00008000 108 109Additions to Chapter 4 of the OpenGL Core Profile Specification, Version 4.3, 110"Event Model" 111 112 Modify Section 4.2.1, "Query Object Queries" 113 114 Add new paragraph after the fist paragraph on p. 44 ending with 115 "... <id> is the name of a query object." 116 117 Initially, zero is bound to the QUERY_BUFFER binding point, indicating 118 that <params> is a pointer into client memory. However, if a non-zero 119 buffer object is bound as the current query result buffer (see section 120 6.1), then <params> is treated as an offset into the designated buffer 121 object. 122 123 Add new paragraph after the third paragraph on p. 44 ending with 124 "... finite amount of time." 125 126 If <pname> is QUERY_RESULT_NO_WAIT, then the query object's result 127 value is returned as a single integer in <params> if the result is 128 available at the time of the state query. If the result is not available 129 then the destination memory location is not overwritten. 130 131Additions to Chapter 6 of the OpenGL Core Profile Specification, Version 4.3, 132"Buffer Objects" 133 134 Modify Section 6.1, "Creating and Binding Buffer Objects" 135 136 Add to Table 6.1: "Buffer object binding targets" 137 138 +--------------------+--------------------------+-------------------------+ 139 | Target name | Purpose | Described in section(s) | 140 +--------------------+--------------------------+-------------------------+ 141 | QUERY_BUFFER | Query result buffer | 4.2.1 | 142 +--------------------+--------------------------+-------------------------+ 143 144Additions to Chapter 7 of the OpenGL Core Profile Specification, Version 4.3, 145"Programs and Shaders" 146 147 Modify Section 7.12, "Shader Memory Access" 148 149 Add to the list of MemoryBarrier <barriers> bullets, p. 138 150 151 * QUERY_BUFFER_BARRIER_BIT: Writes of buffer objects via the QUERY_BUFFER 152 binding (see section 4.2.1) after the barrier will reflect data written 153 by shaders prior to the barrier. Additionally, buffer object writes 154 issued after the barrier will wait on the completion of all shader 155 writes initiated prior to the barrier. 156 157Additions to the AGL/GLX/WGL Specifications 158 159 None. 160 161GLX Protocol 162 163 None. 164 165Errors 166 167 Replace second error case for QueryObject* with the following: 168 169 An INVALID_ENUM error is generated if <pname> is not QUERY_RESULT, 170 QUERY_RESULT_NO_WAIT or QUERY_RESULT_AVAILABLE. 171 172 Add error case for QueryObject* as follows: 173 174 An INVALID_OPERATION error is generated if the command would cause data 175 to be written beyond the bounds of the buffer currently bound to the 176 QUERY_BUFFER target. 177 178New State 179 180 Append to Table 23.73, "Miscellaneous" 181 182 +----------------------+------+--------------+---------------+------------------------------+-------+ 183 | Get Value | Type | Get Command | Initial Value | Description | Sec. | 184 +----------------------+------+--------------+---------------+------------------------------+-------+ 185 | QUERY_BUFFER_BINDING | Z+ | GetIntegeriv | 0 | Query result buffer binding. | 4.2.1 | 186 +----------------------+------+--------------+---------------+------------------------------+-------+ 187 188New Implementation Dependent State 189 190 None. 191 192Usage Examples 193 194 Convenient macro definition for specifying buffer offsets: 195 196 #define BUFFER_OFFSET(i) ((void*)NULL + (i)) 197 198 Example 1: Using occlusion query result in shader 199 200 // Create a buffer object for the query result 201 glGenBuffers(1, &queryBuffer); 202 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 203 glBufferData(GL_QUERY_BUFFER, sizeof(GLuint), 204 NULL, GL_DYNAMIC_COPY); 205 206 // Perform occlusion query 207 glBeginQuery(GL_SAMPLES_PASSED, queryId) 208 ... 209 glEndQuery(GL_SAMPLES_PASSED); 210 211 // Get query results to buffer object 212 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 213 glGetQueryObjectuiv(queryId, GL_QUERY_RESULT, BUFFER_OFFSET(0)); 214 215 // Bind query result buffer as uniform buffer 216 glBindBufferBase(GL_UNIFORM_BUFFER, 0, queryBuffer); 217 ... 218 219 --- Shader --- 220 221 ... 222 uniform queryResult { 223 uint samplesPassed; 224 }; 225 ... 226 void main() { 227 ... 228 if (samplesPassed > threshold) { 229 // complex processing 230 ... 231 } else { 232 // simplified processing 233 ... 234 } 235 ... 236 } 237 238 Example 2: Using occlusion query result in shader only if result is available 239 240 // Create a buffer object for the query result 241 glGenBuffers(1, &queryBuffer); 242 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 243 glBufferData(GL_QUERY_BUFFER, 2 * sizeof(GLuint), 244 NULL, GL_DYNAMIC_COPY); 245 246 // Perform occlusion query 247 glBeginQuery(GL_SAMPLES_PASSED, queryId) 248 ... 249 glEndQuery(GL_SAMPLES_PASSED); 250 251 // Get query availability and result (if available) to buffer object 252 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 253 glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_AVAILABLE, BUFFER_OFFSET(0)); 254 glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT, BUFFER_OFFSET(4)); 255 256 // Bind query result buffer as uniform buffer 257 glBindBufferBase(GL_UNIFORM_BUFFER, 0, queryBuffer); 258 ... 259 260 --- Shader --- 261 262 ... 263 uniform queryResult { 264 uint resultAvailable; 265 uint samplesPassed; 266 }; 267 ... 268 void main() { 269 ... 270 if (resultAvailable) { 271 if (samplesPassed > threshold) { 272 // complex processing 273 ... 274 } else { 275 // simplified processing 276 ... 277 } 278 } else { 279 // default processing if no query result is available 280 ... 281 } 282 ... 283 } 284 285 Example 3: Using a default value and QUERY_RESULT_NO_WAIT 286 287 // Create a buffer object for the query result 288 // Store a default value in the buffer that will be used 289 // if the query results are not available 290 glGenBuffers(1, &queryBuffer); 291 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 292 GLuint defaultValue = 42; 293 glBufferData(GL_QUERY_BUFFER, sizeof(GLuint), 294 &defaultValue, GL_DYNAMIC_COPY); 295 296 // Perform occlusion query 297 glBeginQuery(GL_SAMPLES_PASSED, queryId) 298 ... 299 glEndQuery(GL_SAMPLES_PASSED); 300 301 // Get query results to buffer object with no wait 302 // Default value remains untouched if results are not available 303 glBindBuffer(GL_QUERY_BUFFER, queryBuffer); 304 glGetQueryObjectuiv(queryId, GL_QUERY_RESULT_NO_WAIT, BUFFER_OFFSET(0)); 305 ... 306 307 Example 4: Using transform feedback query result to fill indirect draw buffer 308 309 // Create a buffer object for the indirect draw command 310 glGenBuffers(1, &drawIndirectBuffer); 311 312 // Initialize draw command 313 DrawArraysIndirectCommand cmd = { ... }; 314 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, drawIndirectBuffer); 315 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawArraysIndirectCommand), 316 &cmd, GL_DYNAMIC_COPY); 317 318 // Perform transform feedback query 319 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, queryId) 320 ... 321 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); 322 323 // Write query result to the primCount field of the indirect draw command 324 glBindBuffer(GL_QUERY_BUFFER, drawIndirectBuffer); 325 glGetQueryObjectuiv(queryId, GL_QUERY_RESULT, 326 BUFFER_OFFSET(offsetof(DrawArraysIndirectCommand, primCount))); 327 328 // Execute the indirect draw command 329 glDrawArraysIndirect(GL_TRIANGLES, BUFFER_OFFSET(0)); 330 ... 331 332Issues 333 334 1) What is QUERY_RESULT_NO_WAIT useful for? 335 336 RESOLVED: The application may decide that it does not want to wait for the 337 result of the query object if it's not available at the time. This is not 338 a problem without this extension as the application can always query the 339 availability using QUERY_RESULT_AVAILABLE and decide to actually get the 340 results using QUERY_RESULT only if the result is available. However, when 341 using query buffers, QUERY_RESULT_AVAILABLE and QUERY_RESULT alone cannot 342 provide the same flexibility for shader based decision making as the 343 results are either always available (if QUERY_RESULT was used) or never. 344 QUERY_RESULT_NO_WAIT provides a way to query the result only if it's 345 available. Combined with QUERY_RESULT_AVAILABLE, the shader can decide 346 to use the result or not based on the availability (see usage example 2). 347 348 2) Should QUERY_RESULT_NO_WAIT be accepted by GetQueryObject* in case 349 there is no buffer bound to QUERY_BUFFER? 350 351 RESOLVED: YES, for completeness. 352 353 3) Is there any guarantee that GetQueryObject* will not wait for the 354 query results to become available if <pname> is QUERY_RESULT_NO_WAIT? 355 356 RESOLVED: There is no need to have such guarantee. An implementation may 357 choose to wait for the results even in case of QUERY_RESULT_NO_WAIT, 358 however, that may incur a potential performance hit in case the 359 application expects it to not wait. 360 361 4) Should the INVALID_OPERATION error be generated if a GetQueryObject* 362 command would access data outside the range of the bound query buffer? 363 364 RESOLVED: YES. This requires considering the value of <params> and the 365 size of the type of the written value to determine the maximum addressed 366 byte for the state query command. 367 368 Note: This follows the precedence of the language introduced by 369 ARB_pixel_buffer_object. 370 371 5) Should we support 64 bit versions of the state query commands 372 (GetQueryObjecti64v and GetQueryObjectui64v)? 373 374 RESOLVED: YES, both for completeness and to support timer queries. In this 375 case a 64 bit integer value is written to the buffer. 376 377 6) Should the extension support all query types supported by the current 378 GL implementation? 379 380 RESOLVED: YES. There is not much value in providing additional capability 381 queries that would allow the application to find out which query object 382 types are supported. Also, the GL implementation can always choose to 383 implement the functionality through a GPU-CPU rount-trip for query types 384 that cannot be resolved to a buffer by the hardware. 385 386 7) Is there any precedence that the pointer parameter of a glGet* command 387 is treated as an offset into a bound buffer object? 388 389 RESOLVED: YES, glGetTexImage accepts an offset into the pixel pack buffer 390 in case a pixel pack buffer is bound. As pixel buffer objects are part of 391 the core specification since version 2.1, no precedence is introduced by 392 this extension. 393 394 8) What should be written to the query buffer when QUERY_RESULT_NO_WAIT 395 is used but the results are not available? 396 397 DISCUSSION: Leaving the written value undefined is an option, however 398 in many cases the application can benefit from having a defined value in 399 the query buffer if the results are not available. The following options 400 were considered to support such use cases: 401 402 a. Write a predefined fixed value to the buffer. 403 b. Write a user specified value to the buffer. 404 c. Don't write anything to the buffer. 405 406 The problem with option a. is that it may be difficult to select such 407 a predefined value that would not potentially conflict with a valid 408 value. Option b. could be fine, however it requires new API to specify 409 this default value. Thus, option c. is considered to most preferable. 410 411 RESOLVED: Nothing, the current value in the specified offset of the 412 query buffer is left untouched. 413 414 9) How does ARB_query_buffer_object differ from AMD_query_buffer_object? 415 416 RESOLVED: This extension introduced a new barrier bit accepted by 417 MemoryBarrier that controls the relative ordering of shader buffer writes 418 and query buffer writes. 419 420Revision History 421 422 Rev. Date Author Changes 423 ---- -------- -------- ---------------------------------------------- 424 425 3 03/07/2016 drakos Fixed typo in example #4 426 2 04/02/2013 drakos Added missing function names to the list of 427 functions accepting QUERY_BUFFER as parameter 428 1 03/08/2013 drakos Initial draft based on AMD_query_buffer_object 429 Removed suffixes 430 Updated spec language to GL 4.3 431 Added QUERY_BUFFER_BARRIER_BIT 432