Skip to content

Commit

Permalink
[GL] Make context sharing more robust
Browse files Browse the repository at this point in the history
Contexts sharing may fail if the parent context is in use
when a new context is created. This commit adds a config
flag which results in an additional hidden context to be
created. This context is used as a parent for all other contexts.
That way context sharing will succeed even when all "real"
contexts are busy.
  • Loading branch information
hyazinthh committed Jan 18, 2024
1 parent 7a6d181 commit b150420
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 26 deletions.
10 changes: 10 additions & 0 deletions src/Aardvark.Rendering.GL/Core/Config.fs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ module RuntimeConfig =
/// </summary>
let mutable NumberOfResourceContexts = 2

/// <summary>
/// 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.
/// </summary>
let mutable RobustContextSharing = true

/// <summary>
/// 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.
Expand Down
18 changes: 15 additions & 3 deletions src/Aardvark.Rendering.GL/Core/Context.fs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ type MemoryUsage() =
/// multiple threads to submit GL calls concurrently.
/// </summary>
[<AllowNullLiteral>]
type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this =
type Context(runtime : IRuntime, createContext : ContextHandle option -> ContextHandle) as this =

static let defaultShaderCachePath =
Path.combine [
Expand All @@ -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()

Expand Down Expand Up @@ -243,12 +249,16 @@ type Context(runtime : IRuntime, createContext : unit -> ContextHandle) as this
value
| Some v -> v

[<Obsolete("Use overload with createContext that accepts an optional parent context.")>]
new (runtime : IRuntime, createContext : unit -> ContextHandle) =
new Context(runtime, fun (_ : ContextHandle option) -> createContext())

/// <summary>
/// Creates custom OpenGl context. Usage:
/// let customCtx = app.Context.CreateContext()
/// use __ = app.Context.RenderingLock(customCtx)
/// </summary>
member x.CreateContext() = createContext()
member x.CreateContext() = createContext parentContext

member internal x.ShaderCache = shaderCache

Expand Down Expand Up @@ -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 _ ->
()

Expand Down
20 changes: 17 additions & 3 deletions src/Aardvark.Rendering.GL/Core/ContextHandles.fs
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,22 @@ module ContextHandleOpenTK =

/// <summary>
/// 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.
/// </summary>
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<IGraphicsContextInternal>
ctx.LoadAll()
Expand All @@ -328,4 +336,10 @@ module ContextHandleOpenTK =
handle.OnDisposed.Add dispose
handle.Initialize(debug, setDefaultStates = false)

handle
handle

/// <summary>
/// Creates a new context using the default configuration.
/// </summary>
let create (debug : IDebugConfig) =
createWithParent debug None
37 changes: 22 additions & 15 deletions src/Application/Aardvark.Application.Slim.GL/Application.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -336,14 +339,18 @@ module private OpenGL =
type OpenGlApplication private (runtime : Runtime, shaderCachePath : Option<string>, 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)
Expand Down
6 changes: 4 additions & 2 deletions src/Application/Aardvark.Application.Slim/GLFW.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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<WindowHandle> option = None

let queue = System.Collections.Concurrent.ConcurrentQueue<unit -> unit>()

let existingWindows = System.Collections.Concurrent.ConcurrentHashSet<Window>()
Expand Down
2 changes: 1 addition & 1 deletion src/Application/Aardvark.Application.WPF.GL/Application.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/Tests/Aardvark.Rendering.Tests/Tests/Application.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -63,6 +63,7 @@ module TestApplication =
Config.MajorVersion <- 4
Config.MinorVersion <- 6
RuntimeConfig.UseNewRenderTask <- true
RuntimeConfig.RobustContextSharing <- true
RuntimeConfig.PreferHostSideTextureCompression <- true

let app =
Expand Down

0 comments on commit b150420

Please sign in to comment.