prep work for easier OpenGL interop for cores

This commit is contained in:
CasualPokePlayer 2023-07-23 01:54:36 -07:00
parent 78f5e75534
commit 8ae947fed7
16 changed files with 198 additions and 200 deletions

View File

@ -159,7 +159,7 @@ namespace BizHawk.Bizware.BizwareGL
/// <summary> /// <summary>
/// In case you already have the texture ID (from an opengl emulator gpu core) you can get a Texture2d with it this way. /// In case you already have the texture ID (from an opengl emulator gpu core) you can get a Texture2d with it this way.
/// Otherwise, if this isn't an OpenGL frontend implementation, I guess... try reading the texturedata out of it and making a new texture? /// Otherwise, if this isn't an OpenGL frontend implementation, the core is expected to readback the texture for GetVideoBuffer()
/// </summary> /// </summary>
Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height); Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height);

View File

@ -9,7 +9,6 @@ namespace BizHawk.Bizware.BizwareGL
Owner = owner; Owner = owner;
Opaque = opaque; Opaque = opaque;
Texture2d = tex; Texture2d = tex;
tex.IsUpsideDown = true;
} }
public override string ToString() public override string ToString()

View File

@ -683,8 +683,7 @@ namespace BizHawk.Bizware.Graphics
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height) public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
{ {
// not needed 1st pass (except for GL cores) // only used for OpenGL
// TODO - need to rip the texture data. we had code for that somewhere...
return null; return null;
} }

View File

@ -37,10 +37,7 @@ namespace BizHawk.Bizware.Graphics
{ {
public EDispMethod DispMethodEnum => EDispMethod.OpenGL; public EDispMethod DispMethodEnum => EDispMethod.OpenGL;
private readonly SDL2OpenGLContext OffscreenContext; private readonly GL GL;
private SDL2OpenGLContext ActiveContext;
private GL GL => ActiveContext.GL;
private readonly int _majorVersion, _minorVersion; private readonly int _majorVersion, _minorVersion;
private readonly bool _forwardCompatible; private readonly bool _forwardCompatible;
@ -50,36 +47,20 @@ namespace BizHawk.Bizware.Graphics
public string API => "OPENGL"; public string API => "OPENGL";
public int Version
{
get
{
// doesnt work on older than gl3 maybe
// int major, minor;
// // other overloads may not exist...
// GL.GetInteger(GetPName.MajorVersion, out major);
// GL.GetInteger(GetPName.MinorVersion, out minor);
// supposedly the standard dictates that whatever junk is in the version string, some kind of version is at the beginning
// can be either in major_number.minor_number or major_number.minor_number.release_number, with vendor specific info afterwards
var versionString = GL.GetStringS(StringName.Version);
var versionParts = versionString.Split('.');
var major = int.Parse(versionParts[0]);
var minor = int.Parse(versionParts[1][0].ToString());
// getting a release number is too hard and not needed now
return major * 100 + minor * 10;
}
}
public IGL_OpenGL(int majorVersion, int minorVersion, bool forwardCompatible) public IGL_OpenGL(int majorVersion, int minorVersion, bool forwardCompatible)
{ {
// create an offscreen context, so things can be done without a control
ActiveContext = OffscreenContext = new(majorVersion, minorVersion, forwardCompatible);
_majorVersion = majorVersion; _majorVersion = majorVersion;
_minorVersion = minorVersion; _minorVersion = minorVersion;
_forwardCompatible = forwardCompatible; _forwardCompatible = forwardCompatible;
// we need an active context in order to acquire these functions
// technically, they could be different between contexts
// but with the exact same requested version and config that is highly unlikely in practice
using (new SDL2OpenGLContext(majorVersion, minorVersion, forwardCompatible))
{
GL = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
}
// misc initialization // misc initialization
CreateRenderStates(); CreateRenderStates();
} }
@ -94,7 +75,6 @@ namespace BizHawk.Bizware.Graphics
public void Dispose() public void Dispose()
{ {
OffscreenContext.Dispose();
} }
public void Clear(BizClearBufferMask mask) public void Clear(BizClearBufferMask mask)
@ -477,7 +457,7 @@ namespace BizHawk.Bizware.Graphics
public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height) public Texture2d WrapGLTexture2d(IntPtr glTexId, int width, int height)
{ {
return new(this, glTexId.ToInt32(), width, height); return new(this, (uint)glTexId.ToInt32(), width, height) { IsUpsideDown = true };
} }
public unsafe void LoadTextureData(Texture2d tex, BitmapBuffer bmp) public unsafe void LoadTextureData(Texture2d tex, BitmapBuffer bmp)
@ -505,7 +485,7 @@ namespace BizHawk.Bizware.Graphics
{ {
// create a texture for it // create a texture for it
var texId = GenTexture(); var texId = GenTexture();
var tex = new Texture2d(this, texId, w, h); var tex = new Texture2d(this, texId, w, h) { IsUpsideDown = true }; // TODO: The IsUpsideDown doesn't ever get used here it seems
GL.BindTexture(TextureTarget.Texture2D, texId); GL.BindTexture(TextureTarget.Texture2D, texId);
GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint)w, (uint)h, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero.ToPointer()); GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint)w, (uint)h, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero.ToPointer());
@ -839,26 +819,11 @@ namespace BizHawk.Bizware.Graphics
private VertexLayout sStatePendingVertexLayout; private VertexLayout sStatePendingVertexLayout;
private readonly HashSet<uint> sVertexAttribEnables = new(); private readonly HashSet<uint> sVertexAttribEnables = new();
private void ContextChangeCallback(SDL2OpenGLContext context) private void ContextChangeCallback()
{ {
// null means the current context is being cleared
// set it back to the offscreen context
if (context is null)
{
OffscreenContext.MakeContextCurrent();
context = OffscreenContext;
}
sActiveTexture = -1; sActiveTexture = -1;
sStatePendingVertexLayout = null; sStatePendingVertexLayout = null;
sVertexAttribEnables.Clear(); sVertexAttribEnables.Clear();
ActiveContext = context;
}
public void MakeOffscreenContextCurrent()
{
OffscreenContext.MakeContextCurrent();
ContextChangeCallback(OffscreenContext);
} }
} }
} }

