From 1e07625d1dabe18aa1679e7da7e0c8cc7e8d262c Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 11 Oct 2015 21:03:09 -0500 Subject: [PATCH] d3d display method: do a better job of surviving device resets --- BizHawk.Client.Common/GLManager.cs | 6 +- BizHawk.Client.EmuHawk/Program.cs | 12 +- .../IGL_SlimDX9.cs | 126 ++++++++++++++++-- 3 files changed, 131 insertions(+), 13 deletions(-) diff --git a/BizHawk.Client.Common/GLManager.cs b/BizHawk.Client.Common/GLManager.cs index 44440f04b5..de6826d67d 100644 --- a/BizHawk.Client.Common/GLManager.cs +++ b/BizHawk.Client.Common/GLManager.cs @@ -7,13 +7,17 @@ namespace BizHawk.Client.Common /// /// This singleton class manages OpenGL contexts, in an effort to minimize context changes. /// - public class GLManager + public class GLManager : IDisposable { private GLManager() { } + public void Dispose() + { + } + public static GLManager Instance { get; private set; } public static void CreateInstance() diff --git a/BizHawk.Client.EmuHawk/Program.cs b/BizHawk.Client.EmuHawk/Program.cs index 88f7971321..cd4b51be9b 100644 --- a/BizHawk.Client.EmuHawk/Program.cs +++ b/BizHawk.Client.EmuHawk/Program.cs @@ -220,7 +220,17 @@ namespace BizHawk.Client.EmuHawk } #endif } - } + + //cleanup: + //cleanup IGL stuff so we can get better refcounts when exiting process, for debugging + //DOESNT WORK FOR SOME REASON + //GlobalWin.IGL_GL = new Bizware.BizwareGL.Drivers.OpenTK.IGL_TK(); + //GLManager.Instance.Dispose(); + //if (GlobalWin.IGL_GL != GlobalWin.GL) + // GlobalWin.GL.Dispose(); + //((IDisposable)GlobalWin.IGL_GL).Dispose(); + + } //SubMain //declared here instead of a more usual place to avoid dependencies on the more usual place #if WINDOWS diff --git a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/IGL_SlimDX9.cs b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/IGL_SlimDX9.cs index 6b4c699cfd..27ee3d6cbf 100644 --- a/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/IGL_SlimDX9.cs +++ b/Bizware/BizHawk.Bizware.BizwareGL.SlimDX/IGL_SlimDX9.cs @@ -62,18 +62,41 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX } } + PresentParameters MakePresentParameters() + { + return new PresentParameters + { + BackBufferWidth = 8, + BackBufferHeight = 8, + DeviceWindowHandle = OffscreenNativeWindow.WindowInfo.Handle, + PresentationInterval = PresentInterval.Immediate, + EnableAutoDepthStencil = false + }; + } + + void ResetDevice() + { + ResetHandlers.Reset(); + for(;;) + { + var pp = MakePresentParameters(); + try + { + dev.Reset(pp); + } + catch { } + if (dev.TestCooperativeLevel().IsSuccess) + break; + System.Threading.Thread.Sleep(100); + } + ResetHandlers.Restore(); + } + public void CreateDevice() { DestroyDevice(); - //just create some present params so we can get the device created - var pp = new PresentParameters - { - BackBufferWidth = 8, - BackBufferHeight = 8, - DeviceWindowHandle = OffscreenNativeWindow.WindowInfo.Handle, - PresentationInterval = PresentInterval.Immediate - }; + var pp = MakePresentParameters(); var flags = CreateFlags.SoftwareVertexProcessing; if ((d3d.GetDeviceCaps(0, DeviceType.Hardware).DeviceCaps & DeviceCaps.HWTransformAndLight) != 0) @@ -85,6 +108,9 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX void IDisposable.Dispose() { + ResetHandlers.Reset(); + DestroyDevice(); + d3d.Dispose(); } public void Clear(OpenTK.Graphics.OpenGL.ClearBufferMask mask) @@ -737,7 +763,9 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX public void BeginControl(GLControlWrapper_SlimDX9 control) { _CurrentControl = control; - dev.SetRenderTarget(0, control.SwapChain.GetBackBuffer(0)); + var bb = control.SwapChain.GetBackBuffer(0); + dev.SetRenderTarget(0, bb); + bb.Dispose(); } public void EndControl(GLControlWrapper_SlimDX9 control) @@ -745,13 +773,28 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX if (control != _CurrentControl) throw new InvalidOperationException(); + var bb = dev.GetBackBuffer(0,0); + dev.SetRenderTarget(0,bb); + bb.Dispose(); + _CurrentControl = null; } public void SwapControl(GLControlWrapper_SlimDX9 control) { - control.SwapChain.Present(Present.None); + EndControl(control); + + try + { + var result = control.SwapChain.Present(Present.None); + } + catch(d3d9.Direct3D9Exception ex) + { + if (ex.ResultCode.Name == "D3DERR_DEVICELOST") + ResetDevice(); + } } + public void FreeRenderTarget(RenderTarget rt) { @@ -777,7 +820,9 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX if (rt == null) { - dev.SetRenderTarget(0, _CurrentControl.SwapChain.GetBackBuffer(0)); + var bb = _CurrentControl.SwapChain.GetBackBuffer(0); + dev.SetRenderTarget(0, bb); + bb.Dispose(); dev.DepthStencilSurface = null; return; } @@ -795,6 +840,7 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX control.SwapChain.Dispose(); control.SwapChain = null; } + ResetHandlers.Remove(control, "SwapChain"); var pp = new PresentParameters { @@ -808,8 +854,66 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX }; control.SwapChain = new SwapChain(dev, pp); + ResetHandlers.Add(control, "SwapChain", () => { control.SwapChain.Dispose(); control.SwapChain = null; }, () => RefreshControlSwapChain(control)); } + DeviceLostHandler ResetHandlers = new DeviceLostHandler(); + + class DeviceLostHandler + { + class ResetHandlerKey + { + public string Label; + public object Object; + public override int GetHashCode() + { + return Label.GetHashCode() ^ Object.GetHashCode(); + } + public override bool Equals(object obj) + { + if (obj == null) return false; + var key = obj as ResetHandlerKey; + return key.Label == Label && key.Object == Object; + } + } + + class HandlerSet + { + public Action Reset, Restore; + } + + Dictionary Handlers = new Dictionary(); + + public void Add(object o, string label, Action reset, Action restore) + { + ResetHandlerKey hkey = new ResetHandlerKey() { Object = o, Label = label }; + Handlers[hkey] = new HandlerSet { Reset = reset, Restore = restore }; + } + + public void Remove(object o, string label) + { + ResetHandlerKey hkey = new ResetHandlerKey() { Object = o, Label = label }; + if(Handlers.ContainsKey(hkey)) + Handlers.Remove(hkey); + } + + public void Reset() + { + foreach (var handler in Handlers) + handler.Value.Reset(); + } + + public void Restore() + { + var todo = Handlers.ToArray(); + Handlers.Clear(); + foreach (var item in todo) + item.Value.Restore(); + } + } + + + public IGraphicsControl Internal_CreateGraphicsControl() { var ret = new GLControlWrapper_SlimDX9(this);