From d24f6c6a8583247e40a9484490ddfa13ecf95f21 Mon Sep 17 00:00:00 2001 From: ParantezTech <12572227+par274@users.noreply.github.com> Date: Sun, 11 Oct 2026 01:35:14 +0300 Subject: [PATCH] [GPU] Compile wave64 compute for 32-lane subgroups when the host lacks wave64 --- src/SharpEmu.Libs/Gpu/Pipelines/IShaderPipelineHost.cs | 2 ++ src/SharpEmu.Libs/Gpu/Pipelines/ShaderProgramCache.cs | 10 ++++++---- .../VideoOut/VulkanVideoPresenter.Pipelines.cs | 4 ++++ .../VideoOut/VulkanVideoPresenter.ShaderPrewarm.cs | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/SharpEmu.Libs/Gpu/Pipelines/IShaderPipelineHost.cs b/src/SharpEmu.Libs/Gpu/Pipelines/IShaderPipelineHost.cs index 0177ba2..be02c23 100644 --- a/src/SharpEmu.Libs/Gpu/Pipelines/IShaderPipelineHost.cs +++ b/src/SharpEmu.Libs/Gpu/Pipelines/IShaderPipelineHost.cs @@ -39,6 +39,8 @@ internal interface IShaderPipelineHost // True when a 64-invocation wave64 compute workgroup runs as one 64-lane host subgroup. bool ComputeWave64SubgroupNative => false; + bool ComputeRunsOn32LaneSubgroups(ComputeInputInfo input) => false; + bool GraphicsSubgroupOperationsEnabled { get; } // The device supports shaderSharedInt64Atomics, so LDS 64-bit atomics can be diff --git a/src/SharpEmu.Libs/Gpu/Pipelines/ShaderProgramCache.cs b/src/SharpEmu.Libs/Gpu/Pipelines/ShaderProgramCache.cs index 9e7943d..93c037d 100644 --- a/src/SharpEmu.Libs/Gpu/Pipelines/ShaderProgramCache.cs +++ b/src/SharpEmu.Libs/Gpu/Pipelines/ShaderProgramCache.cs @@ -685,7 +685,8 @@ internal sealed class ShaderProgramCache default: return BuildComputeRequest(entry.Plan, resources, layout, options.ComputeInfo!, options.ComputeSystemRegisters, - sharedInt64Atomics, _host.ExecGuardElisionEnabled, signedZeroInfNanPreserve, _host.ComputeWave64SubgroupNative); + sharedInt64Atomics, _host.ExecGuardElisionEnabled, signedZeroInfNanPreserve, _host.ComputeWave64SubgroupNative, + _host.ComputeRunsOn32LaneSubgroups(options.ComputeInfo!)); } } @@ -702,11 +703,12 @@ internal sealed class ShaderProgramCache private static ShaderCompileRequest BuildComputeRequest(ShaderResourcePlan plan, SpecializedResourceInfo resources, BindingLayout layout, ComputeInputInfo info, Gen5ComputeSystemRegisters? systemRegisters, bool sharedInt64Atomics, bool execGuardElision, - bool signedZeroInfNanPreserve, bool hostWave64Supported = false) => + bool signedZeroInfNanPreserve, bool hostWave64Supported = false, bool hostComputeSubgroup32 = false) => new(plan, resources, layout) { WaveSize = info.WaveSize, HostWave64Supported = info.WaveSize == 64 && hostWave64Supported, + HostComputeSubgroup32 = info.WaveSize == 64 && !hostWave64Supported && hostComputeSubgroup32, EnableExecGuardElision = info.WaveSize != 64 || execGuardElision, TraceDeviceAddressFaults = SharpEmu.HLE.GpuMemory.GuestGpuMemoryHook.TraceEnabled, ScratchDwords = info.ScratchDwords, @@ -721,7 +723,7 @@ internal sealed class ShaderProgramCache internal static bool TryCompilePrewarm(ComputePrewarmRecord record, ShaderCodeCapture code, IGuestGpuBackend compiler, bool sharedInt64Atomics, bool execGuardElision, bool signedZeroInfNanPreserve, out IGuestCompiledShader? compiled, - out BindingLayout? layout, out string error, bool hostWave64Supported = false) + out BindingLayout? layout, out string error, bool hostWave64Supported = false, bool hostComputeSubgroup32 = false) { compiled = null; layout = null; @@ -738,7 +740,7 @@ internal sealed class ShaderProgramCache layout = AllocateLayout(program, plan, resources, record.UserDataBase, record.UserDataCount, record.PushDataCursor, record.Info.DispatchThreadDimensions); var request = BuildComputeRequest(plan, resources, layout, record.Info, record.SystemRegisters, - sharedInt64Atomics, execGuardElision, signedZeroInfNanPreserve, hostWave64Supported); + sharedInt64Atomics, execGuardElision, signedZeroInfNanPreserve, hostWave64Supported, hostComputeSubgroup32); return compiler.TryCompileProgram(request, out compiled, out error) && compiled is not null; } catch (Exception exception) diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Pipelines.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Pipelines.cs index caa9137..d9cecb5 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Pipelines.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.Pipelines.cs @@ -72,6 +72,10 @@ internal static unsafe partial class VulkanVideoPresenter bool IShaderPipelineHost.ComputeWave64Supported => Volatile.Read(ref _nativeSubgroupSize) >= 64; + bool IShaderPipelineHost.ComputeRunsOn32LaneSubgroups(ComputeInputInfo input) => + RequiresComputeSubgroup32(input) || + (Volatile.Read(ref _nativeSubgroupSize) == RdnaSubgroupSize && !RequiresComputeSubgroup64(input)); + // Wave32 compute maps a guest wave to 32-lane host subgroups, and a 64-lane host subgroup // (AMD's default) left lanes 32..63 inactive, so those pipelines are pinned to 32. Wave64 // compute is pinned to 64 instead when the host runs it natively. diff --git a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.ShaderPrewarm.cs b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.ShaderPrewarm.cs index 7b0cba7..06665c1 100644 --- a/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.ShaderPrewarm.cs +++ b/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.ShaderPrewarm.cs @@ -164,7 +164,8 @@ internal static unsafe partial class VulkanVideoPresenter if (!ShaderProgramCache.TryCompilePrewarm( record, code, compiler, sharedInt64Atomics, execGuardElision, _supportsShaderSignedZeroInfNanPreserveFloat32, out var compiled, out var layout, out var error, - ((IShaderPipelineHost)this).ComputeWave64SubgroupNative)) + ((IShaderPipelineHost)this).ComputeWave64SubgroupNative, + ((IShaderPipelineHost)this).ComputeRunsOn32LaneSubgroups(record.Info))) { NoteShaderPrewarmFailure(record, error); return;