SharpDx windowResize

3.8k views Asked by At

I'm trying to implement an update to the backbuffer as soon as my window size has been changed. So my Objects wont get streched. So I tried this

_renderForm.Resize += OnRenderFormOnResize;
private void OnRenderFormOnResize(object sender, EventArgs args)
        {
            // Resize  depth bufer ?
            MessageBox.Show("Width: "+_renderForm.ClientSize.Width.ToString() +" | Height: "+ _renderForm.ClientSize.Height.ToString());

            _swapChain.ResizeBuffers(_desc.BufferCount, _renderForm.ClientSize.Width, _renderForm.ClientSize.Height, Format.Unknown, SwapChainFlags.None);
            DoResize();
        }

I get this error as soon as the window size has been changed.

DXGI_ERROR_IVALID_CALL/InvalidCall

Am I missing something?

1

There are 1 answers

5
mrvux On

You are not allowed to Resize swap chain if any views depending on it are still active. So make sure you call release/dispose on RenderTargetView/ShaderResourceViews created from your backbuffer, then create new ones once Resize has been called.

Please also note that those views need to be detached from pipeline (so if the RenderTargetView associated with your SwapChain is still bound, make sure you unbind it before), othewise dx11 runtime will wait for them to be unattached before dispose, so the call will still fail.

EDIT: To make sure you have all you need, easiest way is to build yourself a swapchain class, which has all the necessary data that you need (please note the DX11Device in my case is also simply wrapping a device).

public class DX11SwapChain : IDX11RenderTarget
{
    private DX11Device device;
    private IntPtr handle;
    private SwapChain swapchain;

    public RenderTargetView RenderView { get; protected set; }
    public RenderTargetViewDescription RenderViewDesc { get; protected set; }

    public Texture2DDescription TextureDesc { get; protected set; }
    private Texture2D resource;


    public IntPtr Handle { get { return this.handle; } }
}

Here is the constructor:

    public DX11SwapChain(DX11Device device, IntPtr handle, Format format, SampleDescription sampledesc)
    {
        this.device = device;
        this.handle = handle;

        SwapChainDescription sd = new SwapChainDescription()
        {
            BufferCount = 1,
            ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), format),
            IsWindowed = true,
            OutputHandle = handle,
            SampleDescription = sampledesc,
            SwapEffect = SwapEffect.Discard,
            Usage = Usage.RenderTargetOutput | Usage.ShaderInput,
            Flags = SwapChainFlags.None
        };

        this.swapchain = new SwapChain(device.Factory, device.Device, sd);

        this.resource = Texture2D.FromSwapChain<Texture2D>(this.swapchain, 0);
        this.TextureDesc = this.resource.Description;

        this.RenderView = new RenderTargetView(device.Device, this.resource);
        this.RenderViewDesc = this.RenderView.Description;

    }

And the Resize method:

    public void Resize()
    {
        this.Resize(0, 0);
    }

    public void Resize(int w, int h)
    {
        if (this.RenderView != null) { this.RenderView.Dispose(); }
        this.resource.Dispose();

        this.swapchain.ResizeBuffers(1,w, h, SharpDX.DXGI.Format.Unknown, SwapChainFlags.AllowModeSwitch);

        this.resource = Texture2D.FromSwapChain<Texture2D>(this.swapchain, 0);

        this.TextureDesc = this.resource.Description;
        this.RenderView = new RenderTargetView(device.Device, this.resource);
    }

Also, just before calling resize, it is good to call (you can eventually also do a small flush):

 device.ImmediateContext.ClearState();

To make sure to unbind everything.

Please note that if you use size dependent resources, you need to also notify your application (in order to recreate elements like temporary render target/depth buffer).

So in that case you can either add a Resized event to your SwapChain class (and listen to it on your canvas). I'm not a big fan of this personally since I often use several SwapChains in the same application.

Another simple way, is to add a method :

 ResizeResources(int widh,int height);

Into your canvas class, and call it on your renderform resize event.