mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-29 01:47:11 +02:00
Delete ShaderConfig and organize shader resources/definitions better (#5509)
* Move some properties out of ShaderConfig * Stop using ShaderConfig on backends * Replace ShaderConfig usages on Translator and passes * Move remaining properties out of ShaderConfig and delete ShaderConfig * Remove ResourceManager property from TranslatorContext * Move Rewriter passes to separate transform pass files * Fix TransformPasses.RunPass on cases where a node is removed * Move remaining ClipDistancePrimitivesWritten and UsedFeatures updates to decode stage * Reduce excessive parameter passing a bit by using structs more * Remove binding parameter from ShaderProperties methods since it is redundant * Replace decoder instruction checks with switch statement * Put GLSL on the same plan as SPIR-V for input/output declaration * Stop mutating TranslatorContext state when Translate is called * Pass most of the graphics state using a struct instead of individual query methods * Auto-format * Auto-format * Add backend logging interface * Auto-format * Remove unnecessary use of interpolated strings * Remove more modifications of AttributeUsage after decode * PR feedback * gl_Layer is not supported on compute
This commit is contained in:
parent
8edfb2bc7b
commit
b423197619
68 changed files with 2653 additions and 2407 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue