1Name 2 3 EXT_disjoint_timer_query 4 5Name Strings 6 7 GL_EXT_disjoint_timer_query 8 9Contact 10 11 Maurice Ribble, Qualcomm (mribble 'at' qualcomm.com) 12 13Contributors 14 15 Matt Trusten 16 Maurice Ribble 17 Daniel Koch 18 Jan-Harald Fredriksen 19 20 Contributors to ANGLE_timer_query 21 Contributors to ARB_timer_query 22 Contributors to EXT_timer_query 23 Contributors to EXT_occlusion_query_boolean 24 This extension is based on the ARB_timer_query and ANGLE_timer_query 25 26IP Status 27 28 No known IP claims. 29 30Status 31 32 Complete 33 34Version 35 36 Version 9, November 20, 2020 37 38Number 39 40 OpenGL ES Extension #150 41 42Dependencies 43 44 OpenGL ES 2.0 or greater required. 45 46 The extension is written against the OpenGL ES 2.0 specification. 47 48 The GetInteger64vEXT command is required only if OpenGL ES 3.0 or 49 later is not supported (see the Interactions section for details). 50 51Overview 52 53 Applications can benefit from accurate timing information in a number of 54 different ways. During application development, timing information can 55 help identify application or driver bottlenecks. At run time, 56 applications can use timing information to dynamically adjust the amount 57 of detail in a scene to achieve constant frame rates. OpenGL 58 implementations have historically provided little to no useful timing 59 information. Applications can get some idea of timing by reading timers 60 on the CPU, but these timers are not synchronized with the graphics 61 rendering pipeline. Reading a CPU timer does not guarantee the completion 62 of a potentially large amount of graphics work accumulated before the 63 timer is read, and will thus produce wildly inaccurate results. 64 glFinish() can be used to determine when previous rendering commands have 65 been completed, but will idle the graphics pipeline and adversely affect 66 application performance. 67 68 This extension provides a query mechanism that can be used to determine 69 the amount of time it takes to fully complete a set of GL commands, and 70 without stalling the rendering pipeline. It uses the query object 71 mechanisms first introduced in the occlusion query extension, which allow 72 time intervals to be polled asynchronously by the application. 73 74New Procedures and Functions 75 76 void GenQueriesEXT(sizei n, uint *ids); 77 void DeleteQueriesEXT(sizei n, const uint *ids); 78 boolean IsQueryEXT(uint id); 79 void BeginQueryEXT(enum target, uint id); 80 void EndQueryEXT(enum target); 81 void QueryCounterEXT(uint id, enum target); 82 void GetQueryivEXT(enum target, enum pname, int *params); 83 void GetQueryObjectivEXT(uint id, enum pname, int *params); 84 void GetQueryObjectuivEXT(uint id, enum pname, uint *params); 85 void GetQueryObjecti64vEXT(uint id, enum pname, int64 *params); 86 void GetQueryObjectui64vEXT(uint id, enum pname, uint64 *params); 87 void GetInteger64vEXT(enum pname, int64 *data) 88 89New Tokens 90 91 Accepted by the <pname> parameter of GetQueryivEXT: 92 93 QUERY_COUNTER_BITS_EXT 0x8864 94 CURRENT_QUERY_EXT 0x8865 95 96 Accepted by the <pname> parameter of GetQueryObjectivEXT, 97 GetQueryObjectuivEXT, GetQueryObjecti64vEXT, and 98 GetQueryObjectui64vEXT: 99 100 QUERY_RESULT_EXT 0x8866 101 QUERY_RESULT_AVAILABLE_EXT 0x8867 102 103 Accepted by the <target> parameter of BeginQueryEXT, EndQueryEXT, and 104 GetQueryivEXT: 105 106 TIME_ELAPSED_EXT 0x88BF 107 108 Accepted by the <target> parameter of GetQueryiv and QueryCounter. 109 Accepted by the <value> parameter of GetBooleanv, GetIntegerv, 110 GetInteger64v, and GetFloatv: 111 112 TIMESTAMP_EXT 0x8E28 113 114 Accepted by the <value> parameter of GetBooleanv, GetIntegerv, 115 GetInteger64v, and GetFloatv: 116 117 GPU_DISJOINT_EXT 0x8FBB 118 119Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation) 120 121 (Modify table 2.1, Correspondence of command suffix letters to GL argument) 122 Add two new types: 123 124 Letter Corresponding GL Type 125 ------ --------------------- 126 i64 int64 127 ui64 uint64 128 129 (Modify table 2.2, GL data types) Add two new types: 130 131 GL Type Minimum Bit Width Description 132 ------- ----------------- ----------------------------- 133 int64 64 Signed 2's complement integer 134 uint64 64 Unsigned binary integer 135 136Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions) 137 138 Add a new section 5.3 "Timer Queries": 139 140 "5.3 Timer Queries 141 142 Timer queries use query objects to track the amount of time needed to 143 fully complete a set of GL commands, or to determine the current time 144 of the GL. 145 146 Timer queries are associated with query objects. The command 147 148 void GenQueriesEXT(sizei n, uint *ids); 149 150 returns <n> previously unused query object names in <ids>. These 151 names are marked as used, but no object is associated with them until 152 the first time they are used by BeginQueryEXT or QueryCounterEXT. Query 153 objects contain one piece of state, an integer result value. This result 154 value is initialized to zero when the object is created. Any positive 155 integer except for zero (which is reserved for the GL) is a valid query 156 object name. 157 158 Query objects are deleted by calling 159 160 void DeleteQueriesEXT(sizei n, const uint *ids); 161 162 <ids> contains <n> names of query objects to be deleted. After a 163 query object is deleted, its name is again unused. Unused names in 164 <ids> are silently ignored. 165 If an active query object is deleted its name immediately becomes unused, 166 but the underlying object is not deleted until it is no longer active. 167 168 A timer query can be started and finished by calling 169 170 void BeginQueryEXT(enum target, uint id); 171 void EndQueryEXT(enum target); 172 173 where <target> is TIME_ELAPSED_EXT. If BeginQueryEXT is called 174 with an unused <id>, that name is marked as used and associated with 175 a new query object. 176 177 If BeginQueryEXT is called with an <id> of zero, if the active query 178 object name for <target> is non-zero, if <id> is the name of an existing 179 query object whose type does not match <target>, or if <id> is the active 180 query object name for any query type, the error INVALID_OPERATION is 181 generated. If EndQueryEXT is called while no query with the same target 182 is in progress, an INVALID_OPERATION error is generated. 183 184 When BeginQueryEXT and EndQueryEXT are called with a <target> of 185 TIME_ELAPSED_EXT, the GL prepares to start and stop the timer used for 186 timer queries. The timer is started or stopped when the effects from all 187 previous commands on the GL client and server state and the framebuffer 188 have been fully realized. On some architectures framebuffer can have 189 different meanings (specifically on some tiling GPUs fully realized might refer 190 to the framebuffer being in tile memory before it gets copied out to system 191 memory). The BeginQueryEXT and EndQueryEXT commands may return before the 192 timer is actually started or stopped. When the timer query timer is finally 193 stopped, the elapsed time (in nanoseconds) is written to the corresponding 194 query object as the query result value, and the query result for that object 195 is marked as available. 196 197 If the elapsed time overflows the number of bits, <n>, available to hold 198 elapsed time, its value becomes undefined. It is recommended, but not 199 required, that implementations handle this overflow case by saturating at 200 2^n - 1. 201 202 The necessary state is a single bit indicating whether a timer 203 query is active, the identifier of the currently active timer 204 query, and a counter keeping track of the time that has passed. 205 206 When the command 207 208 void QueryCounterEXT(uint id, enum target); 209 210 is called with <target> TIMESTAMP_EXT, the GL records the current time 211 into the corresponding query object. The time is recorded after all 212 previous commands on the GL client and server state and the framebuffer 213 have been fully realized. On some architectures framebuffer can have 214 different meanings (specifically on some tiling GPUs fully realized might refer 215 to the framebuffer being in tile memory before it gets copied out to system 216 memory). When the time is recorded, the query result for that object is 217 marked available. QueryCounterEXT timer queries can be used within a 218 BeginQueryEXT / EndQueryEXT block where the <target> is TIME_ELAPSED_EXT and 219 it does not affect the result of that query object. The error 220 INVALID_OPERATION is generated if the <id> is already in use within a 221 BeginQueryEXT/EndQueryEXT block. 222 223 The current time of the GL may be queried by calling GetIntegerv or 224 GetInteger64v with the symbolic constant TIMESTAMP_EXT. This will return 225 the GL time after all previous commands have reached the GL server but have 226 not yet necessarily executed. By using a combination of this synchronous 227 get command and the asynchronous timestamp query object target, 228 applications can measure the latency between when commands reach the GL 229 server and when they are realized in the framebuffer. 230 231 In order to know if the value returned from GetIntegerv or GetQuery is valid 232 GPU_DISJOINT_EXT needs to be used to make sure the GPU did not perform any 233 disjoint operation. This can be done through GetIntegerv by using GPU_- 234 DISJOINT_EXT for <pname>. <params> will be filled with a non-zero value if 235 a disjoint operation occurred since the last time GetIntegerv was used with 236 GPU_DISJOINT_EXT. A zero value will be returned if no disjoint operation 237 occurred, indicating the values returned by this extension that are found 238 in-between subsequent GetIntegerv calls will be valid for performance 239 metrics. 240 241 Disjoint operations occur whenever a change in the GPU occurs that will 242 make the values returned by this extension unusable for performance 243 metrics. An example can be seen with how mobile GPUs need to proactively 244 try to conserve power, which might cause the GPU to go to sleep at the 245 lower levers. This means disjoint states will occur at different times on 246 different platforms and are implementation dependent. When the returned 247 value is non-zero, all time values that were filled since the previous 248 disjoint check should be considered undefined." 249 250Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State 251Requests) 252 253 Add GetInteger64vEXT to section 6.1.1 "Simple Queries", following 254 the prototype for GetIntegerv: 255 256 " void GetInteger64vEXT(enum pname, int64 *data); 257 void GetFloatv(enum value, float *data); 258 259 The commands obtain boolean, integer, 64-bit integer, or floating-point 260 variables..." 261 262 Add a new section 6.1.9 "Timer Queries": 263 264 "The command 265 266 boolean IsQueryEXT(uint id); 267 268 returns TRUE if <id> is the name of a query object. If <id> is zero, 269 or if <id> is a non-zero value that is not the name of a query 270 object, IsQueryEXT returns FALSE. 271 272 Information about a query target can be queried with the command 273 274 void GetQueryivEXT(enum target, enum pname, int *params); 275 276 <target> identifies the query target and can be TIME_ELAPSED_EXT or 277 TIMESTAMP_EXT for timer queries. 278 279 If <pname> is CURRENT_QUERY_EXT, the name of the currently active query 280 for <target>, or zero if no query is active, will be placed in <params>. 281 282 If <pname> is QUERY_COUNTER_BITS_EXT, the implementation-dependent number 283 of bits used to hold the query result for <target> will be placed in 284 <params>. The number of query counter bits may be zero, in which case 285 the counter contains no useful information. 286 287 For timer queries (TIME_ELAPSED_EXT and TIMESTAMP_EXT), if the number 288 of bits is non-zero, the minimum number of bits allowed is 30 which 289 will allow at least 1 second of timing. 290 291 The state of a query object can be queried with the commands 292 293 void GetQueryObjectivEXT(uint id, enum pname, int *params); 294 void GetQueryObjectuivEXT(uint id, enum pname, uint *params); 295 void GetQueryObjecti64vEXT(uint id, enum pname, int64 *params); 296 void GetQueryObjectui64vEXT(uint id, enum pname, uint64 *params); 297 298 If <id> is not the name of a query object, or if the query object 299 named by <id> is currently active, then an INVALID_OPERATION error is 300 generated. 301 302 If <pname> is QUERY_RESULT_EXT, then the query object's result 303 value is returned as a single integer in <params>. If the value is so 304 large in magnitude that it cannot be represented with the requested type, 305 then the nearest value representable using the requested type is 306 returned. If the number of query counter bits for target is zero, then 307 the result is returned as a single integer with the value zero. 308 309 There may be an indeterminate delay before the above query returns. If 310 <pname> is QUERY_RESULT_AVAILABLE_EXT, FALSE is returned if such a delay 311 would be required; otherwise TRUE is returned. It must always be true 312 that if any query object returns a result available of TRUE, all queries 313 of the same type issued prior to that query must also return TRUE. 314 315 Querying the state for a given timer query forces that timer query to 316 complete within a finite amount of time. 317 318 If multiple queries are issued on the same target and id prior to 319 calling GetQueryObject[u]i[64]vEXT, the result returned will always be 320 from the last query issued. The results from any queries before the 321 last one will be lost if the results are not retrieved before starting 322 a new query on the same <target> and <id>. 323 324Errors 325 326 The error INVALID_VALUE is generated if GenQueriesEXT is called where 327 <n> is negative. 328 329 The error INVALID_VALUE is generated if DeleteQueriesEXT is called 330 where <n> is negative. 331 332 The error INVALID_OPERATION is generated if BeginQueryEXT is called 333 when a query of the given <target> is already active. 334 335 The error INVALID_OPERATION is generated if EndQueryEXT is called 336 when a query of the given <target> is not active. 337 338 The error INVALID_OPERATION is generated if BeginQueryEXT is called 339 where <id> is zero. 340 341 The error INVALID_OPERATION is generated if BeginQueryEXT is called 342 where <id> is the name of a query currently in progress. 343 344 The error INVALID_OPERATION is generated if BeginQueryEXT is called 345 where <id> is the name of an existing query object whose type does not 346 match <target>. 347 348 The error INVALID_ENUM is generated if BeginQueryEXT or EndQueryEXT 349 is called where <target> is not TIME_ELAPSED_EXT. 350 351 The error INVALID_ENUM is generated if GetQueryivEXT is called where 352 <target> is not TIME_ELAPSED_EXT or TIMESTAMP_EXT. 353 354 The error INVALID_ENUM is generated if GetQueryivEXT is called where 355 <pname> is not QUERY_COUNTER_BITS_EXT or CURRENT_QUERY_EXT. 356 357 The error INVALID_ENUM is generated if QueryCounterEXT is called where 358 <target> is not TIMESTAMP_EXT. 359 360 The error INVALID_OPERATION is generated if QueryCounterEXT is called 361 on a query object that is already in use inside a 362 BeginQueryEXT/EndQueryEXT. 363 364 The error INVALID_OPERATION is generated if GetQueryObjectivEXT, 365 GetQueryObjectuivEXT, GetQueryObjecti64vEXT, or 366 GetQueryObjectui64vEXT is called where <id> is not the name of a query 367 object. 368 369 The error INVALID_OPERATION is generated if GetQueryObjectivEXT, 370 GetQueryObjectuivEXT, GetQueryObjecti64vEXT, or 371 GetQueryObjectui64vEXT is called where <id> is the name of a currently 372 active query object. 373 374 The error INVALID_ENUM is generated if GetQueryObjectivEXT, 375 GetQueryObjectuivEXT, GetQueryObjecti64vEXT, or 376 GetQueryObjectui64vEXT is called where <pname> is not 377 QUERY_RESULT_EXT or QUERY_RESULT_AVAILABLE_EXT. 378 379New State 380 381 (Add a new table 6.xx, "Query Operations") 382 383 Get Value Type Get Command Initial Value Description Sec 384 --------- ---- ----------- ------------- ----------- ------ 385 - B - FALSE query active 5.3 386 CURRENT_QUERY_EXT Z+ GetQueryivEXT 0 active query ID 5.3 387 QUERY_RESULT_EXT Z+ GetQueryObjectuivEXT, 0 samples-passed count 5.3 388 GetQueryObjectui64vEXT 389 QUERY_RESULT_AVAILABLE_EXT B GetQueryObjectivEXT FALSE query result available 5.3 390 391New Implementation Dependent State 392 393 (Add the following entry to table 6.18): 394 395 Get Value Type Get Command Minimum Value Description Sec 396 -------------------------- ---- ----------- ------------- ---------------- ------ 397 QUERY_COUNTER_BITS_EXT Z+ GetQueryivEXT see 6.1.9 Number of bits in 6.1.9 398 query counter 399 400Interactions with OpenGL ES 2.0 and OpenGL ES 3.x 401 402 If only OpenGL ES 2.0 is supported, then GetInteger64vEXT is defined, 403 and is used instead of the GetInteger64v command defined by OpenGL ES 404 3.x. If OpenGL ES 3.0 or later is supported, GetInteger64vEXT is not 405 required by an implementation of this extension, and the changes to 406 section 6.1.1 are ignored. 407 408Examples 409 410 (1) Here is some rough sample code that demonstrates the intended usage 411 of this extension. 412 413 GLint queries[N]; 414 GLint available = 0; 415 GLint disjointOccurred = 0; 416 /* Timer queries can contain more than 32 bits of data, so always 417 query them using the 64 bit types to avoid overflow */ 418 GLuint64 timeElapsed = 0; 419 420 /* Create a query object. */ 421 glGenQueries(N, queries); 422 423 /* Clear disjoint error */ 424 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred); 425 426 /* Start query 1 */ 427 glBeginQuery(GL_TIME_ELAPSED_EXT, queries[0]); 428 429 /* Draw object 1 */ 430 .... 431 432 /* End query 1 */ 433 glEndQuery(GL_TIME_ELAPSED_EXT); 434 435 ... 436 437 /* Start query N */ 438 glBeginQuery(GL_TIME_ELAPSED_EXT, queries[N-1]); 439 440 /* Draw object N */ 441 .... 442 443 /* End query N */ 444 glEndQuery(GL_TIME_ELAPSED_EXT); 445 446 /* Wait for all results to become available */ 447 while (!available) { 448 glGetQueryObjectiv(queries[N-1], GL_QUERY_RESULT_AVAILABLE, &available); 449 } 450 451 /* Check for disjoint operation for all queries within the last 452 disjoint check. This way we can only check disjoint once for all 453 queries between, and once the last is filled we know all previous 454 will have been filled as well */ 455 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred); 456 457 /* If a disjoint operation occurred, all timer queries in between 458 the last two disjoint checks that were filled are invalid, continue 459 without reading the the values */ 460 if (!disjointOccurred) { 461 for (i = 0; i < N; i++) { 462 /* See how much time the rendering of object i took in nanoseconds. */ 463 glGetQueryObjectui64vEXT(queries[i], GL_QUERY_RESULT, &timeElapsed); 464 465 /* Do something useful with the time if a disjoint operation did 466 not occur. Note that care should be taken to use all 467 significant bits of the result, not just the least significant 468 32 bits. */ 469 AdjustObjectLODBasedOnDrawTime(i, timeElapsed); 470 } 471 } 472 473 This example is sub-optimal in that it stalls at the end of every 474 frame to wait for query results. Ideally, the collection of results 475 would be delayed one frame to minimize the amount of time spent 476 waiting for the GPU to finish rendering. 477 478 (2) This example uses QueryCounter. 479 480 GLint queries[2]; 481 GLint available = 0; 482 GLint disjointOccurred = 0; 483 /* Timer queries can contain more than 32 bits of data, so always 484 query them using the 64 bit types to avoid overflow */ 485 GLuint64 timeStart, timeEnd, timeElapsed = 0; 486 487 /* Create a query object. */ 488 glGenQueries(2, queries); 489 490 /* Clear disjoint error */ 491 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred); 492 493 /* Query current timestamp before drawing */ 494 glQueryCounterEXT(queries[0], GL_TIMESTAMP_EXT); 495 496 /* Draw full rendertarget of objects */ 497 498 /* Query current timestamp after drawing */ 499 glQueryCounterEXT(queries[1], GL_TIMESTAMP_EXT); 500 501 /* Do some other work so you don't stall waiting for available */ 502 503 /* Wait for the query result to become available */ 504 while (!available) { 505 glGetQueryObjectiv(queries[1], GL_QUERY_RESULT_AVAILABLE, &available); 506 } 507 508 /* Check for disjoint operation. */ 509 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred); 510 511 /* If a disjoint operation occurred, continue without reading the the 512 values */ 513 if (!disjointOccurred) { 514 /* Get timestamp for when rendertarget started. */ 515 glGetQueryObjectui64vEXT(queries[0], GL_QUERY_RESULT, &timeStart); 516 /* Get timestamp for when rendertarget finished. */ 517 glGetQueryObjectui64vEXT(queries[1], GL_QUERY_RESULT, &timeEnd); 518 /* See how much time the rendering took in nanoseconds. */ 519 timeElapsed = timeEnd - timeStart; 520 521 /* Do something useful with the time if a disjoint operation did 522 not occur. Note that care should be taken to use all 523 significant bits of the result, not just the least significant 524 32 bits. */ 525 AdjustObjectLODBasedOnDrawTime(timeElapsed); 526 } 527 528 (3) This example demonstrates how to measure the latency between GL 529 commands reaching the server and being realized in the framebuffer. 530 531 /* Submit a frame of rendering commands */ 532 while (!doneRendering) { 533 ... 534 glDrawElements(...); 535 } 536 537 /* Measure rendering latency: 538 Some commands may have already been submitted to hardware, 539 and some of those may have already completed. The goal is 540 to measure the time it takes for the remaining commands to 541 complete, thereby measuring how far behind the app the GPU 542 is lagging, but without synchronizing the GPU with the CPU. */ 543 544 /* Clear disjoint error */ 545 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred); 546 547 /* Queue a query to find out when the frame finishes on the GL */ 548 glQueryCounterEXT(endFrameQuery, GL_TIMESTAMP_EXT); 549 550 /* Get the current GL time without stalling the GL */ 551 glGetIntegerv(GL_TIMESTAMP_EXT, &flushTime); 552 553 /* Finish the frame, submitting outstanding commands to the GL */ 554 SwapBuffers(); 555 556 /* Render another frame */ 557 558 /* Later, compare the query result of <endFrameQuery> 559 and <flushTime> to measure the latency of the frame. 560 A disjoint error still needs to be checked for in order 561 to verify these values are valid. */ 562 563Issues from EXT_timer_query 564 565 (1) What time interval is being measured? 566 567 RESOLVED: The timer starts when all commands prior to BeginQueryEXT() have 568 been fully executed. At that point, everything that should be drawn by 569 those commands has been written to the framebuffer. The timer stops 570 when all commands prior to EndQueryEXT() have been fully executed. 571 572 (2) What unit of time will time intervals be returned in? 573 574 RESOLVED: Nanoseconds (10^-9 seconds). This unit of measurement allows 575 for reasonably accurate timing of even small blocks of rendering 576 commands. The granularity of the timer is implementation-dependent. A 577 32-bit query counter can express intervals of up to approximately 4 578 seconds. 579 580 (3) What should be the minimum number of counter bits for timer queries? 581 582 RESOLVED: 30 bits, which will allow timing sections that take up to 1 583 second to render. 584 585 (4) How are counter results of more than 32 bits returned? 586 587 RESOLVED: Via two new datatypes, int64 and uint64, and their 588 corresponding GetQueryObject entry points. These types hold integer 589 values and have a minimum bit width of 64. 590 591 (5) Should the extension measure total time elapsed between the full 592 completion of the BeginQuery and EndQuery commands, or just time 593 spent in the graphics library? 594 595 RESOLVED: This extension will measure the total time elapsed between 596 the full completion of these commands. Future extensions may implement 597 a query to determine time elapsed at different stages of the graphics 598 pipeline. 599 600 (6) If multiple query types are supported, can multiple query types be 601 active simultaneously? 602 603 RESOLVED: Yes; an application may perform a timer query and another 604 type of query simultaneously. An application can not perform multiple 605 timer queries or multiple queries of other types simultaneously. An 606 application also can not use the same query object for another query 607 and a timer query simultaneously. 608 609 (7) Do query objects have a query type permanently associated with them? 610 611 RESOLVED: No. A single query object can be used to perform different 612 types of queries, but not at the same time. 613 614 Having a fixed type for each query object simplifies some aspects of the 615 implementation -- not having to deal with queries with different result 616 sizes, for example. It would also mean that BeginQuery() with a query 617 object of the "wrong" type would result in an INVALID_OPERATION error. 618 619 UPDATE: This resolution was relevant for EXT_timer_query and OpenGL 2.0. 620 Since EXT_transform_feedback has since been incorporated into the core, 621 the resolution is that BeginQuery will generate error INVALID_OPERATION 622 if <id> represents a query object of a different type. 623 624 (8) How predictable/repeatable are the results returned by the timer 625 query? 626 627 RESOLVED: In general, the amount of time needed to render the same 628 primitives should be fairly constant. But there may be many other 629 system issues (e.g., context switching on the CPU and GPU, virtual 630 memory page faults, memory cache behavior on the CPU and GPU) that can 631 cause times to vary wildly. 632 633 Note that modern GPUs are generally highly pipelined, and may be 634 processing different primitives in different pipeline stages 635 simultaneously. In this extension, the timers start and stop when the 636 BeginQuery/EndQuery commands reach the bottom of the rendering pipeline. 637 What that means is that by the time the timer starts, the GL driver on 638 the CPU may have started work on GL commands issued after BeginQuery, 639 and the higher pipeline stages (e.g., vertex transformation) may have 640 started as well. 641 642 (9) What should the new 64 bit integer type be called? 643 644 RESOLVED: The new types will be called GLint64/GLuint64. The new 645 command suffixes will be i64 and ui64. These names clearly convey the 646 minimum size of the types. These types are similar to the C99 standard 647 type int_least64_t, but we use names similar to the C99 optional type 648 int64_t for simplicity. 649 650Issues from ARB_timer_query 651 652 (10) What about tile-based implementations? The effects of a command are 653 not complete until the frame is completely rendered. Timing recorded 654 before the frame is complete may not be what developers expect. Also 655 the amount of time needed to render the same primitives is not 656 consistent, which conflicts with issue (8) above. The time depends on 657 how early or late in the scene it is placed. 658 659 RESOLVED: The current language supports tile-based rendering okay as it 660 is written. Developers are warned that using timers on tile-based 661 implementation may not produce results they expect since rendering is not 662 done in a linear order. Timing results are calculated when the frame is 663 completed and may depend on how early or late in the scene it is placed. 664 665 (11) Can the GL implementation use different clocks to implement the 666 TIME_ELAPSED and TIMESTAMP queries? 667 668 RESOLVED: Yes, the implementation can use different internal clocks to 669 implement TIME_ELAPSED and TIMESTAMP. If different clocks are 670 used it is possible there is a slight discrepancy when comparing queries 671 made from TIME_ELAPSED and TIMESTAMP; they may have slight 672 differences when both are used to measure the same sequence. However, this 673 is unlikely to affect real applications since comparing the two queries is 674 not expected to be useful. 675 676Issues 677 678 (12) What should we call this extension? 679 680 RESOLVED: EXT_disjoint_timer_query 681 682 (13) Why is this done as a separate extension instead of just supporting 683 ARB_timer_query? 684 685 ARB_timer_query is written against OpenGL 3.2, which includes a lot of 686 the required support for dealing with query objects. None of these 687 functions or tokens exist in OpenGL ES, and as such have to be added in 688 this specification. 689 690 (14) How does this extension differ from ARB_timer_query? 691 692 This extension contains most ARB_timer_query behavior unchanged as well 693 as adds the ability to detect GPU issues using GPU_DISJOINT_EXT. 694 695 (15) Are query objects shareable between multiple contexts? 696 697 RESOLVED: No. Query objects are lightweight and we normally share 698 large data across contexts. Also, being able to share query objects 699 across contexts is not particularly useful. In order to do the async 700 query across contexts, a query on one context would have to be finished 701 before the other context could query it. 702 703 (16) How does this extension interact with EXT_occlusion_query_boolean? 704 705 This extension redefines the Query Api originally defined in the EXT- 706 _occlusion_query_boolean. If both EXT_disjoint_timer_query and EXT- 707 _occlusion_query_boolean are supported, the rules and specification 708 regarding any overlap will be governed by the EXT_occlusion_query_boolean 709 extension. 710 711 This extension should redefine the functionality in the same way, but if 712 some discrepancy is found and both are supported EXT_disjoint_timer_query 713 will yield to the rules and specifications governing the overlap in the 714 order above. 715 716 (17) How does this extension interact with the OpenGL ES 3.0 specification? 717 718 Some of the functionality and requirements described here overlap with the 719 OpenGL ES 3.0 specification. Any overlap for the functions or tokens in 720 this extension were meant to complement each other, but the OpenGL ES 3.0 721 spec takes precedence. If the implementation supports OpenGL ES 3.0 then 722 it should support both the core non-decorated functions and the EXT 723 decorated functions. 724 725 (18) How do times from BeginQueryEXT/EndQueryEXT with a <target> of 726 TIME_ELAPSED_EXT and QueryCounterEXT with a <target> of TIMESTAMP_EXT 727 compare on some Qualcomm and ARM tiling GPUs? 728 729 This does not describe all tiling GPUs, but it is how some tiling GPUs from 730 ARM, Qualcomm, and possibly other vendors work. This is just an 731 implementation note and there is no guarantee all ARM and Qualcomm 732 implementations will work this way. 733 734 TIME_ELAPSED_EXT will be a summation of all the time spent on the workload 735 between begin and end. Tiling architectures might split this work up over a 736 binning pass and rendering many different tiles. It is up to the hardware 737 and/or driver to add up all the time spent on the work between begin and end 738 and report a single number making the implementation transparent to 739 developers using this feature. If the binning pass happens in parallel to 740 rendering pass this time would not be counted twice. On some 741 implementations this does not include the time to copy tile memory to or from 742 the frame buffer in system memory, and on other implementations this time 743 is included. 744 745 TIMESTAMP_EXT is the time when all the commands are complete and copied out 746 of tile memory to the framebuffer in system memory. This can result in a 747 courser grain timestamp than developers familiar with immediate GPUs expect. 748 For example all the draws to an FBO can often all get the same timestamp, or 749 even all the draw calls to multiple FBOs can end up with the same timestamp. 750 If some operation causes a midframe store/load (such as flush or readPixels) 751 then that would create another point for timestamps, but is a lot of extra 752 work for the GPU so it should be avoided. 753 754 If a preemption event happens before the TIMESTAMP_EXT is reported then that 755 time will include the time for preemption. With TIME_ELAPSED_EXT it is 756 undefined if the preemption time is counted or not. Some hardware will 757 count the preemption time (even though it is from a different context). For 758 this behavior GPU_DISJOINT_EXT will be set so you know there was an event 759 from a different context affecting results. Other hardware will not count 760 the time spent in the preempting context and for this cases GPU_DISJOINT_EXT 761 will not be set. 762 763Revision History 764 Revision 9, 2020/11/20 (xndcn) 765 - Minor fix of code sample 766 Revision 8, 2019/12/11 (Jon Leech) 767 - Add actual spec language defining GetInteger64vEXT (github 768 OpenGL-Registry issue 326) 769 Revision 7, 2016/9/2 (Maurice Ribble) 770 - Clarify language dealing with GetInteger64v 771 Revision 6, 2016/7/15 (Maurice Ribble) 772 - Clarified some outstanding questions about tiling GPUs 773 - Added issue 18 774 Revision 5, 2013/6/5 775 - Minor cleanup to match new gl2ext.h 776 Revision 4, 2013/4/25 (Jon Leech) 777 - Cleanup for publication 778 - Fix value assigned to GPU_DISJOINT_EXT 779 Revision 3, 2013/4/8 780 - Minor cleanup of code sample and re-wording 781 Revision 2, 2013/4/2 782 - Minor cleanup 783 Revision 1, 2013/1/2 784 - Copied from revision 1 of ANGLE_timer_query 785 - Added TIMESTAMP_EXT and GPU_DISJOINT_EXT 786