2

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?

Rey
  • 85
  • 1
  • 9
  • I read alot about disposing the backbuffer first so I did that too "_backbuffer.Dispose()" but it has no effect – Rey Sep 06 '13 at 13:46
  • Are you [running in debug mode](http://sharpdx.org/forum/4-general/1774-how-to-debug-a-sharpdxexception) to get all the info you can? – shoelzer Sep 09 '13 at 13:34
  • If you mean if I run it in Debug instead of Release than yes I do. – Rey Sep 09 '13 at 21:36
  • I mean build and run in Debug config, but also turn on DirectX device debugging and "Enable native code debugging". See the link in my other comment for details. – shoelzer Sep 10 '13 at 13:06

1 Answers1

2

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.

mrvux
  • 8,523
  • 1
  • 27
  • 61
  • So if I understood it right, it can't work. I create the backBuffer, depthBuffer, depthView and renderView in a class called canvas.cs I create there also the renderForm and calling the renderLoop. In my Class context.cs which heritage from canvas.cs I call "context.ClearRenderTargetView" and "context.ClearDepthStencilView" So when I'm disposing all those in the Canvas they still existing in the context which lead to an error. So I've to find a way to connect them somehow to make it work right? The thing is it's not possible, so I've to paste those to calls to my canvas.cs right? – Rey Nov 19 '13 at 07:09
  • thanks for this explanation but I dont get the Value of this composition. Because they are kinda the same aren't they? ![Comparison](http://abload.de/img/composition2ksfm.png) Within your SwapChain constructor you meant `Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.Debug, sd, out _device, out this.swapchain);` instead of `this.swapchain = new SwapChain(device.Factory, device.Device, sd);` right? – Rey Nov 19 '13 at 16:31
  • No, they are clearly different. I first create a Device, then use that device to create a SwapChain. (in your diagram, this is incorrect since creating my device is not done in the swapchain class, it's done beforehand). That means I can create 20 swapchains using same device just by instantiating my SwapChain class, or use my Device class with no SwapChain at all (Unit Testing, data processing in compute).... – mrvux Nov 19 '13 at 17:12
  • @catflier Why are you disposing ` this.resource.Dispose();` **twice** in the `Resize` method? – Jeroen van Langen Feb 13 '17 at 15:07
  • @JeroenvanLangen Good point, updated answer, in that case it's not needed as it does not perform addref (and should use marshal release anyway for that one) – mrvux Feb 14 '17 at 15:53