aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader/Translation/Optimizations
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader/Translation/Optimizations')
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs38
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessToIndexed.cs10
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/ConstantFolding.cs4
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs76
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Optimizations/Optimizer.cs26
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))