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 =