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
This commit is contained in:
CasualPokePlayer 2023-08-12 03:56:02 -07:00
parent 9139870e7e
commit 72cc192661
28 changed files with 502 additions and 591 deletions

View File

@ -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

View File

@ -270,7 +270,5 @@ namespace BizHawk.Bizware.BizwareGL
/// Frees the provided vertex layout. For internal use only.
/// </summary>
void Internal_FreeVertexLayout(VertexLayout vertexLayout);
IGraphicsControl Internal_CreateGraphicsControl();
}
}

View File

@ -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<BufferedGraphicsContext> getBufferedGraphicsContext,
IGraphicsControl control = null)
{
_getBufferedGraphicsContext = getBufferedGraphicsContext;
Control = control;
}
public void Dispose()
{
MyBufferedGraphics?.Dispose();
}
private readonly Func<BufferedGraphicsContext> _getBufferedGraphicsContext;
/// <summary>
/// the control associated with this render target (if any)
/// </summary>
private readonly IGraphicsControl Control;
/// <summary>
/// the offscreen render target, if that's what this is representing
/// </summary>
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
}
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
</PropertyGroup>
<Import Project="../MainSlnCommon.props" />
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj" />
</ItemGroup>
</Project>

View File

@ -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<IntPtr, D3D9SwapChain> _createSwapChain;
private D3D9SwapChain _swapChain;
private bool Vsync;
public D3D9Control(Func<IntPtr, D3D9SwapChain> 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();
}
}

View File

@ -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<Func<(SDGraphics Graphics, Rectangle Rectangle)>, 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);
/// <summary>
/// The render target for rendering to this control
/// </summary>
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);
}
}
}

View File

@ -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();

View File

@ -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();
/// <summary>
/// Sets whether presentation operations on this control will vsync
/// </summary>
void SetVsync(bool state);
public abstract void SetVsync(bool state);
/// <summary>
/// Swaps the buffers for this control
/// </summary>
void SwapBuffers();
public abstract void SwapBuffers();
/// <summary>
/// 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
/// </summary>
void Begin();
public abstract void Begin();
/// <summary>
/// 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
/// </summary>
void End();
public abstract void End();
}
}

View File

@ -0,0 +1,27 @@
using System;
using BizHawk.Bizware.BizwareGL;
namespace BizHawk.Bizware.Graphics.Controls
{
/// <summary>
/// A factory for creating a GraphicsControl based on an IGL
/// </summary>
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;
}
}
}

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Import Project="../MainSlnCommon.props" />
<PropertyGroup>
@ -8,9 +8,7 @@
<Nullable>disable</Nullable>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />
<PackageReference Include="Silk.NET.OpenGL.Legacy" Version="2.17.1" />
<PackageReference Include="Silk.NET.OpenGL.Legacy.Extensions.EXT" Version="2.17.1" />
<PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" />
<PackageReference Include="ppy.SDL2-CS" Version="1.0.630-alpha" ExcludeAssets="native;contentFiles" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.BizwareGL/BizHawk.Bizware.BizwareGL.csproj" />

View File

@ -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);
}
}

View File

@ -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<PresentParameters, SwapChain> _resetDeviceCallback;
private readonly Func<PresentParameters, SwapChain> _resetSwapChainCallback;
private SwapChain _swapChain;
internal D3D9SwapChain(Device device, SwapChain swapChain,
Func<PresentParameters, SwapChain> resetDeviceCallback, Func<PresentParameters, SwapChain> 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);
}
}
}

View File

@ -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);
}
/// <exception cref="InvalidOperationException"><paramref name="control"/> does not match control passed to <see cref="BeginControl"/></exception>
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<DrawPrimitiveUPDelegate> _drawPrimitiveUP = new(() =>

View File

@ -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<BufferedGraphicsContext> 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<BufferedGraphicsContext> _getBufferedGraphicsContext;
/// <summary>
/// get Graphics and Rectangle from a control, if any
/// </summary>
private readonly Func<(SDGraphics, Rectangle)> _getControlRenderContext;
/// <summary>
/// the offscreen render target, if that's what this is representing
/// </summary>
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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<IGL_GdiPlus, IGraphicsControl> _createGLControlWrapper;
public IGL_GdiPlus(Func<IGL_GdiPlus, IGraphicsControl> 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();
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -23,6 +23,7 @@
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Audio/BizHawk.Bizware.Audio.csproj" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Input/BizHawk.Bizware.Input.csproj" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics/BizHawk.Bizware.Graphics.csproj" />
<ProjectReference Include="$(ProjectDir)../BizHawk.Bizware.Graphics.Controls/BizHawk.Bizware.Graphics.Controls.csproj" />
<ProjectReference Include="$(ProjectDir)../BizHawk.WinForms.Controls/BizHawk.WinForms.Controls.csproj" />
<Compile Remove="Properties/Settings.Designer.cs" />
<Content Include="images/logo.ico" />
@ -260,9 +261,7 @@
<Compile Update="CustomControls/RepeatButton.cs" SubType="Component" />
<Compile Update="CustomControls/TransparentTrackbar.cs" SubType="Component" />
<Compile Update="CustomControls/ViewportPanel.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GLControlWrapper_GdiPlus.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GLControlWrapper_SlimDX9.cs" SubType="Component" />
<Compile Update="GraphicsImplementations/GraphicsControl.cs" SubType="UserControl" />
<Compile Update="GraphicsImplementations/GraphicsControl_TK.cs" SubType="UserControl" />
<Compile Update="GraphicsImplementations/RetainedGraphicsControl.cs" SubType="UserControl" />
<Compile Update="LogWindow.cs" SubType="Form" />

View File

@ -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;

View File

@ -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;
/// <summary>
/// the render target for rendering to this control
/// </summary>
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();
}
}
}

View File

@ -1,60 +0,0 @@
using System.Windows.Forms;
using BizHawk.Bizware.BizwareGL;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// If this is the main window, things may be special
/// </summary>
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(); }
}
}

View File

@ -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
}

View File

@ -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);
}
/// <summary>
@ -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();
}
}
}

View File

@ -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);

View File

@ -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
{
/// <summary>
/// Thinly wraps a BizwareGL.GraphicsControl for EmuHawk's needs
/// Thinly wraps a GraphicsControl for EmuHawk's needs
/// </summary>
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);

View File

@ -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();
}
}