Resizing Swapchain for Direct2D failing, #466
-
Hi, I've created a winforms control for drawing using direct2d. everything is working fine except when it comes to resizing the swap chain. It's failing for no apparent reason. I've read tons of articles on how to do it properly. I've disposed of all its resources before resizing but still failing. I'd appreciate if anyone could help. I've added the source code of control. using Vortice.DCommon;
using Vortice.Direct2D1;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using FeatureLevel = Vortice.Direct3D.FeatureLevel;
namespace GLibTest
{
public partial class D2DControl : UserControl
{
private ID2D1Factory1? _direct2DFactory;
private ID2D1DeviceContext? _d2dDeviceContext;
private IDXGISwapChain1? _swapChain;
private IDXGISurface? _dxgiBackBuffer;
public delegate void RenderHandler(object sender, ID2D1DeviceContext g);
public event RenderHandler? OnRendering;
public D2DControl()
{
InitializeComponent();
SetControlStyles();
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
InitializeDirect2DResources();
}
protected override void OnHandleDestroyed(EventArgs e)
{
DisposeResources();
base.OnHandleDestroyed(e);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
ResizeRenderTarget();
Invalidate(); // Trigger a repaint after resizing
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Override to avoid flickering; background will be cleared during rendering
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (_d2dDeviceContext == null) return;
_d2dDeviceContext.BeginDraw();
// Trigger custom rendering logic
OnRendering?.Invoke(this, _d2dDeviceContext);
_d2dDeviceContext.EndDraw();
_swapChain?.Present(0, PresentFlags.None);
}
private void SetControlStyles()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
}
private void InitializeDirect2DResources()
{
// Create Direct3D device
var featureLevels = new[]
{
FeatureLevel.Level_11_1,
FeatureLevel.Level_11_0,
FeatureLevel.Level_10_1,
FeatureLevel.Level_10_0
};
using var tempDevice = D3D11.D3D11CreateDevice(
DriverType.Hardware,
DeviceCreationFlags.BgraSupport,
featureLevels);
using var dxgiDevice = tempDevice.QueryInterface<IDXGIDevice>();
// Create Direct2D factory and device
_direct2DFactory = D2D1.D2D1CreateFactory<ID2D1Factory1>(FactoryType.SingleThreaded);
using var d2dDevice = _direct2DFactory.CreateDevice(dxgiDevice);
_d2dDeviceContext = d2dDevice.CreateDeviceContext(DeviceContextOptions.None);
_d2dDeviceContext.UnitMode = UnitMode.Pixels;
CreateSwapChain(tempDevice);
CreateRenderTarget();
}
private void CreateSwapChain(ID3D11Device device)
{
var swapChainDesc = new SwapChainDescription1
{
Width = (uint)ClientSize.Width,
Height = (uint)ClientSize.Height,
Format = Format.B8G8R8A8_UNorm,
Stereo = false,
SampleDescription = new SampleDescription(1, 0),
BufferUsage = Usage.RenderTargetOutput,
BufferCount = 2,
Scaling = Scaling.None,
SwapEffect = SwapEffect.FlipSequential,
};
using var dxgiFactory = device.QueryInterface<IDXGIDevice>()
.GetAdapter()
.GetParent<IDXGIFactory2>();
_swapChain = dxgiFactory.CreateSwapChainForHwnd(device, Handle, swapChainDesc);
}
private void CreateRenderTarget()
{
if (_d2dDeviceContext == null || _swapChain == null) return;
_dxgiBackBuffer = _swapChain.GetBuffer<IDXGISurface>(0);
var bitmapProperties = new BitmapProperties1(new PixelFormat(Format.B8G8R8A8_UNorm, Vortice.DCommon.AlphaMode.Premultiplied), 96, 96, BitmapOptions.Target | BitmapOptions.CannotDraw);
var _renderTarget = _d2dDeviceContext.CreateBitmapFromDxgiSurface(_dxgiBackBuffer, bitmapProperties);
_d2dDeviceContext.Target = _renderTarget;
}
private void ResizeRenderTarget()
{
if (_swapChain == null || _d2dDeviceContext == null) return;
_dxgiBackBuffer?.Dispose();
_d2dDeviceContext.Target.Dispose();
_d2dDeviceContext.Target = null;
var res = _swapChain.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None);
if (res.Failure)
{
// the problem is here. zeroes are fine according to ms docs i've also tried exact values but no luck
//throw new InvalidOperationException("Failed to resize swap chain buffers.");
}
CreateRenderTarget();
}
private void DisposeResources()
{
_d2dDeviceContext?.Dispose();
_swapChain?.Dispose();
_direct2DFactory?.Dispose();
_dxgiBackBuffer?.Dispose();
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hi, |
Beta Was this translation helpful? Give feedback.
-
For anyone else who might face the same issue, the issue was caused by the bulk resizing of the swapchain buffers during the resize operation. It was resolved by ensuring the swapchain is not resized multiple times simultaneously. Here's the relevant code snippet: private bool _resizing = false;
private void ResizeRenderTarget()
{
if (_swapChain == null || _d2dDeviceContext == null || _resizing) return;
_resizing = true;
_dxgiBackBuffer?.Release();
_renderTarget?.Release();
_d2dDeviceContext.Target.Release();
_d2dDeviceContext.Target = null;
var res = _swapChain.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None);
if (res.Failure)
{
throw new InvalidOperationException("Failed to resize swap chain buffers.");
}
CreateRenderTarget();
_resizing = false;
} I believe there's a better way to accomplish this but my code works fine too. |
Beta Was this translation helpful? Give feedback.
For anyone else who might face the same issue, the issue was caused by the bulk resizing of the swapchain buffers during the resize operation. It was resolved by ensuring the swapchain is not resized multiple times simultaneously.
Here's the relevant code snippet: