fix D3D9 crashing on minimize

This commit is contained in:
CasualPokePlayer 2023-08-13 14:20:48 -07:00
parent 56ac05f9a3
commit ae42858560
3 changed files with 65 additions and 42 deletions

View File

@ -1,16 +1,17 @@
using System; using System;
using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
namespace BizHawk.Bizware.Graphics.Controls namespace BizHawk.Bizware.Graphics.Controls
{ {
internal sealed class D3D9Control : GraphicsControl internal sealed class D3D9Control : GraphicsControl
{ {
private readonly Func<IntPtr, D3D9SwapChain> _createSwapChain; private readonly Func<D3D9SwapChain.ControlParameters, D3D9SwapChain> _createSwapChain;
private D3D9SwapChain _swapChain; private D3D9SwapChain _swapChain;
private bool Vsync; private bool Vsync;
public D3D9Control(Func<IntPtr, D3D9SwapChain> createSwapChain) private D3D9SwapChain.ControlParameters ControlParameters => new(Handle, Width, Height, Vsync);
public D3D9Control(Func<D3D9SwapChain.ControlParameters, D3D9SwapChain> createSwapChain)
{ {
_createSwapChain = createSwapChain; _createSwapChain = createSwapChain;
@ -21,12 +22,10 @@ namespace BizHawk.Bizware.Graphics.Controls
DoubleBuffered = false; DoubleBuffered = false;
} }
protected override Size DefaultSize => new(1, 1);
protected override void OnHandleCreated(EventArgs e) protected override void OnHandleCreated(EventArgs e)
{ {
base.OnHandleCreated(e); base.OnHandleCreated(e);
_swapChain = _createSwapChain(Handle); _swapChain = _createSwapChain(ControlParameters);
} }
protected override void OnHandleDestroyed(EventArgs e) protected override void OnHandleDestroyed(EventArgs e)
@ -39,7 +38,7 @@ namespace BizHawk.Bizware.Graphics.Controls
protected override void OnResize(EventArgs e) protected override void OnResize(EventArgs e)
{ {
base.OnResize(e); base.OnResize(e);
_swapChain.Refresh(Vsync); _swapChain.Refresh(ControlParameters);
} }
public override void SetVsync(bool state) public override void SetVsync(bool state)
@ -47,7 +46,7 @@ namespace BizHawk.Bizware.Graphics.Controls
if (Vsync != state) if (Vsync != state)
{ {
Vsync = state; Vsync = state;
_swapChain.Refresh(Vsync); _swapChain.Refresh(ControlParameters);
} }
} }
@ -58,6 +57,6 @@ namespace BizHawk.Bizware.Graphics.Controls
=> _swapChain.SetBackBuffer(); => _swapChain.SetBackBuffer();
public override void SwapBuffers() public override void SwapBuffers()
=> _swapChain.PresentBuffer(); => _swapChain.PresentBuffer(ControlParameters);
} }
} }

View File

@ -7,16 +7,32 @@ namespace BizHawk.Bizware.Graphics
{ {
public sealed class D3D9SwapChain : IDisposable public sealed class D3D9SwapChain : IDisposable
{ {
public readonly struct ControlParameters
{
public readonly IntPtr Handle;
public readonly int Width;
public readonly int Height;
public readonly bool Vsync;
public ControlParameters(IntPtr handle, int width, int height, bool vsync)
{
Handle = handle;
Width = Math.Max(width, 1);
Height = Math.Max(height, 1);
Vsync = vsync;
}
}
private const int D3DERR_DEVICELOST = unchecked((int)0x88760868); private const int D3DERR_DEVICELOST = unchecked((int)0x88760868);
private readonly Device _device; private readonly Device _device;
private readonly Func<PresentParameters, SwapChain> _resetDeviceCallback; private readonly Func<ControlParameters, SwapChain> _resetDeviceCallback;
private readonly Func<PresentParameters, SwapChain> _resetSwapChainCallback; private readonly Func<ControlParameters, SwapChain> _resetSwapChainCallback;
private SwapChain _swapChain; private SwapChain _swapChain;
internal D3D9SwapChain(Device device, SwapChain swapChain, internal D3D9SwapChain(Device device, SwapChain swapChain,
Func<PresentParameters, SwapChain> resetDeviceCallback, Func<PresentParameters, SwapChain> resetSwapChainCallback) Func<ControlParameters, SwapChain> resetDeviceCallback, Func<ControlParameters, SwapChain> resetSwapChainCallback)
{ {
_device = device; _device = device;
_swapChain = swapChain; _swapChain = swapChain;
@ -37,7 +53,7 @@ namespace BizHawk.Bizware.Graphics
_device.DepthStencilSurface = null; _device.DepthStencilSurface = null;
} }
public void PresentBuffer() public void PresentBuffer(ControlParameters cp)
{ {
SetBackBuffer(); SetBackBuffer();
@ -49,19 +65,12 @@ namespace BizHawk.Bizware.Graphics
{ {
if (ex.ResultCode.Code == D3DERR_DEVICELOST) if (ex.ResultCode.Code == D3DERR_DEVICELOST)
{ {
var pp = _swapChain.PresentParameters; _swapChain = _resetDeviceCallback(cp);
pp.BackBufferWidth = pp.BackBufferHeight = 0;
_swapChain = _resetDeviceCallback(pp);
} }
} }
} }
public void Refresh(bool vsync) public void Refresh(ControlParameters cp)
{ => _swapChain = _resetSwapChainCallback(cp);
var pp = _swapChain.PresentParameters;
pp.BackBufferWidth = pp.BackBufferHeight = 0;
pp.PresentationInterval = vsync ? PresentInterval.One : PresentInterval.Immediate;
_swapChain = _resetSwapChainCallback(pp);
}
} }
} }

View File

@ -29,6 +29,7 @@ namespace BizHawk.Bizware.Graphics
private const int D3DERR_DEVICENOTRESET = unchecked((int)0x88760869); private const int D3DERR_DEVICENOTRESET = unchecked((int)0x88760869);
private Device _device; private Device _device;
private Size _maxWindowSize;
private SwapChain _controlSwapchain; private SwapChain _controlSwapchain;
private IntPtr _offscreenSdl2Window; private IntPtr _offscreenSdl2Window;
@ -105,6 +106,11 @@ namespace BizHawk.Bizware.Graphics
flags |= CreateFlags.FpuPreserve; flags |= CreateFlags.FpuPreserve;
_device = new(d3d9, 0, DeviceType.Hardware, pp.DeviceWindowHandle, flags, pp); _device = new(d3d9, 0, DeviceType.Hardware, pp.DeviceWindowHandle, flags, pp);
// save the maximum size a window backbuffer can be
// this allows us to avoid resetting the swapchain on resizing the window
var displayMode = d3d9.Adapters[0].CurrentDisplayMode;
_maxWindowSize = new(displayMode.Width, displayMode.Height);
} }
private PresentParameters MakePresentParameters() private PresentParameters MakePresentParameters()
@ -119,7 +125,22 @@ namespace BizHawk.Bizware.Graphics
}; };
} }
private SwapChain ResetDevice(PresentParameters swapChainPresentParameters) private static PresentParameters MakePresentParameters(D3D9SwapChain.ControlParameters cp)
{
return new()
{
BackBufferWidth = cp.Width,
BackBufferHeight = cp.Height,
BackBufferFormat = Format.X8R8G8B8,
BackBufferCount = 2,
SwapEffect = SwapEffect.Discard,
DeviceWindowHandle = cp.Handle,
Windowed = true,
PresentationInterval = cp.Vsync ? PresentInterval.One : PresentInterval.Immediate
};
}
private SwapChain ResetDevice(D3D9SwapChain.ControlParameters cp)
{ {
SuspendRenderTargets(); SuspendRenderTargets();
_controlSwapchain.Dispose(); _controlSwapchain.Dispose();
@ -151,35 +172,29 @@ namespace BizHawk.Bizware.Graphics
} }
ResumeRenderTargets(); ResumeRenderTargets();
_controlSwapchain = new(_device, swapChainPresentParameters);
return _controlSwapchain; pp = MakePresentParameters(cp);
}
private SwapChain ResetSwapChain(PresentParameters pp)
{
_controlSwapchain.Dispose();
_controlSwapchain = new(_device, pp); _controlSwapchain = new(_device, pp);
return _controlSwapchain; return _controlSwapchain;
} }
public D3D9SwapChain CreateSwapChain(IntPtr handle) private SwapChain ResetSwapChain(D3D9SwapChain.ControlParameters cp)
{
_controlSwapchain.Dispose();
var pp = MakePresentParameters(cp);
_controlSwapchain = new(_device, pp);
return _controlSwapchain;
}
public D3D9SwapChain CreateSwapChain(D3D9SwapChain.ControlParameters cp)
{ {
if (_controlSwapchain != null) if (_controlSwapchain != null)
{ {
throw new InvalidOperationException($"{nameof(IGL_D3D9)} can only have 1 control swap chain"); throw new InvalidOperationException($"{nameof(IGL_D3D9)} can only have 1 control swap chain");
} }
var pp = new PresentParameters var pp = MakePresentParameters(cp);
{
BackBufferCount = 1,
BackBufferFormat = Format.X8R8G8B8,
SwapEffect = SwapEffect.Discard,
DeviceWindowHandle = handle,
Windowed = true,
PresentationInterval = PresentInterval.Immediate
};
_controlSwapchain = new(_device, pp); _controlSwapchain = new(_device, pp);
return new(_device, _controlSwapchain, ResetDevice, ResetSwapChain); return new(_device, _controlSwapchain, ResetDevice, ResetSwapChain);
} }