Merge pull request #829 from TASVideos/d3dresetdevice

Cleanup Direct3D device reset code.
This commit is contained in:
zeromus 2017-04-09 13:39:22 -04:00 committed by GitHub
commit 934e588a61
2 changed files with 53 additions and 108 deletions

View File

@ -37,9 +37,9 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
sdx.FreeControlSwapChain(this);
//if(MyBufferedGraphics != null)
base.Dispose(disposing);
}
IGL_SlimDX9 sdx;

View File

@ -26,13 +26,15 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
public class IGL_SlimDX9 : IGL
{
const int D3DERR_DEVICELOST = -2005530520;
const int D3DERR_DEVICENOTRESET = -2005530519;
static Direct3D d3d;
internal Device dev;
INativeWindow OffscreenNativeWindow;
//rendering state
IntPtr _pVertexData;
RenderTarget _CurrRenderTarget;
Pipeline _CurrPipeline;
GLControlWrapper_SlimDX9 _CurrentControl;
@ -87,15 +89,16 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
};
}
void ResetDevice()
void ResetDevice(GLControlWrapper_SlimDX9 control)
{
ResetHandlers.Reset();
SuspendRenderTargets();
FreeControlSwapChain(control);
for (; ; )
{
var result = dev.TestCooperativeLevel();
if (result.IsSuccess)
break;
if (result.Code == -2005530519) // D3DERR_DEVICENOTRESET
if (result.Code == D3DERR_DEVICENOTRESET)
{
try
{
@ -107,7 +110,8 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
}
System.Threading.Thread.Sleep(100);
}
ResetHandlers.Restore();
RefreshControlSwapChain(control);
ResumeRenderTargets();
}
public void CreateDevice()
@ -128,7 +132,6 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
void IDisposable.Dispose()
{
ResetHandlers.Reset();
DestroyDevice();
d3d.Dispose();
}
@ -844,55 +847,56 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
}
catch(d3d9.Direct3D9Exception ex)
{
if (ex.ResultCode.Name == "D3DERR_DEVICELOST")
ResetDevice();
if (ex.ResultCode.Code == D3DERR_DEVICELOST)
ResetDevice(control);
}
}
HashSet<RenderTarget> _renderTargets = new HashSet<RenderTarget>();
public void FreeRenderTarget(RenderTarget rt)
{
//not needed 1st pass ??
//int id = rt.Id.ToInt32();
//var rtw = ResourceIDs.Lookup[id] as RenderTargetWrapper;
//rtw.Target.Dispose();
//ResourceIDs.Free(rt.Id);
}
public RenderTarget CreateRenderTarget(int w, int h)
{
var d3dtex = new d3d9.Texture(dev, w, h, 1, d3d9.Usage.RenderTarget, d3d9.Format.A8R8G8B8, d3d9.Pool.Default);
var tw = new TextureWrapper() { Texture = d3dtex };
var tex = new Texture2d(this, tw, w, h);
RenderTarget rt = new RenderTarget(this, tw, tex);
ResetHandlers.Add(rt, "RenderTarget", () => ResetRenderTarget(rt), () => RestoreRenderTarget(rt));
return rt;
}
void ResetRenderTarget(RenderTarget rt)
{
var tw = rt.Texture2d.Opaque as TextureWrapper;
tw.Texture.Dispose();
tw.Texture = null;
_renderTargets.Remove(rt);
}
void RestoreRenderTarget(RenderTarget rt)
public RenderTarget CreateRenderTarget(int w, int h)
{
var tw = rt.Texture2d.Opaque as TextureWrapper;
int w = rt.Texture2d.IntWidth;
int h = rt.Texture2d.IntHeight;
var d3dtex = new d3d9.Texture(dev, w, h, 1, d3d9.Usage.RenderTarget, d3d9.Format.A8R8G8B8, d3d9.Pool.Default);
tw.Texture = d3dtex;
//i know it's weird, we have to re-add ourselves to the list
//bad design..
ResetHandlers.Add(rt, "RenderTarget", () => ResetRenderTarget(rt), () => RestoreRenderTarget(rt));
var tw = new TextureWrapper() { Texture = CreateRenderTargetTexture(w, h) };
var tex = new Texture2d(this, tw, w, h);
var rt = new RenderTarget(this, tw, tex);
_renderTargets.Add(rt);
return rt;
}
d3d9.Texture CreateRenderTargetTexture(int w, int h)
{
return new d3d9.Texture(dev, w, h, 1, d3d9.Usage.RenderTarget, d3d9.Format.A8R8G8B8, d3d9.Pool.Default);
}
void SuspendRenderTargets()
{
foreach (var rt in _renderTargets)
{
var tw = rt.Opaque as TextureWrapper;
tw.Texture.Dispose();
tw.Texture = null;
}
}
void ResumeRenderTargets()
{
foreach (var rt in _renderTargets)
{
var tw = rt.Opaque as TextureWrapper;
tw.Texture = CreateRenderTargetTexture(rt.Texture2d.IntWidth, rt.Texture2d.IntHeight);
}
}
public void BindRenderTarget(RenderTarget rt)
{
_CurrRenderTarget = rt;
if (rt == null)
{
//this dispose is needed for correct device resets, I have no idea why
@ -911,15 +915,19 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
dev.DepthStencilSurface = null;
}
public void RefreshControlSwapChain(GLControlWrapper_SlimDX9 control)
public void FreeControlSwapChain(GLControlWrapper_SlimDX9 control)
{
if (control.SwapChain != null)
{
control.SwapChain.Dispose();
control.SwapChain = null;
}
ResetHandlers.Remove(control, "SwapChain");
}
public void RefreshControlSwapChain(GLControlWrapper_SlimDX9 control)
{
FreeControlSwapChain(control);
var pp = new PresentParameters
{
BackBufferWidth = Math.Max(8,control.ClientSize.Width),
@ -932,71 +940,8 @@ 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<ResetHandlerKey, HandlerSet> Handlers = new Dictionary<ResetHandlerKey, HandlerSet>();
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);