Minor reworking of IGL OpenGL context creation
Try to regain compat with < OpenGL 3.0 users, better checks against OpenGL availability
This commit is contained in:
parent
e7f4ad8220
commit
f1e9f10454
|
@ -10,6 +10,7 @@
|
|||
<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" />
|
||||
|
|
|
@ -15,6 +15,7 @@ using BizHawk.Bizware.BizwareGL;
|
|||
using BizHawk.Common;
|
||||
|
||||
using Silk.NET.OpenGL.Legacy;
|
||||
using Silk.NET.OpenGL.Legacy.Extensions.EXT;
|
||||
|
||||
using BizClearBufferMask = BizHawk.Bizware.BizwareGL.ClearBufferMask;
|
||||
using BizPrimitiveType = BizHawk.Bizware.BizwareGL.PrimitiveType;
|
||||
|
@ -38,8 +39,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
public EDispMethod DispMethodEnum => EDispMethod.OpenGL;
|
||||
|
||||
private readonly GL GL;
|
||||
private readonly int _majorVersion, _minorVersion;
|
||||
private readonly bool _forwardCompatible;
|
||||
private readonly ExtFramebufferObject EXT;
|
||||
|
||||
// rendering state
|
||||
private Pipeline _currPipeline;
|
||||
|
@ -47,20 +47,99 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
public string API => "OPENGL";
|
||||
|
||||
public IGL_OpenGL(int majorVersion, int minorVersion, bool forwardCompatible)
|
||||
// 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(() =>
|
||||
{
|
||||
_majorVersion = majorVersion;
|
||||
_minorVersion = minorVersion;
|
||||
_forwardCompatible = forwardCompatible;
|
||||
switch (SDL2OpenGLContext.Version)
|
||||
{
|
||||
case >= 300:
|
||||
return true;
|
||||
case < 200:
|
||||
return false;
|
||||
}
|
||||
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
{
|
||||
using var gl = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
|
||||
return gl.IsExtensionPresent("EXT_framebuffer_object") || gl.IsExtensionPresent("ARB_framebuffer_object");
|
||||
}
|
||||
});
|
||||
|
||||
public static bool Available => _available.Value;
|
||||
|
||||
public IGL_OpenGL()
|
||||
{
|
||||
if (!Available)
|
||||
{
|
||||
throw new InvalidOperationException("The required OpenGL version is unavailable");
|
||||
}
|
||||
|
||||
// the loading of symbols is delayed until actual use, so no need to create a context now
|
||||
// if you want to do offscreen work with this GL make a dummy control or an SDL2OpenGLContext
|
||||
GL = GL.GetApi(SDL2OpenGLContext.GetGLProcAddress);
|
||||
|
||||
// might need to use EXT if < OpenGL 3.0 and ARB_framebuffer_object is unavailable
|
||||
if (SDL2OpenGLContext.Version < 300)
|
||||
{
|
||||
using (new SDL2OpenGLContext(2, 0, 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
|
||||
if (!GL.IsExtensionPresent("ARB_framebuffer_object"))
|
||||
{
|
||||
if (!GL.TryGetExtension(out EXT))
|
||||
{
|
||||
throw new InvalidOperationException("Could not get EXT_framebuffer_object? This shouldn't happen");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// misc initialization
|
||||
CreateRenderStates();
|
||||
}
|
||||
|
||||
// FBO function wrappers
|
||||
private uint GenFramebuffer()
|
||||
=> EXT?.GenFramebuffer() ?? GL.GenFramebuffer();
|
||||
|
||||
private void BindFramebuffer(FramebufferTarget target, uint fbId)
|
||||
{
|
||||
if (EXT != null)
|
||||
{
|
||||
EXT.BindFramebuffer(target, fbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.BindFramebuffer(target, fbId);
|
||||
}
|
||||
}
|
||||
|
||||
private void FramebufferTexture2D(FramebufferTarget fbTarget, FramebufferAttachment fbAttachment, TextureTarget textureTarget, uint fbId, int level)
|
||||
{
|
||||
if (EXT != null)
|
||||
{
|
||||
EXT.FramebufferTexture2D(fbTarget, fbAttachment, textureTarget, fbId, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.FramebufferTexture2D(fbTarget, fbAttachment, textureTarget, fbId, level);
|
||||
}
|
||||
}
|
||||
|
||||
private FramebufferStatus CheckFramebufferStatus(FramebufferTarget target)
|
||||
=> (FramebufferStatus)(EXT?.CheckFramebufferStatus(target) ?? (EXT)GL.CheckFramebufferStatus(target));
|
||||
|
||||
private void DeleteFramebuffer(uint fbId)
|
||||
{
|
||||
if (EXT != null)
|
||||
{
|
||||
EXT.DeleteFramebuffer(fbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.DeleteFramebuffer(fbId);
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginScene()
|
||||
{
|
||||
}
|
||||
|
@ -72,6 +151,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
public void Dispose()
|
||||
{
|
||||
GL.Dispose();
|
||||
EXT?.Dispose();
|
||||
}
|
||||
|
||||
public void Clear(BizClearBufferMask mask)
|
||||
|
@ -86,7 +166,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
|
||||
public IGraphicsControl Internal_CreateGraphicsControl()
|
||||
{
|
||||
var ret = new OpenGLControl(_majorVersion, _minorVersion, _forwardCompatible, ContextChangeCallback);
|
||||
var ret = new OpenGLControl(ContextChangeCallback);
|
||||
ret.CreateControl(); // DisplayManager relies on this context being active for creating the GuiRenderer
|
||||
return ret;
|
||||
}
|
||||
|
@ -470,7 +550,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
public void FreeRenderTarget(RenderTarget rt)
|
||||
{
|
||||
rt.Texture2d.Dispose();
|
||||
GL.DeleteFramebuffer((uint)rt.Opaque);
|
||||
DeleteFramebuffer((uint)rt.Opaque);
|
||||
}
|
||||
|
||||
/// <exception cref="InvalidOperationException">framebuffer creation unsuccessful</exception>
|
||||
|
@ -486,24 +566,24 @@ namespace BizHawk.Bizware.Graphics
|
|||
tex.SetMinFilter(BizTextureMinFilter.Nearest);
|
||||
|
||||
// create the FBO
|
||||
var fbId = GL.GenFramebuffer();
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbId);
|
||||
var fbId = GenFramebuffer();
|
||||
BindFramebuffer(FramebufferTarget.Framebuffer, fbId);
|
||||
|
||||
// bind the tex to the FBO
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, texId, 0);
|
||||
FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, texId, 0);
|
||||
|
||||
// do something, I guess say which color buffers are used by the framebuffer
|
||||
var buffers = stackalloc DrawBufferMode[1];
|
||||
buffers[0] = DrawBufferMode.ColorAttachment0;
|
||||
GL.DrawBuffers(1, buffers);
|
||||
|
||||
if ((FramebufferStatus)GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferStatus.Complete)
|
||||
if (CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferStatus.Complete)
|
||||
{
|
||||
throw new InvalidOperationException($"Error creating framebuffer (at {nameof(GL.CheckFramebufferStatus)})");
|
||||
throw new InvalidOperationException($"Error creating framebuffer (at {nameof(CheckFramebufferStatus)})");
|
||||
}
|
||||
|
||||
// since we're done configuring unbind this framebuffer, to return to the default
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
|
||||
return new(this, fbId, tex);
|
||||
}
|
||||
|
@ -513,11 +593,11 @@ namespace BizHawk.Bizware.Graphics
|
|||
_currRenderTarget = rt;
|
||||
if (rt == null)
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, (uint)rt.Opaque);
|
||||
BindFramebuffer(FramebufferTarget.Framebuffer, (uint)rt.Opaque);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,6 @@ namespace BizHawk.Bizware.Graphics
|
|||
{
|
||||
internal class OpenGLControl : Control, IGraphicsControl
|
||||
{
|
||||
private readonly int _majorVersion;
|
||||
private readonly int _minorVersion;
|
||||
private readonly bool _forwardCompatible;
|
||||
private readonly Action _contextChangeCallback;
|
||||
|
||||
public SDL2OpenGLContext Context { get; private set; }
|
||||
|
@ -21,11 +18,8 @@ namespace BizHawk.Bizware.Graphics
|
|||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public OpenGLControl(int majorVersion, int minorVersion, bool forwardCompatible, Action contextChangeCallback)
|
||||
public OpenGLControl(Action contextChangeCallback)
|
||||
{
|
||||
_majorVersion = majorVersion;
|
||||
_minorVersion = minorVersion;
|
||||
_forwardCompatible = forwardCompatible;
|
||||
_contextChangeCallback = contextChangeCallback;
|
||||
|
||||
// according to OpenTK, these are the styles we want to set
|
||||
|
@ -58,7 +52,7 @@ namespace BizHawk.Bizware.Graphics
|
|||
protected override void OnHandleCreated(EventArgs e)
|
||||
{
|
||||
base.OnHandleCreated(e);
|
||||
Context = new(Handle, _majorVersion, _minorVersion, _forwardCompatible);
|
||||
Context = new(Handle, 2, 0, false);
|
||||
_contextChangeCallback();
|
||||
}
|
||||
|
||||
|
|
|
@ -226,17 +226,18 @@ namespace BizHawk.Client.EmuHawk
|
|||
return TryInitIGL(initialConfig.DispMethod = fallback.Method);
|
||||
}
|
||||
case EDispMethod.OpenGL:
|
||||
if (SDL2OpenGLContext.Version < 200)
|
||||
if (!IGL_OpenGL.Available)
|
||||
{
|
||||
// too old to use, GDI+ will be better
|
||||
// too old to use, need to fallback to something else
|
||||
var fallback = ChooseFallback();
|
||||
new ExceptionBox(new Exception($"Initialization of OpenGL Display Method failed; falling back to {fallback.Name}")).ShowDialog();
|
||||
return TryInitIGL(initialConfig.DispMethod = fallback.Method);
|
||||
}
|
||||
var igl = new IGL_OpenGL();
|
||||
// need to have a context active for checking renderer, will be disposed afterwards
|
||||
using (new SDL2OpenGLContext(2, 0, false))
|
||||
{
|
||||
return CheckRenderer(new IGL_OpenGL(2, 0, false));
|
||||
return CheckRenderer(igl);
|
||||
}
|
||||
default:
|
||||
case EDispMethod.GdiPlus:
|
||||
|
|
Loading…
Reference in New Issue