Reputation: 4364
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
Reputation: 1
perhaps it is because you add the following line between two passes:
GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
Upvotes: 0
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
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