Enable multisampling for WinRT (Windows 8.1 + SharpDX)

Started by
5 comments, last by BlackJoker 9 years, 7 months ago

Hello.

I wish to enable multisampling in my WinRT sharpDX application.

To do that I tried to create depthStencilState, depthStencilBuffer, depthStencilView, renderTargetView,

Then apply it to device:


GraphicsDevice.SetDepthStencilState(depthStencilState);
            GraphicsDevice.SetRenderTargets(depthStencilBuffer, renderTargetView);

and clear targets before drawing:


GraphicsDevice.Clear(renderTargetView, Color.CornflowerBlue);
GraphicsDevice.Clear(depthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);

Bur when I set renger targets, I receive following error:

D3D11 ERROR: ID3D11DeviceContext::OMSetRenderTargets: The RenderTargetView at slot 0 is not compatable with the DepthStencilView. DepthStencilViews may only be used with RenderTargetViews if the effective dimensions of the Views are equal, as well as the Resource types, multisample count, and multisample quality. The RenderTargetView at slot 0 has (w:1920,h:1080,as:1), while the Resource is a Texture2D with (mc:1,mq:0). The DepthStencilView has (w:1920,h:1080,as:1), while the Resource is a Texture2D with (mc:4,mq:0). [ STATE_SETTING ERROR #388: OMSETRENDERTARGETS_INVALIDVIEW]

Here is my resources creation code:


private RenderTargetView renderTargetView;
private DepthStencilView depthStencilView;
private DepthStencilBuffer depthStencilBuffer;

Texture2DDescription depthBufferDescription = new Texture2DDescription();
            depthBufferDescription.Width = (int)SwapChainPanel.ActualWidth;
            depthBufferDescription.Height = (int)SwapChainPanel.ActualHeight;
            depthBufferDescription.MipLevels = 1;
            depthBufferDescription.ArraySize = 1;
            depthBufferDescription.Format = Format.D32_Float;
            depthBufferDescription.SampleDescription.Count = 4;
            depthBufferDescription.SampleDescription.Quality = 0;
            depthBufferDescription.Usage = ResourceUsage.Default;
            depthBufferDescription.BindFlags = BindFlags.DepthStencil;
            depthBufferDescription.CpuAccessFlags = 0;
            depthBufferDescription.OptionFlags = 0;

            DepthStencilStateDescription depthStencilDescription = new DepthStencilStateDescription();
            depthStencilDescription.IsDepthEnabled = true;
            depthStencilDescription.DepthWriteMask = DepthWriteMask.All;
            depthStencilDescription.DepthComparison = Comparison.Less;

            depthStencilDescription.IsStencilEnabled = true;
            depthStencilDescription.StencilReadMask = 0xFF;
            depthStencilDescription.StencilWriteMask = 0xFF;

            //????????? ???????? ???? ??????? ???????
            depthStencilDescription.FrontFace.FailOperation = StencilOperation.Keep;
            depthStencilDescription.FrontFace.DepthFailOperation = StencilOperation.Increment;
            depthStencilDescription.FrontFace.PassOperation = StencilOperation.Keep;
            depthStencilDescription.FrontFace.Comparison = Comparison.Always;

            //????????? ????????, ???? ??????? ?? ???????? ???????
            depthStencilDescription.BackFace.FailOperation = StencilOperation.Keep;
            depthStencilDescription.BackFace.DepthFailOperation = StencilOperation.Decrement;
            depthStencilDescription.BackFace.PassOperation = StencilOperation.Keep;
            depthStencilDescription.BackFace.Comparison = Comparison.Always;
            
            
            DepthStencilViewDescription depthStencilViewDescription = new DepthStencilViewDescription();
            depthStencilViewDescription.Format = Format.D32_Float;
            depthStencilViewDescription.Dimension = DepthStencilViewDimension.Texture2DMultisampled;
            depthStencilViewDescription.Flags = DepthStencilViewFlags.None;

            RenderTargetViewDescription renderTargetViewDescription = new RenderTargetViewDescription();
            renderTargetViewDescription.Format = GraphicsDevice.BackBuffer.Format;
            renderTargetViewDescription.Dimension = RenderTargetViewDimension.Texture2DMultisampled;
            
            depthStencilState =
                ToDispose(SharpDX.Toolkit.Graphics.DepthStencilState.New(GraphicsDevice, depthStencilDescription));
            
            depthStencilBuffer = ToDispose(DepthStencilBuffer.New(GraphicsDevice, depthBufferDescription));
            depthStencilView = ToDispose(new DepthStencilView(GraphicsDevice, GraphicsDevice.DepthStencilBuffer, depthStencilViewDescription));
            
            renderTargetView = ToDispose(new RenderTargetView(GraphicsDevice, GraphicsDevice.BackBuffer, renderTargetViewDescription));

            GraphicsDevice.SetDepthStencilState(depthStencilState);
            GraphicsDevice.SetRenderTargets(depthStencilBuffer, renderTargetView);

I am using SharpDX Toolkit.

Could someone say what I am missng and how to get it work with multisampling?

Advertisement

The error says that the code you showed is correct.

It also says that the color-buffer doesn't have multi-sampling, so the problem is with the back-buffer.

I believe you need to create a texture to render into and then use ResolveRenderTarget ResolveSubresource to copy it to the swap-chain back-buffer for WinRT.

I have added texture description and creation, but there is still no MSAA on the screen:


backbufferTextureDescription = new TextureDescription();
            backbufferTextureDescription.Width = (int)SwapChainPanel.ActualWidth;
            backbufferTextureDescription.Height = (int)SwapChainPanel.ActualHeight;
            backbufferTextureDescription.MipLevels = 1;
            backbufferTextureDescription.ArraySize = 1;
            backbufferTextureDescription.Format = Format.R8G8B8A8_UNorm;
            backbufferTextureDescription.SampleDescription.Count = 4;
            backbufferTextureDescription.SampleDescription.Quality = 0;
            backbufferTextureDescription.Usage = ResourceUsage.Default;
            backbufferTextureDescription.BindFlags = BindFlags.RenderTarget;

            Texture2D backbuffertexture = Texture2D.New(GraphicsDevice, backbufferTextureDescription);

            SharpDX.Direct3D11.DeviceContext device = GraphicsDevice;
            device.ResolveSubresource(GraphicsDevice.BackBuffer, 0, backbuffertexture, 0, Format.R8G8B8A8_UNorm);
GraphicsDevice.SetDepthStencilState(depthStencilState);
GraphicsDevice.SetRenderTargets(depthStencilBuffer, renderTargetView);

And still the same error message. Am I still missing somethings?

Should work if you use that backbuffer texture as the render-target together with the multisampled depth-buffer, and then ResolveSubresource before Swap, to copy the contents of the multisampled texture to the non-multisampled swap-chain backbuffer.

If you want to render directly to the swap-chain backbuffer it must be created with multi-sampling, with the DXGI function CreateSwapChain, but I don't think it's supported like that on WinRT so render-to-texture and ResolveSubresource is needed.

Seems I don`t understand the whole concept correctly.

I need updateSubresource each time frame was rendered?

Now I created depthstencil buffer and render target view as follow:


Texture2DDescription depthBufferDescription = new Texture2DDescription();
            depthBufferDescription.Width = (int)SwapChainPanel.ActualWidth;
            depthBufferDescription.Height = (int)SwapChainPanel.ActualHeight;
            depthBufferDescription.MipLevels = 1;
            depthBufferDescription.ArraySize = 1;
            depthBufferDescription.Format = Format.D32_Float;
            depthBufferDescription.SampleDescription.Count = 4;
            depthBufferDescription.SampleDescription.Quality = 0;
            depthBufferDescription.Usage = ResourceUsage.Default;
            depthBufferDescription.BindFlags = BindFlags.DepthStencil;
            depthBufferDescription.CpuAccessFlags = 0;
            depthBufferDescription.OptionFlags = 0;

depthStencilBuffer = ToDispose(DepthStencilBuffer.New(GraphicsDevice, depthBufferDescription));

and render target view:


rendertoTextureDescription = new TextureDescription();
            rendertoTextureDescription.Width = (int)SwapChainPanel.ActualWidth;
            rendertoTextureDescription.Height = (int)SwapChainPanel.ActualHeight;
            rendertoTextureDescription.MipLevels = 1;
            rendertoTextureDescription.ArraySize = 1;
            rendertoTextureDescription.Format = Format.R8G8B8A8_UNorm;
            rendertoTextureDescription.SampleDescription.Count = 4;
            rendertoTextureDescription.SampleDescription.Quality = 0;
            rendertoTextureDescription.Usage = ResourceUsage.Default;
            rendertoTextureDescription.BindFlags = BindFlags.RenderTarget;
            rendertoTextureDescription.OptionFlags = ResourceOptionFlags.None;
            rendertoTextureDescription.CpuAccessFlags = CpuAccessFlags.None;

            backbuffertexture = Texture2D.New(GraphicsDevice, rendertoTextureDescription);

Then apply it:


renderToTextureRTV = new RenderTargetView(GraphicsDevice, backbuffertexture);
GraphicsDevice.SetRenderTargets(depthStencilBuffer, renderToTextureRTV);
GraphicsDevice.SetViewports(new ViewportF(0,0, (int)SwapChainPanel.ActualWidth, (int)SwapChainPanel.Height));

When I set up new viewport it says the following:

D3D11 ERROR: ID3D11DeviceContext::RSSetViewports: Viewport at slot 0 is invalid. Valid Viewport extents are -32768.000000 <= TopLeftX, TopLeftY, (TopLeftX+Width), (TopLeftY+Height) <= 32767.000000, 0.000000 <= MinDepth, MaxDepth <= 1.000000, and MinDepth <= MaxDepth. Your viewport is: (TopLeftX,Y) = (0.000000, 0.000000), (Width,Height) = (1920.000000, -2147483648.000000), (MinDepth,MaxDepth) = (0.000000, 1.000000) [ STATE_SETTING ERROR #259: DEVICE_RSSETVIEWPORTS_INVALIDVIEWPORT]
Next, I must draw to this texture, So I:

device.ResolveSubresource(backbuffertexture, 0, GraphicsDevice.BackBuffer, 0, Format.R8G8B8A8_UNorm);
GraphicsDevice.Clear(renderToTextureRTV, Color.CornflowerBlue);
and as a result I don`t see any 3d geometry. Only d2d text, which I render to backbuffer.

The error says that the height of the viewport is incorrect... with the value 0x80000000. Maybe Height vs ActualHeight?

Try that first.

The concept is that the DXGI back-buffer can't be multi-sampled with a flip-model swap-chain that must be used in WinRT. For multisampled surfaces to be correctly displayed it must be drawn to an offscreen buffer and then downsized to the swap-chain backbuffer. ResolveSubresource does that, it copies the multisampled surface resolved to the correct resolution.

So ResolveSubresource does what Present normally does, it copies the render-to-texture target contents into the back-buffer, which can then be flipped with an actual Present.

So something like this:


SetRenderTarget(multisampledTexture, multisampledDepth);
ClearRenderTarget();

drawGame();

ResolveSubresource();
Present();

Well, I solved my issue for sharpdx. If anyone will face such issue, do the following:

Create all needed resources when Device created. This is: MSAA depthbuffer, depthstencilview, RenderTarget2D and set all this to device. Then in Draw method you need to set targets each time and resolve subresource after drawing. Here is my code:


//Initialization

DepthStencilStateDescription depthStencilDescription = new DepthStencilStateDescription();
            depthStencilDescription.IsDepthEnabled = true;
            depthStencilDescription.DepthWriteMask = DepthWriteMask.All;
            depthStencilDescription.DepthComparison = Comparison.Less;

            depthStencilDescription.IsStencilEnabled = true;
            depthStencilDescription.StencilReadMask = 0xFF;
            depthStencilDescription.StencilWriteMask = 0xFF;

            //????????? ???????? ???? ??????? ???????
            depthStencilDescription.FrontFace.FailOperation = StencilOperation.Keep;
            depthStencilDescription.FrontFace.DepthFailOperation = StencilOperation.Increment;
            depthStencilDescription.FrontFace.PassOperation = StencilOperation.Keep;
            depthStencilDescription.FrontFace.Comparison = Comparison.Always;

            //????????? ????????, ???? ??????? ?? ???????? ???????
            depthStencilDescription.BackFace.FailOperation = StencilOperation.Keep;
            depthStencilDescription.BackFace.DepthFailOperation = StencilOperation.Decrement;
            depthStencilDescription.BackFace.PassOperation = StencilOperation.Keep;
            depthStencilDescription.BackFace.Comparison = Comparison.Always;
            
            
            DepthStencilViewDescription depthStencilViewDescription = new DepthStencilViewDescription();
            depthStencilViewDescription.Format = Format.D32_Float;
            depthStencilViewDescription.Dimension = DepthStencilViewDimension.Texture2DMultisampled;
            depthStencilViewDescription.Flags = DepthStencilViewFlags.None;
            depthStencilViewDescription.Texture2DMS = new DepthStencilViewDescription.Texture2DMultisampledResource();

            TextureDescription rendertoTextureDescription = new TextureDescription();
            rendertoTextureDescription.Width = (int)SwapChainPanel.ActualWidth;
            rendertoTextureDescription.Height = (int)SwapChainPanel.ActualHeight;
            rendertoTextureDescription.MipLevels = 1;
            rendertoTextureDescription.ArraySize = 1;
            rendertoTextureDescription.Format = Format.R8G8B8A8_UNorm;
            rendertoTextureDescription.SampleDescription.Count = 8;
            rendertoTextureDescription.SampleDescription.Quality = 0;
            rendertoTextureDescription.Usage = ResourceUsage.Default;
            rendertoTextureDescription.BindFlags = BindFlags.RenderTarget|BindFlags.ShaderResource;
            rendertoTextureDescription.OptionFlags = ResourceOptionFlags.Shared;
            rendertoTextureDescription.CpuAccessFlags = CpuAccessFlags.None;

            backbuffertexture = ToDispose(Texture2D.New(GraphicsDevice, rendertoTextureDescription));
            
            rt = ToDispose(RenderTarget2D.New(GraphicsDevice, (SharpDX.Direct3D11.Texture2D)backbuffertexture));
            
            depthStencilState =
                ToDispose(SharpDX.Toolkit.Graphics.DepthStencilState.New(GraphicsDevice, depthStencilDescription));

            depthStencilBuffer = ToDispose(DepthStencilBuffer.New(GraphicsDevice, (int)SwapChainPanel.ActualWidth, (int)SwapChainPanel.ActualHeight, MSAALevel.X8, DepthFormat.Depth32));
            depthStencilView = ToDispose(new DepthStencilView(GraphicsDevice, GraphicsDevice.DepthStencilBuffer, depthStencilViewDescription));

            device = GraphicsDevice;
            GraphicsDevice.SetRenderTargets(depthStencilBuffer, rt);
            GraphicsDevice.SetViewports(new ViewportF(0,0, (int)SwapChainPanel.ActualWidth, (int)SwapChainPanel.ActualHeight));

...
//Drawing

DepthStencilView oldDepth;
                    RenderTargetView[] oldTargets = GraphicsDevice.GetRenderTargets(out oldDepth);
                    GraphicsDevice.SetRenderTargets(depthStencilBuffer,rt);
                    GraphicsDevice.Clear(Color.CornflowerBlue);
//Draw content
...
device.ResolveSubresource(rt, 0, GraphicsDevice.BackBuffer, 0, GraphicsDevice.BackBuffer.Format);

If you want to use Spritebatch, you need to set old targets back after resolving. So, do:


GraphicsDevice.SetRenderTargets(oldDepth, oldTargets);

                        spriteBatch.Begin();
                        spriteBatch.Draw(rt, new RectangleF((int)SwapChainPanel.ActualWidth - 500, (int)SwapChainPanel.ActualHeight - 350, 500, 350), new Rectangle(0, 0, 500, 350), Color.White, 0.0f, new Vector2(100, 100), SpriteEffects.None, 0.0f);
                        spriteBatch.End();

Thats all :)

This topic is closed to new replies.

Advertisement