mirror of
https://github.com/Ryujinx/Opentk.git
synced 2024-12-24 17:35:27 +00:00
Serialize context construction to avoid threading issues with shared contexts.
This commit is contained in:
parent
7e1ebfea6b
commit
544cf9d405
|
@ -32,7 +32,7 @@ namespace OpenTK.Graphics
|
||||||
|
|
||||||
static bool share_contexts = true;
|
static bool share_contexts = true;
|
||||||
static bool direct_rendering = true;
|
static bool direct_rendering = true;
|
||||||
readonly static object context_lock = new object();
|
readonly static object SyncRoot = new object();
|
||||||
// Maps OS-specific context handles to GraphicsContext weak references.
|
// Maps OS-specific context handles to GraphicsContext weak references.
|
||||||
readonly static Dictionary<ContextHandle, WeakReference> available_contexts = new Dictionary<ContextHandle, WeakReference>();
|
readonly static Dictionary<ContextHandle, WeakReference> available_contexts = new Dictionary<ContextHandle, WeakReference>();
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ namespace OpenTK.Graphics
|
||||||
{
|
{
|
||||||
implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
|
implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
|
||||||
|
|
||||||
lock (context_lock)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
available_contexts.Add((implementation as IGraphicsContextInternal).Context, new WeakReference(this));
|
available_contexts.Add((implementation as IGraphicsContextInternal).Context, new WeakReference(this));
|
||||||
}
|
}
|
||||||
|
@ -78,31 +78,31 @@ namespace OpenTK.Graphics
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public GraphicsContext(GraphicsMode mode, IWindowInfo window, int major, int minor, GraphicsContextFlags flags)
|
public GraphicsContext(GraphicsMode mode, IWindowInfo window, int major, int minor, GraphicsContextFlags flags)
|
||||||
{
|
{
|
||||||
bool designMode = false;
|
lock (SyncRoot)
|
||||||
if (mode == null && window == null)
|
|
||||||
designMode = true;
|
|
||||||
else if (mode == null) throw new ArgumentNullException("mode", "Must be a valid GraphicsMode.");
|
|
||||||
else if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
|
|
||||||
|
|
||||||
// Silently ignore invalid major and minor versions.
|
|
||||||
if (major <= 0)
|
|
||||||
major = 1;
|
|
||||||
if (minor < 0)
|
|
||||||
minor = 0;
|
|
||||||
|
|
||||||
Debug.Print("Creating GraphicsContext.");
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
Debug.Indent();
|
bool designMode = false;
|
||||||
Debug.Print("GraphicsMode: {0}", mode);
|
if (mode == null && window == null)
|
||||||
Debug.Print("IWindowInfo: {0}", window);
|
designMode = true;
|
||||||
Debug.Print("GraphicsContextFlags: {0}", flags);
|
else if (mode == null) throw new ArgumentNullException("mode", "Must be a valid GraphicsMode.");
|
||||||
Debug.Print("Requested version: {0}.{1}", major, minor);
|
else if (window == null) throw new ArgumentNullException("window", "Must point to a valid window.");
|
||||||
|
|
||||||
IGraphicsContext shareContext = null;
|
// Silently ignore invalid major and minor versions.
|
||||||
if (GraphicsContext.ShareContexts)
|
if (major <= 0)
|
||||||
|
major = 1;
|
||||||
|
if (minor < 0)
|
||||||
|
minor = 0;
|
||||||
|
|
||||||
|
Debug.Print("Creating GraphicsContext.");
|
||||||
|
try
|
||||||
{
|
{
|
||||||
lock (context_lock)
|
Debug.Indent();
|
||||||
|
Debug.Print("GraphicsMode: {0}", mode);
|
||||||
|
Debug.Print("IWindowInfo: {0}", window);
|
||||||
|
Debug.Print("GraphicsContextFlags: {0}", flags);
|
||||||
|
Debug.Print("Requested version: {0}.{1}", major, minor);
|
||||||
|
|
||||||
|
IGraphicsContext shareContext = null;
|
||||||
|
if (GraphicsContext.ShareContexts)
|
||||||
{
|
{
|
||||||
// A small hack to create a shared context with the first available context.
|
// A small hack to create a shared context with the first available context.
|
||||||
foreach (WeakReference r in GraphicsContext.available_contexts.Values)
|
foreach (WeakReference r in GraphicsContext.available_contexts.Values)
|
||||||
|
@ -111,26 +111,23 @@ namespace OpenTK.Graphics
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Todo: Add a DummyFactory implementing IPlatformFactory.
|
// Todo: Add a DummyFactory implementing IPlatformFactory.
|
||||||
if (designMode)
|
if (designMode)
|
||||||
implementation = new Platform.Dummy.DummyGLContext();
|
implementation = new Platform.Dummy.DummyGLContext();
|
||||||
else
|
else
|
||||||
switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
|
switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
|
||||||
{
|
{
|
||||||
case false: implementation = Factory.Default.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags); break;
|
case false: implementation = Factory.Default.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags); break;
|
||||||
case true: implementation = Factory.Embedded.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags); break;
|
case true: implementation = Factory.Embedded.CreateGLContext(mode, window, shareContext, direct_rendering, major, minor, flags); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (context_lock)
|
|
||||||
{
|
|
||||||
available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this));
|
available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this));
|
||||||
}
|
}
|
||||||
}
|
finally
|
||||||
finally
|
{
|
||||||
{
|
Debug.Unindent();
|
||||||
Debug.Unindent();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +198,7 @@ namespace OpenTK.Graphics
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (context_lock)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
if (available_contexts.Count > 0)
|
if (available_contexts.Count > 0)
|
||||||
{
|
{
|
||||||
|
@ -282,7 +279,7 @@ namespace OpenTK.Graphics
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
void CreateContext(bool direct, IGraphicsContext source)
|
void CreateContext(bool direct, IGraphicsContext source)
|
||||||
{
|
{
|
||||||
lock (context_lock)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this));
|
available_contexts.Add((this as IGraphicsContextInternal).Context, new WeakReference(this));
|
||||||
}
|
}
|
||||||
|
@ -418,7 +415,7 @@ namespace OpenTK.Graphics
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
Debug.Print("Disposing context {0}.", (this as IGraphicsContextInternal).Context.ToString());
|
Debug.Print("Disposing context {0}.", (this as IGraphicsContextInternal).Context.ToString());
|
||||||
lock (context_lock)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
available_contexts.Remove((this as IGraphicsContextInternal).Context);
|
available_contexts.Remove((this as IGraphicsContextInternal).Context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace OpenTK.Platform.Windows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class WinGLContext : DesktopGraphicsContext
|
internal sealed class WinGLContext : DesktopGraphicsContext
|
||||||
{
|
{
|
||||||
|
static object SyncRoot = new object();
|
||||||
|
|
||||||
static IntPtr opengl32Handle;
|
static IntPtr opengl32Handle;
|
||||||
static bool wgl_loaded;
|
static bool wgl_loaded;
|
||||||
const string opengl32Name = "OPENGL32.DLL";
|
const string opengl32Name = "OPENGL32.DLL";
|
||||||
|
@ -36,96 +38,106 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
static WinGLContext()
|
static WinGLContext()
|
||||||
{
|
{
|
||||||
// Dynamically load the OpenGL32.dll in order to use the extension loading capabilities of Wgl.
|
lock (SyncRoot)
|
||||||
if (opengl32Handle == IntPtr.Zero)
|
|
||||||
{
|
{
|
||||||
opengl32Handle = Functions.LoadLibrary(opengl32Name);
|
// Dynamically load the OpenGL32.dll in order to use the extension loading capabilities of Wgl.
|
||||||
if (opengl32Handle == IntPtr.Zero)
|
if (opengl32Handle == IntPtr.Zero)
|
||||||
throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}",
|
{
|
||||||
opengl32Name, Marshal.GetLastWin32Error()));
|
opengl32Handle = Functions.LoadLibrary(opengl32Name);
|
||||||
Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", opengl32Handle));
|
if (opengl32Handle == IntPtr.Zero)
|
||||||
|
throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}",
|
||||||
|
opengl32Name, Marshal.GetLastWin32Error()));
|
||||||
|
Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", opengl32Handle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext,
|
public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext,
|
||||||
int major, int minor, GraphicsContextFlags flags)
|
int major, int minor, GraphicsContextFlags flags)
|
||||||
{
|
{
|
||||||
if (window == null)
|
// There are many ways this code can break when accessed by multiple threads. The biggest offender is
|
||||||
throw new ArgumentNullException("window", "Must point to a valid window.");
|
// the sharedContext stuff, which will only become valid *after* this constructor returns.
|
||||||
if (window.WindowHandle == IntPtr.Zero)
|
// The easiest solution is to serialize all context construction - hence the big lock, below.
|
||||||
throw new ArgumentException("window", "Must be a valid window.");
|
lock (SyncRoot)
|
||||||
|
|
||||||
Mode = format;
|
|
||||||
|
|
||||||
Debug.Print("OpenGL will be bound to handle: {0}", window.WindowHandle);
|
|
||||||
Debug.Write("Setting pixel format... ");
|
|
||||||
this.SetGraphicsModePFD(format, (WinWindowInfo)window);
|
|
||||||
|
|
||||||
if (!wgl_loaded)
|
|
||||||
{
|
{
|
||||||
// We need to create a temp context in order to load wgl extensions (e.g. for multisampling or GL3).
|
if (window == null)
|
||||||
// We cannot rely on OpenTK.Platform.Wgl until we create the context and call Wgl.LoadAll().
|
throw new ArgumentNullException("window", "Must point to a valid window.");
|
||||||
Debug.Print("Creating temporary context for wgl extensions.");
|
if (window.WindowHandle == IntPtr.Zero)
|
||||||
|
throw new ArgumentException("window", "Must be a valid window.");
|
||||||
|
|
||||||
ContextHandle temp_context = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
Mode = format;
|
||||||
Wgl.Imports.MakeCurrent(window.DeviceContext, temp_context.Handle);
|
|
||||||
Wgl.LoadAll();
|
|
||||||
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
|
||||||
Wgl.DeleteContext(temp_context.Handle);
|
|
||||||
wgl_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Wgl.Delegates.wglCreateContextAttribsARB != null)
|
Debug.Print("OpenGL will be bound to handle: {0}", window.WindowHandle);
|
||||||
{
|
Debug.Write("Setting pixel format... ");
|
||||||
try
|
this.SetGraphicsModePFD(format, (WinWindowInfo)window);
|
||||||
|
|
||||||
|
if (!wgl_loaded)
|
||||||
{
|
{
|
||||||
Debug.Write("Using WGL_ARB_create_context... ");
|
// 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.");
|
||||||
|
|
||||||
List<int> attributes = new List<int>();
|
ContextHandle temp_context = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
||||||
attributes.Add((int)ArbCreateContext.MajorVersion);
|
Wgl.Imports.MakeCurrent(window.DeviceContext, temp_context.Handle);
|
||||||
attributes.Add(major);
|
Wgl.LoadAll();
|
||||||
attributes.Add((int)ArbCreateContext.MinorVersion);
|
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
|
||||||
attributes.Add(minor);
|
Wgl.DeleteContext(temp_context.Handle);
|
||||||
if (flags != 0)
|
wgl_loaded = true;
|
||||||
{
|
}
|
||||||
attributes.Add((int)ArbCreateContext.Flags);
|
|
||||||
attributes.Add((int)flags);
|
if (Wgl.Delegates.wglCreateContextAttribsARB != null)
|
||||||
}
|
{
|
||||||
attributes.Add(0);
|
try
|
||||||
|
{
|
||||||
Handle = new ContextHandle(
|
Debug.Write("Using WGL_ARB_create_context... ");
|
||||||
Wgl.Arb.CreateContextAttribs(
|
|
||||||
window.DeviceContext,
|
List<int> attributes = new List<int>();
|
||||||
sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero,
|
attributes.Add((int)ArbCreateContext.MajorVersion);
|
||||||
attributes.ToArray()));
|
attributes.Add(major);
|
||||||
if (Handle == ContextHandle.Zero)
|
attributes.Add((int)ArbCreateContext.MinorVersion);
|
||||||
Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error());
|
attributes.Add(minor);
|
||||||
else
|
if (flags != 0)
|
||||||
Debug.Print("success!");
|
{
|
||||||
|
attributes.Add((int)ArbCreateContext.Flags);
|
||||||
|
#warning "This is not entirely correct: Embedded is not a valid flag! We need to add a GetARBContextFlags(GraphicsContextFlags) method."
|
||||||
|
attributes.Add((int)flags);
|
||||||
|
}
|
||||||
|
attributes.Add(0);
|
||||||
|
|
||||||
|
Handle = new ContextHandle(
|
||||||
|
Wgl.Arb.CreateContextAttribs(
|
||||||
|
window.DeviceContext,
|
||||||
|
sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero,
|
||||||
|
attributes.ToArray()));
|
||||||
|
if (Handle == ContextHandle.Zero)
|
||||||
|
Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error());
|
||||||
|
else
|
||||||
|
Debug.Print("success!");
|
||||||
|
}
|
||||||
|
catch (EntryPointNotFoundException e) { Debug.Print(e.ToString()); }
|
||||||
|
catch (NullReferenceException e) { Debug.Print(e.ToString()); }
|
||||||
}
|
}
|
||||||
catch (EntryPointNotFoundException e) { Debug.Print(e.ToString()); }
|
|
||||||
catch (NullReferenceException e) { Debug.Print(e.ToString()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Handle == ContextHandle.Zero)
|
|
||||||
{
|
|
||||||
// Failed to create GL3-level context, fall back to GL2.
|
|
||||||
Debug.Write("Falling back to GL2... ");
|
|
||||||
Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
|
||||||
if (Handle == ContextHandle.Zero)
|
if (Handle == ContextHandle.Zero)
|
||||||
|
{
|
||||||
|
// Failed to create GL3-level context, fall back to GL2.
|
||||||
|
Debug.Write("Falling back to GL2... ");
|
||||||
Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
||||||
if (Handle == ContextHandle.Zero)
|
if (Handle == ContextHandle.Zero)
|
||||||
throw new GraphicsContextException(
|
Handle = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext));
|
||||||
String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
|
if (Handle == ContextHandle.Zero)
|
||||||
Marshal.GetLastWin32Error()));
|
throw new GraphicsContextException(
|
||||||
}
|
String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
|
||||||
|
Marshal.GetLastWin32Error()));
|
||||||
|
}
|
||||||
|
|
||||||
Debug.WriteLine(String.Format("success! (id: {0})", Handle));
|
Debug.WriteLine(String.Format("success! (id: {0})", Handle));
|
||||||
|
|
||||||
if (sharedContext != null)
|
if (sharedContext != null)
|
||||||
{
|
{
|
||||||
Debug.Print("Sharing state with context {0}", sharedContext.ToString());
|
Debug.Print("Sharing state with context {0}", sharedContext.ToString());
|
||||||
Wgl.Imports.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle);
|
Wgl.Imports.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue