Rework OpenGL version support checking to be more robust, slightly rework OpenGL context creation request (they can now explicitly request the core profile)
This commit is contained in:
parent
a2ea86fae0
commit
67e5505899
|
@ -38,6 +38,8 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
public EDispMethod DispMethodEnum => EDispMethod.OpenGL;
|
||||
|
||||
private static readonly bool _supportsOpenGL3 = OpenGLVersion.SupportsVersion(3, 0);
|
||||
|
||||
private readonly GL GL;
|
||||
private readonly ExtFramebufferObject EXT;
|
||||
|
||||
|
@ -50,15 +52,17 @@ namespace BizHawk.Bizware.Graphics
|
|||
// this IGL either requires at least OpenGL 3.0, or OpenGL 2.0 + the EXT_framebuffer_object or ARB_framebuffer_object extension present
|
||||
private static readonly Lazy<bool> _available = new(() =>
|
||||
{
|
||||
switch (SDL2OpenGLContext.Version)
|
||||
if (_supportsOpenGL3)
|
||||
{
|
||||
case >= 300:
|
||||
return true;
|
||||
case < 200:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
if (!OpenGLVersion.SupportsVersion(2, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using (new SDL2OpenGLContext(2, 0, false, false))
|
||||
{
|
||||
using var gl = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
|
||||
return gl.IsExtensionPresent("EXT_framebuffer_object") || gl.IsExtensionPresent("ARB_framebuffer_object");
|
||||
|
@ -77,9 +81,9 @@ namespace BizHawk.Bizware.Graphics
|
|||
GL = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
|
||||
|
||||
// might need to use EXT if < OpenGL 3.0 and ARB_framebuffer_object is unavailable
|
||||
if (SDL2OpenGLContext.Version < 300)
|
||||
if (!_supportsOpenGL3)
|
||||
{
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
using (new SDL2OpenGLContext(2, 0, false, false))
|
||||
{
|
||||
// ARB_framebuffer_object entrypoints are identical to standard OpenGL 3.0 ones
|
||||
// EXT_framebuffer_object has differently named entrypoints so needs a separate object
|
||||
|
@ -166,7 +170,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = new OpenGLControl(ContextChangeCallback);
|
||||
var ret = new OpenGLControl(_supportsOpenGL3, ContextChangeCallback);
|
||||
ret.CreateControl(); // DisplayManager relies on this context being active for creating the GuiRenderer
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
internal class OpenGLControl : Control, IGraphicsControl
|
||||
{
|
||||
private readonly bool _openGL3;
|
||||
private readonly Action _contextChangeCallback;
|
||||
|
||||
public SDL2OpenGLContext Context { get; private set; }
|
||||
|
@ -18,8 +19,9 @@ namespace BizHawk.Bizware.Graphics
|
|||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public OpenGLControl(Action contextChangeCallback)
|
||||
public OpenGLControl(bool openGL3, Action contextChangeCallback)
|
||||
{
|
||||
_openGL3 = openGL3;
|
||||
_contextChangeCallback = contextChangeCallback;
|
||||
|
||||
// according to OpenTK, these are the styles we want to set
|
||||
|
@ -52,7 +54,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
Context = new(Handle, 2, 0, false);
|
||||
Context = new(Handle, _openGL3 ? 3 : 2, 0, false, false);
|
||||
_contextChangeCallback();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BizHawk.Common.CollectionExtensions;
|
||||
|
||||
using Silk.NET.OpenGL.Legacy;
|
||||
|
||||
using static SDL2.SDL;
|
||||
|
||||
namespace BizHawk.Bizware.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps checking OpenGL versions
|
||||
/// </summary>
|
||||
public static class OpenGLVersion
|
||||
{
|
||||
// TODO: make this a ref struct once we're c# 10 (parameterless struct ctor)
|
||||
private class SavedOpenGLContext : IDisposable
|
||||
{
|
||||
private readonly IntPtr _sdlWindow, _glContext;
|
||||
|
||||
public SavedOpenGLContext()
|
||||
{
|
||||
_sdlWindow = SDL_GL_GetCurrentWindow();
|
||||
_glContext = SDL_GL_GetCurrentContext();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_ = SDL_GL_MakeCurrent(_sdlWindow, _glContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IDictionary<int, bool> _glSupport = new Dictionary<int, bool>();
|
||||
|
||||
private static int PackGLVersion(int major, int minor)
|
||||
=> major * 10 + minor;
|
||||
|
||||
private static bool CheckVersion(int requestedMajor, int requestedMinor)
|
||||
{
|
||||
using (new SavedOpenGLContext())
|
||||
{
|
||||
try
|
||||
{
|
||||
using (new SDL2OpenGLContext(requestedMajor, requestedMinor, true, false))
|
||||
{
|
||||
using var gl = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
|
||||
var versionString = gl.GetStringS(StringName.Version);
|
||||
var versionParts = versionString!.Split('.');
|
||||
var major = int.Parse(versionParts[0]);
|
||||
var minor = int.Parse(versionParts[1][0].ToString());
|
||||
return PackGLVersion(major, minor) >= PackGLVersion(requestedMajor, requestedMinor);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SupportsVersion(int major, int minor)
|
||||
=> _glSupport.GetValueOrPut(PackGLVersion(major, minor),
|
||||
static version => CheckVersion(version / 10, version % 10));
|
||||
}
|
||||
}
|
|
@ -44,35 +44,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
SDL_SetHint(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, "0");
|
||||
}
|
||||
|
||||
private static readonly Lazy<int> _version = new(() =>
|
||||
{
|
||||
var prevWindow = SDL_GL_GetCurrentWindow();
|
||||
var prevContext = SDL_GL_GetCurrentContext();
|
||||
|
||||
try
|
||||
{
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
{
|
||||
using var gl = GL.GetApi(GetGLProcAddress);
|
||||
var versionString = gl.GetStringS(StringName.Version);
|
||||
var versionParts = versionString!.Split('.');
|
||||
var major = int.Parse(versionParts[0]);
|
||||
var minor = int.Parse(versionParts[1][0].ToString());
|
||||
return major * 100 + minor * 10;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
SDL_GL_MakeCurrent(prevWindow, prevContext);
|
||||
}
|
||||
});
|
||||
|
||||
public static int Version => _version.Value;
|
||||
|
||||
private IntPtr _sdlWindow;
|
||||
private IntPtr _glContext;
|
||||
|
||||
private void CreateContext(int majorVersion, int minorVersion, bool forwardCompatible)
|
||||
private void CreateContext(int majorVersion, int minorVersion, bool coreProfile, bool forwardCompatible)
|
||||
{
|
||||
if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion) != 0)
|
||||
{
|
||||
|
@ -84,17 +59,16 @@ namespace BizHawk.Bizware.Graphics
|
|||
throw new($"Could not set GL Minor Version! SDL Error: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
// TODO: Debug flag / debug callback with DEBUG build
|
||||
if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_FLAGS, forwardCompatible
|
||||
? (int)SDL_GLcontext.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG : 0) != 0)
|
||||
{
|
||||
throw new($"Could not set GL Context Flags! SDL Error: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
// if we're requesting OpenGL 3.3+, get the core profile
|
||||
// profiles don't exist otherwise
|
||||
var profile = majorVersion * 10 + minorVersion >= 33
|
||||
var profile = coreProfile
|
||||
? SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE
|
||||
: 0;
|
||||
: SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
|
||||
|
||||
if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, profile) != 0)
|
||||
{
|
||||
|
@ -108,7 +82,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorVersion, bool forwardCompatible)
|
||||
public SDL2OpenGLContext(IntPtr nativeWindowhandle, int majorVersion, int minorVersion, bool coreProfile, bool forwardCompatible)
|
||||
{
|
||||
_sdlWindow = SDL_CreateWindowFrom(nativeWindowhandle);
|
||||
if (_sdlWindow == IntPtr.Zero)
|
||||
|
@ -122,10 +96,10 @@ namespace BizHawk.Bizware.Graphics
|
|||
throw new($"Could not set share context attribute! SDL Error: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
CreateContext(majorVersion, minorVersion, forwardCompatible);
|
||||
CreateContext(majorVersion, minorVersion, coreProfile, forwardCompatible);
|
||||
}
|
||||
|
||||
public SDL2OpenGLContext(int majorVersion, int minorVersion, bool forwardCompatible)
|
||||
public SDL2OpenGLContext(int majorVersion, int minorVersion, bool coreProfile, bool forwardCompatible)
|
||||
{
|
||||
_sdlWindow = SDL_CreateWindow(null, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1,
|
||||
SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL_WindowFlags.SDL_WINDOW_HIDDEN);
|
||||
|
@ -135,14 +109,13 @@ namespace BizHawk.Bizware.Graphics
|
|||
}
|
||||
|
||||
// offscreen contexts are shared (as we want to send texture from it over to our control's context)
|
||||
// make sure to set the current graphics' control context before creating this context
|
||||
// (if no context is set, i.e. first IGL, then this won't do anything)
|
||||
// make sure to set the current graphics control context before creating this context
|
||||
if (SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1) != 0)
|
||||
{
|
||||
throw new($"Could not set share context attribute! SDL Error: {SDL_GetError()}");
|
||||
}
|
||||
|
||||
CreateContext(majorVersion, minorVersion, forwardCompatible);
|
||||
CreateContext(majorVersion, minorVersion, coreProfile, forwardCompatible);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -10,10 +10,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
/// </summary>
|
||||
public class OpenGLProvider : IOpenGLProvider
|
||||
{
|
||||
public int GLVersion => SDL2OpenGLContext.Version;
|
||||
public bool SupportsGLVersion(int major, int minor)
|
||||
=> OpenGLVersion.SupportsVersion(major, minor);
|
||||
|
||||
public object RequestGLContext(int major, int minor, bool forwardCompatible)
|
||||
=> new SDL2OpenGLContext(major, minor, forwardCompatible);
|
||||
public object RequestGLContext(int major, int minor, bool coreProfile, bool forwardCompatible)
|
||||
=> new SDL2OpenGLContext(major, minor, coreProfile, forwardCompatible);
|
||||
|
||||
public void ReleaseGLContext(object context)
|
||||
=> ((SDL2OpenGLContext)context).Dispose();
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
var igl = new IGL_OpenGL();
|
||||
// need to have a context active for checking renderer, will be disposed afterwards
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
using (new SDL2OpenGLContext(OpenGLVersion.SupportsVersion(3, 0) ? 3 : 2, 0, false, false))
|
||||
{
|
||||
return CheckRenderer(igl);
|
||||
}
|
||||
|
|
|
@ -8,16 +8,19 @@ namespace BizHawk.Emulation.Common
|
|||
public interface IOpenGLProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// OpenGL version, using major.minor.build format with decimal points ommitted (e.g. 1.2.3 turns into 123)
|
||||
/// Checks if specified OpenGL version is supported
|
||||
/// The current context will be preserved
|
||||
/// </summary>
|
||||
public int GLVersion { get; }
|
||||
public bool SupportsGLVersion(int major, int minor);
|
||||
|
||||
/// <summary>
|
||||
/// Requests an OpenGL context with specified major / minor / forwardCompatible
|
||||
/// Requests an OpenGL context with specified major / minor
|
||||
/// The core profile can be requested (otherwise, the compatibility profile will be used)
|
||||
/// The forward compatible bit can also be requested
|
||||
/// 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);
|
||||
public object RequestGLContext(int major, int minor, bool coreProfile, bool forwardCompatible);
|
||||
|
||||
/// <summary>
|
||||
/// Frees this OpenGL context
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
|
|||
_configCallbackInterface.GetString = GetStringSettingCallback;
|
||||
|
||||
_openGLProvider = lp.Comm.OpenGLProvider;
|
||||
_supportsOpenGL43 = _openGLProvider.GLVersion >= 430;
|
||||
_supportsOpenGL43 = _openGLProvider.SupportsGLVersion(4, 3);
|
||||
if (!_supportsOpenGL43/* && _syncSettings.GraphicsApi == CitraSyncSettings.EGraphicsApi.OpenGL*/)
|
||||
{
|
||||
throw new("OpenGL 4.3 is required, but it is not supported on this machine");
|
||||
|
@ -161,7 +161,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
|
|||
|
||||
private IntPtr RequestGLContextCallback()
|
||||
{
|
||||
var context = _openGLProvider.RequestGLContext(4, 3, false);
|
||||
var context = _openGLProvider.RequestGLContext(4, 3, true, false);
|
||||
_glContexts.Add(context);
|
||||
var handle = GCHandle.Alloc(context, GCHandleType.Weak);
|
||||
return GCHandle.ToIntPtr(handle);
|
||||
|
|
Loading…
Reference in New Issue