Inside3D!
     

[GLQuake] Depth Buffer Precision and Clearing Fix

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials
View previous topic :: View next topic  
Author Message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Sat Jul 03, 2010 12:43 pm    Post subject: [GLQuake] Depth Buffer Precision and Clearing Fix Reply with quote

This one is depressingly common, I'm afraid. What I'm going to do here is give the Windows API version of what needs to be done; for other operating systems you should be able to figure it out.

First of all a bit of an introduction. OpenGL is great in that it shelters you from having to deal with some of the more down and dirty aspects of the hardware. Unfortunately there are places where the abstraction leaks, and when that happens you can be bitten quite hard. So you do need to roll up your sleeves and get your hands dirty after all.

Most GLQuake-based engines request a 32-bit depth buffer, and leave it at that. However, these engines are most likely actually running with 16-bit depth on everyone's machines. The reson why is that there is actually no such thing as a 32-bit depth buffer on most consumer hardware. Your ChoosePixelFormat call is selecting a 16-bit depth buffer and unless you check what you actually get you'll never know.

I've seen this in the current versions of 3 major engines. So let's fix it.

Assuming you agree that 16-bit depth isn't enough, the first thing to do is pick a better format. Our available formats are going to be 16-bit depth, 24-bit depth (with 8 unused) and 24-bit depth (with 8 stencil). So open gl_vidnt.c, find the bSetupPixelFormat function, and change this line:
Code:
      32,                  // 32-bit z-buffer

to this:
Code:
      24,                  // 24-bit z-buffer

The next step (same function) is needed because the PIXELFORMATDESCRIPTOR you pass doesn't provide an absolute ruling on what you get; GDI may decide to give you something different (we already saw that when we asked for 32 but got 16). So there is a possibility that we got a stencil buffer too. So just before the "return TRUE" line, add this:
Code:
   DescribePixelFormat (hDC, pixelformat, sizeof (PIXELFORMATDESCRIPTOR), &pfd);

Every engine I've tested this on also gave us 8 bits of stencil. Why is this important? Simply, if you also have a stencil buffer, even if you don't actually use it, you should always clear it at the same time as you clear your depth buffer. Otherwise your performance will suffer quite a huge dropoff.

So add a global qboolean called something like gl_havestencil to your gl_vidnt.c, set it to true if your pfd.cStencilBits is greater than 0 (after calling DescribePixelFormat), and then extern it so that it's accessible to gl_rmain.c

Then, when clearing, check if gl_havestencil is true, and if so, add GL_STENCIL_BUFFER_BIT to your glClear call. Easy.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Sajt



Joined: 16 Oct 2004
Posts: 1026

PostPosted: Sun Jul 04, 2010 5:32 am    Post subject: Re: [GLQuake] Depth Buffer Precision and Clearing Fix Reply with quote

mh wrote:
Simply, if you also have a stencil buffer, even if you don't actually use it, you should always clear it at the same time as you clear your depth buffer. Otherwise your performance will suffer quite a huge dropoff.


Hmm, this is interesting, I never knew that. Perhaps some benchmarking is in order...
_________________
F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Sun Jul 04, 2010 11:44 pm    Post subject: Reply with quote

I ran the Win32 GL build of my engine with 16, 24, 32 z buffers requested (no stencil buffer requested) using -bpp 16.

[My engine defaults to the desktop bpp unless otherwise specified so I actually have to do -bpp 16 to get 16 bit color ... to enable switching between fullscreen and windowed mode without reuploading 2D textures as I do not yet have a texture manager capable of re-uploading all the 2D pixs.]

timedemo demo1 results:

32 bit z buffer requested: 295 fps
24 bit z buffer requested: 204 fps
16 bit z buffer requested: 295 fps

I don't know how to interpret the results except at least by starting the engine and doing a timedemo of demo1, I'm not seeing a frames-per-second performance drop off by not clearing the stencil buffer?
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Mon Jul 05, 2010 9:25 am    Post subject: Reply with quote

Hmmmm. Did you check if you're actually getting a 16-bit Z-buffer when you requested a 32-bit one? A 16-bit one will always be faster (less to clear) but at the expense of less precision (dramatically so if using gl_ztrick).
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Mon Jul 05, 2010 9:47 am    Post subject: Reply with quote

Personally I get 24-depth 8-stencil whatever level of depth I set, even without requesting a stencil buffer (each time 24bit colour).

If you have ztrick enabled, you'll never directly clear the depth buffer anyway (you generally should not have ztrick enabled, as its slower on current cards).
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
leileilol



Joined: 15 Oct 2004
Posts: 1321

PostPosted: Mon Jul 05, 2010 10:34 am    Post subject: Reply with quote

ztrick's for voodoo1, it should be taken out and shot in every port in the world, i don't even get an advantage of speed with it even on a trident / powervr
_________________
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Mon Jul 05, 2010 12:13 pm    Post subject: Reply with quote

Curioser and curioser. I always get 16-bit depth unless I explicitly request 24, and then I always get 8-bit stencil too, even if I request 0. D3D is a lot clearer than OpenGL here (you get exactly what you ask for and no messing) but with the downside that you need to check that what you ask for is actually supported first, otherwise it'll blow up. Pros and cons to both approaches.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Mon Jul 05, 2010 12:33 pm    Post subject: Reply with quote

You could walk the list of them with DescribePixelFormat until it fails, in order to enumerate the provided modes and pick the one that best matches your needs.
Which is basically what ChoosePixelFormat does anyway.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Mon Jul 05, 2010 12:37 pm    Post subject: Reply with quote

Great minds or fools?

Here's something I very quickly whipped up:
Code:
#include <windows.h>
#include <stdio.h>
#include <memory.h>
#include <conio.h>


void main (void)
{
   HDC hDC = GetDC (NULL);

   int maxpf = DescribePixelFormat (hDC, 0, 0, NULL);

   printf ("%i available pixel formats\n", maxpf);

   for (int i = 0; i < maxpf; i++)
   {
      PIXELFORMATDESCRIPTOR pfd;

      memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
      pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);

      if (DescribePixelFormat (hDC, (i + 1), sizeof (PIXELFORMATDESCRIPTOR), &pfd))
      {
         if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue;
         if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) continue;
         if (!(pfd.dwFlags & PFD_DOUBLEBUFFER)) continue;
         if (pfd.iPixelType != PFD_TYPE_RGBA) continue;

         printf ("%3i  %2i colour %2i depth %2i stencil\n",
            (i + 1),
            pfd.cColorBits,
            pfd.cDepthBits,
            pfd.cStencilBits);
      }
   }

   ReleaseDC (NULL, hDC);

   printf ("Press any key... ");
   while (!_kbhit ());
}


For Windows Vista and 7 you might also need to add PFD_SUPPORT_COMPOSITION but I've never noticed any practical difference between using it and not using it in Quake.

This of course uses the desktop rather than a window, just because I didn't feel like creating a window. In a Real Program you would want to use a window.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Tue Jul 06, 2010 3:29 am    Post subject: Reply with quote

leileilol wrote:
ztrick's for voodoo1, it should be taken out and shot in every port in the world, i don't even get an advantage of speed with it even on a trident / powervr


Ironically, I get +20 more FPS using gl_ztrick on a GeForce4.

Go figure.
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group