0

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

Krythic
  • 4,184
  • 5
  • 26
  • 67
  • Can `_mousePosition` change asynchronously? You call `GameCamera.LookThrough()` before both loops. You probably need to use the same view transformation for the occlusion pass and the rendering pass. Not sure why you would set up the view twice anyway. – Reto Koradi Sep 16 '14 at 12:54
  • As far as I am aware, I need to look through the camera before each pass to properly setup my View Frustum. I also cannot retest this at the time because I scrapped the code and went with my own permutation of Voxel tessellation. It keeps me at a solid 60fps right now. However, when I have a moment I will try to reimplement this; I just couldn't halt my project over something that can be done in other ways. Looking forward to an answer from someone still though. – Krythic Sep 16 '14 at 17:29
  • I don't think the view frustum should change between the occlusion pass and the corresponding rendering pass. Otherwise, if the frustum really does change, you could have the conditional rendering calls for voxels without ever submitting the corresponding queries. Would be interesting to see if something changes if you remove the second `LookThrough()` call. – Reto Koradi Sep 16 '14 at 17:37
  • To sate your suggestion, I am currently re-implementing the code above. I will get back to you in roughly thirty minutes. – Krythic Sep 16 '14 at 21:23
  • @Reto Koradi I managed to replicate my previous environment, and did as you said; here is my current GameClient class: http://pastebin.com/viBCgT7g It should be noted the crash still occurs when I shift the camera so it is looking beyond the level geometry. – Krythic Sep 16 '14 at 22:05
  • @Reto Koradi, I accidently made that paste last for only two weeks, here is a link for one that wont go extinct(In case anyone else travels down my path looking for a solution) http://pastebin.com/XVHDVuLL – Krythic Sep 16 '14 at 22:20
  • 1
    I still think I might be on the right track. :) Since you call `GameCamera.Frustum.SphereInFrustum()` inside the loop, you could still have a problem if the camera changes while the rendering executes. The key is that you process **exactly the same** list of voxels for the occlusion and the rendering pass. If the `SphereInFrustum()` test does not produce the same result for all voxels for the two passes, you're in trouble. – Reto Koradi Sep 17 '14 at 08:33
  • I am still replacing this with my tessellation code, I get a solid 60fps and am, at most, drawing about 200-300 faces. It is better. – Krythic Sep 17 '14 at 18:09

3 Answers3

1

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.

The Fiddler
  • 2,726
  • 22
  • 28
  • Wait, The Fiddler, as in the guy who wrote OpenTK? Dude, I am honored right now. I will look into your suggestion regarding Apitrace to see if I can pinpoint the error; thanks. – Krythic Sep 16 '14 at 16:52
0

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.

Krythic
  • 4,184
  • 5
  • 26
  • 67
0

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

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