From 72cc192661bd446425af4e88ca814cf3919e1d49 Mon Sep 17 00:00:00 2001 From: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com> Date: Sat, 12 Aug 2023 03:56:02 -0700 Subject: [PATCH] Create a new project to house the IGL WinForms controls (Bizware.Graphics.Controls), thus allowing for Bizware.Graphics to be netstandard2.0 also move GDIPlus IGL stuff over from BizwareGL to Bizware.Graphics --- BizHawk.sln | 6 + src/BizHawk.Bizware.BizwareGL/IGL.cs | 2 - .../RenderTargetWrapper.cs | 67 -------- .../BizHawk.Bizware.Graphics.Controls.csproj | 14 ++ .../Controls/D3D9Control.cs | 63 ++++++++ .../Controls/GDIPlusControl.cs | 62 +++++++ .../Controls}/OpenGLControl.cs | 19 +-- .../GraphicsControl.cs} | 22 +-- .../GraphicsControlFactory.cs | 27 ++++ .../BizHawk.Bizware.Graphics.csproj | 4 +- .../D3D9/D3D9Control.cs | 67 -------- .../D3D9/D3D9SwapChain.cs | 67 ++++++++ src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs | 152 ++++++------------ .../GDIPlus/GDIPlusRenderTarget.cs | 63 ++++++++ .../GDIPlus/GDIPlusTexture.cs} | 13 +- .../GDIPlus/IGL_GDIPlus.cs} | 146 ++++++----------- .../OpenGL/IGL_OpenGL.cs | 7 - .../Renderers}/GDIPlusGuiRenderer.cs | 39 ++--- .../{ => Renderers}/GuiRenderer.cs | 0 .../BizHawk.Client.EmuHawk.csproj | 3 +- .../DisplayManager/DisplayManager.cs | 1 + .../GLControlWrapper_GdiPlus.cs | 76 --------- .../GraphicsControl.cs | 60 ------- .../GraphicsImplementations/IGLExtensions.cs | 2 +- .../RetainedGraphicsControl.cs | 74 +++++---- src/BizHawk.Client.EmuHawk/MainForm.cs | 10 +- .../PresentationPanel.cs | 24 +-- src/BizHawk.Client.EmuHawk/Program.cs | 3 +- 28 files changed, 502 insertions(+), 591 deletions(-) delete mode 100644 src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs create mode 100644 src/BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj create mode 100644 src/BizHawk.Bizware.Graphics.Controls/Controls/D3D9Control.cs create mode 100644 src/BizHawk.Bizware.Graphics.Controls/Controls/GDIPlusControl.cs rename src/{BizHawk.Bizware.Graphics/OpenGL => BizHawk.Bizware.Graphics.Controls/Controls}/OpenGLControl.cs (76%) rename src/{BizHawk.Bizware.BizwareGL/IGraphicsControl.cs => BizHawk.Bizware.Graphics.Controls/GraphicsControl.cs} (68%) create mode 100644 src/BizHawk.Bizware.Graphics.Controls/GraphicsControlFactory.cs delete mode 100644 src/BizHawk.Bizware.Graphics/D3D9/D3D9Control.cs create mode 100644 src/BizHawk.Bizware.Graphics/D3D9/D3D9SwapChain.cs create mode 100644 src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusRenderTarget.cs rename src/{BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs => BizHawk.Bizware.Graphics/GDIPlus/GDIPlusTexture.cs} (58%) rename src/{BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs => BizHawk.Bizware.Graphics/GDIPlus/IGL_GDIPlus.cs} (60%) rename src/{BizHawk.Bizware.BizwareGL => BizHawk.Bizware.Graphics/Renderers}/GDIPlusGuiRenderer.cs (85%) rename src/BizHawk.Bizware.Graphics/{ => Renderers}/GuiRenderer.cs (100%) delete mode 100644 src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs delete mode 100644 src/BizHawk.Client.EmuHawk/GraphicsImplementations/GraphicsControl.cs diff --git a/BizHawk.sln b/BizHawk.sln index 0b8b899cad..1955f548fd 100644 --- a/BizHawk.sln +++ b/BizHawk.sln @@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Input", "sr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Graphics", "src\BizHawk.Bizware.Graphics\BizHawk.Bizware.Graphics.csproj", "{368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.Graphics.Controls", "src\BizHawk.Bizware.Graphics.Controls\BizHawk.Bizware.Graphics.Controls.csproj", "{3D050D35-B57D-4D14-BE0F-FD63552DADB0}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.Bizware.BizwareGL", "src\BizHawk.Bizware.BizwareGL\BizHawk.Bizware.BizwareGL.csproj", "{658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BizHawk.BizInvoke", "src\BizHawk.BizInvoke\BizHawk.BizInvoke.csproj", "{E5D76DC1-84A8-47AF-BE25-E76F06D2FBBC}" @@ -83,6 +85,10 @@ Global {368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Release|Any CPU.ActiveCfg = Release|Any CPU {368BC91D-48CD-492A-B6CF-B5B77F7FE7D4}.Release|Any CPU.Build.0 = Release|Any CPU + {3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D050D35-B57D-4D14-BE0F-FD63552DADB0}.Release|Any CPU.Build.0 = Release|Any CPU {658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU {658BB7AA-74A1-496F-A6AA-B7D3DD9C7CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/src/BizHawk.Bizware.BizwareGL/IGL.cs b/src/BizHawk.Bizware.BizwareGL/IGL.cs index ed7b6d2d23..ccc791bb34 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGL.cs +++ b/src/BizHawk.Bizware.BizwareGL/IGL.cs @@ -270,7 +270,5 @@ namespace BizHawk.Bizware.BizwareGL /// Frees the provided vertex layout. For internal use only. /// void Internal_FreeVertexLayout(VertexLayout vertexLayout); - - IGraphicsControl Internal_CreateGraphicsControl(); } } diff --git a/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs b/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs deleted file mode 100644 index 774fb6343e..0000000000 --- a/src/BizHawk.Bizware.BizwareGL/RenderTargetWrapper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Drawing; -#if false -using System.Drawing.Drawing2D; -#endif - -namespace BizHawk.Bizware.BizwareGL -{ - public class RenderTargetWrapper : IDisposable - { - public RenderTargetWrapper( - Func getBufferedGraphicsContext, - IGraphicsControl control = null) - { - _getBufferedGraphicsContext = getBufferedGraphicsContext; - Control = control; - } - - public void Dispose() - { - MyBufferedGraphics?.Dispose(); - } - - private readonly Func _getBufferedGraphicsContext; - - /// - /// the control associated with this render target (if any) - /// - private readonly IGraphicsControl Control; - - /// - /// the offscreen render target, if that's what this is representing - /// - public RenderTarget Target; - - public BufferedGraphics MyBufferedGraphics; - - public Graphics refGraphics; // ?? hacky? - - public void CreateGraphics() - { - Rectangle r; - if (Control != null) - { - r = Control.ClientRectangle; - refGraphics = Control.CreateGraphics(); - } - else - { - var tw = (GDIPTextureWrapper)Target.Texture2d.Opaque; - r = Target.Texture2d.Rectangle; - refGraphics = Graphics.FromImage(tw.SDBitmap); - } - - MyBufferedGraphics?.Dispose(); - MyBufferedGraphics = _getBufferedGraphicsContext().Allocate(refGraphics, r); -#if false - MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; - - // not sure about this stuff... - // it will wreck alpha blending, for one thing - MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy; - MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed; -#endif - } - } -} diff --git a/src/BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj b/src/BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj new file mode 100644 index 0000000000..afa42186c5 --- /dev/null +++ b/src/BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj @@ -0,0 +1,14 @@ + + + net48 + + + + true + disable + + + + + + diff --git a/src/BizHawk.Bizware.Graphics.Controls/Controls/D3D9Control.cs b/src/BizHawk.Bizware.Graphics.Controls/Controls/D3D9Control.cs new file mode 100644 index 0000000000..597b46a47e --- /dev/null +++ b/src/BizHawk.Bizware.Graphics.Controls/Controls/D3D9Control.cs @@ -0,0 +1,63 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace BizHawk.Bizware.Graphics.Controls +{ + internal sealed class D3D9Control : GraphicsControl + { + private readonly Func _createSwapChain; + private D3D9SwapChain _swapChain; + private bool Vsync; + + public D3D9Control(Func createSwapChain) + { + _createSwapChain = createSwapChain; + + SetStyle(ControlStyles.Opaque, true); + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.UserMouse, true); + DoubleBuffered = false; + } + + protected override Size DefaultSize => new(1, 1); + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + _swapChain = _createSwapChain(Handle); + } + + protected override void OnHandleDestroyed(EventArgs e) + { + base.OnHandleDestroyed(e); + _swapChain.Dispose(); + _swapChain = null; + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + _swapChain.Refresh(Vsync); + } + + public override void SetVsync(bool state) + { + if (Vsync != state) + { + Vsync = state; + _swapChain.Refresh(Vsync); + } + } + + public override void Begin() + => _swapChain.SetBackBuffer(); + + public override void End() + => _swapChain.SetBackBuffer(); + + public override void SwapBuffers() + => _swapChain.PresentBuffer(); + } +} \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics.Controls/Controls/GDIPlusControl.cs b/src/BizHawk.Bizware.Graphics.Controls/Controls/GDIPlusControl.cs new file mode 100644 index 0000000000..de5e412427 --- /dev/null +++ b/src/BizHawk.Bizware.Graphics.Controls/Controls/GDIPlusControl.cs @@ -0,0 +1,62 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +using SDGraphics = System.Drawing.Graphics; + +namespace BizHawk.Bizware.Graphics.Controls +{ + internal sealed class GDIPlusControl : GraphicsControl + { + public GDIPlusControl(Func, GDIPlusRenderTarget> createControlRenderTarget) + { + RenderTarget = createControlRenderTarget(GetControlRenderContext); + + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.Opaque, true); + SetStyle(ControlStyles.UserMouse, true); + } + + private (SDGraphics Graphics, Rectangle Rectangle) GetControlRenderContext() + => (CreateGraphics(), ClientRectangle); + + /// + /// The render target for rendering to this control + /// + private GDIPlusRenderTarget RenderTarget { get; } + + public override void SetVsync(bool state) + { + // not really supported now... + } + + public override void Begin() + => RenderTarget.CreateGraphics(); + + public override void End() + { + } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + RenderTarget.CreateGraphics(); + } + + public override void SwapBuffers() + { + if (RenderTarget.BufferedGraphics == null) + { + return; + } + + using var g = CreateGraphics(); + // not sure we had proof we needed this but it cant hurt + g.CompositingMode = CompositingMode.SourceCopy; + g.CompositingQuality = CompositingQuality.HighSpeed; + RenderTarget.BufferedGraphics.Render(g); + } + } +} \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics/OpenGL/OpenGLControl.cs b/src/BizHawk.Bizware.Graphics.Controls/Controls/OpenGLControl.cs similarity index 76% rename from src/BizHawk.Bizware.Graphics/OpenGL/OpenGLControl.cs rename to src/BizHawk.Bizware.Graphics.Controls/Controls/OpenGLControl.cs index 77729a11ea..3edc498490 100644 --- a/src/BizHawk.Bizware.Graphics/OpenGL/OpenGLControl.cs +++ b/src/BizHawk.Bizware.Graphics.Controls/Controls/OpenGLControl.cs @@ -1,21 +1,14 @@ using System; using System.Windows.Forms; -using BizHawk.Bizware.BizwareGL; using BizHawk.Common; -namespace BizHawk.Bizware.Graphics +namespace BizHawk.Bizware.Graphics.Controls { - internal class OpenGLControl : Control, IGraphicsControl + internal sealed class OpenGLControl : GraphicsControl { public SDL2OpenGLContext Context { get; private set; } - public RenderTargetWrapper RenderTargetWrapper - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - public OpenGLControl() { // according to OpenTK, these are the styles we want to set @@ -75,23 +68,23 @@ namespace BizHawk.Bizware.Graphics } } - public void SetVsync(bool state) + public override void SetVsync(bool state) { MakeContextCurrent(); Context.SetVsync(state); } - public void Begin() + public override void Begin() { MakeContextCurrent(); } - public void End() + public override void End() { SDL2OpenGLContext.MakeNoneCurrent(); } - public void SwapBuffers() + public override void SwapBuffers() { MakeContextCurrent(); Context.SwapBuffers(); diff --git a/src/BizHawk.Bizware.BizwareGL/IGraphicsControl.cs b/src/BizHawk.Bizware.Graphics.Controls/GraphicsControl.cs similarity index 68% rename from src/BizHawk.Bizware.BizwareGL/IGraphicsControl.cs rename to src/BizHawk.Bizware.Graphics.Controls/GraphicsControl.cs index d89a1f0afb..fb32cb464b 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGraphicsControl.cs +++ b/src/BizHawk.Bizware.Graphics.Controls/GraphicsControl.cs @@ -1,40 +1,32 @@ -using System; -using System.Drawing; +using System.Windows.Forms; -namespace BizHawk.Bizware.BizwareGL +namespace BizHawk.Bizware.Graphics.Controls { - public interface IGraphicsControl : IDisposable + public abstract class GraphicsControl : Control { - Rectangle ClientRectangle { get; } - - RenderTargetWrapper RenderTargetWrapper { get; set; } - - Graphics CreateGraphics(); - /// /// Sets whether presentation operations on this control will vsync /// - void SetVsync(bool state); + public abstract void SetVsync(bool state); /// /// Swaps the buffers for this control /// - void SwapBuffers(); + public abstract void SwapBuffers(); /// /// Makes this control current for rendering operations. /// Note that at this time, the window size shouldn't change until End() or else something bad might happen /// Please be aware that this might change the rendering context, meaning that some things you set without calling Begin/End might not be affected /// - void Begin(); + public abstract void Begin(); /// /// Ends rendering on the specified control. /// NOTE: DO NOT EXPECT TO SEE BEGIN/END CALLED IN PAIRS, STRICTLY. /// this is more about GL context management than anything else. - /// See GLManager for details. /// In particular, don't expect to have End() called before doing certain things. Maybe use SwapBuffers instead /// - void End(); + public abstract void End(); } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics.Controls/GraphicsControlFactory.cs b/src/BizHawk.Bizware.Graphics.Controls/GraphicsControlFactory.cs new file mode 100644 index 0000000000..05f11ce9a4 --- /dev/null +++ b/src/BizHawk.Bizware.Graphics.Controls/GraphicsControlFactory.cs @@ -0,0 +1,27 @@ +using System; + +using BizHawk.Bizware.BizwareGL; + +namespace BizHawk.Bizware.Graphics.Controls +{ + /// + /// A factory for creating a GraphicsControl based on an IGL + /// + public static class GraphicsControlFactory + { + public static GraphicsControl CreateGraphicsControl(IGL gl) + { + GraphicsControl ret = gl switch + { + IGL_OpenGL => new OpenGLControl(), + IGL_D3D9 d3d9 => new D3D9Control(d3d9.CreateSwapChain), + IGL_GDIPlus gdiPlus => new GDIPlusControl(gdiPlus.CreateControlRenderTarget), + _ => throw new InvalidOperationException() + }; + + // IGLs need the window handle in order to do things, so best create the control immediately + ret.CreateControl(); + return ret; + } + } +} \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj b/src/BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj index 9fe9297b9f..11c8b38f1b 100644 --- a/src/BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj +++ b/src/BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj @@ -1,6 +1,6 @@  - net48 + netstandard2.0 @@ -8,9 +8,7 @@ disable - - diff --git a/src/BizHawk.Bizware.Graphics/D3D9/D3D9Control.cs b/src/BizHawk.Bizware.Graphics/D3D9/D3D9Control.cs deleted file mode 100644 index a205de7cfd..0000000000 --- a/src/BizHawk.Bizware.Graphics/D3D9/D3D9Control.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Windows.Forms; - -using BizHawk.Bizware.BizwareGL; -using BizHawk.Common; - -using SharpDX.Direct3D9; - -namespace BizHawk.Bizware.Graphics -{ - internal sealed class D3D9Control : Control, IGraphicsControl - { - private readonly IGL_D3D9 _owner; - internal SwapChain SwapChain; - internal bool Vsync; - - public D3D9Control(IGL_D3D9 owner) - { - _owner = owner; - - SetStyle(ControlStyles.Opaque, true); - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.UserMouse, true); - DoubleBuffered = false; - } - - public RenderTargetWrapper RenderTargetWrapper - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - - protected override void OnHandleCreated(EventArgs e) - { - base.OnHandleCreated(e); - _owner.RefreshControlSwapChain(this); - } - - protected override void OnHandleDestroyed(EventArgs e) - { - base.OnHandleDestroyed(e); - IGL_D3D9.FreeControlSwapChain(this); - } - - protected override void OnResize(EventArgs e) - { - base.OnResize(e); - _owner.RefreshControlSwapChain(this); - } - - public void SetVsync(bool state) - { - Vsync = state; - _owner.RefreshControlSwapChain(this); - } - - public void Begin() - => _owner.BeginControl(this); - - public void End() - => _owner.EndControl(this); - - public void SwapBuffers() - => _owner.SwapControl(this); - } -} \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics/D3D9/D3D9SwapChain.cs b/src/BizHawk.Bizware.Graphics/D3D9/D3D9SwapChain.cs new file mode 100644 index 0000000000..938fef167a --- /dev/null +++ b/src/BizHawk.Bizware.Graphics/D3D9/D3D9SwapChain.cs @@ -0,0 +1,67 @@ +using System; + +using SharpDX; +using SharpDX.Direct3D9; + +namespace BizHawk.Bizware.Graphics +{ + public sealed class D3D9SwapChain : IDisposable + { + private const int D3DERR_DEVICELOST = unchecked((int)0x88760868); + + private readonly Device _device; + private readonly Func _resetDeviceCallback; + private readonly Func _resetSwapChainCallback; + + private SwapChain _swapChain; + + internal D3D9SwapChain(Device device, SwapChain swapChain, + Func resetDeviceCallback, Func resetSwapChainCallback) + { + _device = device; + _swapChain = swapChain; + _resetDeviceCallback = resetDeviceCallback; + _resetSwapChainCallback = resetSwapChainCallback; + } + + public void Dispose() + { + _swapChain?.Dispose(); + _swapChain = null; + } + + public void SetBackBuffer() + { + using var surface = _swapChain.GetBackBuffer(0); + _device.SetRenderTarget(0, surface); + _device.DepthStencilSurface = null; + } + + public void PresentBuffer() + { + SetBackBuffer(); + + try + { + _swapChain.Present(Present.None); + } + catch (SharpDXException ex) + { + if (ex.ResultCode.Code == D3DERR_DEVICELOST) + { + var pp = _swapChain.PresentParameters; + pp.BackBufferWidth = pp.BackBufferHeight = 0; + _swapChain = _resetDeviceCallback(pp); + } + } + } + + public void Refresh(bool vsync) + { + var pp = _swapChain.PresentParameters; + pp.BackBufferWidth = pp.BackBufferHeight = 0; + pp.PresentationInterval = vsync ? PresentInterval.One : PresentInterval.Immediate; + _swapChain = _resetSwapChainCallback(pp); + } + } +} diff --git a/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs b/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs index cc8ba5a7d3..cdc2743a51 100644 --- a/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs +++ b/src/BizHawk.Bizware.Graphics/D3D9/IGL_D3D9.cs @@ -12,9 +12,7 @@ using BizHawk.Bizware.BizwareGL; using BizHawk.Common; using BizHawk.Common.StringExtensions; -using SharpDX; using SharpDX.Direct3D9; -using SharpDX.Mathematics.Interop; using static SDL2.SDL; @@ -28,17 +26,16 @@ namespace BizHawk.Bizware.Graphics { public EDispMethod DispMethodEnum => EDispMethod.D3D9; - private const int D3DERR_DEVICELOST = unchecked((int)0x88760868); private const int D3DERR_DEVICENOTRESET = unchecked((int)0x88760869); private Device _device; + private SwapChain _controlSwapchain; private IntPtr _offscreenSdl2Window; private IntPtr OffscreenNativeWindow; // rendering state private Pipeline _currPipeline; - private D3D9Control _currentControl; // misc state private CacheBlendState _rsBlendNoneVerbatim, _rsBlendNoneOpaque, _rsBlendNormal; @@ -110,15 +107,6 @@ namespace BizHawk.Bizware.Graphics _device = new(d3d9, 0, DeviceType.Hardware, pp.DeviceWindowHandle, flags, pp); } - private void DestroyDevice() - { - if (_device != null) - { - _device.Dispose(); - _device = null; - } - } - private PresentParameters MakePresentParameters() { return new() @@ -128,14 +116,15 @@ namespace BizHawk.Bizware.Graphics DeviceWindowHandle = OffscreenNativeWindow, Windowed = true, PresentationInterval = PresentInterval.Immediate, - EnableAutoDepthStencil = false }; } - private void ResetDevice(D3D9Control control) + private SwapChain ResetDevice(PresentParameters swapChainPresentParameters) { SuspendRenderTargets(); - FreeControlSwapChain(control); + _controlSwapchain.Dispose(); + + var pp = MakePresentParameters(); while (true) { @@ -149,7 +138,6 @@ namespace BizHawk.Bizware.Graphics { try { - var pp = MakePresentParameters(); _device.Reset(pp); break; } @@ -162,19 +150,55 @@ namespace BizHawk.Bizware.Graphics Thread.Sleep(100); } - RefreshControlSwapChain(control); ResumeRenderTargets(); + _controlSwapchain = new(_device, swapChainPresentParameters); + + return _controlSwapchain; + } + + private SwapChain ResetSwapChain(PresentParameters pp) + { + _controlSwapchain.Dispose(); + _controlSwapchain = new(_device, pp); + return _controlSwapchain; + } + + public D3D9SwapChain CreateSwapChain(IntPtr handle) + { + if (_controlSwapchain != null) + { + throw new InvalidOperationException($"{nameof(IGL_D3D9)} can only have 1 control swap chain"); + } + + var pp = new PresentParameters + { + BackBufferCount = 1, + BackBufferFormat = Format.X8R8G8B8, + SwapEffect = SwapEffect.Discard, + DeviceWindowHandle = handle, + Windowed = true, + PresentationInterval = PresentInterval.Immediate + }; + + _controlSwapchain = new(_device, pp); + return new(_device, _controlSwapchain, ResetDevice, ResetSwapChain); } public void Dispose() { - DestroyDevice(); + if (_device != null) + { + _device.Dispose(); + _device = null; + } if (_offscreenSdl2Window != IntPtr.Zero) { SDL_DestroyWindow(_offscreenSdl2Window); _offscreenSdl2Window = OffscreenNativeWindow = IntPtr.Zero; } + + _controlSwapchain = null; } public void ClearColor(Color color) @@ -670,7 +694,8 @@ namespace BizHawk.Bizware.Graphics { var tex = new Texture(_device, width, height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed); var tw = new TextureWrapper { Texture = tex }; - return new(this, tw, width, height); + var ret = new Texture2d(this, tw, width, height); + return ret; } public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height) @@ -792,46 +817,6 @@ namespace BizHawk.Bizware.Graphics SetViewport(size.Width, size.Height); } - internal void BeginControl(D3D9Control control) - { - _currentControl = control; - - // this dispose isn't strictly needed but it seems benign - using var surface = control.SwapChain.GetBackBuffer(0); - _device.SetRenderTarget(0, surface); - } - - /// does not match control passed to - internal void EndControl(D3D9Control control) - { - if (control != _currentControl) - { - throw new InvalidOperationException($"{nameof(control)} does not match control passed to {nameof(BeginControl)}"); - } - - using var surface = control.SwapChain.GetBackBuffer(0); - _device.SetRenderTarget(0, surface); - - _currentControl = null; - } - - internal void SwapControl(D3D9Control control) - { - EndControl(control); - - try - { - control.SwapChain.Present(Present.None); - } - catch (SharpDXException ex) - { - if (ex.ResultCode.Code == D3DERR_DEVICELOST) - { - ResetDevice(control); - } - } - } - public void FreeRenderTarget(RenderTarget rt) { var tw = (TextureWrapper)rt.Texture2d.Opaque; @@ -850,13 +835,11 @@ namespace BizHawk.Bizware.Graphics } private Texture CreateRenderTargetTexture(int w, int h) - { - return new(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default); - } + => new(_device, w, h, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default); private void SuspendRenderTargets() { - foreach (var tw in _renderTargets.Select(rt => (TextureWrapper)rt.Opaque)) + foreach (var tw in _renderTargets.Select(tex => (TextureWrapper)tex.Opaque)) { tw.Texture.Dispose(); tw.Texture = null; @@ -876,52 +859,19 @@ namespace BizHawk.Bizware.Graphics { if (rt == null) { - // this dispose is needed for correct device resets, I have no idea why - // don't try caching it either - using var surface = _currentControl.SwapChain.GetBackBuffer(0); - _device.SetRenderTarget(0, surface); + using var bb = _controlSwapchain.GetBackBuffer(0); + _device.SetRenderTarget(0, bb); _device.DepthStencilSurface = null; return; } // dispose doesn't seem necessary for reset here... var tw = (TextureWrapper)rt.Opaque; - _device.SetRenderTarget(0, tw.Texture.GetSurfaceLevel(0)); + using var texSurface = tw.Texture.GetSurfaceLevel(0); + _device.SetRenderTarget(0, texSurface); _device.DepthStencilSurface = null; } - internal static void FreeControlSwapChain(D3D9Control control) - { - control.SwapChain?.Dispose(); - control.SwapChain = null; - } - - internal void RefreshControlSwapChain(D3D9Control control) - { - FreeControlSwapChain(control); - - var pp = new PresentParameters - { - BackBufferWidth = Math.Max(1, control.ClientSize.Width), - BackBufferHeight = Math.Max(1, control.ClientSize.Height), - BackBufferCount = 1, - BackBufferFormat = Format.X8R8G8B8, - SwapEffect = SwapEffect.Discard, - DeviceWindowHandle = control.Handle, - Windowed = true, - PresentationInterval = control.Vsync ? PresentInterval.One : PresentInterval.Immediate - }; - - control.SwapChain = new(_device, pp); - } - - public IGraphicsControl Internal_CreateGraphicsControl() - { - var ret = new D3D9Control(this); - ret.CreateControl(); - return ret; - } - private delegate void DrawPrimitiveUPDelegate(Device device, PrimitiveType primitiveType, int primitiveCount, IntPtr vertexStreamZeroDataRef, int vertexStreamZeroStride); private static readonly Lazy _drawPrimitiveUP = new(() => diff --git a/src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusRenderTarget.cs b/src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusRenderTarget.cs new file mode 100644 index 0000000000..56aa376e9a --- /dev/null +++ b/src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusRenderTarget.cs @@ -0,0 +1,63 @@ +using System; +using System.Drawing; + +using BizHawk.Bizware.BizwareGL; + +using SDGraphics = System.Drawing.Graphics; + +namespace BizHawk.Bizware.Graphics +{ + public class GDIPlusRenderTarget : IDisposable + { + internal GDIPlusRenderTarget(Func getBufferedGraphicsContext, + Func<(SDGraphics Graphics, Rectangle Rectangle)> getControlRenderContext = null) + { + _getBufferedGraphicsContext = getBufferedGraphicsContext; + _getControlRenderContext = getControlRenderContext; + } + + public void Dispose() + { + if (_getControlRenderContext != null) + { + CurGraphics?.Dispose(); + } + + BufferedGraphics?.Dispose(); + } + + private readonly Func _getBufferedGraphicsContext; + + /// + /// get Graphics and Rectangle from a control, if any + /// + private readonly Func<(SDGraphics, Rectangle)> _getControlRenderContext; + + /// + /// the offscreen render target, if that's what this is representing + /// + public RenderTarget Target; + + public SDGraphics CurGraphics; + public BufferedGraphics BufferedGraphics; + + public void CreateGraphics() + { + Rectangle r; + if (_getControlRenderContext != null) + { + (CurGraphics, r) = _getControlRenderContext(); + } + else + { + var gtex = (GDIPlusTexture)Target.Texture2d.Opaque; + CurGraphics?.Dispose(); + CurGraphics = SDGraphics.FromImage(gtex.SDBitmap); + r = Target.Texture2d.Rectangle; + } + + BufferedGraphics?.Dispose(); + BufferedGraphics = _getBufferedGraphicsContext().Allocate(CurGraphics, r); + } + } +} diff --git a/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs b/src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusTexture.cs similarity index 58% rename from src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs rename to src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusTexture.cs index c0ec9763f7..d0726fdb49 100644 --- a/src/BizHawk.Bizware.BizwareGL/GDIPTextureWrapper.cs +++ b/src/BizHawk.Bizware.Graphics/GDIPlus/GDIPlusTexture.cs @@ -1,9 +1,11 @@ using System; using System.Drawing; -namespace BizHawk.Bizware.BizwareGL +using BizHawk.Bizware.BizwareGL; + +namespace BizHawk.Bizware.Graphics { - public class GDIPTextureWrapper : IDisposable + public class GDIPlusTexture : IDisposable { public Bitmap SDBitmap; public TextureMinFilter MinFilter = TextureMinFilter.Nearest; @@ -11,11 +13,8 @@ namespace BizHawk.Bizware.BizwareGL public void Dispose() { - if (SDBitmap != null) - { - SDBitmap.Dispose(); - SDBitmap = null; - } + SDBitmap?.Dispose(); + SDBitmap = null; } } } diff --git a/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs b/src/BizHawk.Bizware.Graphics/GDIPlus/IGL_GDIPlus.cs similarity index 60% rename from src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs rename to src/BizHawk.Bizware.Graphics/GDIPlus/IGL_GDIPlus.cs index 2dfabc7bdd..e5e0dd6388 100644 --- a/src/BizHawk.Bizware.BizwareGL/IGL_GdiPlus.cs +++ b/src/BizHawk.Bizware.Graphics/GDIPlus/IGL_GDIPlus.cs @@ -4,26 +4,20 @@ using System.Drawing; using System.Drawing.Imaging; using System.Numerics; +using BizHawk.Bizware.BizwareGL; + +using SDGraphics = System.Drawing.Graphics; + //TODO - maybe a layer to cache Graphics parameters (notably, filtering) ? -namespace BizHawk.Bizware.BizwareGL +namespace BizHawk.Bizware.Graphics { - public class IGL_GdiPlus : IGL + public class IGL_GDIPlus : IGL { public EDispMethod DispMethodEnum => EDispMethod.GdiPlus; -#if false - // rendering state - private RenderTarget _currRenderTarget; -#endif - - private readonly Func _createGLControlWrapper; - - public IGL_GdiPlus(Func createGLControlWrapper) - => _createGLControlWrapper = createGLControlWrapper; - public void Dispose() { - MyBufferedGraphicsContext.Dispose(); + BufferedGraphicsContext.Dispose(); } public void ClearColor(Color color) @@ -39,8 +33,8 @@ namespace BizHawk.Bizware.BizwareGL public void FreeTexture(Texture2d tex) { - var tw = (GDIPTextureWrapper)tex.Opaque; - tw.Dispose(); + var gtex = (GDIPlusTexture)tex.Opaque; + gtex.Dispose(); } public Shader CreateFragmentShader(string source, string entry, bool required) @@ -99,7 +93,6 @@ namespace BizHawk.Bizware.BizwareGL public void SetPipelineUniform(PipelineUniform uniform, bool value) { - } public void SetPipelineUniformMatrix(PipelineUniform uniform, Matrix4x4 mat, bool transpose) @@ -128,20 +121,19 @@ namespace BizHawk.Bizware.BizwareGL public void SetPipelineUniformSampler(PipelineUniform uniform, Texture2d tex) { - } public void SetMinFilter(Texture2d texture, TextureMinFilter minFilter) - => ((GDIPTextureWrapper) texture.Opaque).MinFilter = minFilter; + => ((GDIPlusTexture) texture.Opaque).MinFilter = minFilter; public void SetMagFilter(Texture2d texture, TextureMagFilter magFilter) - => ((GDIPTextureWrapper) texture.Opaque).MagFilter = magFilter; + => ((GDIPlusTexture) texture.Opaque).MagFilter = magFilter; public Texture2d LoadTexture(Bitmap bitmap) { var sdBitmap = (Bitmap)bitmap.Clone(); - var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap }; - return new(this, tw, bitmap.Width, bitmap.Height); + var gtex = new GDIPlusTexture { SDBitmap = sdBitmap }; + return new(this, gtex, bitmap.Width, bitmap.Height); } public Texture2d LoadTexture(Stream stream) @@ -161,27 +153,27 @@ namespace BizHawk.Bizware.BizwareGL public void LoadTextureData(Texture2d tex, BitmapBuffer bmp) { - var tw = (GDIPTextureWrapper)tex.Opaque; - bmp.ToSysdrawingBitmap(tw.SDBitmap); + var gtex = (GDIPlusTexture)tex.Opaque; + bmp.ToSysdrawingBitmap(gtex.SDBitmap); } public Texture2d LoadTexture(BitmapBuffer bmp) { // definitely needed (by TextureFrugalizer at least) var sdBitmap = bmp.ToSysdrawingBitmap(); - var tw = new GDIPTextureWrapper { SDBitmap = sdBitmap }; - return new(this, tw, bmp.Width, bmp.Height); + var gtex = new GDIPlusTexture { SDBitmap = sdBitmap }; + return new(this, gtex, bmp.Width, bmp.Height); } public BitmapBuffer ResolveTexture2d(Texture2d tex) { - var tw = (GDIPTextureWrapper)tex.Opaque; + var gtex = (GDIPlusTexture)tex.Opaque; var blow = new BitmapLoadOptions { AllowWrap = false // must be an independent resource }; - var bb = new BitmapBuffer(tw.SDBitmap, blow); + var bb = new BitmapBuffer(gtex.SDBitmap, blow); return bb; } @@ -212,16 +204,6 @@ namespace BizHawk.Bizware.BizwareGL // on account of gdi+ working internally with a default view exactly like we want, we don't need to setup a new one here // furthermore, we _cant_, without inverting the GuiView and GuiProjection before drawing, to completely undo it // this might be feasible, but its kind of slow and annoying and worse, seemingly numerically unstable -#if false - if (autoFlip && _currRenderTarget != null) - { - Matrix4 ret = Matrix4.Identity; - ret.M22 = -1; - ret.M42 = dims.Height; - return ret; - } -#endif - return Matrix4x4.Identity; } @@ -237,16 +219,6 @@ namespace BizHawk.Bizware.BizwareGL { SetViewport(size.Width, size.Height); } - - public void BeginControl(IGraphicsControl control) - { - CurrentControl = control; - } - - public void EndControl() - { - CurrentControl = null; - } public void BeginScene() { @@ -254,37 +226,28 @@ namespace BizHawk.Bizware.BizwareGL public void EndScene() { - //maybe an inconsistent semantic with other implementations.. - //but accomplishes the needed goal of getting the current RT to render + // maybe an inconsistent semantic with other implementations.. + // but accomplishes the needed goal of getting the current RT to render BindRenderTarget(null); } - public IGraphicsControl Internal_CreateGraphicsControl() - { - var ret = _createGLControlWrapper(this); - // create a render target for this control - var rtw = new RenderTargetWrapper(() => MyBufferedGraphicsContext, ret); - ret.RenderTargetWrapper = rtw; - return ret; - } - public void FreeRenderTarget(RenderTarget rt) { - var rtw = (RenderTargetWrapper)rt.Opaque; - rtw.Dispose(); + var grt = (GDIPlusRenderTarget)rt.Opaque; + grt.Dispose(); } public RenderTarget CreateRenderTarget(int w, int h) { - var tw = new GDIPTextureWrapper + var gtex = new GDIPlusTexture { SDBitmap = new(w, h, PixelFormat.Format32bppArgb) }; - var tex = new Texture2d(this, tw, w, h); + var tex = new Texture2d(this, gtex, w, h); - var rtw = new RenderTargetWrapper(() => MyBufferedGraphicsContext); - var rt = new RenderTarget(this, rtw, tex); - rtw.Target = rt; + var grt = new GDIPlusRenderTarget(() => BufferedGraphicsContext); + var rt = new RenderTarget(this, grt, tex); + grt.Target = rt; return rt; } @@ -296,56 +259,41 @@ namespace BizHawk.Bizware.BizwareGL _currOffscreenGraphics = null; } -#if false - _currRenderTarget = rt; - if (CurrentRenderTargetWrapper != null) - { - if (CurrentRenderTargetWrapper == CurrentControl.RenderTargetWrapper) - { - // don't do anything til swapbuffers - } - else - { - // CurrentRenderTargetWrapper.MyBufferedGraphics.Render(); - } - } -#endif - if (rt == null) { // null means to use the default RT for the current control - CurrentRenderTargetWrapper = CurrentControl.RenderTargetWrapper; + CurrentRenderTarget = _controlRenderTarget; } else { - var tw = (GDIPTextureWrapper)rt.Texture2d.Opaque; - CurrentRenderTargetWrapper = (RenderTargetWrapper)rt.Opaque; - _currOffscreenGraphics = Graphics.FromImage(tw.SDBitmap); -#if false - if (CurrentRenderTargetWrapper.MyBufferedGraphics == null) - { - CurrentRenderTargetWrapper.CreateGraphics(); - } -#endif + var gtex = (GDIPlusTexture)rt.Texture2d.Opaque; + CurrentRenderTarget = (GDIPlusRenderTarget)rt.Opaque; + _currOffscreenGraphics = SDGraphics.FromImage(gtex.SDBitmap); } } - private Graphics _currOffscreenGraphics; + private GDIPlusRenderTarget _controlRenderTarget; - public Graphics GetCurrentGraphics() + public GDIPlusRenderTarget CreateControlRenderTarget(Func<(SDGraphics Graphics, Rectangle Rectangle)> getControlRenderContext) { - if (_currOffscreenGraphics != null) + if (_controlRenderTarget != null) { - return _currOffscreenGraphics; + throw new InvalidOperationException($"{nameof(IGL_GDIPlus)} can only have one control render target"); } - var rtw = CurrentRenderTargetWrapper; - return rtw.MyBufferedGraphics.Graphics; + _controlRenderTarget = new(() => BufferedGraphicsContext, getControlRenderContext); + return _controlRenderTarget; } - public IGraphicsControl CurrentControl; - public RenderTargetWrapper CurrentRenderTargetWrapper; + private SDGraphics _currOffscreenGraphics; - public readonly BufferedGraphicsContext MyBufferedGraphicsContext = new(); + public SDGraphics GetCurrentGraphics() + { + return _currOffscreenGraphics ?? CurrentRenderTarget.BufferedGraphics.Graphics; + } + + public GDIPlusRenderTarget CurrentRenderTarget; + + public readonly BufferedGraphicsContext BufferedGraphicsContext = new(); } } diff --git a/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs b/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs index 822eb4e243..36567f1974 100644 --- a/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs +++ b/src/BizHawk.Bizware.Graphics/OpenGL/IGL_OpenGL.cs @@ -78,13 +78,6 @@ namespace BizHawk.Bizware.Graphics GL.Clear(ClearBufferMask.ColorBufferBit); } - public IGraphicsControl Internal_CreateGraphicsControl() - { - var ret = new OpenGLControl(); - ret.CreateControl(); // DisplayManager relies on this context being active for creating the GuiRenderer - return ret; - } - public void FreeTexture(Texture2d tex) { GL.DeleteTexture((uint)tex.Opaque); diff --git a/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs b/src/BizHawk.Bizware.Graphics/Renderers/GDIPlusGuiRenderer.cs similarity index 85% rename from src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs rename to src/BizHawk.Bizware.Graphics/Renderers/GDIPlusGuiRenderer.cs index 8dbcdb3a2a..a85b9f5439 100644 --- a/src/BizHawk.Bizware.BizwareGL/GDIPlusGuiRenderer.cs +++ b/src/BizHawk.Bizware.Graphics/Renderers/GDIPlusGuiRenderer.cs @@ -6,14 +6,18 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Numerics; -namespace BizHawk.Bizware.BizwareGL +using BizHawk.Bizware.BizwareGL; + +using SDGraphics = System.Drawing.Graphics; + +namespace BizHawk.Bizware.Graphics { public class GDIPlusGuiRenderer : IGuiRenderer { - private readonly IGL_GdiPlus Gdi; + private readonly IGL_GDIPlus _gdi; - public GDIPlusGuiRenderer(IGL_GdiPlus gl) - => Gdi = gl; + public GDIPlusGuiRenderer(IGL_GDIPlus gdi) + => _gdi = gdi; private readonly Vector4[] CornerColors = { @@ -129,7 +133,7 @@ namespace BizHawk.Bizware.BizwareGL { Begin(); - CurrentBlendState = Gdi.BlendNormal; + CurrentBlendState = _gdi.BlendNormal; Projection = Owner.CreateGuiProjectionMatrix(width, height); Modelview = Owner.CreateGuiViewMatrix(width, height); @@ -166,8 +170,8 @@ namespace BizHawk.Bizware.BizwareGL public void DrawSubrect(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1) { - var tw = (GDIPTextureWrapper)tex.Opaque; - var g = Gdi.GetCurrentGraphics(); + var gtex = (GDIPlusTexture)tex.Opaque; + var g = _gdi.GetCurrentGraphics(); PrepDraw(g, tex); SetupMatrix(g); @@ -184,11 +188,10 @@ namespace BizHawk.Bizware.BizwareGL new(x, y+h), }; - g.DrawImage(tw.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes); + g.DrawImage(gtex.SDBitmap, destPoints, new(x0, y0, x1 - x0, y1 - y0), GraphicsUnit.Pixel, CurrentImageAttributes); g.Transform = new(); // .Reset() doesnt work? } - public void Draw(Art art) { DrawInternal(art, 0, 0, art.Width, art.Height, false, false); } public void Draw(Art art, float x, float y) { DrawInternal(art, x, y, art.Width, art.Height, false, false); } public void Draw(Art art, float x, float y, float width, float height) { DrawInternal(art, x, y, width, height, false, false); } @@ -202,9 +205,9 @@ namespace BizHawk.Bizware.BizwareGL DrawInternal(art, x, y, width, height); } - private void PrepDraw(Graphics g, Texture2d tex) + private void PrepDraw(SDGraphics g, Texture2d tex) { - var tw = (GDIPTextureWrapper)tex.Opaque; + var tw = (GDIPlusTexture)tex.Opaque; // TODO - we can support bicubic for the final presentation... if ((int)tw.MagFilter != (int)tw.MinFilter) @@ -219,12 +222,10 @@ namespace BizHawk.Bizware.BizwareGL _ => g.InterpolationMode }; - if (CurrentBlendState == Gdi.BlendNormal) + if (CurrentBlendState == _gdi.BlendNormal) { g.CompositingMode = CompositingMode.SourceOver; g.CompositingQuality = CompositingQuality.Default; // ? - - // CurrentImageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap); } else // if (CurrentBlendState == Gdi.BlendNoneCopy) @@ -239,7 +240,7 @@ namespace BizHawk.Bizware.BizwareGL } } - private void SetupMatrix(Graphics g) + private void SetupMatrix(SDGraphics g) { // projection is always identity, so who cares i guess // var mat = Projection.Top * Modelview.Top; @@ -259,7 +260,7 @@ namespace BizHawk.Bizware.BizwareGL private void DrawInternal(Texture2d tex, float x, float y, float w, float h, float u0, float v0, float u1, float v1) { - var g = Gdi.GetCurrentGraphics(); + var g = _gdi.GetCurrentGraphics(); PrepDraw(g, tex); SetupMatrix(g); @@ -278,9 +279,9 @@ namespace BizHawk.Bizware.BizwareGL var sw = sx2 - sx; var sh = sy2 - sy; - var tw = (GDIPTextureWrapper)tex.Opaque; + var gtex = (GDIPlusTexture)tex.Opaque; g.PixelOffsetMode = PixelOffsetMode.Half; - g.DrawImage(tw.SDBitmap, destPoints, new(sx, sy, sw, sh), GraphicsUnit.Pixel, CurrentImageAttributes); + g.DrawImage(gtex.SDBitmap, destPoints, new(sx, sy, sw, sh), GraphicsUnit.Pixel, CurrentImageAttributes); g.Transform = new(); // .Reset() doesn't work ? ? } @@ -290,6 +291,6 @@ namespace BizHawk.Bizware.BizwareGL public bool IsActive { get; private set; } - public IGL Owner => Gdi; + public IGL Owner => _gdi; } } \ No newline at end of file diff --git a/src/BizHawk.Bizware.Graphics/GuiRenderer.cs b/src/BizHawk.Bizware.Graphics/Renderers/GuiRenderer.cs similarity index 100% rename from src/BizHawk.Bizware.Graphics/GuiRenderer.cs rename to src/BizHawk.Bizware.Graphics/Renderers/GuiRenderer.cs diff --git a/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index e44c6ae5c2..953911b5a2 100755 --- a/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/src/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -23,6 +23,7 @@ + @@ -260,9 +261,7 @@ - - diff --git a/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index 3c65e9a219..802bc31b0d 100644 --- a/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Drawing; using BizHawk.Bizware.BizwareGL; +using BizHawk.Bizware.Graphics.Controls; using BizHawk.Client.Common; using BizHawk.Emulation.Common; diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs deleted file mode 100644 index 6412d2b61a..0000000000 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GLControlWrapper_GdiPlus.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.Drawing.Drawing2D; -using System.Windows.Forms; - -using BizHawk.Bizware.BizwareGL; - -namespace BizHawk.Client.EmuHawk -{ - public class GLControlWrapper_GdiPlus : Control, IGraphicsControl - { - public GLControlWrapper_GdiPlus(IGL_GdiPlus gdi) - { - _gdi = gdi; - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - SetStyle(ControlStyles.Opaque, true); - SetStyle(ControlStyles.UserMouse, true); - } - - private readonly IGL_GdiPlus _gdi; - - /// - /// the render target for rendering to this control - /// - public RenderTargetWrapper RenderTargetWrapper { get; set; } - - public void SetVsync(bool state) - { - // not really supported now... - } - - public void Begin() - { - _gdi.BeginControl(this); - RenderTargetWrapper.CreateGraphics(); - -#if false - using (var g = CreateGraphics()) - { - MyBufferedGraphics = _gdi.MyBufferedGraphicsContext.Allocate(g, ClientRectangle); - } - - MyBufferedGraphics.Graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; - - // not sure about this stuff... - // it will wreck alpha blending, for one thing - MyBufferedGraphics.Graphics.CompositingMode = CompositingMode.SourceCopy; - MyBufferedGraphics.Graphics.CompositingQuality = CompositingQuality.HighSpeed; -#endif - } - - public void End() - { - _gdi.EndControl(); - } - - public void SwapBuffers() - { - if (RenderTargetWrapper.MyBufferedGraphics == null) - { - return; - } - - using (var g = CreateGraphics()) - { - // not sure we had proof we needed this but it cant hurt - g.CompositingMode = CompositingMode.SourceCopy; - g.CompositingQuality = CompositingQuality.HighSpeed; - RenderTargetWrapper.MyBufferedGraphics.Render(g); - } - - // not too sure about this.. i think we have to re-allocate it so we can support a changed window size. did we do this at the right time anyway? - // maybe I should try caching harder, I hate to reallocate these constantly - RenderTargetWrapper.CreateGraphics(); - } - } -} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GraphicsControl.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GraphicsControl.cs deleted file mode 100644 index 482894ca2f..0000000000 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/GraphicsControl.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Windows.Forms; -using BizHawk.Bizware.BizwareGL; - -namespace BizHawk.Client.EmuHawk -{ - /// - /// a base class for deriving/wrapping from a IGraphicsControl. - /// This is to work around the annoyance that we cant inherit from a control whose type is unknown (it would be delivered by the selected BizwareGL driver) - /// and so we have to resort to composition and c# sucks and events suck. - /// - public class GraphicsControl : UserControl - { - public GraphicsControl(IGL owner) - { - IGL = owner; - - SetStyle(ControlStyles.Opaque, true); - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.UserMouse, true); - - _igc = owner.Internal_CreateGraphicsControl(); - _managed = (Control)_igc; - _managed.Dock = DockStyle.Fill; - Controls.Add(_managed); - - // pass through these events to the form. I tried really hard to find a better way, but there is none. - // (don't use HTTRANSPARENT, it isn't portable, I would assume) - _managed.MouseDoubleClick += (_, e) => OnMouseDoubleClick(e); - _managed.MouseClick += (_, e) => OnMouseClick(e); - _managed.MouseEnter += (_, e) => OnMouseEnter(e); - _managed.MouseLeave += (_, e) => OnMouseLeave(e); - _managed.MouseMove += (_, e) => OnMouseMove(e); - - //the GraphicsControl is occupying all of our area. So we pretty much never get paint events ourselves. - //So lets capture its paint event and use it for ourselves (it doesn't know how to do anything, anyway) - _managed.Paint += GraphicsControl_Paint; - } - - /// - /// If this is the main window, things may be special - /// - public bool MainWindow; - - private void GraphicsControl_Paint(object sender, PaintEventArgs e) - { - OnPaint(e); - } - - public readonly IGL IGL; - - private readonly IGraphicsControl _igc; - private readonly Control _managed; - - public virtual void SetVsync(bool state) { _igc.SetVsync(state); } - public virtual void SwapBuffers() { _igc.SwapBuffers(); } - public virtual void Begin() { _igc.Begin(); } - public virtual void End() { _igc.End(); } - } -} \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/IGLExtensions.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/IGLExtensions.cs index f3885501b4..e470f4550d 100644 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/IGLExtensions.cs +++ b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/IGLExtensions.cs @@ -6,7 +6,7 @@ namespace BizHawk.Client.EmuHawk public static class IGLExtensions { public static IGuiRenderer CreateRenderer(this IGL gl) - => gl is IGL_GdiPlus gdipImpl + => gl is IGL_GDIPlus gdipImpl ? new GDIPlusGuiRenderer(gdipImpl) : new GuiRenderer(gl); // This implementation doesn't seem to require any OpenGL-specific (or D3D-specific) behaviour; can it be used with IGL_GdiPlus too? If so, is GDIPlusGuiRenderer only kept around because it's faster? --yoshi } diff --git a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/RetainedGraphicsControl.cs b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/RetainedGraphicsControl.cs index cf3256510a..6a27a85e8e 100644 --- a/src/BizHawk.Client.EmuHawk/GraphicsImplementations/RetainedGraphicsControl.cs +++ b/src/BizHawk.Client.EmuHawk/GraphicsImplementations/RetainedGraphicsControl.cs @@ -1,6 +1,8 @@ using System.Windows.Forms; + using BizHawk.Bizware.BizwareGL; using BizHawk.Bizware.Graphics; +using BizHawk.Bizware.Graphics.Controls; namespace BizHawk.Client.EmuHawk { @@ -10,10 +12,10 @@ namespace BizHawk.Client.EmuHawk public class RetainedGraphicsControl : GraphicsControl { public RetainedGraphicsControl(IGL gl) - : base(gl) { _gl = gl; - _guiRenderer = new GuiRenderer(gl); + _graphicsControl = GraphicsControlFactory.CreateGraphicsControl(gl); + _guiRenderer = new(gl); } /// @@ -38,13 +40,26 @@ namespace BizHawk.Client.EmuHawk private bool _retain = true; private readonly IGL _gl; + private readonly GraphicsControl _graphicsControl; private RenderTarget _rt; private readonly GuiRenderer _guiRenderer; + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + // todo - check whether we're begun? + _graphicsControl.Begin(); + Draw(); + _graphicsControl.End(); + } + + public override void SetVsync(bool state) + => _graphicsControl.SetVsync(state); + public override void Begin() { - base.Begin(); - + _graphicsControl.Begin(); + if (_retain) { // TODO - frugalize me @@ -54,13 +69,28 @@ namespace BizHawk.Client.EmuHawk } } - protected override void OnPaint(PaintEventArgs e) + public override void End() { - base.OnPaint(e); - // todo - check whether we're begun? - base.Begin(); + if (_retain) + { + _rt.Unbind(); + } + + _graphicsControl.End(); + } + + public override void SwapBuffers() + { + // if we're not retaining, then we haven't been collecting into a framebuffer. just swap it + if (!_retain) + { + _graphicsControl.SwapBuffers(); + return; + } + + // if we're retaining, then we cant draw until we unbind! its semantically a bit odd, but we expect users to call SwapBuffers() before end, so we cant unbind in End() even thoug hit makes a bit more sense. + _rt.Unbind(); Draw(); - base.End(); } private void Draw() @@ -74,31 +104,7 @@ namespace BizHawk.Client.EmuHawk _guiRenderer.SetBlendState(_gl.BlendNoneCopy); _guiRenderer.Draw(_rt.Texture2d); _guiRenderer.End(); - base.SwapBuffers(); - } - - public override void SwapBuffers() - { - // if we're not retaining, then we haven't been collecting into a framebuffer. just swap it - if (!_retain) - { - base.SwapBuffers(); - return; - } - - // if we're retaining, then we cant draw until we unbind! its semantically a bit odd, but we expect users to call SwapBuffers() before end, so we cant unbind in End() even thoug hit makes a bit more sense. - _rt.Unbind(); - Draw(); - } - - public override void End() - { - if (_retain) - { - _rt.Unbind(); - } - - base.End(); + _graphicsControl.SwapBuffers(); } } } \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 40a4f08036..ea8ce20429 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -446,17 +446,15 @@ namespace BizHawk.Client.EmuHawk // TODO GL - a lot of disorganized wiring-up here // installed separately on Unix (via package manager or from https://developer.nvidia.com/cg-toolkit-download), look in $PATH - _presentationPanel = new PresentationPanel( + _presentationPanel = new( Config, GL, ToggleFullscreen, MainForm_MouseClick, MainForm_MouseMove, - MainForm_MouseWheel) - { - GraphicsControl = { MainWindow = true } - }; - DisplayManager = new DisplayManager(Config, Emulator, InputManager, MovieSession, GL, _presentationPanel, () => DisableSecondaryThrottling); + MainForm_MouseWheel); + + DisplayManager = new(Config, Emulator, InputManager, MovieSession, GL, _presentationPanel, () => DisableSecondaryThrottling); Controls.Add(_presentationPanel); Controls.SetChildIndex(_presentationPanel, 0); diff --git a/src/BizHawk.Client.EmuHawk/PresentationPanel.cs b/src/BizHawk.Client.EmuHawk/PresentationPanel.cs index 581e961a86..9cd9ba96c8 100644 --- a/src/BizHawk.Client.EmuHawk/PresentationPanel.cs +++ b/src/BizHawk.Client.EmuHawk/PresentationPanel.cs @@ -4,11 +4,12 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Bizware.BizwareGL; +using BizHawk.Bizware.Graphics.Controls; namespace BizHawk.Client.EmuHawk { /// - /// Thinly wraps a BizwareGL.GraphicsControl for EmuHawk's needs + /// Thinly wraps a GraphicsControl for EmuHawk's needs /// public class PresentationPanel { @@ -28,11 +29,9 @@ namespace BizHawk.Client.EmuHawk _fullscreenToggleCallback = fullscreenToggleCallback; - GraphicsControl = new GraphicsControl(gl) - { - Dock = DockStyle.Fill, - BackColor = Color.Black - }; + GraphicsControl = GraphicsControlFactory.CreateGraphicsControl(gl); + GraphicsControl.Dock = DockStyle.Fill; + GraphicsControl.BackColor = Color.Black; // pass through these events to the form. we might need a more scalable solution for mousedown etc. for zapper and whatnot. // http://stackoverflow.com/questions/547172/pass-through-mouse-events-to-parent-control (HTTRANSPARENT) @@ -43,15 +42,20 @@ namespace BizHawk.Client.EmuHawk } private bool _isDisposed; + public void Dispose() { - if (_isDisposed) return; + if (_isDisposed) + { + return; + } + _isDisposed = true; GraphicsControl.Dispose(); } - //graphics resources - public GraphicsControl GraphicsControl; + // graphics resources + public readonly GraphicsControl GraphicsControl; public Control Control => GraphicsControl; public static implicit operator Control(PresentationPanel self) { return self.GraphicsControl; } @@ -61,7 +65,7 @@ namespace BizHawk.Client.EmuHawk if (e.Button == MouseButtons.Left) { // allow suppression of the toggle.. but if shift is pressed, always do the toggle - bool allowSuppress = Control.ModifierKeys != Keys.Shift; + var allowSuppress = Control.ModifierKeys != Keys.Shift; if (_config.DispChromeAllowDoubleClickFullscreen || !allowSuppress) { _fullscreenToggleCallback(allowSuppress); diff --git a/src/BizHawk.Client.EmuHawk/Program.cs b/src/BizHawk.Client.EmuHawk/Program.cs index 8e90bf96f4..4d5baf4985 100644 --- a/src/BizHawk.Client.EmuHawk/Program.cs +++ b/src/BizHawk.Client.EmuHawk/Program.cs @@ -242,9 +242,8 @@ namespace BizHawk.Client.EmuHawk } default: case EDispMethod.GdiPlus: - static GLControlWrapper_GdiPlus CreateGLControlWrapper(IGL_GdiPlus self) => new(self); // inlining as lambda causes crash, don't wanna know why --yoshi // if this fails, we're screwed - return new IGL_GdiPlus(CreateGLControlWrapper); + return new IGL_GDIPlus(); } }