diff --git a/src/Aardvark.Rendering.GL/Core/Config.fs b/src/Aardvark.Rendering.GL/Core/Config.fs index 213906d0..1ff526c3 100644 --- a/src/Aardvark.Rendering.GL/Core/Config.fs +++ b/src/Aardvark.Rendering.GL/Core/Config.fs @@ -58,6 +58,16 @@ module RuntimeConfig = /// let mutable NumberOfResourceContexts = 2 + /// + /// Determines if context creation and sharing is robust to work properly in some edge cases. + /// When a context is created a parent context has to be provided to enable sharing. If that parent + /// context happens to be currently in use by another thread, context creation or sharing may fail. + /// If this flag is false, a resource context is used as parent without checking if it is actually available. + /// If true, an additional hidden context will be used as parent. + /// Default is true. + /// + let mutable RobustContextSharing = true + /// /// Specifies the expected depth range of normalized device coordinates. /// Setting a depth range of [0, 1] requires GL_ARB_clip_control or OpenGL 4.5. diff --git a/src/Aardvark.Rendering.GL/Core/Context.fs b/src/Aardvark.Rendering.GL/Core/Context.fs index 658d9843..3aeaf8c8 100644 --- a/src/Aardvark.Rendering.GL/Core/Context.fs +++ b/src/Aardvark.Rendering.GL/Core/Context.fs @@ -184,7 +184,7 @@ type MemoryUsage() = /// multiple threads to submit GL calls concurrently. /// [] -type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this = +type Context(runtime : IRuntime, createContext : ContextHandle option -> ContextHandle) as this = static let defaultShaderCachePath = Path.combine [ @@ -193,9 +193,15 @@ type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this "OpenGL" ] + // Hidden unused context for sharing. + // Note: If None is passed to createContext, it's up to the implementation how to choose the parent. + let parentContext = + if RuntimeConfig.RobustContextSharing then Some <| createContext None + else None + let resourceContexts = let n = max 1 RuntimeConfig.NumberOfResourceContexts - Array.init n (ignore >> createContext) + Array.init n (fun _ -> createContext parentContext) let memoryUsage = MemoryUsage() @@ -243,12 +249,16 @@ type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this value | Some v -> v + [] + new (runtime : IRuntime, createContext : unit -> ContextHandle) = + new Context(runtime, fun (_ : ContextHandle option) -> createContext()) + /// /// Creates custom OpenGl context. Usage: /// let customCtx = app.Context.CreateContext() /// use __ = app.Context.RenderingLock(customCtx) /// - member x.CreateContext() = createContext() + member x.CreateContext() = createContext parentContext member internal x.ShaderCache = shaderCache @@ -459,6 +469,8 @@ type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this for c in resourceContexts do ContextHandle.delete c + + parentContext |> Option.iter ContextHandle.delete with _ -> () diff --git a/src/Aardvark.Rendering.GL/Core/ContextHandles.fs b/src/Aardvark.Rendering.GL/Core/ContextHandles.fs index 82465456..dc8957e2 100644 --- a/src/Aardvark.Rendering.GL/Core/ContextHandles.fs +++ b/src/Aardvark.Rendering.GL/Core/ContextHandles.fs @@ -298,14 +298,22 @@ module ContextHandleOpenTK = /// /// Creates a new context using the default configuration. + /// The given context is used as parent for sharing. If parent is None, OpenTK chooses a context to use as parent. /// - let create (debug : IDebugConfig) = + let createWithParent (debug : IDebugConfig) (parent : ContextHandle option) = let window, context = let prev = ContextHandle.Current let mode = Graphics.GraphicsMode(ColorFormat(Config.BitsPerPixel), Config.DepthBits, Config.StencilBits, 1, ColorFormat.Empty, Config.Buffers, false) let window = new NativeWindow(16, 16, "background", GameWindowFlags.Default, mode, DisplayDevice.Default) - let context = new GraphicsContext(GraphicsMode.Default, window.WindowInfo, Config.MajorVersion, Config.MinorVersion, Config.ContextFlags); + + let context = + match parent with + | Some p -> + new GraphicsContext(GraphicsMode.Default, window.WindowInfo, p.Handle, Config.MajorVersion, Config.MinorVersion, Config.ContextFlags); + | _ -> + new GraphicsContext(GraphicsMode.Default, window.WindowInfo, Config.MajorVersion, Config.MinorVersion, Config.ContextFlags); + context.MakeCurrent(window.WindowInfo) let ctx = context |> unbox ctx.LoadAll() @@ -328,4 +336,10 @@ module ContextHandleOpenTK = handle.OnDisposed.Add dispose handle.Initialize(debug, setDefaultStates = false) - handle \ No newline at end of file + handle + + /// + /// Creates a new context using the default configuration. + /// + let create (debug : IDebugConfig) = + createWithParent debug None \ No newline at end of file diff --git a/src/Application/Aardvark.Application.Slim.GL/Application.fs b/src/Application/Aardvark.Application.Slim.GL/Application.fs index 752e14a3..c157d24e 100644 --- a/src/Application/Aardvark.Application.Slim.GL/Application.fs +++ b/src/Application/Aardvark.Application.Slim.GL/Application.fs @@ -273,15 +273,18 @@ module private OpenGL = if old <> NativePtr.zero then glfw.MakeContextCurrent old - - let signature = - runtime.CreateFramebufferSignature([ - DefaultSemantic.Colors, TextureFormat.Rgba8 - DefaultSemantic.DepthStencil, TextureFormat.Depth24Stencil8 - ], samples) let handle = new Aardvark.Rendering.GL.ContextHandle(ctx, info) - do handle.Initialize(runtime.DebugConfig, setDefaultStates = true) + + let signature = + handle.Use (fun _ -> + handle.Initialize(runtime.DebugConfig, setDefaultStates = true) + + runtime.CreateFramebufferSignature([ + DefaultSemantic.Colors, TextureFormat.Rgba8 + DefaultSemantic.DepthStencil, TextureFormat.Depth24Stencil8 + ], samples) + ) { new IWindowSurface with override x.Signature = signature @@ -336,14 +339,18 @@ module private OpenGL = type OpenGlApplication private (runtime : Runtime, shaderCachePath : Option, hideCocoaMenuBar : bool) as this = inherit Application(runtime, OpenGL.interop runtime.DebugConfig, hideCocoaMenuBar) - let createContext() = - let w = this.Instance.CreateWindow WindowConfig.Default - let h = w.Surface.Handle :?> Aardvark.Rendering.GL.ContextHandle - this.Instance.RemoveExistingWindow w - h.OnDisposed.Add w.Dispose - h - - let ctx = new Context(runtime, fun () -> this.Instance.Invoke createContext) + // Note: We ignore the passed parent since we determine the parent context in the CreateWindow method. + // This is always the first created context and should therefore match the passed one anyway. + let createContext (_parent : Aardvark.Rendering.GL.ContextHandle option) = + this.Instance.Invoke (fun _ -> + let w = this.Instance.CreateWindow WindowConfig.Default + let h = w.Surface.Handle :?> Aardvark.Rendering.GL.ContextHandle + this.Instance.RemoveExistingWindow w + h.OnDisposed.Add w.Dispose + h + ) + + let ctx = new Context(runtime, createContext) do ctx.ShaderCachePath <- shaderCachePath runtime.Initialize(ctx) diff --git a/src/Application/Aardvark.Application.Slim/GLFW.fs b/src/Application/Aardvark.Application.Slim/GLFW.fs index 9f2181fb..f1b39beb 100644 --- a/src/Application/Aardvark.Application.Slim/GLFW.fs +++ b/src/Application/Aardvark.Application.Slim/GLFW.fs @@ -588,9 +588,11 @@ type Instance(runtime : Aardvark.Rendering.IRuntime, interop : IWindowInterop, h // For GL we need to specify a parent window to enable context sharing // Simply use the one that was created first, assuming it is still valid and unused. - // Obviously this is not a safe assumption, but should at least be more reliable than - // using the last created one. + // If GL.RuntimeConfig.RobustContextSharing is false, this will be a resource context which + // may not always be available. If the flag is true, this will be a hidden context that + // is guaranteed to be available. let mutable parentWindow : nativeptr option = None + let queue = System.Collections.Concurrent.ConcurrentQueue unit>() let existingWindows = System.Collections.Concurrent.ConcurrentHashSet() diff --git a/src/Application/Aardvark.Application.WPF.GL/Application.fs b/src/Application/Aardvark.Application.WPF.GL/Application.fs index 578bea46..bc05865e 100644 --- a/src/Application/Aardvark.Application.WPF.GL/Application.fs +++ b/src/Application/Aardvark.Application.WPF.GL/Application.fs @@ -12,7 +12,7 @@ type OpenGlApplication(forceNvidia : bool, debug : IDebugConfig, shaderCachePath OpenTK.Toolkit.Init(new OpenTK.ToolkitOptions(Backend=OpenTK.PlatformBackend.PreferNative)) |> ignore let runtime = new Runtime(debug) - let ctx = new Context(runtime, fun () -> ContextHandleOpenTK.create debug) + let ctx = new Context(runtime, ContextHandleOpenTK.createWithParent debug) do ctx.ShaderCachePath <- shaderCachePath runtime.Initialize(ctx) diff --git a/src/Application/Aardvark.Application.WinForms.GL/Application.fs b/src/Application/Aardvark.Application.WinForms.GL/Application.fs index eddee907..1e0219ce 100644 --- a/src/Application/Aardvark.Application.WinForms.GL/Application.fs +++ b/src/Application/Aardvark.Application.WinForms.GL/Application.fs @@ -15,7 +15,7 @@ type OpenGlApplication(forceNvidia : bool, debug : IDebugConfig, shaderCachePath with e -> Report.Warn("Could not set UnhandledExceptionMode.") let runtime = new Runtime(debug) - let ctx = new Context(runtime, fun () -> ContextHandleOpenTK.create debug) + let ctx = new Context(runtime, ContextHandleOpenTK.createWithParent debug) do ctx.ShaderCachePath <- shaderCachePath runtime.Initialize(ctx) diff --git a/src/Tests/Aardvark.Rendering.Tests/Tests/Application.fs b/src/Tests/Aardvark.Rendering.Tests/Tests/Application.fs index d767735c..7c98928f 100644 --- a/src/Tests/Aardvark.Rendering.Tests/Tests/Application.fs +++ b/src/Tests/Aardvark.Rendering.Tests/Tests/Application.fs @@ -42,7 +42,7 @@ module TestApplication = let toolkit = Toolkit.Init(ToolkitOptions(Backend = PlatformBackend.PreferNative)) let runtime = new Runtime(debug) - let ctx = new Context(runtime, fun () -> ContextHandleOpenTK.create runtime.DebugConfig) + let ctx = new Context(runtime, ContextHandleOpenTK.createWithParent runtime.DebugConfig) runtime.Initialize(ctx) @@ -63,6 +63,7 @@ module TestApplication = Config.MajorVersion <- 4 Config.MinorVersion <- 6 RuntimeConfig.UseNewRenderTask <- true + RuntimeConfig.RobustContextSharing <- true RuntimeConfig.PreferHostSideTextureCompression <- true let app =