blob: 8a95d579f1f933b918240c025c8d48e5900b7137 [file] [log] [blame]
Name
EXT_occlusion_query_boolean
Name Strings
GL_EXT_occlusion_query_boolean
Contributors
All those who have contributed to the definition of occlusion
query functionality in the OpenGL ARB and OpenGL ES workgroups,
upon which this extension spec is entirely dependent.
Contact
Benj Lipchak, Apple (lipchak 'at' apple.com)
Status
Complete
Version
Date: July 22, 2011
Revision: 2
Number
OpenGL ES Extension #100
Dependencies
Written based on the wording of the OpenGL ES 2.0.25 Full Specification
(November 2, 2010).
Overview
This extension defines a mechanism whereby an application can
query whether any pixels (or, more precisely, samples) are drawn
by a primitive or group of primitives.
The primary purpose of such a query (hereafter referred to as an
"occlusion query") is to determine the visibility of an object.
Typically, the application will render the major occluders in the
scene, then perform an occlusion query for each detail object in
the scene. On subsequent frames, the previous results of the
occlusion queries can be used to decide whether to draw an object
or not.
New Procedures and Functions
void GenQueriesEXT(sizei n, uint *ids);
void DeleteQueriesEXT(sizei n, const uint *ids);
boolean IsQueryEXT(uint id);
void BeginQueryEXT(enum target, uint id);
void EndQueryEXT(enum target);
void GetQueryivEXT(enum target, enum pname, int *params);
void GetQueryObjectuivEXT(uint id, enum pname, uint *params);
New Tokens
Accepted by the <target> parameter of BeginQueryEXT, EndQueryEXT,
and GetQueryivEXT:
ANY_SAMPLES_PASSED_EXT 0x8C2F
ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
Accepted by the <pname> parameter of GetQueryivEXT:
CURRENT_QUERY_EXT 0x8865
Accepted by the <pname> parameter of GetQueryObjectivEXT and
GetQueryObjectuivEXT:
QUERY_RESULT_EXT 0x8866
QUERY_RESULT_AVAILABLE_EXT 0x8867
Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)
Add a new section "Asynchronous Queries" between sections 2.12 and 2.13
and renumber subsequent sections:
"2.13 Asynchronous Queries
Asynchronous queries provide a mechanism to return information about the
processing of a sequence of GL commands. There is one query type
supported by the GL. Occlusion queries (see section 4.1.6) set a boolean
to true when any fragments or samples pass the depth test.
The results of asynchronous queries are not returned by the GL immediately
after the completion of the last command in the set; subsequent commands
can be processed while the query results are not complete. When available,
the query results are stored in an associated query object. The commands
described in section 6.1.6 provide mechanisms to determine when query
results are available and return the actual results of the query. The
name space for query objects is the unsigned integers, with zero reserved
by the GL.
Each type of query supported by the GL has an active query object name. If
the active query object name for a query type is non-zero, the GL is
currently tracking the information corresponding to that query type and the
query results will be written into the corresponding query object. If the
active query object for a query type name is zero, no such information is
being tracked.
A query object is created and made active by calling
void BeginQueryEXT(enum target, uint id);
<target> indicates the type of query to be performed; valid values of
<target> are defined in subsequent sections. If the query object name <id>
has not been created, the name is marked as used and associated with a new
query object of the type specified by <target>. Otherwise <id> must be the
name of an existing query object of that type.
BeginQueryEXT fails and an INVALID_OPERATION error is generated if <id>
is not a name returned from a previous call to GenQueriesEXT, or if such
a name has since been deleted with DeleteQueriesEXT.
BeginQueryEXT sets the active query object name for the query type given
by <target> to <id>. If BeginQueryEXT is called with an <id> of zero, if
the active query object name for <target> is non-zero (for the targets
ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if the
active query for either 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.
The command
void EndQueryEXT(enum target);
marks the end of the sequence of commands to be tracked for the query type
given by <target>. The active query object for <target> is updated to
indicate that query results are not available, and the active query object
name for <target> is reset to zero. When the commands issued prior to
EndQueryEXT have completed and a final query result is available, the
query object active when EndQueryEXT is called is updated by the GL. The
query object is updated to indicate that the query results are available
and to contain the query result. If the active query object name for
<target> is zero when EndQueryEXT is called, the error INVALID_OPERATION
is generated.
The command
void GenQueriesEXT(sizei n, uint *ids);
returns <n> previously unused query object names in <ids>. These names are
marked as used, for the purposes of GenQueriesEXT only, but no object is
associated with them until the first time they are used by BeginQueryEXT.
Query objects are deleted by calling
void DeleteQueriesEXT(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, as is the value zero. 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 (see section C.1).
Query objects contain two pieces of state: a single bit indicating whether
a query result is available, and an integer containing the query result
value. The number of bits used to represent the query result is
implementation-dependent and may vary by query object type. In the initial
state of a query object, the result is available and its value is zero.
The necessary state for each query type is an unsigned integer holding the
active query object name (zero if no query object is active), and any state
necessary to keep the current results of an asynchronous query in progress.
Only a single type of occlusion query can be active at one time, so the
required state for occlusion queries is shared."
Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
None
Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
Operations and the Frame Buffer)
Add a new section "Occlusion Queries" between sections 4.1.5 and
4.1.6 and renumber subsequent sections:
"4.1.6 Occlusion Queries
Occlusion queries use query objects to track the number of fragments or
samples that pass the depth test. An occlusion query can be started and
finished by calling BeginQueryEXT and EndQueryEXT, respectively, with a
target of ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.
When an occlusion query is started with the target
ANY_SAMPLES_PASSED_EXT, the samples-boolean state maintained by the GL is
set to FALSE. While that occlusion query is active, the samples-boolean
state is set to TRUE if any fragment or sample passes the depth test. When
the occlusion query finishes, the samples-boolean state of FALSE or TRUE 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 target of
the query is ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, an implementation may
choose to use a less precise version of the test which can additionally set
the samples-boolean state to TRUE in some other implementation dependent
cases."
Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
None
Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and
State Requests)
Add a new section "Asynchronous Queries" between sections 6.1.5 and
6.1.6 and renumber subsequent sections:
"6.1.6 Asynchronous Queries
The command
boolean IsQueryEXT(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, IsQueryEXT returns FALSE.
Information about a query target can be queried with the command
void GetQueryivEXT(enum target, enum pname, int *params);
<target> identifies the query target, and must be one of
ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.
<pname> must be CURRENT_QUERY_EXT. The name of the currently active
query for <target>, or zero if no query is active, will be placed in
<params>.
The state of a query object can be queried with the command
void GetQueryObjectuivEXT(uint id, enum pname, uint *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. <pname> must be QUERY_RESULT_EXT or QUERY_RESULT_AVAILABLE_EXT.
If <pname> is QUERY_RESULT_EXT, 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.
There may be an indeterminate delay before the above query returns. If
<pname> is QUERY_RESULT_AVAILABLE_EXT, 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 any given query object forces that occlusion query
to complete within a finite amount of time. Repeatedly querying the
QUERY_RESULT_AVAILABLE_EXT state for any given query object is guaranteed
to return true eventually. Note that multiple queries to the same occlusion
object may result in a significant performance loss. For better performance
it is recommended to wait N frames before querying this state. N is
implementation dependent but is generally between one and three.
If multiple queries are issued using the same object name prior to calling
GetQueryObjectuivEXT, the result and availability information returned
will always be from the last query issued. The results from any queries
before the last one will be lost if they are not retrieved before starting
a new query on the same <target> and <id>."
Additions to Appendix C of the OpenGL ES 2.0 Specification (Shared Object and
Multiple Contexts)
Change the first sentence of the first paragraph of section C.1.2 to read:
"When a buffer, texture, renderbuffer, or query is deleted, ..."
Add the following sentence to the end of section C.1.2:
"A query object is in use so long as it is the active query object for a
query type and index, as described in section 2.13."
Errors
The error INVALID_OPERATION is generated if BeginQueryEXT is called
where <id> is not a name returned from a previous call to GenQueriesEXT,
or if such a name has since been deleted with DeleteQueriesEXT.
The error INVALID_OPERATION is generated if BeginQueryEXT is called
where <id> is zero.
The error INVALID_OPERATION is generated if BeginQueryEXT is called
where <id> is the name of an existing query object whose type does not
match <target>.
The error INVALID_OPERATION is generated if BeginQueryEXT is called
where <id> is the active query object name for any query type.
The error INVALID_OPERATION is generated if BeginQueryEXT is called
when the active query object name for either ANY_SAMPLES_PASSED_EXT or
ANY_SAMPLES_PASSED_CONSERVATIVE_EXT is non-zero.
The error INVALID_OPERATION is generated if EndQueryEXT is called
when the active query object name for <target> is zero.
The error INVALID_OPERATION is generated if GetQueryObjectuivEXT is
called where <id> is not the name of a query object.
The error INVALID_OPERATION is generated if GetQueryObjectuivEXT is
called where <id> is the name of a currently active query object.
The error INVALID_VALUE is generated if GenQueriesEXT is called where
<n> is negative.
The error INVALID_VALUE is generated if DeleteQueriesEXT is called
where <n> is negative.
The error INVALID_ENUM is generated if BeginQueryEXT, EndQueryEXT,
or GetQueryivEXT is called where <target> is not
ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.
The error INVALID_ENUM is generated if GetQueryivEXT is called where
<pname> is not CURRENT_QUERY_EXT.
The error INVALID_ENUM is generated if GetQueryObjectuivEXT is called
where <pname> is not QUERY_RESULT_EXT or QUERY_RESULT_AVAILABLE_EXT.
New State
(table 6.18, p. 233)
Int'l
Get Value Type Get Command Value Description Sec
-------------------------- ---- -------------------- ----- ---------------------- -----
- B - FALSE query active 4.1.6
CURRENT_QUERY_EXT Z+ GetQueryivEXT 0 active query ID 4.1.6
QUERY_RESULT_EXT B GetQueryObjectuivEXT FALSE samples-passed 4.1.6
QUERY_RESULT_AVAILABLE_EXT B GetQueryObjectuivEXT FALSE query result available 4.1.6
Issues
(1) What should the enum be called?
RESOLVED: The enum should be called ANY_SAMPLES_PASSED as in
ARB_occlusion_query2 to retain compatibility between the two
extensions.
(2) Can application-provided names be used as query object names?
ARB_occlusion_query allows application-provided names, but this
was later removed in core OpenGL.
RESOLVED: No, we will follow core OpenGL on this.
(3) Should calling GenQueries or DeleteQueries when a query is
active produce an error?
This behavior is in ARB_occlusion_query but was
removed in OpenGL 3.0.
RESOLVED: Not an error. Calling DeleteQueries marks the name
as no longer used, but the object is not deleted until it is no
longer in use (i.e. no longer active).
(4) What is the interaction with multisample?
RESOLVED: The query result is set to true if at least one
sample passes the depth test.
(5) Exactly what stage in the pipeline are we counting samples at?
RESOLVED: We are counting immediately after _both_ the depth and
stencil tests, i.e., samples that pass both. Note that the depth
test comes after the stencil test, so to say that it is the
number that pass the depth test is sufficient; though it is often
conceptually helpful to think of the depth and stencil tests as
being combined, because the depth test's result impacts the
stencil operation used.
(6) Is it guaranteed that occlusion queries return in order?
RESOLVED: Yes.
If occlusion test X occurred before occlusion query Y, and the driver
informs the app that occlusion query Y is done, the app can infer that
occlusion query X is also done.
(7) Will polling a query for QUERY_RESULT_AVAILABLE without a Flush
possibly cause an infinite loop?
RESOLVED: No.
(8) Should there be a "target" parameter to BeginQuery?
RESOLVED: Yes. This distinguishes the boolean queries
defined by this extension (and ARB_occlusion_query2) from
the counter queries defined by ARB_occlusion_query.
(9) 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.
(10) Should there be a limit on how many queries can be outstanding?
RESOLVED: No. If an implementation has an internal limit, it can
flush the pipeline when it runs out.
(11) Can an implementation sometimes return a conservative result,
i.e. return true even though no samples were drawn?
RESOLVED: Yes, but only when explicitly enabled by the
application.
Allowing such results with no restrictions effectively makes
the functionality of the extension optional, which decreases
its value. Precise restrictions are presumably hard to
specify.
One situation where this restriction could be relevant is if
an implementation performs a conservative early depth test at
a lower precision and wants to base the occlusion query result
on that whenever the early depth test can be used.
(12) Should the restrictions in issue 11 be explicitly enabled
by the application in order to be in effect?
RESOLVED: Yes.
The restrictions could be enabled by a hint call or by using
a different enum in the BeginQuery call.
This would enable the application to choose whether it wants a
precise (but possibly slow) version or an approximate (but
possibly faster) version.
(13) Can the restrictions in issue 18 be applied nondeterministically?
An implementation might benefit from taking the decision of
whether to apply a particular restriction on a case by case
basis. Some of these decisions could depend on
nondeterministic effects such as memory bus timing.
RESOLVED: No. This would violate the GL repeatability
principle.
(14) How does an application request that the result is allowed to
be conservative (as defined in issue 11)?
RESOLVED: It is specified as a separate query target,
ANY_SAMPLES_PASSED_CONSERVATIVE.
Revision History
Date: 5/03/2011
Revision: 1 (Benj Lipchak)
- Initial draft based on XXX_occlusion_query_boolean
Date: 7/22/2011
Revision: 2 (Benj Lipchak)
- Rename from APPLE to EXT