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

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
            }
        }
