From ddf4b92a9cfbe98f798dd86a7c123b065a832d51 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Mon, 29 Mar 2021 21:52:25 +0100 Subject: Implement parallel host shader cache compilation. --- Ryujinx.Graphics.OpenGL/HwCapabilities.cs | 2 + Ryujinx.Graphics.OpenGL/Program.cs | 80 +++++++++++++++++++++---------- Ryujinx.Graphics.OpenGL/Renderer.cs | 16 +++---- 3 files changed, 64 insertions(+), 34 deletions(-) (limited to 'Ryujinx.Graphics.OpenGL') diff --git a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs index 6795b423..08b0e6af 100644 --- a/Ryujinx.Graphics.OpenGL/HwCapabilities.cs +++ b/Ryujinx.Graphics.OpenGL/HwCapabilities.cs @@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.OpenGL private static readonly Lazy _supportsPolygonOffsetClamp = new Lazy(() => HasExtension("GL_EXT_polygon_offset_clamp")); private static readonly Lazy _supportsViewportSwizzle = new Lazy(() => HasExtension("GL_NV_viewport_swizzle")); private static readonly Lazy _supportsSeamlessCubemapPerTexture = new Lazy(() => HasExtension("GL_ARB_seamless_cubemap_per_texture")); + private static readonly Lazy _supportsParallelShaderCompile = new Lazy(() => HasExtension("GL_ARB_parallel_shader_compile")); private static readonly Lazy _maximumComputeSharedMemorySize = new Lazy(() => GetLimit(All.MaxComputeSharedMemorySize)); private static readonly Lazy _storageBufferOffsetAlignment = new Lazy(() => GetLimit(All.ShaderStorageBufferOffsetAlignment)); @@ -34,6 +35,7 @@ namespace Ryujinx.Graphics.OpenGL public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value; public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value; public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value; + public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value; public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia; public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.Amd || _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix; diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs index d39e181d..decc75b1 100644 --- a/Ryujinx.Graphics.OpenGL/Program.cs +++ b/Ryujinx.Graphics.OpenGL/Program.cs @@ -13,11 +13,26 @@ namespace Ryujinx.Graphics.OpenGL { public int Handle { get; private set; } - public int FragmentIsBgraUniform { get; } - public int FragmentRenderScaleUniform { get; } - public int ComputeRenderScaleUniform { get; } + public int FragmentIsBgraUniform { get; private set; } + public int FragmentRenderScaleUniform { get; private set; } + public int ComputeRenderScaleUniform { get; private set; } - public bool IsLinked { get; private set; } + public bool IsLinked + { + get + { + if (_status == ProgramLinkStatus.Incomplete) + { + CheckProgramLink(true); + } + + return _status == ProgramLinkStatus.Success; + } + } + + private bool _initialized; + private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; + private IShader[] _shaders; public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors) { @@ -82,18 +97,7 @@ namespace Ryujinx.Graphics.OpenGL GL.LinkProgram(Handle); - for (int index = 0; index < shaders.Length; index++) - { - int shaderHandle = ((Shader)shaders[index]).Handle; - - GL.DetachShader(Handle, shaderHandle); - } - - CheckProgramLink(); - - FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra"); - FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale"); - ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale"); + _shaders = shaders; } public Program(ReadOnlySpan code) @@ -109,32 +113,60 @@ namespace Ryujinx.Graphics.OpenGL GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4); } } - - CheckProgramLink(); - - FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra"); - FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale"); - ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale"); } public void Bind() { + if (!_initialized) + { + FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra"); + FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale"); + ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale"); + + _initialized = true; + } + GL.UseProgram(Handle); } - private void CheckProgramLink() + public ProgramLinkStatus CheckProgramLink(bool blocking) { + if (!blocking && HwCapabilities.SupportsParallelShaderCompile) + { + GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed); + + if (completed == 0) + { + return ProgramLinkStatus.Incomplete; + } + } + GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status); + if (_shaders != null) + { + for (int index = 0; index < _shaders.Length; index++) + { + int shaderHandle = ((Shader)_shaders[index]).Handle; + + GL.DetachShader(Handle, shaderHandle); + } + + _shaders = null; + } + if (status == 0) { // Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log. + _status = ProgramLinkStatus.Failure; Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed."); } else { - IsLinked = true; + _status = ProgramLinkStatus.Success; } + + return _status; } public byte[] GetBinary() diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index cc8fa195..0382ba86 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -130,6 +130,11 @@ namespace Ryujinx.Graphics.OpenGL PrintGpuInformation(); + if (HwCapabilities.SupportsParallelShaderCompile) + { + GL.Arb.MaxShaderCompilerThreads(Math.Min(Environment.ProcessorCount, 8)); + } + _counters.Initialize(); } @@ -177,16 +182,7 @@ namespace Ryujinx.Graphics.OpenGL public IProgram LoadProgramBinary(byte[] programBinary) { - Program program = new Program(programBinary); - - if (program.IsLinked) - { - return program; - } - - program.Dispose(); - - return null; + return new Program(programBinary); } public void CreateSync(ulong id) -- cgit v1.2.3