mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-22 09:03:36 +00:00
SPIR-V: Transform feedback support
This commit is contained in:
parent
afa54813f7
commit
f51f9e90d4
3 changed files with 124 additions and 23 deletions
|
@ -13,6 +13,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
partial class CodeGenContext : Module
|
partial class CodeGenContext : Module
|
||||||
{
|
{
|
||||||
|
private readonly StructuredProgramInfo _info;
|
||||||
|
|
||||||
public ShaderConfig Config { get; }
|
public ShaderConfig Config { get; }
|
||||||
|
|
||||||
public int InputVertices { get; }
|
public int InputVertices { get; }
|
||||||
|
@ -65,8 +67,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
public SpirvDelegates Delegates { get; }
|
public SpirvDelegates Delegates { get; }
|
||||||
|
|
||||||
public CodeGenContext(ShaderConfig config, GeneratorPool<Instruction> instPool, GeneratorPool<LiteralInteger> integerPool) : base(0x00010300, instPool, integerPool)
|
public CodeGenContext(
|
||||||
|
StructuredProgramInfo info,
|
||||||
|
ShaderConfig config,
|
||||||
|
GeneratorPool<Instruction> instPool,
|
||||||
|
GeneratorPool<LiteralInteger> integerPool) : base(0x00010300, instPool, integerPool)
|
||||||
{
|
{
|
||||||
|
_info = info;
|
||||||
Config = config;
|
Config = config;
|
||||||
|
|
||||||
if (config.Stage == ShaderStage.Geometry)
|
if (config.Stage == ShaderStage.Geometry)
|
||||||
|
@ -217,17 +224,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||||
|
|
||||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
int attrOffset = attrInfo.BaseValue;
|
||||||
|
AggregateType type = attrInfo.Type;
|
||||||
|
|
||||||
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||||
|
if (isUserAttr && Config.TransformFeedbackEnabled &&
|
||||||
|
((isOutAttr && Config.Stage != ShaderStage.Fragment) ||
|
||||||
|
(!isOutAttr && Config.Stage != ShaderStage.Vertex)))
|
||||||
|
{
|
||||||
|
attrOffset = attr;
|
||||||
|
type = elemType;
|
||||||
|
}
|
||||||
|
|
||||||
var ioVariable = isOutAttr ? Outputs[attrInfo.BaseValue] : Inputs[attrInfo.BaseValue];
|
var ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||||
|
|
||||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
if ((type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||||
{
|
{
|
||||||
return ioVariable;
|
return ioVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
|
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||||
|
|
||||||
if (Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
if (Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||||
{
|
{
|
||||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
||||||
|
@ -300,6 +318,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return _functions[funcIndex];
|
return _functions[funcIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TransformFeedbackOutput GetTransformFeedbackOutput(int location, int component)
|
||||||
|
{
|
||||||
|
int index = (AttributeConsts.UserAttributeBase / 4) + location * 4 + component;
|
||||||
|
return _info.TransformFeedbackOutputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransformFeedbackOutput GetTransformFeedbackOutput(int location)
|
||||||
|
{
|
||||||
|
int index = location / 4;
|
||||||
|
return _info.TransformFeedbackOutputs[index];
|
||||||
|
}
|
||||||
|
|
||||||
public Instruction GetType(AggregateType type, int length = 1)
|
public Instruction GetType(AggregateType type, int length = 1)
|
||||||
{
|
{
|
||||||
if (type.HasFlag(AggregateType.Array))
|
if (type.HasFlag(AggregateType.Array))
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||||
using Spv.Generator;
|
using Spv.Generator;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using static Spv.Specification;
|
using static Spv.Specification;
|
||||||
|
|
||||||
|
@ -335,14 +336,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Config.TransformFeedbackEnabled)
|
DeclareInputOrOutput(context, attr, false, iq);
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DeclareInputOrOutput(context, attr, false, iq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,14 +365,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
private static void DeclareOutputAttribute(CodeGenContext context, int attr)
|
private static void DeclareOutputAttribute(CodeGenContext context, int attr)
|
||||||
{
|
{
|
||||||
if (context.Config.TransformFeedbackEnabled)
|
DeclareInputOrOutput(context, attr, true);
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DeclareInputOrOutput(context, attr, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeclareInvocationId(CodeGenContext context)
|
public static void DeclareInvocationId(CodeGenContext context)
|
||||||
|
@ -388,6 +375,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
private static void DeclareInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
private static void DeclareInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||||
{
|
{
|
||||||
|
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||||
|
if (isUserAttr && context.Config.TransformFeedbackEnabled &&
|
||||||
|
((isOutAttr && context.Config.Stage != ShaderStage.Fragment) ||
|
||||||
|
(!isOutAttr && context.Config.Stage != ShaderStage.Vertex)))
|
||||||
|
{
|
||||||
|
DeclareInputOrOutput(context, attr, (attr >> 2) & 3, isOutAttr, iq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||||
var attrInfo = AttributeInfo.From(context.Config, attr);
|
var attrInfo = AttributeInfo.From(context.Config, attr);
|
||||||
|
|
||||||
|
@ -410,8 +406,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
if (attrInfo.IsBuiltin)
|
if (attrInfo.IsBuiltin)
|
||||||
{
|
{
|
||||||
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
||||||
|
|
||||||
|
if (context.Config.TransformFeedbackEnabled && isOutAttr)
|
||||||
|
{
|
||||||
|
var tfOutput = context.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
||||||
|
if (tfOutput.Valid)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||||
|
context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
|
||||||
|
context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
else if (isUserAttr)
|
||||||
{
|
{
|
||||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
@ -439,6 +446,60 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
dict.Add(attrInfo.BaseValue, spvVar);
|
dict.Add(attrInfo.BaseValue, spvVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void DeclareInputOrOutput(CodeGenContext context, int attr, int component, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||||
|
{
|
||||||
|
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||||
|
var attrInfo = AttributeInfo.From(context.Config, attr);
|
||||||
|
|
||||||
|
if (dict.ContainsKey(attr))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||||
|
var attrType = context.GetType(attrInfo.Type & AggregateType.ElementTypeMask);
|
||||||
|
|
||||||
|
if (context.Config.Stage == ShaderStage.Geometry && !isOutAttr && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||||
|
{
|
||||||
|
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||||
|
}
|
||||||
|
|
||||||
|
var spvType = context.TypePointer(storageClass, attrType);
|
||||||
|
var spvVar = context.Variable(spvType, storageClass);
|
||||||
|
|
||||||
|
Debug.Assert(attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd);
|
||||||
|
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||||
|
|
||||||
|
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||||
|
context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
|
||||||
|
|
||||||
|
if (isOutAttr)
|
||||||
|
{
|
||||||
|
var tfOutput = context.GetTransformFeedbackOutput(location, component);
|
||||||
|
if (tfOutput.Valid)
|
||||||
|
{
|
||||||
|
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||||
|
context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
|
||||||
|
context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (iq)
|
||||||
|
{
|
||||||
|
case PixelImap.Constant:
|
||||||
|
context.Decorate(spvVar, Decoration.Flat);
|
||||||
|
break;
|
||||||
|
case PixelImap.ScreenLinear:
|
||||||
|
context.Decorate(spvVar, Decoration.NoPerspective);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AddGlobalVariable(spvVar);
|
||||||
|
dict.Add(attr, spvVar);
|
||||||
|
}
|
||||||
|
|
||||||
private static BuiltIn GetBuiltIn(CodeGenContext context, int attr)
|
private static BuiltIn GetBuiltIn(CodeGenContext context, int attr)
|
||||||
{
|
{
|
||||||
return attr switch
|
return attr switch
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
integerPool = IntegerPool.Allocate();
|
integerPool = IntegerPool.Allocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeGenContext context = new CodeGenContext(config, instPool, integerPool);
|
CodeGenContext context = new CodeGenContext(info, config, instPool, integerPool);
|
||||||
|
|
||||||
context.AddCapability(Capability.GroupNonUniformBallot);
|
context.AddCapability(Capability.GroupNonUniformBallot);
|
||||||
context.AddCapability(Capability.ImageBuffer);
|
context.AddCapability(Capability.ImageBuffer);
|
||||||
|
@ -56,6 +56,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
context.AddCapability(Capability.SubgroupBallotKHR);
|
context.AddCapability(Capability.SubgroupBallotKHR);
|
||||||
context.AddCapability(Capability.SubgroupVoteKHR);
|
context.AddCapability(Capability.SubgroupVoteKHR);
|
||||||
|
|
||||||
|
if (config.TransformFeedbackEnabled && config.Stage != ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
context.AddCapability(Capability.TransformFeedback);
|
||||||
|
}
|
||||||
|
|
||||||
if (config.Stage == ShaderStage.Geometry)
|
if (config.Stage == ShaderStage.Geometry)
|
||||||
{
|
{
|
||||||
context.AddCapability(Capability.Geometry);
|
context.AddCapability(Capability.Geometry);
|
||||||
|
@ -193,6 +198,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
localSizeY,
|
localSizeY,
|
||||||
localSizeZ);
|
localSizeZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.Config.TransformFeedbackEnabled && context.Config.Stage != ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
context.AddExecutionMode(spvFunc, ExecutionMode.Xfb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue