Sign in to follow this  
AlexSenko

SlimDX WPF No Z-Buffer

Recommended Posts

I spend a lot of time to find why z-buffer don't work in my modified WpfSample10 and then founded information from microsoft site([url="http://msdn.microsoft.com/en-us/library/windows/desktop/bb205074(v=vs.85).aspx"]http://msdn.microsof...4(v=vs.85).aspx[/url]):

[quote][color="#2A2A2A"]When a buffer is used as a render target, depth-stencil testing and multiple render targets are not supported.[/color][/quote].

And the only way to use SlimDX in WPF is to use texture as render target?
Is there any way to make Z-buffer working in SlimDX WPF?

Share this post


Link to post
Share on other sites
[quote name='Feuerrader' timestamp='1317816029' post='4869356']
I spend a lot of time to find why z-buffer don't work in my modified WpfSample10 and then founded information from microsoft site([url="http://msdn.microsoft.com/en-us/library/windows/desktop/bb205074%28v=vs.85%29.aspx"]http://msdn.microsof...4(v=vs.85).aspx[/url]):

[quote][color="#2A2A2A"]When a buffer is used as a render target, depth-stencil testing and multiple render targets are not supported.[/color][/quote].

And the only way to use SlimDX in WPF is to use texture as render target?
Is there any way to make Z-buffer working in SlimDX WPF?
[/quote]
As I understand it, the documentation says that a plain d3d10 buffer (and not a texture) can be bound as a RenderTargetView (though I have never tested this kind of bindings) but then you cannot bind any depthstencilviews.

Have you tried in the WPF sample to create a separate render target/depth stencil buffer, render your d3d10 scene to it, and then copy the resulting rendertarget to the shared d3d9 surface?

Share this post


Link to post
Share on other sites
[quote name='AlexandreMutel' timestamp='1317818122' post='4869367']
Have you tried in the WPF sample to create a separate render target/depth stencil buffer, render your d3d10 scene to it, and then copy the resulting rendertarget to the shared d3d9 surface?
[/quote]

Yes, I do in such way, this part of code left from sample and it works pretty well except Z-Buffer.


RenderTarget Texture initialization:
[code] var renderTexDesc = new Texture2DDescription()

{
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
Format = Format.B8G8R8A8_UNorm,
Width = WindowWidth,
Height = WindowHeight,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.Shared,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};

SharedTexture = new Texture2D(device, renderTexDesc);
sampleRenderView = new RenderTargetView(device, SharedTexture);[/code]

DepthStencil initialization:

[code]var depthDesc = new Texture2DDescription()
{
BindFlags = BindFlags.DepthStencil,
Format = Format.D32_Float,
Width = WindowWidth,
Height = WindowHeight,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.None,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};



DepthTexture = new Texture2D(device, depthDesc);
depthStencilView = new DepthStencilView(device, DepthTexture);


var dsDesc = new DepthStencilStateDescription
{
IsDepthEnabled = true,
IsStencilEnabled = false,
DepthWriteMask = DepthWriteMask.All,
DepthComparison = Comparison.Less
};

depthStencilState = DepthStencilState.FromDescription(device, dsDesc);[/code]


Rasterizer initialization:

[code]var rasterizerState = new RasterizerStateDescription()
{
CullMode = CullMode.None,
FillMode = FillMode.Solid,
IsFrontCounterclockwise = false,
DepthBias = 0,
DepthBiasClamp = 0,
SlopeScaledDepthBias = 0,
IsDepthClipEnabled = true,
IsScissorEnabled = false,
IsMultisampleEnabled = true,
IsAntialiasedLineEnabled = true
};

device.Rasterizer.State = RasterizerState.FromDescription(device, rasterizerState);[/code]


Render:

[code] public void Render(int arg)
{
device.OutputMerger.DepthStencilState = depthStencilState;
device.OutputMerger.SetTargets(depthStencilView, sampleRenderView);

device.Rasterizer.SetViewports(new Viewport(0, 0, WindowWidth, WindowHeight, 0.0f, 1.0f));
device.ClearRenderTargetView(sampleRenderView, new Color4(0.0f, 0.0f, 0.0f));
device.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);


Matrix worldMatrix = GetWorldViewProj(arg);

DataStream ds = new DataStream(worldMatrix.ToArray(), true, false);
SampleEffect.GetVariableByName("WorldViewProj").AsMatrix().SetMatrix(worldMatrix);

EffectTechnique technique = SampleEffect.GetTechniqueByIndex(0);
EffectPass pass = technique.GetPassByIndex(0);

for (int i = 0; i < technique.Description.PassCount; ++i)
{
pass.Apply();
renderDataManager.Render(worldMatrix);
}

device.Flush();

OnSceneRender();
}[/code]

Share this post


Link to post
Share on other sites
[quote name='Feuerrader' timestamp='1317819089' post='4869375']
[quote name='AlexandreMutel' timestamp='1317818122' post='4869367']
Have you tried in the WPF sample to create a separate render target/depth stencil buffer, render your d3d10 scene to it, and then copy the resulting rendertarget to the shared d3d9 surface?
[/quote]

