From 812091bc2dd4ffa10cd87f2e90602763c45e2ff3 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 30 Apr 2024 10:37:32 +0200 Subject: [PATCH] [GL] Improve querying of supported sample counts - Estimation of supported sample counts is more accurate for textures if format queries are not supported. Takes into account parameters such as GL_MAX_SAMPLES now. - For framebuffer signatures the formats of the attachments are considered rather than just checking parameters such as GL_MAX_FRAMEBUFFER_SAMPLES. --- src/Aardvark.Rendering.GL/Core/Context.fs | 92 +++++++++++++++---- .../Resources/FramebufferSignature.fs | 56 ++++++----- .../Resources/Textures/Texture.fs | 5 +- 3 files changed, 113 insertions(+), 40 deletions(-) diff --git a/src/Aardvark.Rendering.GL/Core/Context.fs b/src/Aardvark.Rendering.GL/Core/Context.fs index 3aeaf8c8c..e7ac35344 100644 --- a/src/Aardvark.Rendering.GL/Core/Context.fs +++ b/src/Aardvark.Rendering.GL/Core/Context.fs @@ -232,6 +232,16 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context let mutable numProgramBinaryFormats : Option = None + let mutable maxSamples : Option = None + + let mutable maxColorTextureSamples : Option = None + + let mutable maxIntegerSamples : Option = None + + let mutable maxDepthTextureSamples : Option = None + + let mutable maxFramebufferSamples : Option = None + let mutable shaderCachePath : Option = Some defaultShaderCachePath let formatSampleCounts = FastConcurrentDict() @@ -240,11 +250,12 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context let sharedMemoryManager = SharedMemoryManager(fun _ -> this.ResourceLock) - let getOrQuery (var : byref<'T option>) (query : unit -> 'T) = + let getOrQuery (description : string) (var : byref<'T option>) (query : unit -> 'T) = match var with | None -> use __ = this.ResourceLock let value = query() + GL.Check $"Failed to query {description}" var <- Some value value | Some v -> v @@ -278,48 +289,48 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context member x.Runtime = runtime member x.Driver = - getOrQuery &driverInfo Driver.readInfo + getOrQuery "driver info" &driverInfo Driver.readInfo member x.PackAlignment = - getOrQuery &packAlignment (fun _ -> + getOrQuery "pack alignment" &packAlignment (fun _ -> GL.GetInteger(GetPName.PackAlignment) ) member x.UnpackAlignment = - getOrQuery &unpackAlignment (fun _ -> + getOrQuery "unpack alignment" &unpackAlignment (fun _ -> GL.GetInteger(GetPName.UnpackAlignment) ) member x.MaxTextureSize = - getOrQuery &maxTextureSize (fun _ -> + getOrQuery "max texture size" &maxTextureSize (fun _ -> let s = GL.GetInteger(GetPName.MaxTextureSize) V2i s ) member x.MaxTextureSize3D = - getOrQuery &maxTextureSize3d (fun _ -> + getOrQuery "max 3D texture size" &maxTextureSize3d (fun _ -> let s = GL.GetInteger(GetPName.Max3DTextureSize) V3i s ) member x.MaxTextureSizeCube = - getOrQuery &maxTextureSizeCube (fun _ -> + getOrQuery "max cube texture size" &maxTextureSizeCube (fun _ -> GL.GetInteger(GetPName.MaxCubeMapTextureSize) ) member x.MaxTextureArrayLayers = - getOrQuery &maxTextureArrayLayers (fun _ -> + getOrQuery "max texture array layers" &maxTextureArrayLayers (fun _ -> GL.GetInteger(GetPName.MaxArrayTextureLayers) ) member x.MaxRenderbufferSize = - getOrQuery &maxRenderbufferSize (fun _ -> + getOrQuery "max renderbuffer size" &maxRenderbufferSize (fun _ -> let s = GL.GetInteger(GetPName.MaxRenderbufferSize) V2i s ) member x.MaxComputeWorkGroupSize = - getOrQuery &maxComputeWorkGroupSize (fun _ -> + getOrQuery "max compute work group size" &maxComputeWorkGroupSize (fun _ -> let mutable res = V3i.Zero GL.GetInteger(GetIndexedPName.MaxComputeWorkGroupSize, 0, &res.X) GL.GetInteger(GetIndexedPName.MaxComputeWorkGroupSize, 1, &res.Y) @@ -328,15 +339,40 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context ) member x.MaxComputeWorkGroupInvocations = - getOrQuery &maxComputeWorkGroupInvocations (fun _ -> + getOrQuery "max compute work group invocations" &maxComputeWorkGroupInvocations (fun _ -> GL.GetInteger(GetPName.MaxComputeWorkGroupInvocations) ) member x.NumProgramBinaryFormats = - getOrQuery &numProgramBinaryFormats (fun _ -> + getOrQuery "number of program binary formats" &numProgramBinaryFormats (fun _ -> GL.GetInteger(GetPName.NumProgramBinaryFormats) ) + member x.MaxSamples = + getOrQuery "max samples" &maxSamples (fun _ -> + GL.GetInteger(GetPName.MaxSamples) + ) + + member x.MaxColorTextureSamples = + getOrQuery "max color texture samples" &maxColorTextureSamples (fun _ -> + GL.GetInteger(GetPName.MaxColorTextureSamples) + ) + + member x.MaxIntegerSamples = + getOrQuery "max integer samples" &maxIntegerSamples (fun _ -> + GL.GetInteger(GetPName.MaxIntegerSamples) + ) + + member x.MaxDepthTextureSamples = + getOrQuery "max depth texture samples" &maxDepthTextureSamples (fun _ -> + GL.GetInteger(GetPName.MaxDepthTextureSamples) + ) + + member x.MaxFramebufferSamples = + getOrQuery "max framebuffer samples" &maxFramebufferSamples (fun _ -> + GL.GetInteger(unbox 0x9318) + ) + member internal x.ImportMemoryBlock(external : ExternalMemoryBlock) = sharedMemoryManager.Import external @@ -423,6 +459,29 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context /// member internal x.GetFormatSamples(target : ImageTarget, format : TextureFormat) = formatSampleCounts.GetOrCreate((target, format), fun _ -> + let estimate() = + let maxSamples = + [ + x.MaxSamples + + if format.IsColorRenderable then + x.MaxColorTextureSamples + + if format.IsIntegerFormat then + x.MaxIntegerSamples + + if format.HasDepth || format.HasStencil then + x.MaxDepthTextureSamples + ] + |> List.min + |> max 1 + + Report.Line(3, $"[GL] Internal format queries not supported, assuming up to {maxSamples} are supported (target = {target}, format = {format})") + + [1; 2; 4; 8; 16; 32; 64] + |> List.filter ((>=) maxSamples) + |> Set.ofList + if GL.ARB_internalformat_query then let format = TextureFormat.toSizedInternalFormat format @@ -433,12 +492,13 @@ type Context(runtime : IRuntime, createContext : ContextHandle option -> Context let buffer = GL.Dispatch.GetInternalformat(target, format, InternalFormatParameter.Samples, count) GL.Check "could not query sample counts" - Set.ofArray buffer + buffer + |> Set.ofArray + |> Set.add 1 else - Set.empty + estimate() else - Log.warn "[GL] Internal format queries not supported, assuming all sample counts are supported (target = %A, format = %A)" target format - Set.ofList [1; 2; 4; 8; 16; 32; 64] + estimate() ) /// diff --git a/src/Aardvark.Rendering.GL/Resources/FramebufferSignature.fs b/src/Aardvark.Rendering.GL/Resources/FramebufferSignature.fs index f6f97b332..5e37ba92f 100644 --- a/src/Aardvark.Rendering.GL/Resources/FramebufferSignature.fs +++ b/src/Aardvark.Rendering.GL/Resources/FramebufferSignature.fs @@ -46,28 +46,42 @@ module internal FramebufferSignatureContextExtensions = perLayerUniforms : Set) = use __ = x.ResourceLock - let maxSamples = - let counts = [ - if not colorAttachments.IsEmpty then - GL.GetInteger(GetPName.MaxColorTextureSamples) - - if colorAttachments |> Map.exists (fun _ att -> att.Format.IsIntegerFormat) then - GL.GetInteger(GetPName.MaxIntegerSamples) - - if depthStencilAttachment.IsSome then - GL.GetInteger(GetPName.MaxDepthTextureSamples) - ] - - if counts.IsEmpty then GL.GetInteger(GetPName.MaxFramebufferSamples) - else List.min counts - - GL.Check "could not query maximum samples for framebuffer signature" - let samples = - if samples > maxSamples then - Log.warn "[GL] cannot create framebuffer signature with %d samples (using %d instead)" samples maxSamples - maxSamples + if samples = 1 then samples else - samples + let framebufferMaxSamples = max 1 x.MaxFramebufferSamples + + let get fmt = + let rb = x.GetFormatSamples(ImageTarget.Renderbuffer, fmt) + let tex = x.GetFormatSamples(ImageTarget.Texture2DMultisample, fmt) + Set.union rb tex + + let counts = + let all = + Set.ofList [1; 2; 4; 8; 16; 32; 64] + + let color = + colorAttachments + |> Seq.map (_.Value.Format >> get) + |> List.ofSeq + + let depthStencil = + depthStencilAttachment + |> Option.map get + |> Option.toList + + all :: (color @ depthStencil) + |> Set.intersectMany + |> Set.filter ((>=) framebufferMaxSamples) + + if counts.Contains samples then samples + else + let fallback = + counts + |> Set.toList + |> List.minBy ((-) samples >> abs) + + Log.warn "[GL] Cannot create framebuffer signature with %d samples (using %d instead)" samples fallback + fallback new FramebufferSignature(x.Runtime, colorAttachments, depthStencilAttachment, samples, layers, perLayerUniforms) \ No newline at end of file diff --git a/src/Aardvark.Rendering.GL/Resources/Textures/Texture.fs b/src/Aardvark.Rendering.GL/Resources/Textures/Texture.fs index 6a1f6e2e1..3ea275db3 100644 --- a/src/Aardvark.Rendering.GL/Resources/Textures/Texture.fs +++ b/src/Aardvark.Rendering.GL/Resources/Textures/Texture.fs @@ -195,10 +195,9 @@ module internal TextureUtilitiesAndExtensions = let fallback = counts |> Set.toList - |> List.sortBy ((-) samples >> abs) - |> List.head + |> List.minBy ((-) samples >> abs) - Log.warn "[GL] cannot create %A image with %d samples (using %d instead)" format samples fallback + Log.warn "[GL] Cannot create %A image with %d samples (using %d instead)" format samples fallback fallback else 1