1Name 2 3 EXT_timer_query 4 5Name Strings 6 7 GL_EXT_timer_query 8 9Contact 10 11 James Jones, NVIDIA Corporation (jajones 'at' nvidia.com) 12 13Contributors 14 15 Axel Mamode, Sony 16 Brian Paul, Tungsten Graphics 17 Pat Brown, NVIDIA 18 Remi Arnaud, Sony 19 20Status 21 22 Shipping (version 1.0) 23 24 Supported by NVIDIA Release 80 drivers. 25 26Version 27 28 Last Modified Date: 2013/06/25 29 Revision: 3 30 31Number 32 33 319 34 35Dependencies 36 37 Written based on the wording of the OpenGL 2.0 specification. 38 39 OpenGL 1.5 is required. 40 41 This extension modifies ARB_occlusion_query and NV_occlusion_query. 42 43Overview 44 45 Applications can benefit from accurate timing information in a number of 46 different ways. During application development, timing information can 47 help identify application or driver bottlenecks. At run time, 48 applications can use timing information to dynamically adjust the amount 49 of detail in a scene to achieve constant frame rates. OpenGL 50 implementations have historically provided little to no useful timing 51 information. Applications can get some idea of timing by reading timers 52 on the CPU, but these timers are not synchronized with the graphics 53 rendering pipeline. Reading a CPU timer does not guarantee the completion 54 of a potentially large amount of graphics work accumulated before the 55 timer is read, and will thus produce wildly inaccurate results. 56 glFinish() can be used to determine when previous rendering commands have 57 been completed, but will idle the graphics pipeline and adversely affect 58 application performance. 59 60 This extension provides a query mechanism that can be used to determine 61 the amount of time it takes to fully complete a set of GL commands, and 62 without stalling the rendering pipeline. It uses the query object 63 mechanisms first introduced in the occlusion query extension, which allow 64 time intervals to be polled asynchronously by the application. 65 66Issues 67 68 What time interval is being measured? 69 70 RESOLVED: The timer starts when all commands prior to BeginQuery() have 71 been fully executed. At that point, everything that should be drawn by 72 those commands has been written to the framebuffer. The timer stops 73 when all commands prior to EndQuery() have been fully executed. 74 75 What unit of time will time intervals be returned in? 76 77 RESOLVED: Nanoseconds (10^-9 seconds). This unit of measurement allows 78 for reasonably accurate timing of even small blocks of rendering 79 commands. The granularity of the timer is implementation-dependent. A 80 32-bit query counter can express intervals of up to approximately 4 81 seconds. 82 83 What should be the minimum number of counter bits for timer queries? 84 85 RESOLVED: 30 bits, which will allow timing sections that take up to 1 86 second to render. 87 88 How are counter results of more than 32 bits returned? 89 90 RESOLVED: Using the int64 and uint64 datatypes (introduced in OpenGL 91 3.2 and used by this extension as well), and corresponding 92 GetQueryObject entry points. These types hold integer values and have 93 a minimum bit width of 64. 94 95 Should the extension measure total time elapsed between the full 96 completion of the BeginQuery and EndQuery commands, or just time spent in 97 the graphics library? 98 99 RESOLVED: This extension will measure the total time elapsed between 100 the full completion of these commands. Future extensions may implement 101 a query to determine time elapsed at different stages of the graphics 102 pipeline. 103 104 This extension introduces a second query type supported by 105 BeginQuery/EndQuery. Can multiple query types be active simultaneously? 106 107 RESOLVED: Yes; an application may perform an occlusion query and a 108 timer query simultaneously. An application can not perform multiple 109 occlusion queries or multiple timer queries simultaneously. An 110 application also can not use the same query object for an occlusion 111 query and a timer query simultaneously. 112 113 Do query objects have a query type permanently associated with them? 114 115 RESOLVED: No. A single query object can be used to perform different 116 types of queries, but not at the same time. 117 118 Having a fixed type for each query object simplifies some aspects of the 119 implementation -- not having to deal with queries with different result 120 sizes, for example. It would also mean that BeginQuery() with a query 121 object of the "wrong" type would result in an INVALID_OPERATION error. 122 123 How predictable/repeatable are the results returned by the timer query? 124 125 RESOLVED: In general, the amount of time needed to render the same 126 primitives should be fairly constant. But there may be many other 127 system issues (e.g., context switching on the CPU and GPU, virtual 128 memory page faults, memory cache behavior on the CPU and GPU) that can 129 cause times to vary wildly. 130 131 Note that modern GPUs are generally highly pipelined, and may be 132 processing different primitives in different pipeline stages 133 simultaneously. In this extension, the timers start and stop when the 134 BeginQuery/EndQuery commands reach the bottom of the rendering pipeline. 135 What that means is that by the time the timer starts, the GL driver on 136 the CPU may have started work on GL commands issued after BeginQuery, 137 and the higher pipeline stages (e.g., vertex transformation) may have 138 started as well. 139 140 What should the new 64 bit integer type be called? 141 142 RESOLVED: The new types will be called GLint64/GLuint64 The new 143 command suffixes will be i64 and ui64. These names clearly convey the 144 minimum size of the types. These types are similar to the C99 standard 145 type int_least64_t, but we use names similar to the C99 optional type 146 int64_t for simplicity. 147 148 (note: previous versions of EXT_timer_query used GLint64EXT and and 149 GLuint64EXT. These types were later promoted to core in OpenGL 3.2, 150 and this extension was changed to use the core datatypes for 151 compatibility with changes to the OpenGL ES EXT_disjoint_timer_query 152 extension, which introduces the same query entry points, and would 153 have otherwise have had different function signatures). 154 155New Procedures and Functions 156 157 void GetQueryObjecti64vEXT(uint id, enum pname, int64 *params); 158 void GetQueryObjectui64vEXT(uint id, enum pname, uint64 *params); 159 160New Tokens 161 162 Accepted by the <target> parameter of BeginQuery, EndQuery, and 163 GetQueryiv: 164 165 TIME_ELAPSED_EXT 0x88BF 166 167Additions to Chapter 2 of the OpenGL 2.0 Specification (OpenGL Operation) 168 169 (Modify table 2.1, Correspondence of command suffix letters to GL argument 170 types, p. 8) Add two new types and suffixes: 171 172 Letter Corresponding GL Type 173 ------ --------------------- 174 i64 int64 175 ui64 uint64 176 177 (Modify table 2.2, GL data types, p. 9) Add two new types: 178 179 Minimum 180 GL Type Bit Width Description 181 --------- --------- ------------------------------------ 182 int64 64 signed 2's complement binary integer 183 uint64 64 unsigned binary integer 184 185Additions to Chapter 3 of the OpenGL 2.0 Specification (Rasterization) 186 187 None. 188 189Additions to Chapter 4 of the OpenGL 2.0 Specification (Per-Fragment 190Operations and the Framebuffer) 191 192 (Replace Section 4.1.7, Occlusion Queries, p.204) 193 194 Section 4.1.7, Asynchronous Queries 195 196 Asynchronous queries provide a mechanism to return information about the 197 processing of a sequence of GL commands. There are two query types 198 supported by the GL. Occlusion queries (section 4.1.7.1) count the number 199 of fragments or samples that pass the depth test. Timer queries (section 200 4.1.12) record the amount of time needed to fully process these commands. 201 202 The results of asynchronous queries are not returned by the GL immediately 203 after the completion of the last command in the set; subsequent commands 204 can be processed while the query results are not complete. When 205 available, the query results are stored in an associated query object. 206 The commands described in section 6.1.12 provide mechanisms to determine 207 when query results are available and return the actual results of the 208 query. The name space for query objects is the unsigned integers, with 209 zero reserved by the GL. 210 211 Each type of query supported by the GL has an active query object name. 212 If the active query object name for a query type is non-zero, the GL is 213 currently tracking the information corresponding to that query type and 214 the query results will be written into the corresponding query object. If 215 the active query object for a query type name is zero, no such information 216 is being tracked. 217 218 A query object is created by calling 219 220 void BeginQuery(enum target, uint id); 221 222 with an unused name <id>. <target> indicates the type of query to be 223 performed; valid values of <target> are defined in subsequent sections. 224 When a query object is created, the name <id> is marked as used and 225 associated with a new query object. 226 227 BeginQuery sets the active query object name for the query type given by 228 <target> to <id>. If BeginQuery is called with an <id> of zero, if the 229 active query object name for <target> is non-zero, or if <id> is the 230 active query object name for any query type, the error INVALID_OPERATION 231 is generated. 232 233 The command 234 235 void EndQuery(enum target); 236 237 marks the end of the sequence of commands to be tracked for the query type 238 given by <target>. The active query object for <target> is updated to 239 indicate that query results are not available, and the active query object 240 name for <target> is reset to zero. When the commands issued prior to 241 EndQuery have completed and a final query result is available, the query 242 object active when EndQuery is called is updated by the GL. The query 243 object is updated to indicate that the query results are available and to 244 contain the query result. If the active query object name for <target> is 245 zero when EndQuery is called, the error INVALID_OPERATION is generated. 246 247 The command 248 249 void GenQueries(sizei n, uint *ids); 250 251 returns <n> previously unused query object names in <ids>. These names are 252 marked as used, but no object is associated with them until the first time 253 they are used by BeginQuery. 254 255 Query objects are deleted by calling 256 257 void DeleteQueries(sizei n, const uint *ids); 258 259 <ids> contains <n> names of query objects to be deleted. After a query 260 object is deleted, its name is again unused. Unused names in <ids> are 261 silently ignored. 262 263 Calling either GenQueries or DeleteQueries while any query of any target 264 is active causes an INVALID_OPERATION error to be generated. 265 266 Query objects contain two pieces of state: a single bit indicating 267 whether a query result is available, and an integer containing the query 268 result value. The number of bits used to represent the query result is 269 implementation-dependent. In the initial state of a query object, the 270 result is available and its value is zero. 271 272 The necessary state for each query type is an unsigned integer holding the 273 active query object name (zero if no query object is active), and any 274 state necessary to keep the current results of an asynchronous query in 275 progress. 276 277 Section 4.1.7.1, Occlusion Queries 278 279 Occlusion queries use query objects to track the number of fragments or 280 samples that pass the depth test. An occlusion query can be started and 281 finished by calling BeginQuery and EndQuery, respectively, with a <target> 282 of SAMPLES_PASSED. 283 284 When an occlusion query starts, the samples-passed count maintained by the 285 GL is set to zero. When an occlusion query is active, the samples-passed 286 count is incremented for each fragment that passes the depth test. If the 287 value of SAMPLE BUFFERS is 0, then the samples-passed count is incremented 288 by 1 for each fragment. If the value of SAMPLE BUFFERS is 1, then the 289 samples-passed count is incremented by the number of samples whose 290 coverage bit is set. However, implementations, at their discretion, may 291 instead increase the samples-passed count by the value of SAMPLES if any 292 sample in the fragment is covered. When an occlusion query finishes and 293 all fragments generated by the commands issued prior to EndQuery have been 294 generated, the samples-passed count is written to the corresponding query 295 object as the query result value, and the query result for that object is 296 marked as available. 297 298 If the samples-passed count overflows, (i.e., exceeds the value 2^n - 1, 299 where n is the number of bits in the samples-passed count), its value 300 becomes undefined. It is recommended, but not required, that 301 implementations handle this overflow case by saturating at 2^n - 1 and 302 incrementing no further. 303 304 (Add new Section 4.1.12, Timer Queries, p.212) 305 306 Timer queries use query objects (section 4.1.7) to track the amount of 307 time needed to fully complete a set of GL commands. A timer query can be 308 started and finished by calling BeginQuery and EndQuery, respectively, 309 with a <target> of TIME_ELAPSED_EXT. 310 311 When BeginQuery and EndQuery are called with a <target> of 312 TIME_ELAPSED_EXT, the GL prepares to start and stop the timer used for 313 timer queries. The timer is started or stopped when the effects from all 314 previous commands on the GL client and server state and the framebuffer 315 have been fully realized. The BeginQuery and EndQuery commands may return 316 before the timer is actually started or stopped. When the timer query 317 timer is finally stopped, the elapsed time (in nanoseconds) is written to 318 the corresponding query object as the query result value, and the query 319 result for that object is marked as available. 320 321 If the elapsed time overflows the number of bits, <n>, available to hold 322 elapsed time, its value becomes undefined. It is recommended, but not 323 required, that implementations handle this overflow case by saturating at 324 2^n - 1. 325 326Additions to Chapter 5 of the OpenGL 2.0 Specification (Special Functions) 327 328 None. 329 330Additions to Chapter 6 of the OpenGL 2.0 Specification (State and State 331Requests) 332 333 (Replace Section 6.1.12, Occlusion Queries, p. 254) 334 335 Section 6.1.12, Asynchronous Queries 336 337 The command 338 339 boolean IsQuery(uint id); 340 341 returns TRUE if <id> is the name of a query object. If <id> is zero, or if 342 <id> is a non-zero value that is not the name of a query object, IsQuery 343 returns FALSE. 344 345 Information about a query target can be queried with the command 346 347 void GetQueryiv(enum target, enum pname, int *params); 348 349 <target> identifies the query target and can be SAMPLES_PASSED for 350 occlusion queries or TIME_ELAPSED_EXT for timer queries. 351 352 If <pname> is CURRENT_QUERY, the name of the currently active query for 353 <target>, or zero if no query is active, will be placed in <params>. 354 355 If <pname> is QUERY_COUNTER_BITS, the implementation-dependent number of 356 bits used to hold the query result for <target> will be placed in params. 357 The number of query counter bits may be zero, in which case the counter 358 contains no useful information. 359 360 For occlusion queries (SAMPLES_PASSED), if the number of bits is non-zero, 361 the minimum number of bits allowed is a function of the implementation's 362 maximum viewport dimensions (MAX_VIEWPORT_DIMS). The counter must be able 363 to represent at least two overdraws for every pixel in the viewport. The 364 formula to compute the allowable minimum value (where n is the minimum 365 number of bits) is: 366 367 n = min(32, ceil(log_2(maxViewportWidth * maxViewportHeight * 2))). 368 369 For timer queries (TIME_ELAPSED_EXT), if the minimum number if bits is 370 non-zero, it must be at least 30. 371 372 The state of a query object can be queried with the commands 373 374 void GetQueryObjectiv(uint id, enum pname, int *params); 375 void GetQueryObjectuiv(uint id, enum pname, uint *params); 376 void GetQueryObjecti64vEXT(uint id, enum pname, int64 *params); 377 void GetQueryObjectui64vEXT(uint id, enum pname, uint64 *params); 378 If <id> is not the name of a query object, or if the query object named by 379 <id> is currently active, then an INVALID_OPERATION error is generated. 380 381 If <pname> is QUERY_RESULT, then the query object's result value is 382 returned as a single integer in <params>. If the value is so large in 383 magnitude that it cannot be represented with the requested type, then the 384 nearest value representable using the requested type is returned. If the 385 number of query counter bits for any <target> is zero, then the result is 386 returned as a single integer with a value of 0. 387 388 There may be an indeterminate delay before the above query returns. If 389 <pname> is QUERY_RESULT_AVAILABLE, FALSE is returned if such a delay would 390 be required, TRUE is returned otherwise. It must always be true that if 391 any query object returns a result available of TRUE, all queries of the 392 same type issued prior to that query must also return TRUE. 393 394 Querying the state for any given query object forces the corresponding 395 query to complete within a finite amount of time. 396 397 If multiple queries are issued using the same object name prior to calling 398 GetQueryObject[u]iv, the result and availability information returned will 399 always be from the last query issued. The results from any queries before 400 the last one will be lost if they are not retrieved before starting a new 401 query on the same <target> and <id>. 402 403GLX Protocol (Modification to the GLX 1.3 Protocol Encoding Specification) 404 405 Add to Section 1.4 (p.2), Common Types 406 407 INT64 A 64-bit signed integer value. 408 409 CARD64 A 64-bit unsigned integer value. 410 411 Two new non-rendering GL commands are added. These commands are sent 412 seperately (i.e., not as part of a glXRender or glXRenderLarge request), 413 using the glXVendorPrivateWithReply request: 414 415 GetQueryObjecti64vEXT 416 1 CARD8 opcode (X assigned) 417 1 1328 GLX opcode (glXVendorPrivateWithReply) 418 2 4 request length 419 4 GLX_CONTEXT_TAG context tag 420 4 CARD32 id 421 4 ENUM pname 422 => 423 1 1 reply 424 1 unused 425 2 CARD16 sequence number 426 4 m reply length, m=(n==1?0:n) 427 4 unused 428 4 CARD32 n 429 430 if (n=1) this follows: 431 432 8 INT64 params 433 8 unused 434 435 otherwise this follows: 436 437 16 unused 438 n*8 LISTofINT64 params 439 440 GetQueryObjectui64vEXT 441 1 CARD8 opcode (X assigned) 442 1 1329 GLX opcode (glXVendorPrivateWithReply) 443 2 4 request length 444 4 GLX_CONTEXT_TAG context tag 445 4 CARD32 id 446 4 ENUM pname 447 => 448 1 1 reply 449 1 unused 450 2 CARD16 sequence number 451 4 m reply length, m=(n==1?0:n) 452 4 unused 453 4 CARD32 n 454 455 if (n=1) this follows: 456 457 8 CARD64 params 458 8 unused 459 460 otherwise this follows: 461 462 16 unused 463 n*8 CARD64 params 464 465Errors 466 467 All existing errors for query objects apply unchanged from the 468 ARB_occlusion_query spec, except the modification below: 469 470 The error INVALID_ENUM is generated if BeginQueryARB, EndQueryARB, or 471 GetQueryivARB is called where <target> is not SAMPLES_PASSED or 472 TIME_ELAPSED_EXT. 473 474 The error INVALID_OPERATION is generated if GetQueryObjecti64vEXT or 475 GetQueryObjectui64vEXT is called where <id> is not the name of a query 476 object. 477 478 The error INVALID_OPERATION is generated if GetQueryObjecti64vEXT or 479 GetQueryObjectui64vEXT is called where <id> is the name of a currently 480 active query object. 481 482 The error INVALID_ENUM is generated if GetQueryObjecti64vEXT or 483 GetQueryObjectui64vEXT is called where <pname> is not QUERY_RESULT or 484 QUERY_RESULT_AVAILABLE. 485 486New State 487 488 (table 6.37, p 298) Update the occlusion query / query object state to 489 cover timer queries: 490 491 Get Value Type Get Command Init. Value Description Sec Attribute 492 ---------------------- ---- ---------------- ----------- ------------------------- ----- --------- 493 CURRENT_QUERY 2xZ+ GetQueryiv 0 Active query object name 4.1.7 - 494 (occlusion and timer) 495 QUERY_RESULT 2xZ+ GetQueryObjectiv 0 Query object result 4.1.7 - 496 (samples passed or 497 time elapsed) 498 QUERY_RESULT_AVAILABLE 2xB GetQueryObjectiv TRUE Query object result 4.1.7 - 499 available? 500 501New Implementation Dependent State 502 503 (table 6.34, p. 295) Update the occlusion query / query object state to 504 cover timer queries: 505 506 Get Value Type Get Command Minimum Value Description Sec Attribute 507 -------------------- ---- ----------- ------------- -------------------------- ------ --------- 508 QUERY_COUNTER_BITS 2xZ+ GetQueryiv see 6.1.12 Asynchronous query counter 6.1.12 - 509 bits (occlusion and timer 510 queries) 511 512Dependencies on ARB_occlusion_query and NV_occlusion_query 513 514 If ARB_occlusion_query or NV_occlusion_query is supported, the previous 515 spec edits are considered to apply to the nearly identical language in 516 these extension specifications. Note that the functionality provided by 517 these extensions is included in OpenGL versions 1.5 and greater. 518 519Usage Examples 520 521 Here is some rough sample code that demonstrates the intended usage 522 of this extension. 523 524 GLint queries[N]; 525 GLint available = 0; 526 // timer queries can contain more than 32 bits of data, so always 527 // query them using the 64 bit types to avoid overflow 528 GLuint64 timeElapsed = 0; 529 530 // Create a query object. 531 glGenQueries(N, queries); 532 533 // Start query 1 534 glBeginQuery(GL_TIME_ELAPSED_EXT, queries[0]); 535 536 // Draw object 1 537 .... 538 539 // End query 1 540 glEndQuery(GL_TIME_ELAPSED_EXT); 541 542 ... 543 544 // Start query N 545 glBeginQuery(GL_TIME_ELAPSED_EXT, queries[N-1]); 546 547 // Draw object N 548 .... 549 550 // End query N 551 glEndQuery(GL_TIME_ELAPSED_EXT); 552 553 // Wait for all results to become available 554 while (!available) { 555 glGetQueryObjectiv(queries[N-1], GL_QUERY_RESULT_AVAILABLE, &available); 556 } 557 558 for (i = 0; i < N; i++) { 559 // See how much time the rendering of object i took in nanoseconds. 560 glGetQueryObjectui64vEXT(queries[i], GL_QUERY_RESULT, &timeElapsed); 561 562 // Do something useful with the time. Note that care should be 563 // taken to use all significant bits of the result, not just the 564 // least significant 32 bits. 565 AdjustObjectLODBasedOnDrawTime(i, timeElapsed); 566 } 567 568 This example is sub-optimal in that it stalls at the end of every 569 frame to wait for query results. Ideally, the collection of results 570 would be delayed one frame to minimize the amount of time spent 571 waiting for the GPU to finish rendering. 572 573Revision History 574 575 Version 3, June 25, 2013 (Jon Leech) - replace int64EXT / uint64EXT with 576 core int64/uint64 types, for compatibility with EXT_disjoint_timer_query 577 (Bug 10449). 578