View File

@ -11,7 +11,7 @@ namespace BizHawk.Bizware.Graphics
private readonly int _majorVersion; private readonly int _majorVersion;
private readonly int _minorVersion; private readonly int _minorVersion;
private readonly bool _forwardCompatible; private readonly bool _forwardCompatible;
private readonly Action<SDL2OpenGLContext> _contextChangeCallback; private readonly Action _contextChangeCallback;
public SDL2OpenGLContext Context { get; private set; } public SDL2OpenGLContext Context { get; private set; }
@ -21,7 +21,7 @@ namespace BizHawk.Bizware.Graphics
set => throw new NotImplementedException(); set => throw new NotImplementedException();
} }
public OpenGLControl(int majorVersion, int minorVersion, bool forwardCompatible, Action<SDL2OpenGLContext> contextChangeCallback) public OpenGLControl(int majorVersion, int minorVersion, bool forwardCompatible, Action contextChangeCallback)
{ {
_majorVersion = majorVersion; _majorVersion = majorVersion;
_minorVersion = minorVersion; _minorVersion = minorVersion;
@ -59,8 +59,7 @@ namespace BizHawk.Bizware.Graphics
{ {
base.OnHandleCreated(e); base.OnHandleCreated(e);
Context = new(Handle, _majorVersion, _minorVersion, _forwardCompatible); Context = new(Handle, _majorVersion, _minorVersion, _forwardCompatible);
_contextChangeCallback();
_contextChangeCallback(Context);
} }
protected override void OnHandleDestroyed(EventArgs e) protected override void OnHandleDestroyed(EventArgs e)
@ -69,7 +68,7 @@ namespace BizHawk.Bizware.Graphics
if (Context.IsCurrent) if (Context.IsCurrent)
{ {
_contextChangeCallback(null); _contextChangeCallback();
} }
Context.Dispose(); Context.Dispose();
@ -92,7 +91,7 @@ namespace BizHawk.Bizware.Graphics
if (!Context.IsCurrent) if (!Context.IsCurrent)
{ {
Context.MakeContextCurrent(); Context.MakeContextCurrent();
_contextChangeCallback(Context); _contextChangeCallback();
} }
} }
} }
@ -110,7 +109,8 @@ namespace BizHawk.Bizware.Graphics
public void End() public void End()
{ {
_contextChangeCallback(null); SDL2OpenGLContext.MakeNoneCurrent();
_contextChangeCallback();
} }
public void SwapBuffers() public void SwapBuffers()

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Runtime.InteropServices;
using Silk.NET.OpenGL.Legacy;
using static SDL2.SDL; using static SDL2.SDL;
@ -9,7 +8,7 @@ namespace BizHawk.Bizware.Graphics
/// <summary> /// <summary>
/// Wraps an SDL2 OpenGL context /// Wraps an SDL2 OpenGL context
/// </summary> /// </summary>
internal class SDL2OpenGLContext : IDisposable public class SDL2OpenGLContext : IDisposable
{ {
static SDL2OpenGLContext() static SDL2OpenGLContext()
{ {
@ -41,11 +40,50 @@ namespace BizHawk.Bizware.Graphics
SDL_SetHint(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, "1"); SDL_SetHint(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, "1");
} }
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate IntPtr glGetStringDelegate(int name);
private static readonly Lazy<int> _version = new(() =>
{
var prevWindow = SDL_GL_GetCurrentWindow();
var prevContext = SDL_GL_GetCurrentContext();
try
{
using (new SDL2OpenGLContext(2, 0, false))
{
var getStringFp = GetGLProcAddress("glGetString");
if (getStringFp == IntPtr.Zero) // uhhh?
{
return 0;
}
var getStringFunc = Marshal.GetDelegateForFunctionPointer<glGetStringDelegate>(getStringFp);
const int GL_VERSION = 0x1F02;
var version = getStringFunc(GL_VERSION);
if (version == IntPtr.Zero)
{
return 0;
}
var versionString = Marshal.PtrToStringAnsi(version);
var versionParts = versionString!.Split('.');
var major = int.Parse(versionParts[0]);
var minor = int.Parse(versionParts[1][0].ToString());
return major * 100 + minor;
}
}
finally
{
SDL_GL_MakeCurrent(prevWindow, prevContext);
}
});
public static int Version => _version.Value;
private IntPtr _sdlWindow; private IntPtr _sdlWindow;
private IntPtr _glContext; private IntPtr _glContext;
public GL GL { get; private set; }
private void CreateContext(int majorVersion, int minorVersion, bool forwardCompatible) private void CreateContext(int majorVersion, int minorVersion, bool forwardCompatible)
{ {
if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion) != 0) if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion) != 0)
@ -80,10 +118,6 @@ namespace BizHawk.Bizware.Graphics
{ {
throw new($"Could not create GL Context! SDL Error: {SDL_GetError()}"); throw new($"Could not create GL Context! SDL Error: {SDL_GetError()}");
} }
// get GL functions
// these are specific towards a context, and so these are owned by the context here
GL = GL.GetApi(SDL_GL_GetProcAddress);
} }
public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorVersion, bool forwardCompatible) public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorVersion, bool forwardCompatible)
@ -146,6 +180,15 @@ namespace BizHawk.Bizware.Graphics
_ = SDL_GL_MakeCurrent(_sdlWindow, _glContext); _ = SDL_GL_MakeCurrent(_sdlWindow, _glContext);
} }
public static void MakeNoneCurrent()
{
// no-op if nothing is current
_ = SDL_GL_MakeCurrent(IntPtr.Zero, IntPtr.Zero);
}
public static IntPtr GetGLProcAddress(string proc)
=> SDL_GL_GetProcAddress(proc);
public void SetVsync(bool state) public void SetVsync(bool state)
{ {
if (!IsCurrent) if (!IsCurrent)

View File

@ -196,7 +196,9 @@ namespace BizHawk.Client.Common
private RetroShaderChain _shaderChainUser; private RetroShaderChain _shaderChainUser;
protected virtual void ActivateGLContext() => throw new NotImplementedException(); public virtual void ActivateOpenGLContext() => throw new NotImplementedException();
protected virtual void ActivateGraphicsControlContext() => throw new NotImplementedException();
protected virtual void SwapBuffersOfGraphicsControl() => throw new NotImplementedException(); protected virtual void SwapBuffersOfGraphicsControl() => throw new NotImplementedException();
@ -771,12 +773,10 @@ namespace BizHawk.Client.Common
private FilterProgram UpdateSourceInternal(JobInfo job) private FilterProgram UpdateSourceInternal(JobInfo job)
{ {
//no drawing actually happens. it's important not to begin drawing on a control // no drawing actually happens
if (!job.Simulate/* && !job.Offscreen*/) if (!job.Simulate)
{ {
// i don't want to do this for offscreen jobs ActivateGraphicsControlContext();
// but it seems that would be required in case this context isn't active
ActivateGLContext();
if (job.ChainOutsize.Width == 0 || job.ChainOutsize.Height == 0) if (job.ChainOutsize.Width == 0 || job.ChainOutsize.Height == 0)
{ {
@ -791,17 +791,14 @@ namespace BizHawk.Client.Common
} }
var videoProvider = job.VideoProvider; var videoProvider = job.VideoProvider;
var glTextureProvider = videoProvider as IGLTextureProvider;
var simulate = job.Simulate; var simulate = job.Simulate;
var chainOutsize = job.ChainOutsize; var chainOutsize = job.ChainOutsize;
//simulate = true;
var videoBuffer = videoProvider.GetVideoBuffer();
var bufferWidth = videoProvider.BufferWidth; var bufferWidth = videoProvider.BufferWidth;
var bufferHeight = videoProvider.BufferHeight; var bufferHeight = videoProvider.BufferHeight;
var presenterTextureWidth = bufferWidth; var presenterTextureWidth = bufferWidth;
var presenterTextureHeight = bufferHeight; var presenterTextureHeight = bufferHeight;
var isGlTextureId = videoBuffer.Length == 1;
var vw = videoProvider.VirtualWidth; var vw = videoProvider.VirtualWidth;
var vh = videoProvider.VirtualHeight; var vh = videoProvider.VirtualHeight;
@ -854,23 +851,22 @@ namespace BizHawk.Client.Common
Texture2d videoTexture = null; Texture2d videoTexture = null;
if (!simulate) if (!simulate)
{ {
if (isGlTextureId) if (glTextureProvider != null && _gl.DispMethodEnum == EDispMethod.OpenGL)
{ {
// FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code // FYI: this is a million years from happening on n64, since it's all geriatric non-FBO code
// is it workable for saturn? videoTexture = _gl.WrapGLTexture2d(new(glTextureProvider.GetGLTexture()), bufferWidth, bufferHeight);
videoTexture = _gl.WrapGLTexture2d(new(videoBuffer[0]), bufferWidth, bufferHeight);
} }
else else
{ {
// wrap the VideoProvider data in a BitmapBuffer (no point to refactoring that many IVideoProviders) // wrap the VideoProvider data in a BitmapBuffer (no point to refactoring that many IVideoProviders)
bb = new(bufferWidth, bufferHeight, videoBuffer); bb = new(bufferWidth, bufferHeight, videoProvider.GetVideoBuffer());
bb.DiscardAlpha(); bb.DiscardAlpha();
//now, acquire the data sent from the videoProvider into a texture //now, acquire the data sent from the videoProvider into a texture
videoTexture = _videoTextureFrugalizer.Get(bb); videoTexture = _videoTextureFrugalizer.Get(bb);
// lets not use this. lets define BizwareGL to make clamp by default (TBD: check opengl) // lets not use this. lets define BizwareGL to make clamp by default (TBD: check opengl)
// GL.SetTextureWrapMode(videoTexture, true); // _gl.SetTextureWrapMode(videoTexture, true);
} }
} }
@ -897,7 +893,6 @@ namespace BizHawk.Client.Common
fPresent.TextureSize = new(presenterTextureWidth, presenterTextureHeight); fPresent.TextureSize = new(presenterTextureWidth, presenterTextureHeight);
fPresent.BackgroundColor = videoProvider.BackgroundColor; fPresent.BackgroundColor = videoProvider.BackgroundColor;
fPresent.GuiRenderer = _renderer; fPresent.GuiRenderer = _renderer;
fPresent.Flip = isGlTextureId;
fPresent.Config_FixAspectRatio = GlobalConfig.DispFixAspectRatio; fPresent.Config_FixAspectRatio = GlobalConfig.DispFixAspectRatio;
fPresent.Config_FixScaleInteger = GlobalConfig.DispFixScaleInteger; fPresent.Config_FixScaleInteger = GlobalConfig.DispFixScaleInteger;
fPresent.Padding = (ClientExtraPadding.Left, ClientExtraPadding.Top, ClientExtraPadding.Right, ClientExtraPadding.Bottom); fPresent.Padding = (ClientExtraPadding.Left, ClientExtraPadding.Top, ClientExtraPadding.Right, ClientExtraPadding.Bottom);
@ -932,7 +927,7 @@ namespace BizHawk.Client.Common
public void Blank() public void Blank()
{ {
ActivateGLContext(); ActivateGraphicsControlContext();
_gl.BeginScene(); _gl.BeginScene();
_gl.BindRenderTarget(null); _gl.BindRenderTarget(null);
_gl.SetClearColor(Color.Black); _gl.SetClearColor(Color.Black);

View File

@ -435,7 +435,6 @@ namespace BizHawk.Client.Common.Filters
public int BackgroundColor; public int BackgroundColor;
public bool AutoPrescale; public bool AutoPrescale;
public IGuiRenderer GuiRenderer; public IGuiRenderer GuiRenderer;
public bool Flip;
public IGL GL; public IGL GL;
private bool nop; private bool nop;
private LetterboxingLogic LL; private LetterboxingLogic LL;
@ -491,7 +490,7 @@ namespace BizHawk.Client.Common.Filters
public override void SetInputFormat(string channel, SurfaceState state) public override void SetInputFormat(string channel, SurfaceState state)
{ {
bool need = state.SurfaceFormat.Size != OutputSize || FilterOption != eFilterOption.None || Flip; bool need = state.SurfaceFormat.Size != OutputSize || FilterOption != eFilterOption.None;
if (!need) if (!need)
{ {
@ -575,14 +574,7 @@ namespace BizHawk.Client.Common.Filters
//this was handled earlier by another filter //this was handled earlier by another filter
} }
GuiRenderer.Modelview.Translate(LL.vx, LL.vy); GuiRenderer.Draw(InputTexture, LL.vx, LL.vy, LL.vw, LL.vh);
if (Flip)
{
GuiRenderer.Modelview.Scale(1, -1);
GuiRenderer.Modelview.Translate(0, -LL.vh);
}
GuiRenderer.Draw(InputTexture,0,0,LL.vw,LL.vh);
GuiRenderer.End(); GuiRenderer.End();
} }
} }

View File

@ -20,8 +20,6 @@ namespace BizHawk.Client.EmuHawk
private readonly PresentationPanel _presentationPanel; // well, its the final layer's target, at least private readonly PresentationPanel _presentationPanel; // well, its the final layer's target, at least
private readonly GLManager.ContextRef _crGraphicsControl;
private GraphicsControl _graphicsControl => _presentationPanel.GraphicsControl; private GraphicsControl _graphicsControl => _presentationPanel.GraphicsControl;
public DisplayManager( public DisplayManager(
@ -36,14 +34,17 @@ namespace BizHawk.Client.EmuHawk
{ {
_presentationPanel = presentationPanel; _presentationPanel = presentationPanel;
_getIsSecondaryThrottlingDisabled = getIsSecondaryThrottlingDisabled; _getIsSecondaryThrottlingDisabled = getIsSecondaryThrottlingDisabled;
// setup the GL context manager, needed for coping with multiple opengl cores vs opengl display method
// but is it tho? --yoshi
// turns out it was, calling Instance getter here initialises it, and the encapsulated Activate call is necessary too --yoshi
_crGraphicsControl = GLManager.GetContextForGraphicsControl(_graphicsControl);
} }
protected override void ActivateGLContext() => GLManager.Instance.Activate(_crGraphicsControl); public override void ActivateOpenGLContext()
{
if (_gl.DispMethodEnum == EDispMethod.OpenGL)
{
_graphicsControl.Begin();
}
}
protected override void ActivateGraphicsControlContext() => _graphicsControl.Begin();
protected override Size GetGraphicsControlSize() => _graphicsControl.Size; protected override Size GetGraphicsControlSize() => _graphicsControl.Size;

View File

@ -1,91 +0,0 @@
using System;
using BizHawk.Bizware.BizwareGL;
using BizHawk.Bizware.Graphics;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// This singleton class manages OpenGL contexts, in an effort to minimize context changes.
/// </summary>
public class GLManager : IDisposable
{
private GLManager()
{
}
public void Dispose()
{
}
private static readonly Lazy<GLManager> _lazyInstance = new(() => new());
public static GLManager Instance => _lazyInstance.Value;
public void ReleaseGLContext(object o)
{
var cr = (ContextRef)o;
cr.GL.Dispose();
}
public ContextRef CreateGLContext(int majorVersion, int minorVersion, bool forwardCompatible)
{
var gl = new IGL_OpenGL(majorVersion, minorVersion, forwardCompatible);
return new() { GL = gl };
}
public static ContextRef GetContextForGraphicsControl(GraphicsControl gc)
{
return new()
{
Gc = gc,
GL = gc.IGL
};
}
private ContextRef _activeContext;
public void Invalidate()
{
_activeContext = null;
}
public void Activate(ContextRef cr)
{
if (cr == _activeContext)
{
// D3D9 needs a begin signal to set the swap chain to the next backbuffer
if (cr.GL.DispMethodEnum is EDispMethod.D3D9)
{
cr.Gc.Begin();
}
return;
}
_activeContext = cr;
if (cr.Gc != null)
{
cr.Gc.Begin();
}
else
{
if (cr.GL is IGL_OpenGL gl)
{
gl.MakeOffscreenContextCurrent();
}
}
}
public void Deactivate()
{
//this is here for future use and tracking purposes.. however.. instead of relying on this, we should just make sure we always activate what we need before we use it
}
public class ContextRef
{
public IGL GL { get; set; }
public GraphicsControl Gc { get; set; }
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using BizHawk.Bizware.Graphics;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// Provides a way for a core to use OpenGL
/// </summary>
public class OpenGLProvider : IOpenGLProvider
{
public int GLVersion => SDL2OpenGLContext.Version;
public object RequestGLContext(int major, int minor, bool forwardCompatible)
=> new SDL2OpenGLContext(major, minor, forwardCompatible);
public void ReleaseGLContext(object context)
=> ((SDL2OpenGLContext)context).Dispose();
public void ActivateGLContext(object context)
=> ((SDL2OpenGLContext)context).MakeContextCurrent();
public void DeactivateGLContext()
=> SDL2OpenGLContext.MakeNoneCurrent();
public IntPtr GetGLProcAddress(string proc)
=> SDL2OpenGLContext.GetGLProcAddress(proc);
}
}

View File

@ -226,7 +226,8 @@ namespace BizHawk.Client.EmuHawk
message => this.ModalMessageBox(message, "Warning", EMsgBoxIcon.Warning), message => this.ModalMessageBox(message, "Warning", EMsgBoxIcon.Warning),
AddOnScreenMessage, AddOnScreenMessage,
cfp, cfp,
prefs); prefs,
new OpenGLProvider());
} }
private void SetImages() private void SetImages()
@ -3837,6 +3838,7 @@ namespace BizHawk.Client.EmuHawk
//path = ioa_openrom.Path; //path = ioa_openrom.Path;
} }
DisplayManager.ActivateOpenGLContext(); // required in case the core wants to created a shared OpenGL context
var result = loader.LoadRom(path, nextComm, ioaRetro?.CorePath, forcedCoreName: MovieSession.QueuedCoreName); var result = loader.LoadRom(path, nextComm, ioaRetro?.CorePath, forcedCoreName: MovieSession.QueuedCoreName);
if (result) Game = loader.Game; if (result) Game = loader.Game;

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -227,16 +226,14 @@ namespace BizHawk.Client.EmuHawk
return TryInitIGL(initialConfig.DispMethod = fallback.Method); return TryInitIGL(initialConfig.DispMethod = fallback.Method);
} }
case EDispMethod.OpenGL: case EDispMethod.OpenGL:
var glOpenGL = new IGL_OpenGL(2, 0, false); if (SDL2OpenGLContext.Version < 200)
if (glOpenGL.Version < 200)
{ {
// too old to use, GDI+ will be better // too old to use, GDI+ will be better
glOpenGL.Dispose();
var fallback = ChooseFallback(); var fallback = ChooseFallback();
new ExceptionBox(new Exception($"Initialization of OpenGL Display Method failed; falling back to {fallback.Name}")).ShowDialog(); new ExceptionBox(new Exception($"Initialization of OpenGL Display Method failed; falling back to {fallback.Name}")).ShowDialog();
return TryInitIGL(initialConfig.DispMethod = fallback.Method); return TryInitIGL(initialConfig.DispMethod = fallback.Method);
} }
return CheckRenderer(glOpenGL); return CheckRenderer(new IGL_OpenGL(2, 0, false));
default: default:
case EDispMethod.GdiPlus: case EDispMethod.GdiPlus:
static GLControlWrapper_GdiPlus CreateGLControlWrapper(IGL_GdiPlus self) => new(self); // inlining as lambda causes crash, don't wanna know why --yoshi static GLControlWrapper_GdiPlus CreateGLControlWrapper(IGL_GdiPlus self) => new(self); // inlining as lambda causes crash, don't wanna know why --yoshi

View File

@ -14,13 +14,15 @@ namespace BizHawk.Emulation.Common
Action<string> showMessage, Action<string> showMessage,
Action<string, int?> notifyMessage, Action<string, int?> notifyMessage,
ICoreFileProvider coreFileProvider, ICoreFileProvider coreFileProvider,
CorePreferencesFlags prefs CorePreferencesFlags prefs,
IOpenGLProvider oglProvider
) )
{ {
ShowMessage = showMessage; ShowMessage = showMessage;
Notify = notifyMessage; Notify = notifyMessage;
CoreFileProvider = coreFileProvider; CoreFileProvider = coreFileProvider;
CorePreferences = prefs; CorePreferences = prefs;
OpenGLProvider = oglProvider;
} }
public ICoreFileProvider CoreFileProvider { get; } public ICoreFileProvider CoreFileProvider { get; }
@ -47,5 +49,10 @@ namespace BizHawk.Emulation.Common
/// Yeah, I put more stuff in corecomm. If you don't like it, change the settings/syncsettings stuff to support multiple "settings sets" to act like ini file sections kind of, so that we can hand a generic settings object to cores instead of strictly ones defined by the cores /// Yeah, I put more stuff in corecomm. If you don't like it, change the settings/syncsettings stuff to support multiple "settings sets" to act like ini file sections kind of, so that we can hand a generic settings object to cores instead of strictly ones defined by the cores
/// </summary> /// </summary>
public CorePreferencesFlags CorePreferences { get; } public CorePreferencesFlags CorePreferences { get; }
/// <summary>
/// Interface to provide OpenGL resources to the core
/// </summary>
public IOpenGLProvider OpenGLProvider { get; }
} }
} }

