2012-07-25 09:13:45 -07:00
|
|
|
Name
|
|
|
|
|
|
|
|
ANGLE_timer_query
|
|
|
|
|
|
|
|
Name Strings
|
|
|
|
|
|
|
|
GL_ANGLE_timer_query
|
|
|
|
|
|
|
|
Contributors
|
|
|
|
|
|
|
|
Contributors to ARB_occlusion_query
|
|
|
|
Contributors to EXT_timer_query
|
|
|
|
Contributors to ARB_timer_query
|
|
|
|
Ben Vanik, Google Inc.
|
|
|
|
Daniel Koch, TransGaming Inc.
|
|
|
|
|
|
|
|
Contact
|
|
|
|
|
|
|
|
Ben Vanik, Google Inc. (benvanik 'at' google 'dot' com)
|
|
|
|
|
|
|
|
Status
|
|
|
|
|
|
|
|
Draft
|
|
|
|
|
|
|
|
Version
|
|
|
|
|
|
|
|
Last Modified Date: Apr 28, 2011
|
|
|
|
Author Revision: 1
|
|
|
|
|
|
|
|
Number
|
|
|
|
|
|
|
|
OpenGL ES Extension #??
|
|
|
|
|
|
|
|
Dependencies
|
|
|
|
|
|
|
|
OpenGL ES 2.0 is required.
|
|
|
|
|
|
|
|
The extension is written against the OpenGL ES 2.0 specification.
|
|
|
|
|
|
|
|
Overview
|
|
|
|
|
|
|
|
Applications can benefit from accurate timing information in a number of
|
|
|
|
different ways. During application development, timing information can
|
|
|
|
help identify application or driver bottlenecks. At run time,
|
|
|
|
applications can use timing information to dynamically adjust the amount
|
|
|
|
of detail in a scene to achieve constant frame rates. OpenGL
|
|
|
|
implementations have historically provided little to no useful timing
|
|
|
|
information. Applications can get some idea of timing by reading timers
|
|
|
|
on the CPU, but these timers are not synchronized with the graphics
|
|
|
|
rendering pipeline. Reading a CPU timer does not guarantee the completion
|
|
|
|
of a potentially large amount of graphics work accumulated before the
|
|
|
|
timer is read, and will thus produce wildly inaccurate results.
|
|
|
|
glFinish() can be used to determine when previous rendering commands have
|
|
|
|
been completed, but will idle the graphics pipeline and adversely affect
|
|
|
|
application performance.
|
|
|
|
|
|
|
|
This extension provides a query mechanism that can be used to determine
|
|
|
|
the amount of time it takes to fully complete a set of GL commands, and
|
|
|
|
without stalling the rendering pipeline. It uses the query object
|
|
|
|
mechanisms first introduced in the occlusion query extension, which allow
|
|
|
|
time intervals to be polled asynchronously by the application.
|
|
|
|
|
|
|
|
IP Status
|
|
|
|
|
|
|
|
No known IP claims.
|
|
|
|
|
|
|
|
New Procedures and Functions
|
|
|
|
|
|
|
|
void GenQueriesANGLE(sizei n, uint *ids);
|
|
|
|
void DeleteQueriesANGLE(sizei n, const uint *ids);
|
|
|
|
boolean IsQueryANGLE(uint id);
|
|
|
|
void BeginQueryANGLE(enum target, uint id);
|
|
|
|
void EndQueryANGLE(enum target);
|
|
|
|
void QueryCounterANGLE(uint id, enum target);
|
|
|
|
void GetQueryivANGLE(enum target, enum pname, int *params);
|
|
|
|
void GetQueryObjectivANGLE(uint id, enum pname, int *params);
|
|
|
|
void GetQueryObjectuivANGLE(uint id, enum pname, uint *params);
|
|
|
|
void GetQueryObjecti64vANGLE(uint id, enum pname, int64 *params);
|
|
|
|
void GetQueryObjectui64vANGLE(uint id, enum pname, uint64 *params);
|
|
|
|
|
|
|
|
New Tokens
|
|
|
|
|
|
|
|
Accepted by the <pname> parameter of GetQueryivANGLE:
|
|
|
|
|
|
|
|
QUERY_COUNTER_BITS_ANGLE 0x8864
|
|
|
|
CURRENT_QUERY_ANGLE 0x8865
|
|
|
|
|
|
|
|
Accepted by the <pname> parameter of GetQueryObjectivANGLE,
|
|
|
|
GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, and
|
|
|
|
GetQueryObjectui64vANGLE:
|
|
|
|
|
|
|
|
QUERY_RESULT_ANGLE 0x8866
|
|
|
|
QUERY_RESULT_AVAILABLE_ANGLE 0x8867
|
|
|
|
|
|
|
|
Accepted by the <target> parameter of BeginQueryANGLE, EndQueryANGLE, and
|
|
|
|
GetQueryivANGLE:
|
|
|
|
|
|
|
|
TIME_ELAPSED_ANGLE 0x88BF
|
|
|
|
|
|
|
|
Accepted by the <target> parameter of GetQueryivANGLE and
|
|
|
|
QueryCounterANGLE:
|
|
|
|
|
|
|
|
TIMESTAMP_ANGLE 0x8E28
|
|
|
|
|
|
|
|
Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)
|
|
|
|
|
|
|
|
(Modify table 2.1, Correspondence of command suffix letters to GL argument)
|
|
|
|
Add two new types:
|
|
|
|
|
|
|
|
Letter Corresponding GL Type
|
|
|
|
------ ---------------------
|
|
|
|
i64 int64ANGLE
|
|
|
|
ui64 uint64ANGLE
|
|
|
|
|
|
|
|
(Modify table 2.2, GL data types) Add two new types:
|
|
|
|
|
|
|
|
GL Type Minimum Bit Width Description
|
|
|
|
------- ----------------- -----------------------------
|
|
|
|
int64ANGLE 64 Signed 2's complement integer
|
|
|
|
uint64ANGLE 64 Unsigned binary integer
|
|
|
|
|
|
|
|
Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
|
|
|
|
|
|
|
|
Add a new section 5.3 "Timer Queries":
|
|
|
|
|
|
|
|
"5.3 Timer Queries
|
|
|
|
|
|
|
|
Timer queries use query objects to track the amount of time needed to
|
|
|
|
fully complete a set of GL commands, or to determine the current time
|
|
|
|
of the GL.
|
|
|
|
|
|
|
|
Timer queries are associated with query objects. The command
|
|
|
|
|
|
|
|
void GenQueriesANGLE(sizei n, uint *ids);
|
|
|
|
|
|
|
|
returns <n> previously unused query object names in <ids>. These
|
|
|
|
names are marked as used, but no object is associated with them until
|
|
|
|
the first time they are used by BeginQueryANGLE. Query objects contain
|
|
|
|
one piece of state, an integer result value. This result value is
|
|
|
|
initialized to zero when the object is created. Any positive integer
|
|
|
|
except for zero (which is reserved for the GL) is a valid query
|
|
|
|
object name.
|
|
|
|
|
|
|
|
Query objects are deleted by calling
|
|
|
|
|
|
|
|
void DeleteQueriesANGLE(sizei n, const uint *ids);
|
|
|
|
|
|
|
|
<ids> contains <n> names of query objects to be deleted. After a
|
|
|
|
query object is deleted, its name is again unused. Unused names in
|
|
|
|
<ids> are silently ignored.
|
|
|
|
If an active query object is deleted its name immediately becomes unused,
|
|
|
|
but the underlying object is not deleted until it is no longer active.
|
|
|
|
|
|
|
|
A timer query can be started and finished by calling
|
|
|
|
|
|
|
|
void BeginQueryANGLE(enum target, uint id);
|
|
|
|
void EndQueryANGLE(enum target);
|
|
|
|
|
|
|
|
where <target> is TIME_ELAPSED_ANGLE. If BeginQueryANGLE is called
|
|
|
|
with an unused <id>, that name is marked as used and associated with
|
|
|
|
a new query object.
|
|
|
|
|
|
|
|
If BeginQueryANGLE is called with an <id> of zero, if the active query
|
|
|
|
object name for <target> is non-zero, if <id> is the name of an existing
|
|
|
|
query object whose type does not match <target>, or if <id> is the active
|
|
|
|
query object name for any query type, the error INVALID_OPERATION is
|
|
|
|
generated. If EndQueryANGLE is called while no query with the same target
|
|
|
|
is in progress, an INVALID_OPERATION error is generated.
|
|
|
|
|
|
|
|
When BeginQueryANGLE and EndQueryANGLE are called with a <target> of
|
|
|
|
TIME_ELAPSED_ANGLE, the GL prepares to start and stop the timer used for
|
|
|
|
timer queries. The timer is started or stopped when the effects from all
|
|
|
|
previous commands on the GL client and server state and the framebuffer
|
|
|
|
have been fully realized. The BeginQueryANGLE and EndQueryANGLE commands
|
|
|
|
may return before the timer is actually started or stopped. When the timer
|
|
|
|
query timer is finally stopped, the elapsed time (in nanoseconds) is
|
|
|
|
written to the corresponding query object as the query result value, and
|
|
|
|
the query result for that object is marked as available.
|
|
|
|
|
|
|
|
If the elapsed time overflows the number of bits, <n>, available to hold
|
|
|
|
elapsed time, its value becomes undefined. It is recommended, but not
|
|
|
|
required, that implementations handle this overflow case by saturating at
|
|
|
|
2^n - 1.
|
|
|
|
|
|
|
|
The necessary state is a single bit indicating whether an timer
|
|
|
|
query is active, the identifier of the currently active timer
|
|
|
|
query, and a counter keeping track of the time that has passed.
|
|
|
|
|
|
|
|
When the command
|
|
|
|
|
|
|
|
void QueryCounterANGLE(uint id, enum target);
|
|
|
|
|
|
|
|
is called with <target> TIMESTAMP_ANGLE, the GL records the current time
|
|
|
|
into the corresponding query object. The time is recorded after all
|
|
|
|
previous commands on the GL client and server state and the framebuffer
|
|
|
|
have been fully realized. When the time is recorded, the query result for
|
|
|
|
that object is marked available. QueryCounterANGLE timer queries can be
|
|
|
|
used within a BeginQueryANGLE / EndQueryANGLE block where the <target> is
|
|
|
|
TIME_ELAPSED_ANGLE and it does not affect the result of that query object.
|
|
|
|
The error INVALID_OPERATION is generated if the <id> is already in use
|
|
|
|
within a BeginQueryANGLE/EndQueryANGLE block."
|
|
|
|
|
|
|
|
Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
|
|
|
|
Requests)
|
|
|
|
|
|
|
|
Add a new section 6.1.9 "Timer Queries":
|
|
|
|
|
|
|
|
"The command
|
|
|
|
|
|
|
|
boolean IsQueryANGLE(uint id);
|
|
|
|
|
|
|
|
returns TRUE if <id> is the name of a query object. If <id> is zero,
|
|
|
|
or if <id> is a non-zero value that is not the name of a query
|
|
|
|
object, IsQueryANGLE returns FALSE.
|
|
|
|
|
|
|
|
Information about a query target can be queried with the command
|
|
|
|
|
|
|
|
void GetQueryivANGLE(enum target, enum pname, int *params);
|
|
|
|
|
|
|
|
<target> identifies the query target and can be TIME_ELAPSED_ANGLE or
|
|
|
|
TIMESTAMP_ANGLE for timer queries.
|
|
|
|
|
|
|
|
If <pname> is CURRENT_QUERY_ANGLE, the name of the currently active query
|
|
|
|
for <target>, or zero if no query is active, will be placed in <params>.
|
|
|
|
|
|
|
|
If <pname> is QUERY_COUNTER_BITS_ANGLE, the implementation-dependent number
|
|
|
|
of bits used to hold the query result for <target> will be placed in
|
|
|
|
<params>. The number of query counter bits may be zero, in which case
|
|
|
|
the counter contains no useful information.
|
|
|
|
|
|
|
|
For timer queries (TIME_ELAPSED_ANGLE and TIMESTAMP_ANGLE), if the number
|
|
|
|
of bits is non-zero, the minimum number of bits allowed is 30 which
|
|
|
|
will allow at least 1 second of timing.
|
|
|
|
|
|
|
|
The state of a query object can be queried with the commands
|
|
|
|
|
|
|
|
void GetQueryObjectivANGLE(uint id, enum pname, int *params);
|
|
|
|
void GetQueryObjectuivANGLE(uint id, enum pname, uint *params);
|
|
|
|
void GetQueryObjecti64vANGLE(uint id, enum pname, int64 *params);
|
|
|
|
void GetQueryObjectui64vANGLE(uint id, enum pname, uint64 *params);
|
|
|
|
|
|
|
|
If <id> is not the name of a query object, or if the query object
|
|
|
|
named by <id> is currently active, then an INVALID_OPERATION error is
|
|
|
|
generated.
|
|
|
|
|
|
|
|
If <pname> is QUERY_RESULT_ANGLE, then the query object's result
|
|
|
|
value is returned as a single integer in <params>. If the value is so
|
|
|
|
large in magnitude that it cannot be represented with the requested type,
|
|
|
|
then the nearest value representable using the requested type is
|
|
|
|
returned. If the number of query counter bits for target is zero, then
|
|
|
|
the result is returned as a single integer with the value zero.
|
|
|
|
|
|
|
|
There may be an indeterminate delay before the above query returns. If
|
|
|
|
<pname> is QUERY_RESULT_AVAILABLE_ANGLE, FALSE is returned if such a delay
|
|
|
|
would be required; otherwise TRUE is returned. It must always be true
|
|
|
|
that if any query object returns a result available of TRUE, all queries
|
|
|
|
of the same type issued prior to that query must also return TRUE.
|
|
|
|
|
|
|
|
Querying the state for a given timer query forces that timer query to
|
|
|
|
complete within a finite amount of time.
|
|
|
|
|
|
|
|
If multiple queries are issued on the same target and id prior to
|
|
|
|
calling GetQueryObject[u]i[64]vANGLE, the result returned will always be
|
|
|
|
from the last query issued. The results from any queries before the
|
|
|
|
last one will be lost if the results are not retrieved before starting
|
|
|
|
a new query on the same <target> and <id>."
|
|
|
|
|
|
|
|
Errors
|
|
|
|
|
|
|
|
The error INVALID_VALUE is generated if GenQueriesANGLE is called where
|
|
|
|
<n> is negative.
|
|
|
|
|
|
|
|
The error INVALID_VALUE is generated if DeleteQueriesANGLE is called
|
|
|
|
where <n> is negative.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if BeginQueryANGLE is called
|
|
|
|
when a query of the given <target> is already active.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if EndQueryANGLE is called
|
|
|
|
when a query of the given <target> is not active.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if BeginQueryANGLE is called
|
|
|
|
where <id> is zero.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if BeginQueryANGLE is called
|
|
|
|
where <id> is the name of a query currently in progress.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if BeginQueryANGLE is called
|
|
|
|
where <id> is the name of an existing query object whose type does not
|
|
|
|
match <target>.
|
|
|
|
|
|
|
|
The error INVALID_ENUM is generated if BeginQueryANGLE or EndQueryANGLE
|
|
|
|
is called where <target> is not TIME_ELAPSED_ANGLE.
|
|
|
|
|
|
|
|
The error INVALID_ENUM is generated if GetQueryivANGLE is called where
|
|
|
|
<target> is not TIME_ELAPSED_ANGLE or TIMESTAMP_ANGLE.
|
|
|
|
|
|
|
|
The error INVALID_ENUM is generated if GetQueryivANGLE is called where
|
|
|
|
<pname> is not QUERY_COUNTER_BITS_ANGLE or CURRENT_QUERY_ANGLE.
|
|
|
|
|
|
|
|
The error INVALID_ENUM is generated if QueryCounterANGLE is called where
|
|
|
|
<target> is not TIMESTAMP_ANGLE.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if QueryCounterANGLE is called
|
|
|
|
on a query object that is already in use inside a
|
|
|
|
BeginQueryANGLE/EndQueryANGLE.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if GetQueryObjectivANGLE,
|
|
|
|
GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
|
|
|
|
GetQueryObjectui64vANGLE is called where <id> is not the name of a query
|
|
|
|
object.
|
|
|
|
|
|
|
|
The error INVALID_OPERATION is generated if GetQueryObjectivANGLE,
|
|
|
|
GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
|
|
|
|
GetQueryObjectui64vANGLE is called where <id> is the name of a currently
|
|
|
|
active query object.
|
|
|
|
|
|
|
|
The error INVALID_ENUM is generated if GetQueryObjectivANGLE,
|
|
|
|
GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
|
|
|
|
GetQueryObjectui64vANGLE is called where <pname> is not
|
|
|
|
QUERY_RESULT_ANGLE or QUERY_RESULT_AVAILABLE_ANGLE.
|
|
|
|
|
|
|
|
New State
|
|
|
|
|
|
|
|
(Add a new table 6.xx, "Query Operations")
|
|
|
|
|
|
|
|
Get Value Type Get Command Initial Value Description Sec
|
|
|
|
--------- ---- ----------- ------------- ----------- ------
|
|
|
|
- B - FALSE query active 5.3
|
|
|
|
CURRENT_QUERY_ANGLE Z+ GetQueryivANGLE 0 active query ID 5.3
|
|
|
|
QUERY_RESULT_ANGLE Z+ GetQueryObjectuivANGLE, 0 samples-passed count 5.3
|
|
|
|
GetQueryObjectui64vANGLE
|
|
|
|
QUERY_RESULT_AVAILABLE_ANGLE B GetQueryObjectivANGLE FALSE query result available 5.3
|
|
|
|
|
|
|
|
New Implementation Dependent State
|
|
|
|
|
|
|
|
(Add the following entry to table 6.18):
|
|
|
|
|
|
|
|
Get Value Type Get Command Minimum Value Description Sec
|
|
|
|
-------------------------- ---- ----------- ------------- ---------------- ------
|
|
|
|
QUERY_COUNTER_BITS_ANGLE Z+ GetQueryivANGLE see 6.1.9 Number of bits in 6.1.9
|
|
|
|
query counter
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
|
|
|
(1) Here is some rough sample code that demonstrates the intended usage
|
|
|
|
of this extension.
|
|
|
|
|
|
|
|
GLint queries[N];
|
|
|
|
GLint available = 0;
|
|
|
|
// timer queries can contain more than 32 bits of data, so always
|
|
|
|
// query them using the 64 bit types to avoid overflow
|
|
|
|
GLuint64ANGLE timeElapsed = 0;
|
|
|
|
|
|
|
|
// Create a query object.
|
|
|
|
glGenQueriesANGLE(N, queries);
|
|
|
|
|
|
|
|
// Start query 1
|
|
|
|
glBeginQueryANGLE(GL_TIME_ELAPSED_ANGLE, queries[0]);
|
|
|
|
|
|
|
|
// Draw object 1
|
|
|
|
....
|
|
|
|
|
|
|
|
// End query 1
|
|
|
|
glEndQueryANGLE(GL_TIME_ELAPSED_ANGLE);
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
// Start query N
|
|
|
|
glBeginQueryANGLE(GL_TIME_ELAPSED_ANGLE, queries[N-1]);
|
|
|
|
|
|
|
|
// Draw object N
|
|
|
|
....
|
|
|
|
|
|
|
|
// End query N
|
|
|
|
glEndQueryANGLE(GL_TIME_ELAPSED_ANGLE);
|
|
|
|
|
|
|
|
// Wait for all results to become available
|
|
|
|
while (!available) {
|
|
|
|
glGetQueryObjectivANGLE(queries[N-1], GL_QUERY_RESULT_AVAILABLE_ANGLE, &available);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
// See how much time the rendering of object i took in nanoseconds.
|
|
|
|
glGetQueryObjectui64vANGLE(queries[i], GL_QUERY_RESULT_ANGLE, &timeElapsed);
|
|
|
|
|
|
|
|
// Do something useful with the time. Note that care should be
|
|
|
|
// taken to use all significant bits of the result, not just the
|
|
|
|
// least significant 32 bits.
|
|
|
|
AdjustObjectLODBasedOnDrawTime(i, timeElapsed);
|
|
|
|
}
|
|
|
|
|
|
|
|
This example is sub-optimal in that it stalls at the end of every
|
|
|
|
frame to wait for query results. Ideally, the collection of results
|
|
|
|
would be delayed one frame to minimize the amount of time spent
|
|
|
|
waiting for the GPU to finish rendering.
|
|
|
|
|
|
|
|
(2) This example is basically the same as the example above but uses
|
|
|
|
QueryCounter instead.
|
|
|
|
|
|
|
|
GLint queries[N+1];
|
|
|
|
GLint available = 0;
|
|
|
|
// timer queries can contain more than 32 bits of data, so always
|
|
|
|
// query them using the 64 bit types to avoid overflow
|
|
|
|
GLuint64ANGLE timeStart, timeEnd, timeElapsed = 0;
|
|
|
|
|
|
|
|
// Create a query object.
|
|
|
|
glGenQueriesANGLE(N+1, queries);
|
|
|
|
|
|
|
|
// Query current timestamp 1
|
|
|
|
glQueryCounterANGLE(queries[0], GL_TIMESTAMP_ANGLE);
|
|
|
|
|
|
|
|
// Draw object 1
|
|
|
|
....
|
|
|
|
|
|
|
|
// Query current timestamp N
|
|
|
|
glQueryCounterANGLE(queries[N-1], GL_TIMESTAMP_ANGLE);
|
|
|
|
|
|
|
|
// Draw object N
|
|
|
|
....
|
|
|
|
|
|
|
|
// Query current timestamp N+1
|
|
|
|
glQueryCounterANGLE(queries[N], GL_TIMESTAMP_ANGLE);
|
|
|
|
|
|
|
|
// Wait for all results to become available
|
|
|
|
while (!available) {
|
|
|
|
glGetQueryObjectivANGLE(queries[N], GL_QUERY_RESULT_AVAILABLE_ANGLE, &available);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < N; i++) {
|
|
|
|
// See how much time the rendering of object i took in nanoseconds.
|
|
|
|
glGetQueryObjectui64vANGLE(queries[i], GL_QUERY_RESULT_ANGLE, &timeStart);
|
|
|
|
glGetQueryObjectui64vANGLE(queries[i+1], GL_QUERY_RESULT_ANGLE, &timeEnd);
|
|
|
|
timeElapsed = timeEnd - timeStart;
|
|
|
|
|
|
|
|
// Do something useful with the time. Note that care should be
|
|
|
|
// taken to use all significant bits of the result, not just the
|
|
|
|
// least significant 32 bits.
|
|
|
|
AdjustObjectLODBasedOnDrawTime(i, timeElapsed);
|
|
|
|
}
|
|
|
|
|
|
|
|
Issues from EXT_timer_query
|
|
|
|
|
|
|
|
(1) What time interval is being measured?
|
|
|
|
|
|
|
|
RESOLVED: The timer starts when all commands prior to BeginQuery() have
|
|
|
|
been fully executed. At that point, everything that should be drawn by
|
|
|
|
those commands has been written to the framebuffer. The timer stops
|
|
|
|
when all commands prior to EndQuery() have been fully executed.
|
|
|
|
|
|
|
|
(2) What unit of time will time intervals be returned in?
|
|
|
|
|
|
|
|
RESOLVED: Nanoseconds (10^-9 seconds). This unit of measurement allows
|
|
|
|
for reasonably accurate timing of even small blocks of rendering
|
|
|
|
commands. The granularity of the timer is implementation-dependent. A
|
|
|
|
32-bit query counter can express intervals of up to approximately 4
|
|
|
|
seconds.
|
|
|
|
|
|
|
|
(3) What should be the minimum number of counter bits for timer queries?
|
|
|
|
|
|
|
|
RESOLVED: 30 bits, which will allow timing sections that take up to 1
|
|
|
|
second to render.
|
|
|
|
|
|
|
|
(4) How are counter results of more than 32 bits returned?
|
|
|
|
|
|
|
|
RESOLVED: Via two new datatypes, int64ANGLE and uint64ANGLE, and their
|
|
|
|
corresponding GetQueryObject entry points. These types hold integer
|
|
|
|
values and have a minimum bit width of 64.
|
|
|
|
|
|
|
|
(5) Should the extension measure total time elapsed between the full
|
|
|
|
completion of the BeginQuery and EndQuery commands, or just time
|
|
|
|
spent in the graphics library?
|
|
|
|
|
|
|
|
RESOLVED: This extension will measure the total time elapsed between
|
|
|
|
the full completion of these commands. Future extensions may implement
|
|
|
|
a query to determine time elapsed at different stages of the graphics
|
|
|
|
pipeline.
|
|
|
|
|
|
|
|
(6) If multiple query types are supported, can multiple query types be
|
|
|
|
active simultaneously?
|
|
|
|
|
|
|
|
RESOLVED: Yes; an application may perform a timer query and another
|
|
|
|
type of query simultaneously. An application can not perform multiple
|
|
|
|
timer queries or multiple queries of other types simultaneously. An
|
|
|
|
application also can not use the same query object for another query
|
|
|
|
and a timer query simultaneously.
|
|
|
|
|
|
|
|
(7) Do query objects have a query type permanently associated with them?
|
|
|
|
|
|
|
|
RESOLVED: No. A single query object can be used to perform different
|
|
|
|
types of queries, but not at the same time.
|
|
|
|
|
|
|
|
Having a fixed type for each query object simplifies some aspects of the
|
|
|
|
implementation -- not having to deal with queries with different result
|
|
|
|
sizes, for example. It would also mean that BeginQuery() with a query
|
|
|
|
object of the "wrong" type would result in an INVALID_OPERATION error.
|
|
|
|
|
|
|
|
UPDATE: This resolution was relevant for EXT_timer_query and OpenGL 2.0.
|
|
|
|
Since EXT_transform_feedback has since been incorporated into the core,
|
|
|
|
the resolution is that BeginQuery will generate error INVALID_OPERATION
|
|
|
|
if <id> represents a query object of a different type.
|
|
|
|
|
|
|
|
(8) How predictable/repeatable are the results returned by the timer
|
|
|
|
query?
|
|
|
|
|
|
|
|
RESOLVED: In general, the amount of time needed to render the same
|
|
|
|
primitives should be fairly constant. But there may be many other
|
|
|
|
system issues (e.g., context switching on the CPU and GPU, virtual
|
|
|
|
memory page faults, memory cache behavior on the CPU and GPU) that can
|
|
|
|
cause times to vary wildly.
|
|
|
|
|
|
|
|
Note that modern GPUs are generally highly pipelined, and may be
|
|
|
|
processing different primitives in different pipeline stages
|
|
|
|
simultaneously. In this extension, the timers start and stop when the
|
|
|
|
BeginQuery/EndQuery commands reach the bottom of the rendering pipeline.
|
|
|
|
What that means is that by the time the timer starts, the GL driver on
|
|
|
|
the CPU may have started work on GL commands issued after BeginQuery,
|
|
|
|
and the higher pipeline stages (e.g., vertex transformation) may have
|
|
|
|
started as well.
|
|
|
|
|
|
|
|
(9) What should the new 64 bit integer type be called?
|
|
|
|
|
|
|
|
RESOLVED: The new types will be called GLint64ANGLE/GLuint64ANGLE. The new
|
|
|
|
command suffixes will be i64 and ui64. These names clearly convey the
|
|
|
|
minimum size of the types. These types are similar to the C99 standard
|
|
|
|
type int_least64_t, but we use names similar to the C99 optional type
|
|
|
|
int64_t for simplicity.
|
|
|
|
|
|
|
|
Issues from ARB_timer_query
|
|
|
|
|
|
|
|
(10) What about tile-based implementations? The effects of a command are
|
|
|
|
not complete until the frame is completely rendered. Timing recorded
|
|
|
|
before the frame is complete may not be what developers expect. Also
|
|
|
|
the amount of time needed to render the same primitives is not
|
|
|
|
consistent, which conflicts with issue (8) above. The time depends on
|
|
|
|
how early or late in the scene it is placed.
|
|
|
|
|
|
|
|
RESOLVED: The current language supports tile-based rendering okay as it
|
|
|
|
is written. Developers are warned that using timers on tile-based
|
|
|
|
implementation may not produce results they expect since rendering is not
|
|
|
|
done in a linear order. Timing results are calculated when the frame is
|
|
|
|
completed and may depend on how early or late in the scene it is placed.
|
|
|
|
|
|
|
|
(11) Can the GL implementation use different clocks to implement the
|
|
|
|
TIME_ELAPSED and TIMESTAMP queries?
|
|
|
|
|
|
|
|
RESOLVED: Yes, the implemenation can use different internal clocks to
|
|
|
|
implement TIME_ELAPSED and TIMESTAMP. If different clocks are
|
|
|
|
used it is possible there is a slight discrepancy when comparing queries
|
|
|
|
made from TIME_ELAPSED and TIMESTAMP; they may have slight
|
|
|
|
differences when both are used to measure the same sequence. However, this
|
|
|
|
is unlikely to affect real applications since comparing the two queries is
|
|
|
|
not expected to be useful.
|
|
|
|
|
|
|
|
Issues
|
|
|
|
|
|
|
|
(12) What should we call this extension?
|
|
|
|
|
|
|
|
RESOLVED: ANGLE_timer_query
|
|
|
|
|
|
|
|
(13) Why is this done as a separate extension instead of just supporting
|
|
|
|
ARB_timer_query?
|
|
|
|
|
|
|
|
ARB_timer_query is written against OpenGL 3.2, which includes a lot of
|
|
|
|
the required support for dealing with query objects. None of these
|
|
|
|
functions or tokens exist in OpenGL ES, and as such have to be added in
|
|
|
|
this specification.
|
|
|
|
|
|
|
|
(14) How does this extension differ from ARB_timer_query?
|
|
|
|
|
|
|
|
This extension contains most ARB_timer_query behavior unchanged as well
|
|
|
|
as a subset of the query support required to use it from the core
|
|
|
|
OpenGL 3.2 spec. It omits the glGetInteger(TIMESTAMP) functionality used to
|
|
|
|
query the current time on the GPU, but the behavior for all remaining
|
|
|
|
functionality taken from ARB_timer_query is the same.
|
|
|
|
|
|
|
|
(15) Are query objects shareable between multiple contexts?
|
|
|
|
|
|
|
|
RESOLVED: No. Query objects are lightweight and we normally share
|
|
|
|
large data across contexts. Also, being able to share query objects
|
|
|
|
across contexts is not particularly useful. In order to do the async
|
|
|
|
query across contexts, a query on one context would have to be finished
|
|
|
|
before the other context could query it.
|
|
|
|
|
|
|
|
Revision History
|
|
|
|
|
|
|
|
Revision 1, 2011/04/28
|
|
|
|
- copied from revision 9 of ARB_timer_query and revision 7 of
|
|
|
|
ARB_occlusion_query
|
|
|
|
- removed language that was clearly not relevant to ES2
|
|
|
|
- rebased changes against the OpenGL ES 2.0 specification
|