Yes, I do in such way, this part of code left from sample and it works pretty well except Z-Buffer.
[/quote]
Seems not exactly. What I was suggesting is that you create 2 render target buffer: one used with the z-buffer, but that is not shared (no ResourceOptionFlags.Shared on it). One that is shared, and receive a copy of the 1st render target (device.CopyResource between them)

Share this post


Link to post
Share on other sites
In such way?

Initialization:

[code] var renderTexDescShared = new Texture2DDescription()
{
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
Format = Format.B8G8R8A8_UNorm,
Width = WindowWidth,
Height = WindowHeight,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.Shared,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};

SharedTexture = new Texture2D(device, renderTexDescShared);
sampleRenderViewShared = new RenderTargetView(device, SharedTexture);

var renderTexDesc = new Texture2DDescription()
{
BindFlags = BindFlags.RenderTarget,
Format = Format.B8G8R8A8_UNorm,
Width = WindowWidth,
Height = WindowHeight,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
OptionFlags = ResourceOptionFlags.None,
CpuAccessFlags = CpuAccessFlags.None,
ArraySize = 1
};

renderTexture = new Texture2D(device, renderTexDesc);
sampleRenderView = new RenderTargetView(device, renderTexture);[/code]


Render:
[code]public void Render(int arg)
{
device.OutputMerger.DepthStencilState = depthStencilState;
device.OutputMerger.SetTargets(depthStencilView, sampleRenderView);

device.Rasterizer.SetViewports(new Viewport(0, 0, WindowWidth, WindowHeight, 0.0f, 1.0f));
device.ClearRenderTargetView(sampleRenderView, new Color4(0.0f, 0.0f, 0.0f));
device.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);


Matrix worldMatrix = GetWorldViewProj(arg);

DataStream ds = new DataStream(worldMatrix.ToArray(), true, false);
SampleEffect.GetVariableByName("WorldViewProj").AsMatrix().SetMatrix(worldMatrix);

EffectTechnique technique = SampleEffect.GetTechniqueByIndex(0);
EffectPass pass = technique.GetPassByIndex(0);



for (int i = 0; i < technique.Description.PassCount; ++i)
{
pass.Apply();
renderDataManager.Render(worldMatrix);
}


device.Flush();

device.CopyResource(renderTexture, SharedTexture);

OnSceneRender(); }[/code]


