From 04e6d9335a77a495a34f3ab168c849a918b518ae Mon Sep 17 00:00:00 2001 From: thefiddler Date: Sat, 28 Dec 2013 01:14:59 +0100 Subject: [PATCH] [Graphics] Improved support for external OpenGL contexts When combining OpenTK with a third-party OpenGL toolkit, it is now possible to implement a suitable GetAddress() and GetCurrentContext() implementation in terms of the third-party toolkit. If no implementation is specified, then OpenTK will try to guess the most suitable implementation within its own platform backends. If no custom implementation is defined, and if no suitable implementation can be found, then OpenTK will throw a PlatformNotSupportedException. If a suitable implementation is found or defined, then OpenTK will attempt to load OpenGL entry points using that implementation. In this case third-party toolkit remains solely responsible for managing its context via its MakeCurrent(), SwapBuffers(), etc implementations. --- Source/OpenTK/Graphics/GraphicsContext.cs | 116 +++++++++++++++++------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/Source/OpenTK/Graphics/GraphicsContext.cs b/Source/OpenTK/Graphics/GraphicsContext.cs index 6c0b93f..1fd39b2 100644 --- a/Source/OpenTK/Graphics/GraphicsContext.cs +++ b/Source/OpenTK/Graphics/GraphicsContext.cs @@ -39,14 +39,13 @@ namespace OpenTK.Graphics /// public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal { + public delegate IntPtr GetAddressDelegate(string function); + public delegate ContextHandle GetCurrentContextDelegate(); + #region --- Fields --- IGraphicsContext implementation; // The actual render context implementation for the underlying platform. bool disposed; - // Indicates that this context was created through external means, e.g. Tao.Sdl or GLWidget#. - // In this case, We'll assume that the external program will manage the lifetime of this - // context - we'll not destroy it manually. - readonly bool IsExternal; bool check_errors = true; // Cache for the context handle. We need this for RemoveContext() // in case the user does not call Dispose(). When this happens, @@ -67,17 +66,6 @@ namespace OpenTK.Graphics #region --- Constructors --- - // Necessary to allow creation of dummy GraphicsContexts (see CreateDummyContext static method). - GraphicsContext(ContextHandle handle) - { - implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle); - - lock (SyncRoot) - { - AddContext(this); - } - } - /// /// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window. /// @@ -164,54 +152,81 @@ namespace OpenTK.Graphics } /// - /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. + /// Initializes a new instance of the class using + /// an external context handle that was created by a third-party library. /// - /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. - /// The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo. - /// Occurs if handle is identical to a context already registered with OpenTK. - public GraphicsContext(ContextHandle handle, IWindowInfo window) - : this(handle, window, null, 1, 0, GraphicsContextFlags.Default) - { } - - /// - /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. - /// - /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. - /// The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo. - /// A different context that shares resources with this instance, if any. - /// Pass null if the context is not shared or if this is the first GraphicsContext instruct you construct. - /// The major version of the context (e.g. "2" for "2.1"). - /// The minor version of the context (e.g. "1" for "2.1"). - /// A bitwise combination of that describe this context. - /// Occurs if handle is identical to a context already registered with OpenTK. - public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags) - : this(handle) + /// + /// A valid, unique handle for an external OpenGL context, or ContextHandle.Zero to use the current context. + /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before. + /// + /// + /// A GetAddressDelegate instance that accepts the name of an OpenGL function and returns + /// a valid function pointer, or IntPtr.Zero if that function is not supported. This delegate should be + /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with + /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function + /// pointers.) + /// + /// + /// A GetCurrentContextDelegate instance that returns the handle of the current OpenGL context, + /// or IntPtr.Zero if no context is current on the calling thread. This delegate should be implemented + /// using the same toolkit that created the OpenGL context (i.e. if the context was created with + /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve + /// the current context.) + /// + public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent) { + if (getAddress == null || getCurrent == null) + throw new ArgumentNullException(); + lock (SyncRoot) { - IsExternal = true; - + // Replace a zero-handle by the current context, if any if (handle == ContextHandle.Zero) { - implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle); + handle = getCurrent(); } - else if (available_contexts.ContainsKey(handle)) + + // Make sure this handle corresponds to a valid, unique OpenGL context + if (handle == ContextHandle.Zero) { - throw new GraphicsContextException("Context already exists."); + throw new GraphicsContextMissingException(); } - else + else if (available_contexts.ContainsKey(handle)) { - switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded) - { - case false: implementation = Factory.Default.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break; - case true: implementation = Factory.Embedded.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break; - } + throw new InvalidOperationException("Context handle has already been added"); } - (this as IGraphicsContextInternal).LoadAll(); + // We have a valid handle for an external OpenGL context, wrap it into a + // DummyGLContext instance. + implementation = new Platform.Dummy.DummyGLContext(handle, getAddress); + GetCurrentContext = getCurrent ?? GetCurrentContext; + AddContext(this); } + implementation.LoadAll(); } + /// + /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. + /// + /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. + /// This parameter is reserved. + public GraphicsContext(ContextHandle handle, IWindowInfo window) + : this(handle, window, null, 1, 0, GraphicsContextFlags.Default) + { } + + /// + /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. + /// + /// The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved. + /// This parameter is reserved.. + public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags) + : this(handle, Platform.Utilities.CreateGetAddress(), Factory.Default.CreateGetCurrentGraphicsContext()) + { } + #endregion #region Public Members @@ -309,6 +324,7 @@ namespace OpenTK.Graphics /// Instances created by this method will not be functional. Instance methods will have no effect. /// This method requires that a context is current on the calling thread. /// + [Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")] public static GraphicsContext CreateDummyContext() { ContextHandle handle = GetCurrentContext(); @@ -326,12 +342,13 @@ namespace OpenTK.Graphics /// /// Instances created by this method will not be functional. Instance methods will have no effect. /// + [Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")] public static GraphicsContext CreateDummyContext(ContextHandle handle) { if (handle == ContextHandle.Zero) throw new ArgumentOutOfRangeException("handle"); - return new GraphicsContext(handle); + return new GraphicsContext(handle, (IWindowInfo)null); } #endregion @@ -352,7 +369,6 @@ namespace OpenTK.Graphics #region public static IGraphicsContext CurrentContext - internal delegate ContextHandle GetCurrentContextDelegate(); internal static GetCurrentContextDelegate GetCurrentContext; /// -- 2.7.4