diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/CodeGen')
4 files changed, 46 insertions, 7 deletions
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs index 751d0350..fe0d275b 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Glsl/GlslGenerator.cs @@ -28,18 +28,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl for (int i = 1; i < info.Functions.Count; i++) { - PrintFunction(context, info, info.Functions[i]); + PrintFunction(context, info.Functions[i]); context.AppendLine(); } } - PrintFunction(context, info, info.Functions[0], MainFunctionName); + PrintFunction(context, info.Functions[0], MainFunctionName); return context.GetCode(); } - private static void PrintFunction(CodeGenContext context, StructuredProgramInfo info, StructuredFunction function, string funcName = null) + private static void PrintFunction(CodeGenContext context, StructuredFunction function, string funcName = null) { context.CurrentFunction = function; @@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl Declarations.DeclareLocals(context, function); - PrintBlock(context, function.MainBlock); + PrintBlock(context, function.MainBlock, funcName == MainFunctionName); context.LeaveScope(); } @@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl return $"{Declarations.GetVarTypeName(context, function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})"; } - private static void PrintBlock(CodeGenContext context, AstBlock block) + private static void PrintBlock(CodeGenContext context, AstBlock block, bool isMainFunction) { AstBlockVisitor visitor = new AstBlockVisitor(block); @@ -112,10 +112,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl } }; + bool supportsBarrierDivergence = context.Config.GpuAccessor.QueryHostSupportsShaderBarrierDivergence(); + bool mayHaveReturned = false; + foreach (IAstNode node in visitor.Visit()) { if (node is AstOperation operation) { + if (!supportsBarrierDivergence) + { + if (operation.Inst == IntermediateRepresentation.Instruction.Barrier) + { + // Barrier on divergent control flow paths may cause the GPU to hang, + // so skip emitting the barrier for those cases. + if (visitor.Block.Type != AstBlockType.Main || mayHaveReturned || !isMainFunction) + { + context.Config.GpuAccessor.Log($"Shader has barrier on potentially divergent block, the barrier will be removed."); + + continue; + } + } + else if (operation.Inst == IntermediateRepresentation.Instruction.Return) + { + mayHaveReturned = true; + } + } + string expr = InstGen.GetExpression(context, operation); if (expr != null) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs index c1bfa088..1f5167e6 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs @@ -76,6 +76,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv public SpirvDelegates Delegates { get; } + public bool IsMainFunction { get; private set; } + public bool MayHaveReturned { get; set; } + public CodeGenContext( StructuredProgramInfo info, ShaderConfig config, @@ -108,8 +111,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv Delegates = new SpirvDelegates(this); } - public void StartFunction() + public void StartFunction(bool isMainFunction) { + IsMainFunction = isMainFunction; + MayHaveReturned = false; _locals.Clear(); _localForArgs.Clear(); _funcArgs.Clear(); diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs index 4be0c62b..6c115752 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs @@ -242,6 +242,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv private static OperationResult GenerateBarrier(CodeGenContext context, AstOperation operation) { + // Barrier on divergent control flow paths may cause the GPU to hang, + // so skip emitting the barrier for those cases. + if (!context.Config.GpuAccessor.QueryHostSupportsShaderBarrierDivergence() && + (context.CurrentBlock.Type != AstBlockType.Main || context.MayHaveReturned || !context.IsMainFunction)) + { + context.Config.GpuAccessor.Log($"Shader has barrier on potentially divergent block, the barrier will be removed."); + + return OperationResult.Invalid; + } + context.ControlBarrier( context.Constant(context.TypeU32(), Scope.Workgroup), context.Constant(context.TypeU32(), Scope.Workgroup), @@ -1092,6 +1102,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv private static OperationResult GenerateReturn(CodeGenContext context, AstOperation operation) { + context.MayHaveReturned = true; + if (operation.SourcesCount != 0) { context.ReturnValue(context.Get(context.CurrentFunction.ReturnType, operation.GetSource(0))); diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs index a55e09fd..5c736b60 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs @@ -148,7 +148,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv context.CurrentFunction = function; context.AddFunction(spvFunc); - context.StartFunction(); + context.StartFunction(isMainFunction: funcIndex == 0); Declarations.DeclareParameters(context, function); |