gl errors with occlusion queries

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
I'm using occlusion queries to modulate the brightness of the sun in my engine. It looks and works great. Now, for purposes of correctness, I use two occlusion queries, one to see how many fragments *would* pass ( drawn with color and depth buffers masked, and depth test turned off ) and the second drawn normally. I get a ratio of the two to modulate my glare.

I just ran my app under GL profiler to try to track down a bug elswhere and I see that I'm getting a GL_INVALID_OPERATION on my occlusion tests. The spec says:

Code:
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.

I have to assume one of these is my problem, but I'm not certain how to work around it. I was under the operation that any number of occlusion queries could be run simultaneously...

Here's my code:

Code:
void CelestialBody::displayHaloOcclusionQueryTest( void )
{
    Camera *camera = world()->activeCamera();
    if ( !camera ) return;

    /*
        The dot-product approaches 1.0 as the camera faces the body.
    */
    float d = camera->looking() * _dir,
          radius = sinf( _haloArcSize * DEG2RAD ) * camera->farPlane();

    /*
        No point going further if we're facing away
    */
    if ( d < EPSILON ) return;

    float size = d * d * radius,
          alpha = d;

    /*
        Read result from last frame's occlusion query.
        Then, perform a new occlusion query,
        and then draw our halo.
        
        Queries will be one frame old, but who's going to notice?
    */
    
    readOcclusionQueryResult();
    performOcclusionQuery();                    

    /*
        Use the result from the last occlusion query to
        modulate out halo.
    */

    alpha = clamp( _occlusionQueryResult * alpha, 0.0f, 1.0f );
    displayHalo( camera, size, alpha, false );        
}

void CelestialBody::performOcclusionQuery( void )
{
    Camera *camera = world()->activeCamera();

    float distance = camera->farPlane(),
          size = sinf( _arcSize * DEG2RAD ) * distance;

    vec3 pos( camera->position() + (_dir * distance )),
         up, right, down, left;

    camera->billboardVectors( up, right, down, left );
    
    right *= size;
    up *= size;
    left *= size;
    down *= size;
    
    vec3 ll( pos + left + down ),
         lr( pos + right + down ),
         ur( pos + right + up ),
         ul( pos + left + up );

    glActiveTextureARB( GL_TEXTURE0_ARB );
    glDisable( GL_TEXTURE_2D );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    
    glColor4f( 0,0,0,1 );

    glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
    glDepthMask( GL_FALSE );

    /*
        Run first query to see how many fragments *would* pass.
        To do this turn off depth test.
    */
    
    glDisable( GL_DEPTH_TEST );
    glBeginQuery( GL_SAMPLES_PASSED, _queryIDs[0] );

    glBegin( GL_QUADS );

        glVertex3fv( ll.v );
        glVertex3fv( lr.v );
        glVertex3fv( ur.v );
        glVertex3fv( ul.v );        

    glEnd();

    glEndQuery( GL_SAMPLES_PASSED );
        
    
    /*
        Run second query to see how many fragments *did* pass,
        by turning depth test back on.
    */

    glEnable( GL_DEPTH_TEST );
    glBeginQuery( GL_SAMPLES_PASSED, _queryIDs[1] );

    glBegin( GL_QUADS );

        glVertex3fv( ll.v );
        glVertex3fv( lr.v );
        glVertex3fv( ur.v );
        glVertex3fv( ul.v );        

    glEnd();

    glEndQuery( GL_SAMPLES_PASSED );
    

    glEnable( GL_TEXTURE_2D );
    glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );    
}

void CelestialBody::readOcclusionQueryResult( void )
{
    GLint fragmentsThatShouldPass = 0, fragmentsThatDidPass = 0;

    // !!! GL_INVALID_OPERATION thrown here...
    glGetQueryObjectivARB( _queryIDs[0], GL_QUERY_RESULT, &fragmentsThatShouldPass );
    glGetQueryObjectivARB( _queryIDs[1], GL_QUERY_RESULT, &fragmentsThatDidPass );

    if ( fragmentsThatShouldPass == 0 ) _occlusionQueryResult = 0.0f;    
    else _occlusionQueryResult = (float) fragmentsThatDidPass / (float) fragmentsThatShouldPass;
}

I get the GL_INVALID_OPERATION in the last method above, on the line:
Code:
    // !!! GL_INVALID_OPERATION thrown here...
    glGetQueryObjectivARB( _queryIDs[0], GL_QUERY_RESULT, &fragmentsThatShouldPass );

And here's the code that creates the query objects:

Code:
void CelestialBody::setUseOcclusionQuery( bool oq )
{
    /*
        Determine if occlusion querying is available, and if
        it's real.
    */
    
    _occlusionQueryAvailable = GLEW_ARB_occlusion_query;
    
    if ( _occlusionQueryAvailable )
    {
        GLint queryCounterBits = 0;
        glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &queryCounterBits);
        if ( queryCounterBits == 0 )
        {
            _occlusionQueryAvailable = false;
        }
    }
    
    if ( !_occlusionQueryAvailable )
    {
        using namespace PANSICore;
        Logger::log( LogEntry::Debug, "CelestialBody::setUseOcclusionQuery",
                     "OcclusionQuery is not available, using ray testing." );
                    
        oq = false;
    }

    if ( oq )
    {
        Ray_Delete( _ray );
        _ray = NULL;

        if ( !_queryIDs[0] )
        {
            glGenQueriesARB( 2, _queryIDs );
        }

        setRequiresStepping( false );
    }
    else
    {
        if ( !_ray )
        {
            _ray = new Ray( this );
        }
        
        if ( _queryIDs[0] )
        {
            glDeleteQueriesARB( 2, _queryIDs );
            _queryIDs[0] = 0;
            _queryIDs[1] = 0;
        }

        /*
            Need to be stepped to update the ray
        */
        setRequiresStepping( true );
    }
    
}

As far as I can tell, I'm doing the right thing. I've got two query objects, and I only run one at a time.

Any ideas?
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
UPDATE:

I changed my code which performs the query to check if the results are available ( as well as wether the query object names are valid ) and I still get the error, just now it's on the call to GL_QUERY_RESULT_AVAILABLE.

What's even more baffling is that if I tell Profiler to continue -- past the breaks on error -- once the first frame is done rendering it works fine.

Baffling!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  2D Pixel Collision Detection using OCCLUSION Elphaba 0 3,333 Jun 8, 2009 06:30 AM
Last Post: Elphaba
  Occlusion query code failing on ATI 9600 TomorrowPlusX 4 5,489 Mar 10, 2007 08:52 AM
Last Post: arekkusu
  Occlusion query failing for fogged occluders TomorrowPlusX 12 6,508 Jan 8, 2006 05:03 PM
Last Post: arekkusu
  Occlusion queries... SLOW. TomorrowPlusX 8 4,440 Aug 19, 2005 07:05 AM
Last Post: TomorrowPlusX