View File

@ -0,0 +1,44 @@
using System;
namespace BizHawk.Emulation.Common
{
/// <summary>
/// Defines an interface for cores to obtain OpenGL contexts and functions
/// </summary>
public interface IOpenGLProvider
{
/// <summary>
/// OpenGL version, using major.minor.build format with decimal points ommitted (e.g. 1.2.3 turns into 123)
/// </summary>
public int GLVersion { get; }
/// <summary>
/// Requests an OpenGL context with specified major / minor / forwardCompatible
/// The requested OpenGL context will be shared with the current context
/// Note: creating a context implicitly makes that created context current
/// </summary>
public object RequestGLContext(int major, int minor, bool forwardCompatible);
/// <summary>
/// Frees this OpenGL context
/// </summary>
public void ReleaseGLContext(object context);
/// <summary>
/// Sets this OpenGL context to current
/// </summary>
public void ActivateGLContext(object context);
/// <summary>
/// Deactivates the current OpenGL context
/// No context will be current after this call
/// </summary>
public void DeactivateGLContext();
/// <summary>
/// Gets an OpenGL function pointer
/// The user must make a context active before using this
/// </summary>
public IntPtr GetGLProcAddress(string proc);
}
}

View File

@ -0,0 +1,15 @@
namespace BizHawk.Emulation.Common
{
/// <summary>
/// This service is an extension of IVideoProvider, providing the ability to pass an OpenGL texture to the client
/// If available and the client is using OpenGL for display, this texture will be used
/// If unavailable or the client is not using OpenGL for display, the client will fall back to the base <see cref="IVideoProvider"/>
/// </summary>
public interface IGLTextureProvider : IVideoProvider, ISpecializedEmulatorService
{
/// <summary>
/// Returns an OpenGL texture of the current video content
/// </summary>
int GetGLTexture();
}
}