mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-23 05:41:04 +00:00
Cleaned up temporary context construction
The temporary context is now retained until the actual context has been constructed. If we don't do this, then WGL_ARB_create_context may fail to work correctly on specific GPUs (e.g. Intel). This may affect issue #19.
This commit is contained in:
parent
a57b4c4270
commit
d8a4ca1162
|
@ -28,35 +28,38 @@ namespace OpenTK.Platform.Windows
|
|||
internal sealed class WinGLContext : DesktopGraphicsContext
|
||||
{
|
||||
static readonly object LoadLock = new object();
|
||||
static readonly object SyncRoot = new object();
|
||||
|
||||
bool vsync_supported;
|
||||
|
||||
readonly WinGraphicsMode ModeSelector;
|
||||
|
||||
#region --- Contructors ---
|
||||
|
||||
static WinGLContext()
|
||||
{
|
||||
lock (LoadLock)
|
||||
{
|
||||
// We need to create a temp context in order to load
|
||||
// wgl extensions (e.g. for multisampling or GL3).
|
||||
// We cannot rely on OpenTK.Platform.Wgl until we
|
||||
// create the context and call Wgl.LoadAll().
|
||||
Debug.Print("Creating temporary context for wgl extensions.");
|
||||
using (INativeWindow native = new NativeWindow())
|
||||
// We cannot rely on any WGL extensions before
|
||||
// we load them with the temporary context.
|
||||
class TemporaryContext : IDisposable
|
||||
{
|
||||
public ContextHandle Context;
|
||||
|
||||
public TemporaryContext(INativeWindow native)
|
||||
{
|
||||
Debug.WriteLine("[WGL] Creating temporary context to load extensions");
|
||||
|
||||
if (native == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
// Create temporary context and load WGL entry points
|
||||
// First, set a compatible pixel format to the device context
|
||||
// of the temp window
|
||||
WinWindowInfo window = native.WindowInfo as WinWindowInfo;
|
||||
WinGraphicsMode selector = new WinGraphicsMode(window.DeviceContext);
|
||||
SetGraphicsModePFD(selector, GraphicsMode.Default, window);
|
||||
WinGLContext.SetGraphicsModePFD(selector, GraphicsMode.Default, window);
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Then, construct a temporary context and load all wgl extensions
|
||||
ContextHandle temp_context = new ContextHandle(Wgl.CreateContext(window.DeviceContext));
|
||||
if (temp_context != ContextHandle.Zero)
|
||||
Context = new ContextHandle(Wgl.CreateContext(window.DeviceContext));
|
||||
if (Context != ContextHandle.Zero)
|
||||
{
|
||||
// Make the context current.
|
||||
// Note: on some video cards and on some virtual machines, wglMakeCurrent
|
||||
|
@ -64,52 +67,72 @@ namespace OpenTK.Platform.Windows
|
|||
// is to call wglMakeCurrent in a loop until it succeeds.
|
||||
// See https://www.opengl.org/discussion_boards/showthread.php/171058-nVidia-wglMakeCurrent()-multiple-threads
|
||||
// Sigh...
|
||||
for (int retry = 0; retry < 5; retry++)
|
||||
for (int retry = 0; retry < 5 && !success; retry++)
|
||||
{
|
||||
bool success = Wgl.MakeCurrent(window.DeviceContext, temp_context.Handle);
|
||||
success = Wgl.MakeCurrent(window.DeviceContext, Context.Handle);
|
||||
if (!success)
|
||||
{
|
||||
Debug.Print("wglMakeCurrent failed with error: {0}. Retrying", Marshal.GetLastWin32Error());
|
||||
System.Threading.Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// wglMakeCurrent succeeded, we are done here!
|
||||
break;
|
||||
Debug.Print("[WGL] CreateContext failed with error: {0}", Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
Debug.WriteLine("[WGL] Failed to create temporary context");
|
||||
}
|
||||
}
|
||||
|
||||
// Load wgl extensions and destroy temporary context
|
||||
Wgl.LoadAll();
|
||||
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
||||
Wgl.DeleteContext(temp_context.Handle);
|
||||
}
|
||||
else
|
||||
public void Dispose()
|
||||
{
|
||||
Debug.Print("wglCreateContext failed with error: {0}", Marshal.GetLastWin32Error());
|
||||
}
|
||||
if (Context != ContextHandle.Zero)
|
||||
{
|
||||
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
||||
Wgl.DeleteContext(Context.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region --- Contructors ---
|
||||
|
||||
public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext,
|
||||
int major, int minor, GraphicsContextFlags flags)
|
||||
{
|
||||
// There are many ways this code can break when accessed by multiple threads. The biggest offender is
|
||||
// the sharedContext stuff, which will only become valid *after* this constructor returns.
|
||||
// The easiest solution is to serialize all context construction - hence the big lock, below.
|
||||
lock (SyncRoot)
|
||||
lock (LoadLock)
|
||||
{
|
||||
if (window == null)
|
||||
throw new ArgumentNullException("window", "Must point to a valid window.");
|
||||
if (window.Handle == IntPtr.Zero)
|
||||
throw new ArgumentException("window", "Must be a valid window.");
|
||||
|
||||
IntPtr current_context = Wgl.GetCurrentContext();
|
||||
INativeWindow temp_window = null;
|
||||
TemporaryContext temp_context = null;
|
||||
try
|
||||
{
|
||||
if (current_context == IntPtr.Zero)
|
||||
{
|
||||
// Create temporary context to load WGL extensions
|
||||
temp_window = new NativeWindow();
|
||||
temp_context = new TemporaryContext(temp_window);
|
||||
current_context = Wgl.GetCurrentContext();
|
||||
if (current_context != IntPtr.Zero && current_context == temp_context.Context.Handle)
|
||||
{
|
||||
Wgl.LoadAll();
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Print("OpenGL will be bound to window:{0} on thread:{1}", window.Handle,
|
||||
System.Threading.Thread.CurrentThread.ManagedThreadId);
|
||||
|
||||
lock (LoadLock)
|
||||
{
|
||||
ModeSelector = new WinGraphicsMode(window.DeviceContext);
|
||||
Mode = SetGraphicsModePFD(ModeSelector, format, (WinWindowInfo)window);
|
||||
|
||||
|
@ -146,9 +169,7 @@ namespace OpenTK.Platform.Windows
|
|||
if (Handle == ContextHandle.Zero)
|
||||
Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error());
|
||||
}
|
||||
catch (EntryPointNotFoundException e) { Debug.Print(e.ToString()); }
|
||||
catch (NullReferenceException e) { Debug.Print(e.ToString()); }
|
||||
}
|
||||
catch (Exception e) { Debug.Print(e.ToString()); }
|
||||
}
|
||||
|
||||
if (Handle == ContextHandle.Zero)
|
||||
|
@ -165,6 +186,21 @@ namespace OpenTK.Platform.Windows
|
|||
}
|
||||
|
||||
Debug.WriteLine(String.Format("success! (id: {0})", Handle));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (temp_context != null)
|
||||
{
|
||||
temp_context.Dispose();
|
||||
temp_context = null;
|
||||
}
|
||||
if (temp_window != null)
|
||||
{
|
||||
temp_window.Dispose();
|
||||
temp_window = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: is this comment still true?
|
||||
// On intel drivers, wgl entry points appear to change
|
||||
|
@ -174,6 +210,7 @@ namespace OpenTK.Platform.Windows
|
|||
// side-effects (i.e. the old contexts can still be handled
|
||||
// using the new entry points.)
|
||||
// Sigh...
|
||||
Wgl.MakeCurrent(window.DeviceContext, Handle.Handle);
|
||||
Wgl.LoadAll();
|
||||
|
||||
if (sharedContext != null)
|
||||
|
@ -184,7 +221,6 @@ namespace OpenTK.Platform.Windows
|
|||
Debug.WriteLine(result ? "success!" : "failed with win32 error " + Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ArbCreateContext GetARBContextFlags(GraphicsContextFlags flags)
|
||||
{
|
||||
|
@ -231,7 +267,6 @@ namespace OpenTK.Platform.Windows
|
|||
|
||||
public override void MakeCurrent(IWindowInfo window)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
lock (LoadLock)
|
||||
{
|
||||
bool success;
|
||||
|
@ -347,7 +382,7 @@ namespace OpenTK.Platform.Windows
|
|||
{
|
||||
// See https://www.opengl.org/wiki/Load_OpenGL_Functions
|
||||
long a = address.ToInt64();
|
||||
bool is_valid = (a < -1 )|| (a > 3);
|
||||
bool is_valid = (a < -1) || (a > 3);
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue