| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- using Ryujinx.Graphics.Shader.IntermediateRepresentation;
- using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
- namespace Ryujinx.Graphics.Shader.Translation
- {
- static class ShaderIdentifier
- {
- public static ShaderIdentification Identify(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(Function[] functions, out int layerInputAttr)
- {
- bool writesLayer = false;
- layerInputAttr = 0;
- if (functions.Length != 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 Operation operation))
- {
- continue;
- }
- if (IsResourceWrite(operation.Inst))
- {
- return false;
- }
- if (operation.Inst == Instruction.StoreAttribute)
- {
- return false;
- }
- if (operation.Inst == Instruction.Copy && operation.Dest.Type == OperandType.Attribute)
- {
- Operand src = operation.GetSource(0);
- if (src.Type == OperandType.LocalVariable && src.AsgOp is Operation asgOp && asgOp.Inst == Instruction.LoadAttribute)
- {
- src = Attribute(asgOp.GetSource(0).Value);
- }
- if (src.Type == OperandType.Attribute)
- {
- if (operation.Dest.Value == AttributeConsts.Layer)
- {
- if ((src.Value & AttributeConsts.LoadOutputMask) != 0)
- {
- return false;
- }
- writesLayer = true;
- layerInputAttr = src.Value;
- }
- else if (src.Value != operation.Dest.Value)
- {
- return false;
- }
- }
- else if (src.Type == OperandType.Constant)
- {
- int dstComponent = (operation.Dest.Value >> 2) & 3;
- 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)
- {
- 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:
- case Instruction.StoreGlobal:
- case Instruction.StoreGlobal16:
- case Instruction.StoreGlobal8:
- case Instruction.StoreStorage:
- case Instruction.StoreStorage16:
- case Instruction.StoreStorage8:
- return true;
- }
- return false;
- }
- }
- }
|