Detecting forced driver MSAA in deferred renderer

sebbbi

Veteran
I am having problems detecting forced multisample antialiasing in DX9.

Background info:
I create the d3d device with automatic depth buffer and color buffer. Before creating the device I search for a suitable 24+ bit depth buffer format with at least 8 bits of stencil. Then I find a compatible color buffer for it (with same color depth and using CheckDepthStencilMatch to verify compatiblity). These d3dformats are set as AutoDepthStencilFormat and BackBufferFormat in the D3D_PRESENT_PARAMETERS structure. No problems so far.

Then I create my four g-buffers (render targets) for the deferred renderer. These are created with same size and same format as the backbuffer, and use the same z-buffer as the backbuffer. However if forced AA is enabled, the driver silently creates the z-buffer as a multisample buffer and it's incompatible with the non-multisampled g-buffers.

ATI drivers seem to handle this situation properly, and notice that the z-buffer is used with a non-multisampled buffer and disable the forced driver AA. NVidia drivers however do not handle this situation properly, causing the graphics get really messed up when forced AA is used.

To fix this issue I could either:

A) Make all g-buffers multisampled if the z-buffer buffer is multisampled. However both NVidia and ATI drivers tell me incorrect information about the real buffer format. D3DSURFACE_DESC always informs me that z-buffer is not multisampled, making it impossible for me to detect the real format of the z-buffer.

B) Check that if the depth buffer is multisampled, and give user a warning stating that he should disable the forced MSAA if he wants to run the application. This is also impossible to do, as the driver doesn't reveal the true buffer format for the application.

C) Create a separate non-multisampled z-buffer for the g-buffers, and hope that the driver is clever enough to not force it to be multisampled. However if I use this technique, I must do a separate z-only pass for both buffers, and this costs a lot of performance (I cannot copy z-buffer from multisampled format to non-multisampled format). As I cannot detect in any way that the forced driver AA is enabled, this is a really bad way to fix the problem (causing the performance drop even if antialiasing is disabled).

Is there any way to solve this problem properly, without sacrificing any performance? Are other games using deferred rendering handled differently by the graphics card drivers (driver detection perhaps)?


Update:
According to my testing I assume that when forced MSAA is enabled, GeForce drivers silently create two copies of the z-buffer, one multisampled (used with backbuffer) and one non-multisampled (used with g-buffers). At beginning of frame rendering I set the backbuffer & z-buffer as my rendertarget combination, and clear the color, depth and stencil values. This seems to clear only the multisampled driver created extra z-buffer, and when I later in the frame set my g-buffers as the render target, the drivers silently starts to use the non-multisampled z-buffer and it still has last frame information in it. Only the surfaces with smaller z-values are rendered. I could of course clear the z-buffer twice in the frame rendering, but that would cause problems, as I use the z-information with both g-buffer rendertargets (geometry rendering) and with backbuffer (light area rendering, particle rendering, etc).
 
Last edited by a moderator:
I'd suggest you simply don't use AutoDepthStencil. Just create your own depth buffer with CreateDepthStencilSurface(). That should survive any driver overrides.
 
A) Make all g-buffers multisampled if the z-buffer buffer is multisampled. However both NVidia and ATI drivers tell me incorrect information about the real buffer format. D3DSURFACE_DESC always informs me that z-buffer is not multisampled, making it impossible for me to detect the real format of the z-buffer.
The runtime is telling you it's point-sampled, not the driver. The runtime has no concept of "driver overrides" and this call is handled by the runtime.
B) Check that if the depth buffer is multisampled, and give user a warning stating that he should disable the forced MSAA if he wants to run the application. This is also impossible to do, as the driver doesn't reveal the true buffer format for the application.
What you can do is:
- Clear backbuffer to black
- Draw a white triangle
- Lock the backbuffer and look for gray pixels

If there are any gray pixels, then AA is enabled and you can issue a warning to the user. You may need to play around with the shape of the triangle you draw in order to assure that some antialiasing occurs.
 
The runtime is telling you it's point-sampled, not the driver. The runtime has no concept of "driver overrides" and this call is handled by the runtime.

Yes of course. I stated that bit slightly confusingly. The get-methods just return the runtime state, not the hardware/driver state. Pure devices do not even have the get methods. This of course explains why I don't get the real info of the forced MSAA depthbuffer and backbuffer formats.

If there are any gray pixels, then AA is enabled and you can issue a warning to the user. You may need to play around with the shape of the triangle you draw in order to assure that some antialiasing occurs.

Sounds like a quite hacky implementation :). But this should work fine on all current hardware. I just have to do a full test with all our 20 test setups to be sure that there are no false positives.

I'd suggest you simply don't use AutoDepthStencil. Just create your own depth buffer with CreateDepthStencilSurface(). That should survive any driver overrides.

I was thinking about that, but then I remembered that all my old applications used the manual method (of creating backbuffer, frontbuffer and z-buffer swap chain) before AutoDepthStencil was introduced in DirectX. I automatically dismissed this option, because I thought the driver would likely force the format of my manually created depth stencil surfaces also (as the forced MSAA worked fine on my old applications). However most likely there are different driver hacks for different DirectX versions. Going to try this method when I get at work.

But there is still a potential problem. If I don't autogenerate the depth buffer, and the driver still generates a multisample backbuffer (when forced MSAA is enabled), my backbuffer and depthbuffer are now mismatched. Should I also create the backbuffer chain manually? Front buffer is fine I suppose (as the multisampling is resolved before writing to it).
 
Last edited by a moderator:
Tested removing EnableAutoDepthStencil from d3d device creation, and creating my own depthbuffer with CreateDepthStencilSurface. This does not fix the problem with GeForces. When forced MSAA is enabled, the driver still forces the color backbuffer in multisample format and the depthbuffer I create is not multisampled. I do not get any error when I call SetDepthStencilSurface (using D3D debug runtime), but the depth buffer doesn't work. On all Radeons this method works fine, but I really need something that works on GeForces as well.

I would not want to implement the single polygon rendering -> stretchRect to a lockable hardware buffer (resolves MSAA) -> lock and search for grey pixels.
 
Do you need a depth buffer for your "window" renderbuffer anyway? Why don't just drop it?

Yes, I combine the lighting passes to the backbuffer, and the light area objects need to be z-buffered. Otherwise lights that are for example behind a wall get processed and pixel shader performance gets wasted. Also after lighting some of the post process filters, the volumetric soft particle rendering and sprite rendering use z-buffer also. I could render everything to a manually created offscreen buffer and copy the result to backbuffer before flipping, but this would consume some performance (not that much, but there must be a better way to solve this problem).

Update: I am now copying data from the last post process buffer to the backbuffer, instead of using back buffer as rendertarget when rendering the last post process effect. This downgraded less than 1 fps of my performance, so I am pretty pleased about the end result. Graphics memory usage also remained the same.
 
Last edited by a moderator:
Back
Top