mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-25 16:50:17 +00:00
* dotnet format style --severity info Some changes were manually reverted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Silence dotnet format IDE0059 warnings * Address or silence dotnet format CA1069 warnings * Address or silence dotnet format CA2211 warnings * Address review comments * Fix formatting for switch expressions * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Fix naming rule violation, Convert shader properties to auto-property and convert values to const * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Run dotnet format after rebase * Address IDE0251 warnings * Address a few disabled IDE0060 warnings * Silence IDE0060 in .editorconfig * Run dotnet format after rebase * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First dotnet format pass * Fix naming rule violations * Add trailing commas * Remove unused members and most unnecessary value assignments * Remove more unnecessary assignments * Remove NRE suppressor
183 lines
7.3 KiB
C#
183 lines
7.3 KiB
C#
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Ryujinx.Graphics.Shader.Translation
|
|
{
|
|
static class ShaderIdentifier
|
|
{
|
|
public static ShaderIdentification Identify(IReadOnlyList<Function> functions, ShaderConfig config)
|
|
{
|
|
if (config.Stage == ShaderStage.Geometry &&
|
|
config.GpuAccessor.QueryPrimitiveTopology() == InputTopology.Triangles &&
|
|
!config.GpuAccessor.QueryHostSupportsGeometryShader() &&
|
|
IsLayerPassthroughGeometryShader(functions, out int layerInputAttr))
|
|
{
|
|
config.SetGeometryShaderLayerInputAttribute(layerInputAttr);
|
|
|
|
return ShaderIdentification.GeometryLayerPassthrough;
|
|
}
|
|
|
|
return ShaderIdentification.None;
|
|
}
|
|
|
|
private static bool IsLayerPassthroughGeometryShader(IReadOnlyList<Function> functions, out int layerInputAttr)
|
|
{
|
|
bool writesLayer = false;
|
|
layerInputAttr = 0;
|
|
|
|
if (functions.Count != 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int verticesCount = 0;
|
|
int totalVerticesCount = 0;
|
|
|
|
foreach (BasicBlock block in functions[0].Blocks)
|
|
{
|
|
// We are not expecting loops or any complex control flow here, so fail in those cases.
|
|
if (block.Branch != null && block.Branch.Index <= block.Index)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (INode node in block.Operations)
|
|
{
|
|
if (node is not Operation operation)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (IsResourceWrite(operation.Inst, operation.StorageKind))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (operation.Inst == Instruction.Store && operation.StorageKind == StorageKind.Output)
|
|
{
|
|
Operand src = operation.GetSource(operation.SourcesCount - 1);
|
|
Operation srcAttributeAsgOp = null;
|
|
|
|
if (src.Type == OperandType.LocalVariable &&
|
|
src.AsgOp is Operation asgOp &&
|
|
asgOp.Inst == Instruction.Load &&
|
|
asgOp.StorageKind.IsInputOrOutput())
|
|
{
|
|
if (asgOp.StorageKind != StorageKind.Input)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
srcAttributeAsgOp = asgOp;
|
|
}
|
|
|
|
if (srcAttributeAsgOp != null)
|
|
{
|
|
IoVariable dstAttribute = (IoVariable)operation.GetSource(0).Value;
|
|
IoVariable srcAttribute = (IoVariable)srcAttributeAsgOp.GetSource(0).Value;
|
|
|
|
if (dstAttribute == IoVariable.Layer && srcAttribute == IoVariable.UserDefined)
|
|
{
|
|
if (srcAttributeAsgOp.SourcesCount != 4)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
writesLayer = true;
|
|
layerInputAttr = srcAttributeAsgOp.GetSource(1).Value * 4 + srcAttributeAsgOp.GetSource(3).Value;
|
|
}
|
|
else
|
|
{
|
|
if (dstAttribute != srcAttribute)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int inputsCount = operation.SourcesCount - 2;
|
|
|
|
if (dstAttribute == IoVariable.UserDefined)
|
|
{
|
|
if (operation.GetSource(1).Value != srcAttributeAsgOp.GetSource(1).Value)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
inputsCount--;
|
|
}
|
|
|
|
for (int i = 0; i < inputsCount; i++)
|
|
{
|
|
int dstIndex = operation.SourcesCount - 2 - i;
|
|
int srcIndex = srcAttributeAsgOp.SourcesCount - 1 - i;
|
|
|
|
if ((dstIndex | srcIndex) < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (operation.GetSource(dstIndex).Type != OperandType.Constant ||
|
|
srcAttributeAsgOp.GetSource(srcIndex).Type != OperandType.Constant ||
|
|
operation.GetSource(dstIndex).Value != srcAttributeAsgOp.GetSource(srcIndex).Value)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (src.Type == OperandType.Constant)
|
|
{
|
|
int dstComponent = operation.GetSource(operation.SourcesCount - 2).Value;
|
|
float expectedValue = dstComponent == 3 ? 1f : 0f;
|
|
|
|
if (src.AsFloat() != expectedValue)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (operation.Inst == Instruction.EmitVertex)
|
|
{
|
|
verticesCount++;
|
|
}
|
|
else if (operation.Inst == Instruction.EndPrimitive)
|
|
{
|
|
totalVerticesCount += verticesCount;
|
|
verticesCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return totalVerticesCount + verticesCount == 3 && writesLayer;
|
|
}
|
|
|
|
private static bool IsResourceWrite(Instruction inst, StorageKind storageKind)
|
|
{
|
|
switch (inst)
|
|
{
|
|
case Instruction.AtomicAdd:
|
|
case Instruction.AtomicAnd:
|
|
case Instruction.AtomicCompareAndSwap:
|
|
case Instruction.AtomicMaxS32:
|
|
case Instruction.AtomicMaxU32:
|
|
case Instruction.AtomicMinS32:
|
|
case Instruction.AtomicMinU32:
|
|
case Instruction.AtomicOr:
|
|
case Instruction.AtomicSwap:
|
|
case Instruction.AtomicXor:
|
|
case Instruction.ImageAtomic:
|
|
case Instruction.ImageStore:
|
|
return true;
|
|
case Instruction.Store:
|
|
return storageKind == StorageKind.StorageBuffer ||
|
|
storageKind == StorageKind.SharedMemory ||
|
|
storageKind == StorageKind.LocalMemory;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|