| Name |
| |
| ARB_occlusion_query |
| |
| Name Strings |
| |
| GL_ARB_occlusion_query |
| |
| Contributors |
| |
| Ross Cunniff |
| Matt Craighead |
| Daniel Ginsburg |
| Kevin Lefebvre |
| Bill Licea-Kane |
| Nick Triantos |
| |
| Contact |
| |
| Matt Craighead, NVIDIA Corporation (mcraighead 'at' nvidia.com) |
| Daniel Ginsburg, AMD (dan.ginsburg 'at' amd.com) |
| |
| Notice |
| |
| Copyright (c) 2003-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 |
| |
| IP Status |
| |
| HP has claimed that they hold IP around use of this extension. HP |
| has committed to releasing rights to this IP to the ARB if the |
| functionality is included in OpenGL (April 10, 2003). |
| |
| Status |
| |
| Approved by the ARB (version 1.0), June 10, 2003, pending further minor |
| revisions |
| |
| Version |
| |
| Date: April 21, 2007 |
| Revision: 7 |
| $Id$ |
| |
| Number |
| |
| ARB Extension #29 |
| |
| Dependencies |
| |
| Written based on the wording of the OpenGL 1.4 specification. |
| |
| HP_occlusion_test affects the definition of this extension. |
| |
| Overview |
| |
| This extension defines a mechanism whereby an application can query |
| the number of pixels (or, more precisely, samples) 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 the bounding box of each |
| detail object in the scene. Only if said bounding box is visible, |
| i.e., if at least one sample is drawn, should the corresponding object |
| be drawn. |
| |
| The earlier HP_occlusion_test extension defined a similar mechanism, |
| but it had two major shortcomings. |
| |
| - It returned the result as a simple GL_TRUE/GL_FALSE result, when in |
| fact it is often useful to know exactly how many samples were |
| drawn. |
| - It provided only a simple "stop-and-wait" model for using multiple |
| queries. The application begins an occlusion test and ends it; |
| then, at some later point, it asks for the result, at which point |
| the driver must stop and wait until the result from the previous |
| test is back before the application can even begin the next one. |
| This is a very simple model, but its performance is mediocre when |
| an application wishes to perform many queries, and it eliminates |
| most of the opportunities for parallelism between the CPU and GPU. |
| |
| This extension solves both of those problems. It returns as its |
| result the number of samples that pass the depth and stencil tests, |
| and it encapsulates occlusion queries in "query objects" that allow |
| applications to issue many queries before asking for the result of |
| any one. As a result, they can overlap the time it takes for the |
| occlusion query results to be returned with other, more useful work, |
| such as rendering other parts of the scene or performing other |
| computations on the CPU. |
| |
| There are many situations where a pixel/sample count, rather than a |
| boolean result, is useful. |
| |
| - Objects that are visible but cover only a very small number of |
| pixels can be skipped at a minimal reduction of image quality. |
| - Knowing exactly how many pixels an object might cover may help the |
| application decide which level-of-detail model should be used. If |
| only a few pixels are visible, a low-detail model may be |
| acceptable. |
| - "Depth peeling" techniques, such as order-independent transparency, |
| need to know when to stop rendering more layers; it is difficult to |
| determine a priori how many layers are needed. A boolean result |
| allows applications to stop when more layers will not affect the |
| image at all, but this will likely result in unacceptable |
| performance. Instead, it makes more sense to stop rendering when |
| the number of pixels in each layer falls below a given threshold. |
| - Occlusion queries can replace glReadPixels of the depth buffer to |
| determine whether (for example) a light source is visible for the |
| purposes of a lens flare effect or a halo to simulate glare. Pixel |
| counts allow you to compute the percentage of the light source that |
| is visible, and the brightness of these effects can be modulated |
| accordingly. |
| |
| Issues |
| |
| How is this extension different from NV_occlusion_query? |
| |
| The following changes have been made. |
| - A "target" parameter has been added. Only one target exists at |
| present, SAMPLES_PASSED_ARB, but future extensions could add |
| additional types of queries. |
| - Terminology changed slightly. "Pixel" was being used |
| incorrectly, where "fragment" or "sample" would be more |
| accurate. |
| - Various NVIDIA-specific references have been removed. |
| - Interactions with multisample have been changed slightly to |
| allow implementations based on either a sample count or a |
| fragment count. The result is returned in units of samples. |
| - Clarified that using an id of zero is illegal. |
| - Added missing spec language for IsQuery entry point. |
| - General language, issues, etc. cleanup. |
| - HP_occlusion_test is no longer required. |
| - Modified the minimum required counter bits to be dependent on |
| the implementation's maximum viewport or the value 0 |
| - Clarified that active query state is per target server state. |
| This implies that a loop of QUERY_RESULT_AVAILABLE_ARB will |
| return TRUE in finite time. NV_occlusion_query asked |
| that the application flush to prevent an infinite loop. |
| - Clarified the behavior of the async QUERY_RESULT_AVAILABLE_ARB |
| command. |
| - When the count of samples that pass the occlusion query overflows, |
| the value should saturate. |
| |
| Should we use an object-based interface? |
| |
| RESOLVED: Yes, this makes the interface much simpler, and it is |
| friendly for indirect rendering. |
| |
| What is the difference between a "query object" and an "occlusion |
| query"? |
| |
| "Occlusion query" is a synonym for "query object used with target |
| SAMPLES_PASSED". |
| |
| Should we offer a way to poll whether an occlusion query has |
| completed and its result is available? |
| |
| RESOLVED. Yes, this allows applications to use CPU time that might |
| have been spent spinning more usefully. However, the polling |
| method introduced in the NV_occlusion_query spec allowed for a |
| potential infinite loop if the application does not do a flush. |
| This version of the spec clarifies the behavior which now makes such |
| a flush unnecessary. |
| |
| Is GetQueryObjectuivARB necessary? |
| |
| RESOLVED: Yes, it makes using a 32-bit count less painful. |
| |
| Should there be a limit on how many queries can be outstanding? |
| |
| RESOLVED: No. This would make the extension much more |
| difficult to spec and use. Allowing this does not add any |
| significant implementation burden; and even if drivers have some |
| internal limit on the number of outstanding queries, it is not |
| expected that applications will need to know this to achieve |
| optimal or near-optimal performance. |
| |
| What happens if BeginQueryARB is called when a query is already |
| outstanding for a different object on the same target? |
| |
| RESOLVED: This is an INVALID_OPERATION error. |
| |
| What happens if BeginQueryARB is called with an ID of a query that is |
| already in progress? |
| |
| RESOLVED: This is also an INVALID_OPERATION error. |
| |
| What parameters should EndQueryARB have? |
| |
| RESOLVED: Just a target. It doesn't need to take an "id" |
| argument, since this would be redundant -- only one query can be |
| active for any given target at a given time. |
| |
| How many bits should we require the samples-passed count to be, at |
| minimum? |
| |
| RESOLVED. The largest minimum that can be required of a GL |
| implementation is 32, the minimum bit width of an int or uint. |
| |
| The minimum number of bits required for the samples-passed |
| count will be dependent on the implementation's maximum viewport size. |
| In order to allow for two overdraws in the case of only one sample |
| buffer, the minimum counter precision (n) will be determined by: |
| |
| n = min (32 , ceil (log2 (maxViewportWidth x maxViewportHeight x |
| 1 sample x 2 overdraws) ) ) |
| |
| An implementation can either set QUERY_COUNTER_BITS_ARB to the |
| value 0, or to some number greater than or equal to n. If an |
| implementation returns 0 for QUERY_COUNTER_BITS_ARB, then the |
| occlusion queries will always return that zero samples passed the |
| occlusion test, and so an application should not use occlusion queries |
| on that implementation. |
| |
| Note that other targets may come along in the future that require more |
| or fewer bits. |
| |
| What should we do about overflows? |
| |
| RESOLVED: Overflows are required to saturate, though it is expected |
| that several current implementations will not conform to this |
| requirement. |
| |
| The ideal behavior is to saturate. This ensures that you always |
| get a "large" result when you render many samples. It also |
| ensures that apps which want a boolean test can do this without |
| worrying about the rare case where the result ends up exactly at |
| zero after wrapping. |
| |
| Either way, it's unlikely that this matters much as long as a |
| sufficient number of bits are required. |
| |
| What is the interaction with multisample? |
| |
| RESOLVED: We count samples, not pixels -- even if MULTISAMPLE is |
| disabled but SAMPLE_BUFFERS is 1. |
| |
| A given fragment may have anywhere between zero and SAMPLES of |
| its samples covered. Ideally, the samples-passed count would be |
| incremented by the precise number of samples, but we permit |
| implementations to instead increment the samples-passed count by |
| SAMPLES if at least one sample in a given fragment is covered. |
| |
| Note that the depth/stencil test optimization whereby |
| implementations may choose to depth test at only one of the |
| samples when MULTISAMPLE is disabled does not cause this to |
| become ill-specified, because we are counting the number of |
| samples that are still alive _after_ the depth test stage. The |
| particular mechanism used to decide whether to kill or keep those |
| samples is not relevant. |
| |
| 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. |
| |
| Is it guaranteed that occlusion queries return in order? |
| |
| RESOLVED: Yes. It makes sense to do this. 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. For applications that do poll, this allows |
| them to do so with less effort. |
| |
| Will polling a query without a Flush possibly cause an infinite loop? |
| |
| RESOLVED: No. An infinite loop was possible in the original |
| NV_occlusion_query spec if an application did not perform a |
| flush prior to polling. This behavior was removed in this version |
| of the spec as it violated language in the core GL spec. |
| |
| Instead of allowing for an infinite loop, performing a |
| QUERY_RESULT_AVAILABLE_ARB will perform a flush if the result |
| is not ready yet on the first time it is queried. This ensures |
| that the async query will return true in finite time. |
| |
| This behavior is not a significant performance loss over the original |
| version of the spec. A flush would need to be performed at some |
| point anyway and the flush performed when QUERY_RESULT_AVAILABLE_ARB |
| is requested will only occur *if the result is not back yet*. |
| |
| What should be the interaction between this spec and |
| HP_occlusion_test? |
| |
| RESOLVED: Whereas NV_occlusion_query required that you implement |
| HP_occlusion_test, and even went so far as to specify the precise |
| behavior of HP_occlusion_test (since the HP_occlusion_test spec |
| did not contain those details), this spec does not. This spec |
| explains the interaction with HP_occlusion_test, but does not |
| attempt to double as a spec for that extension. |
| |
| What happens if HP_occlusion_test and ARB_occlusion_query usage is |
| overlapped? |
| |
| RESOLVED: The two can be overlapped safely. Counting is enabled |
| if either an occlusion query is active *or* OCCLUSION_TEST_HP is |
| enabled. The alternative (producing an error) does not work -- |
| it would require that PopAttrib be capable of producing an error, |
| which would be rather problematic. |
| |
| Note that BeginQueryARB, not EndQueryARB, resets the sample |
| count (and therefore the occlusion test result). This can avoid |
| certain types of strange behavior where an occlusion query's |
| samples-passed count does not always correspond to the samples |
| rendered during the occlusion query. The spec would make sense |
| the other way, but the behavior would be strange. |
| |
| Should there be a "target" parameter to BeginQueryARB? |
| |
| RESOLVED: Yes. Whereas NV_occlusion_query wasn't trying to solve |
| a problem beyond simple occlusion queries, this extension creates |
| a framework useful for future queries. |
| |
| Does GenQueriesARB need a "target" parameter? |
| |
| RESOLVED: No. A query can be reused any number of times with any |
| targets. |
| |
| How can one ask for the currently active query? |
| |
| RESOLVED: A new entry point has been added to query information |
| about a given query target. This makes it unnecessary to add two |
| new enumerants (# of bits and current query ID) for each new |
| target that is introduced. |
| |
| 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. |
| |
| What happens when an app begins a query on a target, ends it, begins |
| a query on the same target with the same id, ends it, and then tries |
| to retrieve data about the query using GetQueryObjecti[u]vARB? Which |
| query does the GetQueryObjecti[u]vARB return results for? |
| |
| RESOLVED. In this case, the result retrieved from |
| GetQueryObjecti[u]vARB will be from the last query on that target and |
| id. The result returned from GetQueryObjecti[u]vARB will always be from |
| the last BeginQueryARB/EndQueryARB pair on that target and id. |
| |
| Is this extension useful for saving geometry, fill rate, or both? |
| |
| The answer to this question is to some extent implementation- |
| dependent, but it is expected that it is most useful for reducing |
| geometry workload, and less so for fill rate. |
| |
| For the cost of rendering a bounding box, you can potentially |
| save rendering a normal object. A bounding box consists of only |
| 12 triangles, whereas the original object might have contained |
| thousands or even millions of triangles. |
| |
| Using bounding box occlusion queries may either help or hurt in |
| fill-limited situations, because rendering the pixels of a |
| bounding box is not free. In most situations, a bounding box |
| will probably have more pixels than the original object. Those |
| pixels can probably be rendered more quickly, though, since they |
| involve only Z reads (no Z writes or color traffic), and they |
| need not be textured or otherwise shaded. |
| |
| In multipass rendering situations, however, occlusion queries can |
| almost always save fill rate, because wrapping an object with an |
| occlusion query is generally cheap. See "Usage Examples" for an |
| illustration. |
| |
| What can be said about guaranteeing correctness when using |
| occlusion queries, especially as it relates to invariance? |
| |
| Invariance is critical to guarantee the correctness of occlusion |
| queries. If occlusion queries go through a different code path |
| than standard rendering, the fragments rendered may be different. |
| |
| However, the invariance issues are difficult at best to solve. |
| Because of the vagaries of floating-point precision, it is |
| difficult to guarantee that rendering a bounding box will render |
| at least as many pixels with equal or smaller Z values than the |
| object itself would have rendered. |
| |
| Likewise, many other aspects of rendering state tend to be |
| different when performing an occlusion query. Color and depth |
| writes are typically disabled, as are texturing, vertex programs, |
| and any fancy per-fragment math. So unless all these features |
| have guarantees of invariance themselves (unlikely at best), |
| requiring invariance for ARB_occlusion_query would be futile. |
| |
| In general, implementations are recommended to be fully invariant |
| with respect to whether any given type of query is active, |
| insofar as it is possible. That is, having an occlusion query |
| active should not affect the operation of any other stage of the |
| pipeline. Following this rule is essential to numerous occlusion |
| query algorithms working correctly. However, to permit |
| implementations where this feature is implemented in software, |
| this rule is only a recommendation, not a requirement. |
| |
| Another unrelated problem that can threaten correctness is near |
| and far clipping. The bounding box of an object may penetrate |
| the near clip plane, even though the original object may not |
| have. In such a circumstance, a bounding box occlusion query may |
| produce an incorrect result. Whenever you design an algorithm |
| using occlusion queries, it is best to be careful about the near |
| and far clip planes. |
| |
| How can frame-to-frame coherency help applications using this |
| extension get even higher performance? |
| |
| Usually, if an object is visible one frame, it will be visible |
| the next frame, and if it is not visible, it will not be visible |
| the next frame. |
| |
| Of course, for most applications, "usually" isn't good enough. |
| It is undesirable, but acceptable, to render an object that |
| *isn't* visible, because that only costs performance. It is |
| generally unacceptable to *not* render an object that *is* |
| visible. |
| |
| The simplest approach is that visible objects should be checked |
| every N frames (where, say, N=5) to see if they have become |
| occluded, while objects that were occluded last frame must be |
| rechecked again in the current frame to guarantee that they are |
| still occluded. This will reduce the number of wasteful |
| occlusion queries by almost a factor of N. |
| |
| Other, more complicated techniques exist but are beyond the scope |
| of this extension document. |
| |
| Do occlusion queries make other visibility algorithms obsolete? |
| |
| No. |
| |
| Occlusion queries are helpful, but they are not a cure-all. They |
| should be only one of many items in your bag of tricks to decide |
| whether objects are visible or invisible. They are not an excuse |
| to skip frustum culling, or precomputing visibility using portals |
| for static environments, or other standard visibility techniques. |
| |
| New Procedures and Functions |
| |
| void GenQueriesARB(sizei n, uint *ids); |
| void DeleteQueriesARB(sizei n, const uint *ids); |
| boolean IsQueryARB(uint id); |
| void BeginQueryARB(enum target, uint id); |
| void EndQueryARB(enum target); |
| void GetQueryivARB(enum target, enum pname, int *params); |
| void GetQueryObjectivARB(uint id, enum pname, int *params); |
| void GetQueryObjectuivARB(uint id, enum pname, uint *params); |
| |
| New Tokens |
| |
| Accepted by the <target> parameter of BeginQueryARB, EndQueryARB, |
| and GetQueryivARB: |
| |
| SAMPLES_PASSED_ARB 0x8914 |
| |
| Accepted by the <pname> parameter of GetQueryivARB: |
| |
| QUERY_COUNTER_BITS_ARB 0x8864 |
| CURRENT_QUERY_ARB 0x8865 |
| |
| Accepted by the <pname> parameter of GetQueryObjectivARB and |
| GetQueryObjectuivARB: |
| |
| QUERY_RESULT_ARB 0x8866 |
| QUERY_RESULT_AVAILABLE_ARB 0x8867 |
| |
| Additions to Chapter 2 of the OpenGL 1.4 Specification (OpenGL Operation) |
| |
| Modify Section 2.1, OpenGL Fundamentals (p. 4) |
| |
| (modify fourth paragraph, p. 4) It also means that queries and |
| pixel read operations return state consistent with complete |
| execution of all previously invoked GL commands, except where |
| explicitly specified otherwise |
| |
| Additions to Chapter 3 of the OpenGL 1.4 Specification (Rasterization) |
| |
| None. |
| |
| Additions to Chapter 4 of the OpenGL 1.4 Specification (Per-Fragment |
| Operations and the Frame Buffer) |
| |
| Add a new section "Occlusion Queries" between sections 4.1.6 and |
| 4.1.7: |
| |
| "4.1.6A Occlusion Queries |
| |
| Occlusion queries can be used to track the number of fragments or |
| samples that pass the depth test. |
| |
| Occlusion queries are associated with query objects. The command |
| |
| void GenQueriesARB(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 BeginQueryARB. 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 DeleteQueriesARB(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. |
| |
| An occlusion query can be started and finished by calling |
| |
| void BeginQueryARB(enum target, uint id); |
| void EndQueryARB(enum target); |
| |
| where <target> is SAMPLES_PASSED_ARB. If BeginQueryARB is called |
| with an unused <id>, that name is marked as used and associated with |
| a new query object. If BeginQueryARB is called while another query |
| is already in progress with the same target, an INVALID_OPERATION |
| error is generated. If EndQueryARB is called while no query with the |
| same target is in progress, an INVALID_OPERATION error is generated. |
| Calling either GenQueriesARB or DeleteQueriesARB while any query of |
| any target is active causes an INVALID_OPERATION error to be |
| generated. |
| |
| BeginQueryARB with a <target> of SAMPLES_PASSED_ARB resets the |
| current samples-passed count to zero and sets the query active |
| state to TRUE and the active query id to <id>. EndQueryARB with |
| a target of SAMPLES_PASSED_ARB initializes a copy of the current |
| samples-passed count into the active occlusion query object's results |
| value, sets the active occlusion query object's result available to |
| FALSE, sets the query active state to FALSE, and the active query |
| id to 0. |
| |
| If BeginQueryARB is called with an <id> of zero, or where <id> is the |
| name of a query currently in progress, an INVALID_OPERATION error is |
| generated. |
| |
| When an occlusion query is active, the samples-passed count increases |
| by a certain quantity for each fragment that passes the depth test. |
| If the value of SAMPLE_BUFFERS is 0, then the samples-passed count |
| increases by 1 for each fragment. If the value of SAMPLE_BUFFERS is |
| 1, then the samples-passed count increases by the number of samples |
| whose coverage bit is set. However, implementations, at their |
| discretion, are allowed to instead increase the samples-passed count |
| by the value of SAMPLES if any sample in the fragment is covered. |
| |
| If the samples-passed count overflows, i.e., 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. |
| |
| The necessary state is a single bit indicating whether an occlusion |
| query is active, the identifier of the currently active occlusion |
| query, and a counter keeping track of the number of samples that |
| have passed." |
| |
| Additions to Chapter 5 of the OpenGL 1.4 Specification (Special Functions) |
| |
| Add to the end of Section 5.4 "Display Lists": |
| |
| "DeleteQueriesARB, GenQueriesARB, IsQueryARB, GetQueryivARB, |
| GetQueryObjectivARB, and GetQueryObjectuivARB are not compiled into |
| display lists but are executed immediately." |
| |
| Additions to Chapter 6 of the OpenGL 1.4 Specification (State and |
| State Requests) |
| |
| Add a new section 6.1.13 "Occlusion Queries": |
| |
| "The command |
| |
| boolean IsQueryARB(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, IsQueryARB returns FALSE. |
| |
| Information about a query target can be queried with the command |
| |
| void GetQueryivARB(enum target, enum pname, int *params); |
| |
| If <pname> is CURRENT_QUERY_ARB, 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_ARB, the number of bits in the counter for |
| <target> will be placed in <params>. The minimum number of query counter |
| bits allowed is a function of the implementation's maximum viewport |
| dimensions (MAX_VIEWPORT_DIMS). If the counter is non-zero, then the |
| counter must be able to represent at least two overdraws for every pixel |
| in the viewport using only one sample buffer. The formula to compute the |
| allowable minimum value is below (where n is the minimum number of bits): |
| |
| n = (min (32, ceil (log2 (maxViewportWidth x maxViewportHeight x 2) ) ) ) or |
| 0 |
| |
| If the value of n is 0, then the result from GetQueryiv(SAMPLES_PASSED_ARB) |
| will always return 0, |
| |
| The state of a query object can be queried with the commands |
| |
| void GetQueryObjectivARB(uint id, enum pname, int *params); |
| void GetQueryObjectuivARB(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. |
| |
| If <pname> is QUERY_RESULT_ARB, then the query object's result value |
| is placed in <params>. |
| |
| Often, query object results will be returned asynchronously with |
| respect to the host processor's operation. As a result, sometimes, |
| if a result is queried, the host must wait until the result is back. |
| If <pname> is QUERY_RESULT_AVAILABLE_ARB, the value placed in |
| <params> indicates whether or not such a wait would occur if the |
| result of that query object were to be queried presently. A result |
| of TRUE means no wait would be required; a result of FALSE means that |
| some wait would occur. It must always be true that if the result for one |
| query is available, the result for all previous queries must also be |
| available at that point in time. |
| |
| Querying the state for a given occlusion query forces that occlusion |
| 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]iVARB, 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." |
| |
| Dependencies on HP_occlusion_test |
| |
| When GetIntegerv is called with <pname> of OCCLUSION_TEST_RESULT_HP, |
| the current samples-passed count is reset to zero. The occlusion |
| test result is TRUE when the samples-passed count is nonzero, and |
| FALSE when it is zero. Sample counting is active (i.e. the samples- |
| passed count increases as fragments are drawn) whenever either an |
| occlusion query is active *or* OCCLUSION_TEST_HP is enabled. |
| |
| GLX Protocol |
| |
| Seven new GL commands are added. |
| |
| The following two rendering commands are sent to the server as part |
| of a glXRender request: |
| |
| BeginQueryARB |
| 2 12 rendering command length |
| 2 231 rendering command opcode |
| 4 ENUM target |
| 4 CARD32 id |
| |
| EndQueryARB |
| 2 8 rendering command length |
| 2 232 rendering command opcode |
| 4 ENUM target |
| |
| The remaining fivecommands are non-rendering commands. These |
| commands are sent separately (i.e., not as part of a glXRender or |
| glXRenderLarge request), using glx single requests: |
| |
| DeleteQueriesARB |
| 1 CARD8 opcode (X assigned) |
| 1 161 GLX opcode |
| 2 3+n request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 INT32 n |
| n*4 LISTofCARD32 ids |
| |
| GenQueriesARB |
| 1 CARD8 opcode (X assigned) |
| 1 162 GLX opcode |
| 2 3 request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 INT32 n |
| => |
| 1 1 reply |
| 1 unused |
| 2 CARD16 sequence number |
| 4 n reply length |
| 24 unused |
| n*4 LISTofCARD32 queries |
| |
| IsQueryARB |
| 1 CARD8 opcode (X assigned) |
| 1 163 GLX opcode |
| 2 3 request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 CARD32 id |
| => |
| 1 1 reply |
| 1 unused |
| 2 CARD16 sequence number |
| 4 0 reply length |
| 4 BOOL32 return value |
| 20 unused |
| |
| GetQueryivARB |
| 1 CARD8 opcode (X assigned) |
| 1 164 GLX opcode |
| 2 4 request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 ENUM target |
| 4 ENUM pname |
| => |
| 1 1 reply |
| 1 unused |
| 2 CARD16 sequence number |
| 4 m reply length, m=(n==1?0:n) |
| 4 unused |
| 4 CARD32 n |
| |
| if (n=1) this follows: |
| |
| 4 INT32 params |
| 12 unused |
| |
| otherwise this follows: |
| |
| 16 unused |
| n*4 LISTofINT32 params |
| |
| GetQueryObjectivARB |
| 1 CARD8 opcode (X assigned) |
| 1 165 GLX opcode |
| 2 4 request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 CARD32 id |
| 4 ENUM pname |
| => |
| 1 1 reply |
| 1 unused |
| 2 CARD16 sequence number |
| 4 m reply length, m=(n==1?0:n) |
| 4 unused |
| 4 CARD32 n |
| |
| if (n=1) this follows: |
| |
| 4 INT32 params |
| 12 unused |
| |
| otherwise this follows: |
| |
| 16 unused |
| n*4 LISTofINT32 params |
| |
| GetQueryObjectuivARB |
| 1 CARD8 opcode (X assigned) |
| 1 166 GLX opcode |
| 2 4 request length |
| 4 GLX_CONTEXT_TAG context tag |
| 4 CARD32 id |
| 4 ENUM pname |
| => |
| 1 1 reply |
| 1 unused |
| 2 CARD16 sequence number |
| 4 m reply length, m=(n==1?0:n) |
| 4 unused |
| 4 CARD32 n |
| |
| if (n=1) this follows: |
| |
| 4 CARD32 params |
| 12 unused |
| |
| otherwise this follows: |
| |
| 16 unused |
| n*4 LISTofCARD32 params |
| |
| Errors |
| |
| The error INVALID_VALUE is generated if GenQueriesARB is called where |
| <n> is negative. |
| |
| The error INVALID_VALUE is generated if DeleteQueriesARB is called |
| where <n> is negative. |
| |
| The error INVALID_OPERATION is generated if GenQueriesARB or |
| DeleteQueriesARB is called when a query of any target is active. |
| |
| The error INVALID_ENUM is generated if BeginQueryARB, EndQueryARB, or |
| GetQueryivARB is called where <target> is not SAMPLES_PASSED_ARB. |
| |
| The error INVALID_OPERATION is generated if BeginQueryARB is called |
| when a query of the given <target> is already active. |
| |
| The error INVALID_OPERATION is generated if EndQueryARB is called |
| when a query of the given <target> is not active. |
| |
| The error INVALID_OPERATION is generated if BeginQueryARB is called |
| where <id> is zero. |
| |
| The error INVALID_OPERATION is generated if BeginQueryARB is called |
| where <id> is is the name of a query currently in progress. |
| |
| The error INVALID_ENUM is generated if GetQueryivARB is called where |
| <pname> is not QUERY_COUNTER_BITS_ARB or CURRENT_QUERY_ARB. |
| |
| The error INVALID_OPERATION is generated if GetQueryObjectivARB or |
| GetQueryObjectuivARB is called where <id> is not the name of a query |
| object. |
| |
| The error INVALID_OPERATION is generated if GetQueryObjectivARB or |
| GetQueryObjectuivARB is called where <id> is the name of a currently |
| active query object. |
| |
| The error INVALID_ENUM is generated if GetQueryObjectivARB or |
| GetQueryObjectuivARB is called where <pname> is not QUERY_RESULT_ARB |
| or QUERY_RESULT_AVAILABLE_ARB. |
| |
| The error INVALID_OPERATION is generated if any of the commands |
| defined in this extension is executed between the execution of Begin |
| and the corresponding execution of End. |
| |
| New State |
| |
| (table 6.18, p. 233) |
| |
| Get Value Type Get Command Initial Value Description Sec Attribute |
| --------- ---- ----------- ------------- ----------- ------ --------- |
| - B - FALSE query active 4.1.6A - |
| CURRENT_QUERY_ARB Z+ GetQueryiv 0 active query ID 4.1.6A - |
| QUERY_RESULT_ARB Z+ GetQueryObjectuivARB 0 samples-passed count 4.1.6A - |
| QUERY_RESULT_AVAILABLE_ARB B GetQueryObjectivARB FALSE query result available 4.1.6A - |
| |
| New Implementation Dependent State |
| |
| (table 6.29, p. 224) Add the following entry: |
| |
| Get Value Type Get Command Minimum Value Description Sec Attribute |
| -------------------------- ---- ----------- ------------- ---------------- ------ -------------- |
| QUERY_COUNTER_BITS_ARB Z+ GetQueryiv see 6.1.13 Number of bits in 6.1.13 - |
| query counter |
| |
| Revision History |
| |
| Date: 4/21/2007 |
| Revision: 7 (Jon Leech) |
| - Added QUERY_RESULT_ARB and QUERY_RESULT_AVAILABLE to state table |
| 6.18 (also fixed in OpenGL 2.1 spec). |
| |
| Date: 11/4/2006 |
| Revision: 6 (Benj Lipchak, AMD) |
| - Updated contact info after ATI/AMD merger. |
| |
| Date: 10/27/2004 |
| Revision: 5? (James Jones, NVIDIA) |
| - Added GLX protocol. |
| |
| Usage Examples |
| |
| Here is some rough sample code that illustrates how this extension |
| can be used. |
| |
| GLuint queries[N]; |
| GLuint sampleCount; |
| GLint available; |
| GLuint bitsSupported; |
| |
| // check to make sure functionality is supported |
| glGetQueryiv(GL_QUERY_COUNTER_BITS_ARB, &bitsSupported); |
| if (bitsSupported == 0) { |
| // render scene without using occlusion queries |
| } |
| |
| glGenQueriesARB(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++) { |
| glBeginQueryARB(GL_SAMPLES_PASSED_ARB, queries[i]); |
| // render bounding box for object i |
| glEndQueryARB(GL_SAMPLES_PASSED_ARB); |
| } |
| |
| 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(); |
| glGetQueryObjectivARB(queries[i], |
| GL_QUERY_RESULT_AVAILABLE_ARB, |
| &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++) { |
| glGetQueryObjectuivARB(queries[i], GL_QUERY_RESULT_ARB, |
| &sampleCount); |
| if (sampleCount > 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 sampleCount; |
| |
| glGenQueriesARB(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++) { |
| glBeginQueryARB(GL_SAMPLES_PASSED_ARB, queries[i]); |
| // render object i |
| glEndQueryARB(GL_SAMPLES_PASSED_ARB); |
| } |
| |
| // 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++) { |
| glGetQueryObjectuivARB(queries[i], GL_QUERY_RESULT_ARB, |
| &sampleCount); |
| if (sampleCount > 0) { |
| // render object i |
| } |
| } |