Adding ANGLE_timer_query draft extension spec.

Issue=142
Signed-off-by: Daniel Koch


git-svn-id: http://angleproject.googlecode.com/svn/trunk@627 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/extensions/ANGLE_timer_query.txt b/extensions/ANGLE_timer_query.txt
new file mode 100644
index 0000000..3cc3858
--- /dev/null
+++ b/extensions/ANGLE_timer_query.txt
@@ -0,0 +1,591 @@
+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