Krythic
Krythic

Reputation: 4364

OpenTK Graphics Card Crashing During Occlusion Culling

I recently implemented Frustum culling in my game, and in an attempt to squeeze every last drop out of my render cycle I also decided to implement Occlusion Culling. It works brilliantly, however, I was distressed to discover that if I dont look at anything in my game(If I look out into the void and away from my game objects) my graphics card literally crashes. I am running a voxel-type game, which means it is a world filled with cubes. If there is no cubes present in my line of sight the crash occurs.

Here is my render loop which contains the Occlusion code:

protected override void OnRenderFrame( FrameEventArgs e ) {
    base.OnRenderFrame( e );

    GL.MatrixMode( MatrixMode.Modelview );
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    GL.EnableClientState( ArrayCap.VertexArray );
    GL.EnableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );

    /**
     * Pass 1
     * Do Occlusion Testing
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    foreach( Voxel voxel in World.VisibleVoxels ) {
        if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
            try {
                GL.BeginQuery( QueryTarget.SamplesPassed , voxel.OcclusionID );
                voxel.Render( GameCamera );
                GL.EndQuery( QueryTarget.SamplesPassed );
            } catch( Exception ex ) {
                //
                Console.WriteLine( "Setting It" );
                Console.WriteLine( ex.StackTrace );
            }
        }
    }
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    /**
     * Pass 2
     * Normal Rendering
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    foreach( Voxel voxel in World.VisibleVoxels ) {
        if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
            try {
                GL.NV.BeginConditionalRender( voxel.OcclusionID , NvConditionalRender.QueryWaitNv );
                voxel.Render( GameCamera );
                GL.NV.EndConditionalRender();
            } catch( Exception ex ) {
                Console.WriteLine( "Testing It" );
                Console.WriteLine( ex.StackTrace );
            }

        }
    }
    GL.DisableClientState( ArrayCap.VertexArray );
    GL.DisableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    RenderDeveloperHud();
    SwapBuffers();
    this.Title = GAME_NAME + " FPS: " + ( int )this.RenderFrequency;
}

I desperatly need to find a solution for this. It seems to me that OpenTK/OpenGL flips its shit when there is nothing visible in my viewport, but I dont know why. The loop itself should pass through if nothing is visible. Am I missing something here?

I can literally reproduce this crash every time I start the game and look away from the level. And by crash I mean my entire monitor goes black, hangs up, and then resumes with a message saying my display driver stopped working

Upvotes: 0

Views: 379

Answers (3)

Lin JiaRui
Lin JiaRui

Reputation: 1

perhaps it is because you add the following line between two passes:

GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );

Upvotes: 0

Krythic
Krythic

Reputation: 4364

As much as it infuriates me, I have to answer my own question again. I think I pinpointed the error, although I dont particularly understand it...it doesnt crash anymore. Instead of having two passes, i compressed my render cycle down to a single iteration; this solved the graphics card crash. Anyone know why this works:

protected override void OnRenderFrame( FrameEventArgs e ) {

    base.OnRenderFrame( e );

    GL.MatrixMode( MatrixMode.Modelview );
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    GL.EnableClientState( ArrayCap.VertexArray );
    GL.EnableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );

    /**
     * Pass 1
     * Normal Rendering && Occlusion Test
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    if(NeedsOcclusionPass) {
        foreach(Voxel voxel in World.VisibleVoxels) {
            if(GameCamera.Frustum.SphereInFrustum(voxel.Location.X, voxel.Location.Y, voxel.Location.Z, 2.0f)) {
                GL.BeginQuery(QueryTarget.SamplesPassed, voxel.OcclusionID);
                voxel.Render(GameCamera);
                GL.EndQuery(QueryTarget.SamplesPassed);
            }
        }
        NeedsOcclusionPass = false;
    } else {
        foreach( Voxel voxel in World.VisibleVoxels ) {
            if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
                GL.NV.BeginConditionalRender( voxel.OcclusionID , NvConditionalRender.QueryNoWaitNv );
                voxel.Render( GameCamera );
                GL.NV.EndConditionalRender();
            }
        }
        NeedsOcclusionPass = true;
    }

    GL.DisableClientState( ArrayCap.VertexArray );
    GL.DisableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    //RenderDeveloperHud();
    SwapBuffers();
    this.Title = GAME_NAME + " FPS: " + ( int )this.RenderFrequency;
}

But my original code above causes a crash? Now I am just more confused than anything. (And no the issue was not caused by the double call of GameCamera.LookThrough(); It just seems that having two passes itself was the error.

Edit: After further testing and various forms of literature I have come to the conclusion that I was using the above code completely wrong. According to other sources, I should be disabling almost EVERYTHING before beginning the occlusion queries. This means: textures, lighting,and even the depth buffer. I still don't know what caused the crashing of my graphics card, however, it most certainly stems from my lack of understanding on the topic.

Upvotes: 0

The Fiddler
The Fiddler

Reputation: 2794

Applications can crash GPUs by passing invalid state or data - or sometimes even with valid ones.

Try using apitrace to trace the OpenGL commands issued to the driver and catch the command that is causing the crash.

Running your application with a debug version of OpenTK.dll will also help you catch errors: OpenTK will use GL.GetError() after every GL command and raise an exception if something is amiss. To build a debug version of OpenTK, download the source code and build OpenTK.sln.

Upvotes: 1

Related Questions