Name ARB_occlusion_query2 Name Strings GL_ARB_occlusion_query2 Contributors Aske Simon Christensen Bill Licea-Kane Cass Everitt Jeff Bolz Maurice Ribble Contact Bill Licea-Kane (bill 'at' amd.com) Notice Copyright (c) 2010-2013 The Khronos Group Inc. Copyright terms at http://www.khronos.org/registry/speccopyright.html Specification Update Policy Khronos-approved extension specifications are updated in response to issues and bugs prioritized by the Khronos OpenGL Working Group. For extensions which have been promoted to a core Specification, fixes will first appear in the latest version of that core Specification, and will eventually be backported to the extension document. This policy is described in more detail at https://www.khronos.org/registry/OpenGL/docs/update_policy.php Status Complete. Approved by the ARB at the 2010/01/22 F2F meeting. Approved by the Khronos Board of Promoters on March 10, 2010. Version Date: March 21, 2010 Revision: 11 $Id$ Number ARB Extension #80 Dependencies Written based on the wording of OpenGL Specification Version 3.2 (Core Profile) - July 24, 2009 Version 3.2 (Compatibility Profile) interacts with this extension. OpenGL 1.x is required. ARB_occlusion_query interacts with this extension. Conditional rendering interacts with this extension. Overview This extension trivially adds a boolean occlusion query to ARB_occlusion_query. While the counter-based occlusion query provided by ARB_occlusion_query is flexible, there is still value to a simple boolean, which is often sufficient for applications. IP Status There are no known claims. HP claimed IP to a related extension, ARB_occlusion_query. HP committed to releasing rights to this IP to the ARB if the functionality is included in OpenGL (April 10, 2003). ARB_occlusion_query was promoted to core OpenGL 1.5 (July 29, 2003). New Procedures and Functions None New Tokens Accepted by the parameter of BeginQuery, EndQuery, and GetQueryiv: ANY_SAMPLES_PASSED 0x8C2F Additions to Chapter 2 of the OpenGL 3.2 Specification (OpenGL Operation) 2.14 Asynchronous Queries p. 89-90, replace last sentence of first paragraph Occlusion queries (see section 4.1.6) count the number of fragments or samples that pass the depth test, | or set a boolean to true when fragments or samples pass the depth | test. p. 90, modify the last paragraph before "The command void EndQuery..." BeginQuery sets the active query object name for the query type given by target to id. If BeginQuery is called with an id of zero, if the active query object name for target is non-zero | (for the targets SAMPLES_PASSED or ANY_SAMPLES PASSED, if the active query object | for either target is non-zero), if id is the name of an existing query object whose type does not match target, if id is the active query object name for any query type, or if id is the active query object for condtional rendering (see section 2.15), the error INVALID_OPERATION is generated. 2.15 Conditional Rendering p. 91 Add clause prior to "all rendering commands between" "or if the result (ANY_SAMPLES_PASSED) is false," Add clause prior to "such commands are not discarded." "or if the result is true," p. 92 Change last sentence of Section 2.15 The error INVALID_OPERATION is generated if id is the name of a query object with a target other than | SAMPLES_PASSED | or ANY_SAMPLES_PASSED, or id is the name of a query currently in progress. Additions to Chapter 4 of the OpenGL 3.2 Specification (Per-Fragment Operations and the Frame Buffer) p. 192, Replace 4.1.6 Occlusion Queries Occlusion queries use query objects to track fragments or samples that pass the depth test. An occlusion query can be started and finished by calling BeginQuery and EndQuery, respectively, with a target of | SAMPLES_PASSED or ANY_SAMPLES_PASSED. When an occlusion query is started | with the target SAMPLES_PASSED, the samples-passed count maintained by the GL is set to zero. While that occlusion query is active, the samples-passed count is incremented for each fragment that passes the depth test. If the value of SAMPLE_BUFFERS is 0, then the samples-passed count is incremented by 1 for each fragment. If the value of SAMPLE_BUFFERS is 1, then the samples-passed count is incremented by the number of samples whose coverage bit is set. However, implementations, at their discretion, may instead increase the samples-passed count by the value of SAMPLES if any sample in the fragment is covered. When an occlusion query finishes and all fragments generated by commands issued prior to EndQuery have been generated, the samples-passed count 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 samples-passed count overflows (exceeds the value 2^n - 1, where n is the number of bits in the samples-passed count), its value becomes undefined. It is recommended, but not required, that implementations handle this overflow case by saturating at 2^n - 1 and incrementing no further. | When an occlusion query is started with the target ANY_SAMPLES_PASSED, | 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. Additions to Chapter 6 of the OpenGL 3.2 Specification (State and State Requests) 6.1.6 Asynchronous Queries p. 255 Modify the Sentence beginning with "Information about the query target can be..." ...target idendifies the query target, and must be one of | SAMPLES_PASSED or ANY_SAMPLES_PASSED for occlusion queries... Modify the paragraph beginning with "For occlusion queries (SAMPLES_PASSED)..." For occlusion queries | (SAMPLES_PASSED and ANY_SAMPLES_PASSED), the number of bits | depends on the target. For a target of ANY_SAMPLES_PASSED, if | the number of bits is non-zero, the minimum number of bits is 1. For a target | of SAMPLES_PASSED, if the number of bits is non-zero, ... Dependencies Version 3.2 (Compatibility Profile) interacts with this extension. Other than adjusting the page numbers referenced in the edits, there are no further changes required for the Compatibility Profile specification. ARB_occlusion_query If ARB_occlusion_query is not supported, then delete the enum SAMPLES_PASSED and delete sections of text refering to SAMPLES_PASSED, and incorporate all other enums, entry points and state introduced by ARB_occlusion_query into this extension. Conditional Rendering If Conditional Rendering is not supported, delete edits to section on Conditional Rendering. New State (table 6.33, p. 298) Get Value Type Get Command Initial Value Description Sec Attribute --------- ---- ----------- ------------- ----------- ------ --------- QUERY_RESULT Z+ GetQueryObjectuiv 0 samples-passed count 6.1.6 - | FALSE or any-samples-passed | boolean value Usage Examples Here is some rough sample code that illustrates how this extension can be used. GLuint queries[N]; GLint sampleBoolean; GLint available; glGenQueries(N, queries); ... // before this point, render major occluders glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthMask(GL_FALSE); // also disable texturing and any fancy shaders for (i = 0; i < N; i++) { glBeginQuery(GL_ANY_SAMPLES_PASSED, queries[i]); // render bounding box for object i glEndQuery(GL_ANY_SAMPLES_PASSED); } glFlush(); // Do other work until "most" of the queries are back, to avoid // wasting time spinning i = N*3/4; // instead of N-1, to prevent the GPU from going idle do { DoSomeStuff(); glGetQueryObjectiv(queries[i], GL_QUERY_RESULT_AVAILABLE, &available); } while (!available); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDepthMask(GL_TRUE); // reenable other state, such as texturing for (i = 0; i < N; i++) { glGetQueryObjectuiv(queries[i], GL_QUERY_RESULT, &sampleBoolean); if (sampleBoolean != 0) { // render object i } } Here is some rough sample code for a simple multipass rendering application that does not use occlusion queries. for (i = 0; i < N; i++) { // First rendering pass glDisable(GL_BLEND); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); // configure shader 0 // render object i // Second rendering pass glEnable(GL_BLEND); glBlendFunc(...); glDepthFunc(GL_EQUAL); glDepthMask(GL_FALSE); // configure shader 1 // render object i } Here is the previous example, enhanced using occlusion queries. GLuint queries[N]; GLuint sampleBoolean; glGenQueries(N, queries); ... // First rendering pass plus almost-free visibility checks glDisable(GL_BLEND); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); // configure shader 0 for (i = 0; i < N; i++) { glBeginQuery(GL_ANY_SAMPLES_PASSED, queries[i]); // render object i glEndQuery(GL_ANY_SAMPLES_PASSED); } // Second pass only on objects that were visible glEnable(GL_BLEND); glBlendFunc(...); glDepthFunc(GL_EQUAL); glDepthMask(GL_FALSE); // configure shader 1 for (i = 0; i < N; i++) { glGetQueryObjectuiv(queries[i], GL_QUERY_RESULT, &sampleBoolean); if (sampleBoolean != 0) { // render object i } } Issues 1) Can an occlusion query with a target of SAMPLES_PASSED be active at the same time as an occlusion query with a target of ANY_SAMPLES_PASSED? Resolved. No! Specifically, it is an error to BeginQuery for the targets SAMPLES_PASSED or ANY_SAMPLES_PASSED if the active query is non-zero for EITHER target. 2) How many query types are there? Unresolved. The spec says "There are two query types" (p. 89), and list them as Transform Feedback Queries and Occlusion Queries. The spec says "Each type of query supported by the GL has an active query object name." (p. 90) Table 6.47 Miscellaneous (p. 312) says there are CURRENT_QUERY 3 x Z+. I believe there are three: Primitive Queries (target PRIMITIVES_GENERATED) Transform Feedback Queries (target TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) and Occlusion Queries (target SAMPLES_PASSED or ANY_SAMPLES_PASSED) It is probable that the spec should say "There are three query types" and list them as Primitive Queries (section 2.17), Transform Feedback Queries (section 2.16) and Occlusion Queries (section 4.1.6). A separate bug will be posted for the core specification to clarify Primitive Queries and Transform Feedback. This extension currently assumes that the bug will be resolved and only edits the Occlusion Queries type to expand it to two targets. 3) Can we limit the number of query objects active? Unresolved. This draft doesn't. But, yes, we can limit the number of query objects active. The language to do so would be straightforward, but why? There can only be ONE occlusion query active at a time. The query object created (or re-used) at BeginQuery contains the state to save the boolean. At EndQuery the boolean for the current query is copied to the query object's state. (Clearly, OES can make another choice. But not sure why right now.) 4) Currently, if a draw within BeginQuery/EndQuery passes a depth test, and a subsequent draw later covers all the pixels, can an implementation return false (assuming the application queried the result after the subsequent draw)? Unresolved. This draft defers the issue. The language to allow this is non-trivial. Please note, the typical application will: * set the color/depth masks to true, and blend state * draw the major occluders * draw visible opaque objects (coarsly sorted if possible) * set the color/depth masks to false * draw proxies for geometry which *might* be visible, with occlusion queries * set the color masks to true, and blend state * draw any transparent objects (sorted if possible) * swap * set the color/depth masks to true, and blend state * draw the major occluders * test the queries that are available from the prior frame * draw visible and newly visible opaque objects (coarsly sorted if possible) * set the color/depth masks to false * draw proxies for geometry which *might* be visible, with occlusion queries * set the color masks to true, and blend state * draw any transparent objects (sorted if possible) * swap This technique has the disadvantage that the newly exposed geometry is one frame late, but this is generally not considered an issue. The advantage that in general the results are available by the time the query is tested. Note that no opaque occluders follow the queries in a frame. Another common variation is: * set the color/depth masks to true, and blend state * draw the major occluders * draw the visible opaque objects (corsely sorted if possible) with occlusion queries * set the color/depth mask to false * draw proxies for geometry which *might* be visible, with occlusion queries * set the color masks to true, and blend state * draw any transparent objects (sorted if possible) * swap * set the color/depth masks to true, and blend state * draw the major occluders * test the queries that are available from the prior frame * draw the still visible and newly visible opaque objects (coarsely sorted if possible) with occlusion queries * set the color/depth mask to false * draw proxies for geometry which *might* be visible, with occlusion queries * set the color masks to true, and blend state * draw any transparent objects (sorted if possible) * swap This technique still has the disadvantage that newly exposed geometry is one frame late, but still not considered an issue. The advantage is that in general the results are available by the time the query is tested. This technique also culls geometry that was visible as it gets occluded. (Though there can be some "picket fence" issues and the occlusion query for actual geometry and proxy geometry can cycle between false-true.) Note that opaque occluders follow the queries in a frame. 5) What is this extension called? Resolved. Earlier drafts were EXT_occlusion_query2. This draft is ARB_occlusion_query2. 6) What should the enum be called? Resolved. ANY_SAMPLES_PASSED. 7) Do we need "state required" for occlusion query objects? Resolved. No. That listing of state required had been moved to asynchronous queries Section 2.14. It has been excised from the occlusion query section. 8) Can an occlusion query "morph" from SAMPLES_PASSED to ANY_SAMPLES_PASSED? That is, can the sequence BeginQuery( SAMPLES_PASSED )...EndQuery( ANY_SAMPLES_PASSED ) (or vice-versa)? Resolved. No. Note this falls naturally by leaving the EndQuery error language alone. ("If the active query object name for target is zero when EndQuery is called, the error INVALID_OPERATION is generated.") Revision History 2010-03-21 11, pbrown Minor typo/wording fixes. 2010-01-26 10, pbrown Assign enum value for ANY_SAMPLES_PASSED, using same allocation from OES_occlusion_query. Enums are functionally equivalent. 2010-01-21 9, wwlk JUST update version, date 2010-01-20 8, wwlk Update issue 1, add issues 7 and 8. Update the spec language to make it clear that you can't start an occlusion query if an occlusion query (of either type) is already active. Update the spec language to trivially clarify conditional rendering. 2009-12-10 7, Jon Leech Remove ARB suffixes for core 3.3 spec inclusion. Fix equation typos. 2009-11-13 6, wwlk Updated name and name strings to match ARB_occlusion_query2 2009-10-22 5, wwlk Renamed to ARB_occlusion_query2 (and changed EXT to ARB) Renamed ENUM (and updated ENUMs throughout) to ANY_SAMPLES_PASSED Misc typos (Synchronos, COmpatibility) 2009-10-02 4, wwlk Updates from comments. Renamed to EXT_occlusion_query_boolean Renamed ENUM(s) Elaborated on issue 4. 2009-09-29 3, wwlk updates from comments. Added issues 4,5,6. 2009-09-28 2, wwlk minor typo, add conditional rendering 2009-09-28 1, wwlk first draft