The same problems :( I'll prepare video in several minutes

Share this post


Link to post
Share on other sites
I ran into the exact same problem. Spent nearly a week to resolve this (using DX11) and utterly failed.
Looking forward to a solution.

EDIT:
I'm using a deferred renderer, thus i already tried the solution that Alexander proposed (copy non-shared mainbuffer to shared surface). No dice. Something screws up the z-buffer. I was already suspecting WPF to somehow interfere with the device. But then again, i have no idea...


EDIT cont:
I just recalled that i tested this without a shared texture. Instead of D3DImage, i used the WinFormsHost control in WPF and rendered directly to the handle (using a swapchain as usual). Now guess what, z-buffer is still broken. That's when i gave up, suspecting WPF to screw with my DX11 device.

If anyone knows anything about this, i'm nervous to get some real answers.

Share this post


Link to post
Share on other sites
[quote name='chlerub' timestamp='1317821467' post='4869399']
EDIT cont:
I just recalled that i tested this without a shared texture. Instead of D3DImage, i used the WinFormsHost control in WPF and rendered directly to the handle (using a swapchain as usual). Now guess what, z-buffer is still broken. That's when i gave up, suspecting WPF to screw with my DX11 device.
[/quote]

It was my last hope :(

Share this post


Link to post
Share on other sites
[quote name='Feuerrader' timestamp='1317823539' post='4869412']
[quote name='chlerub' timestamp='1317821467' post='4869399']
EDIT cont:
I just recalled that i tested this without a shared texture. Instead of D3DImage, i used the WinFormsHost control in WPF and rendered directly to the handle (using a swapchain as usual). Now guess what, z-buffer is still broken. That's when i gave up, suspecting WPF to screw with my DX11 device.
[/quote]

It was my last hope :(
[/quote]

Yeah, it was my last hope too. And it's extremely puzzling to say the least. Also there's virtually no information about this to be found anywhere.
I wonder if the creators of (for example) SlimDXControl ever tested their code with anything else than a simple triangle - cause it appears they most certainly have not.
(along with a number of other devs that have blogged about WPF/DX10-11 interop)

After testing the hell out of this topic for a week i put in on the shelf with a big sign saying "FUTILE".
I guess there's no need to state how frustrating this is, especially since WPF and DirectX are developed by the same company.

Share this post


Link to post
Share on other sites
I have just tested my code in WinForms, the same result, Z-Buffer do not work. May be any problems with shader?

[code]struct VS_IN
{
float4 pos : POSITION;
float4 col : COLOR;
};


struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};



float4x4 WorldViewProj : WORLDVIEWPROJECTION;

PS_IN VS( VS_IN input )
{
PS_IN output = (PS_IN)0;

output.pos = mul(input.pos, WorldViewProj);
output.col = input.col;

return output;
}

float4 PS( PS_IN input ) : SV_Target
{
return input.col;
}


technique10 Render
{
pass P0
{
SetGeometryShader( 0 );
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}[/code]

Share this post


Link to post
Share on other sites
Shader looks fine. Could you attach a minimal project (Edit: The WinForms variant, WPF doesn't seem to work with PIX here, please) ?

Also: Check against the reference device, I begin to suspect you have a driver issue.

Share this post


Link to post
Share on other sites
[quote name='unbird' timestamp='1317978272' post='4870032']
Shader looks fine. Could you attach a minimal project (Edit: The WinForms variant, WPF doesn't seem to work with PIX here, please) ?

Also: Check against the reference device, I begin to suspect you have a driver issue.
[/quote]

WinForms sources:
[url="http://www.rush.by/source.zip"]http://www.rush.by/source.zip[/url]

System config:
i5-2500, Win7 x64, nVidia GTS450 with latest drivers and updates.

When I change in DepthStencilStateDescription

[code]DepthComparison = Comparison.Less[/code]

to

[code]DepthComparison = Comparison.LessEqual[/code]

I see that something changed, when peak(as on video) is in far side of scene Z-buffer is ok, but if peak is in near side - z-buffer fault. On video "DepthComparison = Comparison.Less".

Share this post


Link to post
Share on other sites
I'm missing the Atomicus.Chart.Axis project to compile it (referenced in Atomicus.Chart.Interface).

EDIT: Sorry, my bad, had some other troubles (was still working with the older version of SlimDX). I can debug now...

Share this post


Link to post
Share on other sites
[quote name='unbird' timestamp='1317979548' post='4870039']
I'm missing the Atomicus.Chart.Axis project to compile it (referenced in Atomicus.Chart.Interface).
[/quote]

i forgot to remove reference, sorry, it is not used, can be removed.

Share this post


Link to post
Share on other sites
Ok, first your error was the perspective projection (in DXRenderer.GetWorldViewProj()):
[code]
Matrix.PerspectiveFovLH((float)Math.PI / 4f, 1f, 100f, 0f)
[/code]
Rather use something like (switching near and far, and yeah, a near of 0 isn't good either)
[code]
Matrix.PerspectiveFovLH((float)Math.PI / 4f, 1f, 0.1f, 100f)
[/code]
Then I had a hell of a detour. It really looked stubborn, just as if depth wasn't written ever. Played around with swapping calls and setting everything [i]again[/i] prior to drawing. That did not help. Unfortunately I could not PIX it either, so my next steps were to compare and re-incorporate stuff from a test project I did two days ago (WPF sample with a [i]working[/i] depth).

Comparing all descriptions/flags: Everything looked fine.

I changed the resized logic: You recreate almost everything - including the device (InitD3D is called twice at startup!). I suspected a forgotten/wrongly bound view or a backbuffer/depth size mismatch or something. So I used SwapChain.ResizeTarget/ResizeBuffers instead, grabbing the dimensions once only (with the needed texture and view recreation). Did not help either.

Suspecting your mesh, I used my grid mesh. Same behaviour.

Then I [i]finally[/i] looked closer at your shader:
[code]
struct PS_OUT
{
float4 col: SV_Target;
float dep: SV_Depth;
};

//...

PS_OUT PS( PS_IN input )
{
PS_OUT output = (PS_OUT)0;
output.col = input.col;
output.col.g = 0;
return output;
}
[/code]

This is not the one you provided two posts ago :P. The (PS_OUT)0 cast will overwrite all your real depth values with zero. That's the problem.

Omitting SV_Depth output in the pixelshader finally gave a correct result.

I think you owe me a favor :wink:

Share this post


Link to post
Share on other sites
yes, here was my first mistake:[code] Matrix.PerspectiveFovLH((float)Math.PI / 4f, 1f, 100f, 0f)[/code]

the result of this mistake was like Z-Buffer not work and i tried everything about Z-Buffer, but nothing about projection matrices.

And my last hope was to make depth calculations manually in shader(or something like this) and I started write something in shader :)

Now everything works fine, even in WPF. Thanks to [b]unbird[/b].

P.S. Really I see that DirectX/SlimDX rendering cannot depend on WPF, because rendering to shared texture is made just in .Net, not in WPF or WinForms. So I think [b]chlerub [/b]can also solve his problem.

Share this post


Link to post
Share on other sites
@Feuerrader: You're welcome. Glad to hear it's working in WPF, too.

I wanted to add something, though it's a bit off topic. I see this pretty often (Output being some struct)

[code]
Output result = (Output)0;
//...
[/code]

I wonder why. I don't do this, because...

If you do this:
[code]
Output result;
// ...
// fill result with values
// ...
return result;
[/code]

... and then forget to fill all entries of result the compiler will scream with an error:

[code]
error X4000: variable 'result' used without having been completely initialized
[/code]

This is pretty useful information, so why mute it ? Shader debugging is hard enough.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this