diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Optimizations')
5 files changed, 102 insertions, 52 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs index bf087aff..43d98d3c 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs @@ -1,12 +1,13 @@ using Ryujinx.Graphics.Shader.Instructions; using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; using System.Collections.Generic; namespace Ryujinx.Graphics.Shader.Translation.Optimizations { class BindlessElimination { - public static void RunPass(BasicBlock block, ShaderConfig config) + public static void RunPass(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor) { // We can turn a bindless into regular access by recognizing the pattern // produced by the compiler for separate texture and sampler. @@ -43,7 +44,15 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (bindlessHandle.Type == OperandType.ConstantBuffer) { - SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType, isImage: false); + SetHandle( + resourceManager, + gpuAccessor, + texOp, + bindlessHandle.GetCbufOffset(), + bindlessHandle.GetCbufSlot(), + rewriteSamplerType, + isImage: false); + continue; } @@ -140,7 +149,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (handleType == TextureHandleType.SeparateConstantSamplerHandle) { SetHandle( - config, + resourceManager, + gpuAccessor, texOp, TextureHandle.PackOffsets(src0.GetCbufOffset(), ((src1.Value >> 20) & 0xfff), handleType), TextureHandle.PackSlots(src0.GetCbufSlot(), 0), @@ -150,7 +160,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations else if (src1.Type == OperandType.ConstantBuffer) { SetHandle( - config, + resourceManager, + gpuAccessor, texOp, TextureHandle.PackOffsets(src0.GetCbufOffset(), src1.GetCbufOffset(), handleType), TextureHandle.PackSlots(src0.GetCbufSlot(), src1.GetCbufSlot()), @@ -173,17 +184,17 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { if (texOp.Inst == Instruction.ImageAtomic) { - texOp.Format = config.GetTextureFormatAtomic(cbufOffset, cbufSlot); + texOp.Format = ShaderProperties.GetTextureFormatAtomic(gpuAccessor, cbufOffset, cbufSlot); } else { - texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot); + texOp.Format = ShaderProperties.GetTextureFormat(gpuAccessor, cbufOffset, cbufSlot); } } bool rewriteSamplerType = texOp.Type == SamplerType.TextureBuffer; - SetHandle(config, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); + SetHandle(resourceManager, gpuAccessor, texOp, cbufOffset, cbufSlot, rewriteSamplerType, isImage: true); } } } @@ -220,11 +231,18 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations return null; } - private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType, bool isImage) + private static void SetHandle( + ResourceManager resourceManager, + IGpuAccessor gpuAccessor, + TextureOperation texOp, + int cbufOffset, + int cbufSlot, + bool rewriteSamplerType, + bool isImage) { if (rewriteSamplerType) { - SamplerType newType = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot); + SamplerType newType = gpuAccessor.QuerySamplerType(cbufOffset, cbufSlot); if (texOp.Inst.IsTextureQuery()) { @@ -253,7 +271,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - int binding = config.ResourceManager.GetTextureOrImageBinding( + int binding = resourceManager.GetTextureOrImageBinding( texOp.Inst, texOp.Type, texOp.Format, diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs index 4b1bf76e..2bd31fe1 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs @@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { private const int NvnTextureBufferIndex = 2; - public static void RunPass(BasicBlock block, ShaderConfig config) + public static void RunPass(BasicBlock block, ResourceManager resourceManager) { // We can turn a bindless texture access into a indexed access, // as long the following conditions are true: @@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations Operand ldcSrc0 = handleAsgOp.GetSource(0); if (ldcSrc0.Type != OperandType.Constant || - !config.ResourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) || + !resourceManager.TryGetConstantBufferSlot(ldcSrc0.Value, out int src0CbufSlot) || src0CbufSlot != NvnTextureBufferIndex) { continue; @@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations continue; } - TurnIntoIndexed(config, texOp, addSrc1.Value / 4); + TurnIntoIndexed(resourceManager, texOp, addSrc1.Value / 4); Operand index = Local(); @@ -102,9 +102,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - private static void TurnIntoIndexed(ShaderConfig config, TextureOperation texOp, int handle) + private static void TurnIntoIndexed(ResourceManager resourceManager, TextureOperation texOp, int handle) { - int binding = config.ResourceManager.GetTextureOrImageBinding( + int binding = resourceManager.GetTextureOrImageBinding( texOp.Inst, texOp.Type | SamplerType.Indexed, texOp.Format, diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs index 0cca0ac6..3941303b 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs @@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { static class ConstantFolding { - public static void RunPass(ShaderConfig config, Operation operation) + public static void RunPass(ResourceManager resourceManager, Operation operation) { if (!AreAllSourcesConstant(operation)) { @@ -158,7 +158,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations int binding = operation.GetSource(0).Value; int fieldIndex = operation.GetSource(1).Value; - if (config.ResourceManager.TryGetConstantBufferSlot(binding, out int cbufSlot) && fieldIndex == 0) + if (resourceManager.TryGetConstantBufferSlot(binding, out int cbufSlot) && fieldIndex == 0) { int vecIndex = operation.GetSource(2).Value; int elemIndex = operation.GetSource(3).Value; diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs index 2433aeb2..0f043f77 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs @@ -205,7 +205,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } } - public static void RunPass(HelperFunctionManager hfm, BasicBlock[] blocks, ShaderConfig config) + public static void RunPass( + HelperFunctionManager hfm, + BasicBlock[] blocks, + ResourceManager resourceManager, + IGpuAccessor gpuAccessor, + TargetLanguage targetLanguage) { GtsContext gtsContext = new(hfm); @@ -220,14 +225,20 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (IsGlobalMemory(operation.StorageKind)) { - LinkedListNode<INode> nextNode = ReplaceGlobalMemoryWithStorage(gtsContext, config, block, node); + LinkedListNode<INode> nextNode = ReplaceGlobalMemoryWithStorage( + gtsContext, + resourceManager, + gpuAccessor, + targetLanguage, + block, + node); if (nextNode == null) { // The returned value being null means that the global memory replacement failed, // so we just make loads read 0 and stores do nothing. - config.GpuAccessor.Log($"Failed to reserve storage buffer for global memory operation \"{operation.Inst}\"."); + gpuAccessor.Log($"Failed to reserve storage buffer for global memory operation \"{operation.Inst}\"."); if (operation.Dest != null) { @@ -286,7 +297,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static LinkedListNode<INode> ReplaceGlobalMemoryWithStorage( GtsContext gtsContext, - ShaderConfig config, + ResourceManager resourceManager, + IGpuAccessor gpuAccessor, + TargetLanguage targetLanguage, BasicBlock block, LinkedListNode<INode> node) { @@ -303,7 +316,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations Operand offset = result.Offset; - bool storageUnaligned = config.GpuAccessor.QueryHasUnalignedStorageBuffer(); + bool storageUnaligned = gpuAccessor.QueryHasUnalignedStorageBuffer(); if (storageUnaligned) { @@ -312,7 +325,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations Operand baseAddressMasked = Local(); Operand hostOffset = Local(); - int alignment = config.GpuAccessor.QueryHostStorageBufferOffsetAlignment(); + int alignment = gpuAccessor.QueryHostStorageBufferOffsetAlignment(); Operation maskOp = new(Instruction.BitwiseAnd, baseAddressMasked, baseAddress, Const(-alignment)); Operation subOp = new(Instruction.Subtract, hostOffset, globalAddress, baseAddressMasked); @@ -333,13 +346,19 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations offset = newOffset; } - if (CanUseInlineStorageOp(operation, config.Options.TargetLanguage)) + if (CanUseInlineStorageOp(operation, targetLanguage)) { - return GenerateInlineStorageOp(config, node, operation, offset, result); + return GenerateInlineStorageOp(resourceManager, node, operation, offset, result); } else { - if (!TryGenerateSingleTargetStorageOp(gtsContext, config, operation, result, out int functionId)) + if (!TryGenerateSingleTargetStorageOp( + gtsContext, + resourceManager, + targetLanguage, + operation, + result, + out int functionId)) { return null; } @@ -354,7 +373,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations // the base address might be stored. // Generate a helper function that will check all possible storage buffers and use the right one. - if (!TryGenerateMultiTargetStorageOp(gtsContext, config, block, operation, out int functionId)) + if (!TryGenerateMultiTargetStorageOp( + gtsContext, + resourceManager, + gpuAccessor, + targetLanguage, + block, + operation, + out int functionId)) { return null; } @@ -375,14 +401,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } private static LinkedListNode<INode> GenerateInlineStorageOp( - ShaderConfig config, + ResourceManager resourceManager, LinkedListNode<INode> node, Operation operation, Operand offset, SearchResult result) { bool isStore = operation.Inst == Instruction.Store || operation.Inst.IsAtomic(); - if (!config.ResourceManager.TryGetStorageBufferBinding(result.SbCbSlot, result.SbCbOffset, isStore, out int binding)) + if (!resourceManager.TryGetStorageBufferBinding(result.SbCbSlot, result.SbCbOffset, isStore, out int binding)) { return null; } @@ -474,7 +500,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool TryGenerateSingleTargetStorageOp( GtsContext gtsContext, - ShaderConfig config, + ResourceManager resourceManager, + TargetLanguage targetLanguage, Operation operation, SearchResult result, out int functionId) @@ -514,7 +541,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } if (!TryGenerateStorageOp( - config, + resourceManager, + targetLanguage, context, operation.Inst, operation.StorageKind, @@ -555,7 +583,9 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations private static bool TryGenerateMultiTargetStorageOp( GtsContext gtsContext, - ShaderConfig config, + ResourceManager resourceManager, + IGpuAccessor gpuAccessor, + TargetLanguage targetLanguage, BasicBlock block, Operation operation, out int functionId) @@ -624,7 +654,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations if (targetCbs.Count == 0) { - config.GpuAccessor.Log($"Failed to find storage buffer for global memory operation \"{operation.Inst}\"."); + gpuAccessor.Log($"Failed to find storage buffer for global memory operation \"{operation.Inst}\"."); } if (gtsContext.TryGetFunctionId(operation, isMultiTarget: true, targetCbs, out functionId)) @@ -685,13 +715,14 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations SearchResult result = new(sbCbSlot, sbCbOffset); - int alignment = config.GpuAccessor.QueryHostStorageBufferOffsetAlignment(); + int alignment = gpuAccessor.QueryHostStorageBufferOffsetAlignment(); Operand baseAddressMasked = context.BitwiseAnd(baseAddrLow, Const(-alignment)); Operand hostOffset = context.ISubtract(globalAddressLow, baseAddressMasked); if (!TryGenerateStorageOp( - config, + resourceManager, + targetLanguage, context, operation.Inst, operation.StorageKind, @@ -781,7 +812,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations } private static bool TryGenerateStorageOp( - ShaderConfig config, + ResourceManager resourceManager, + TargetLanguage targetLanguage, EmitterContext context, Instruction inst, StorageKind storageKind, @@ -794,7 +826,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations resultValue = null; bool isStore = inst.IsAtomic() || inst == Instruction.Store; - if (!config.ResourceManager.TryGetStorageBufferBinding(result.SbCbSlot, result.SbCbOffset, isStore, out int binding)) + if (!resourceManager.TryGetStorageBufferBinding(result.SbCbSlot, result.SbCbOffset, isStore, out int binding)) { return false; } @@ -820,7 +852,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations resultValue = context.AtomicCompareAndSwap(StorageKind.StorageBuffer, binding, Const(0), wordOffset, compare, value); break; case Instruction.AtomicMaxS32: - if (config.Options.TargetLanguage == TargetLanguage.Spirv) + if (targetLanguage == TargetLanguage.Spirv) { resultValue = context.AtomicMaxS32(StorageKind.StorageBuffer, binding, Const(0), wordOffset, value); } @@ -836,7 +868,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations resultValue = context.AtomicMaxU32(StorageKind.StorageBuffer, binding, Const(0), wordOffset, value); break; case Instruction.AtomicMinS32: - if (config.Options.TargetLanguage == TargetLanguage.Spirv) + if (targetLanguage == TargetLanguage.Spirv) { resultValue = context.AtomicMinS32(StorageKind.StorageBuffer, binding, Const(0), wordOffset, value); } diff --git a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs index e7805027..17427a5f 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs @@ -7,40 +7,40 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations { static class Optimizer { - public static void RunPass(HelperFunctionManager hfm, BasicBlock[] blocks, ShaderConfig config) + public static void RunPass(TransformContext context) { - RunOptimizationPasses(blocks, config); + RunOptimizationPasses(context.Blocks, context.ResourceManager); // TODO: Some of those are not optimizations and shouldn't be here. - GlobalToStorage.RunPass(hfm, blocks, config); + GlobalToStorage.RunPass(context.Hfm, context.Blocks, context.ResourceManager, context.GpuAccessor, context.TargetLanguage); - bool hostSupportsShaderFloat64 = config.GpuAccessor.QueryHostSupportsShaderFloat64(); + bool hostSupportsShaderFloat64 = context.GpuAccessor.QueryHostSupportsShaderFloat64(); // Those passes are looking for specific patterns and only needs to run once. - for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + for (int blkIndex = 0; blkIndex < context.Blocks.Length; blkIndex++) { - BindlessToIndexed.RunPass(blocks[blkIndex], config); - BindlessElimination.RunPass(blocks[blkIndex], config); + BindlessToIndexed.RunPass(context.Blocks[blkIndex], context.ResourceManager); + BindlessElimination.RunPass(context.Blocks[blkIndex], context.ResourceManager, context.GpuAccessor); // FragmentCoord only exists on fragment shaders, so we don't need to check other stages. - if (config.Stage == ShaderStage.Fragment) + if (context.Stage == ShaderStage.Fragment) { - EliminateMultiplyByFragmentCoordW(blocks[blkIndex]); + EliminateMultiplyByFragmentCoordW(context.Blocks[blkIndex]); } // If the host does not support double operations, we need to turn them into float operations. if (!hostSupportsShaderFloat64) { - DoubleToFloat.RunPass(hfm, blocks[blkIndex]); + DoubleToFloat.RunPass(context.Hfm, context.Blocks[blkIndex]); } } // Run optimizations one last time to remove any code that is now optimizable after above passes. - RunOptimizationPasses(blocks, config); + RunOptimizationPasses(context.Blocks, context.ResourceManager); } - private static void RunOptimizationPasses(BasicBlock[] blocks, ShaderConfig config) + private static void RunOptimizationPasses(BasicBlock[] blocks, ResourceManager resourceManager) { bool modified; @@ -79,7 +79,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations continue; } - ConstantFolding.RunPass(config, operation); + ConstantFolding.RunPass(resourceManager, operation); Simplification.RunPass(operation); if (DestIsLocalVar(operation)) |