aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Shader')
-rw-r--r--src/Ryujinx.Graphics.Shader/Constants.cs6
-rw-r--r--src/Ryujinx.Graphics.Shader/IGpuAccessor.cs9
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs39
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs32
4 files changed, 84 insertions, 2 deletions
diff --git a/src/Ryujinx.Graphics.Shader/Constants.cs b/src/Ryujinx.Graphics.Shader/Constants.cs
index 7f1445ed..39d6b238 100644
--- a/src/Ryujinx.Graphics.Shader/Constants.cs
+++ b/src/Ryujinx.Graphics.Shader/Constants.cs
@@ -10,5 +10,11 @@ namespace Ryujinx.Graphics.Shader
public const int NvnBaseVertexByteOffset = 0x640;
public const int NvnBaseInstanceByteOffset = 0x644;
public const int NvnDrawIndexByteOffset = 0x648;
+
+ // Transform Feedback emulation.
+
+ public const int TfeInfoBinding = 0;
+ public const int TfeBufferBaseBinding = 1;
+ public const int TfeBuffersCount = 4;
}
} \ No newline at end of file
diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index d3794cdd..1c2b2809 100644
--- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -368,6 +368,15 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Queries host GPU transform feedback support.
+ /// </summary>
+ /// <returns>True if the GPU and driver supports transform feedback, false otherwise</returns>
+ bool QueryHostSupportsTransformFeedback()
+ {
+ return true;
+ }
+
+ /// <summary>
/// Queries host support for writes to the viewport index from vertex or tessellation shader stages.
/// </summary>
/// <returns>True if writes to the viewport index from vertex or tessellation are supported, false otherwise</returns>
diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 6ca74a37..87e5457f 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -234,6 +234,45 @@ namespace Ryujinx.Graphics.Shader.Translation
public void PrepareForVertexReturn()
{
+ if (!Config.GpuAccessor.QueryHostSupportsTransformFeedback() && Config.GpuAccessor.QueryTransformFeedbackEnabled())
+ {
+ Operand vertexCount = this.Load(StorageKind.StorageBuffer, Constants.TfeInfoBinding, Const(1));
+
+ for (int tfbIndex = 0; tfbIndex < Constants.TfeBuffersCount; tfbIndex++)
+ {
+ var locations = Config.GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex);
+ var stride = Config.GpuAccessor.QueryTransformFeedbackStride(tfbIndex);
+
+ Operand baseOffset = this.Load(StorageKind.StorageBuffer, Constants.TfeInfoBinding, Const(0), Const(tfbIndex));
+ Operand baseVertex = this.Load(StorageKind.Input, IoVariable.BaseVertex);
+ Operand baseInstance = this.Load(StorageKind.Input, IoVariable.BaseInstance);
+ Operand vertexIndex = this.Load(StorageKind.Input, IoVariable.VertexIndex);
+ Operand instanceIndex = this.Load(StorageKind.Input, IoVariable.InstanceIndex);
+
+ Operand outputVertexOffset = this.ISubtract(vertexIndex, baseVertex);
+ Operand outputInstanceOffset = this.ISubtract(instanceIndex, baseInstance);
+
+ Operand outputBaseVertex = this.IMultiply(outputInstanceOffset, vertexCount);
+
+ Operand vertexOffset = this.IMultiply(this.IAdd(outputBaseVertex, outputVertexOffset), Const(stride / 4));
+ baseOffset = this.IAdd(baseOffset, vertexOffset);
+
+ for (int j = 0; j < locations.Length; j++)
+ {
+ byte location = locations[j];
+ if (location == 0xff)
+ {
+ continue;
+ }
+
+ Operand offset = this.IAdd(baseOffset, Const(j));
+ Operand value = Instructions.AttributeMap.GenerateAttributeLoad(this, null, location * 4, isOutput: true, isPerPatch: false);
+
+ this.Store(StorageKind.StorageBuffer, Constants.TfeBufferBaseBinding + tfbIndex, Const(0), offset, value);
+ }
+ }
+ }
+
if (Config.GpuAccessor.QueryViewportTransformDisable())
{
Operand x = this.Load(StorageKind.Output, IoVariable.Position, null, Const(0));
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 41558dc3..534bda70 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -132,6 +132,11 @@ namespace Ryujinx.Graphics.Shader.Translation
_transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>();
+ TransformFeedbackEnabled =
+ stage != ShaderStage.Compute &&
+ gpuAccessor.QueryTransformFeedbackEnabled() &&
+ gpuAccessor.QueryHostSupportsTransformFeedback();
+
UsedInputAttributesPerPatch = new HashSet<int>();
UsedOutputAttributesPerPatch = new HashSet<int>();
@@ -139,6 +144,31 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
+
+ if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
+ {
+ StructureType tfeInfoStruct = new StructureType(new StructureField[]
+ {
+ new StructureField(AggregateType.Array | AggregateType.U32, "base_offset", 4),
+ new StructureField(AggregateType.U32, "vertex_count")
+ });
+
+ BufferDefinition tfeInfoBuffer = new BufferDefinition(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
+
+ Properties.AddStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
+
+ StructureType tfeDataStruct = new StructureType(new StructureField[]
+ {
+ new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
+ });
+
+ for (int i = 0; i < Constants.TfeBuffersCount; i++)
+ {
+ int binding = Constants.TfeBufferBaseBinding + i;
+ BufferDefinition tfeDataBuffer = new BufferDefinition(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
+ Properties.AddStorageBuffer(binding, tfeDataBuffer);
+ }
+ }
}
public ShaderConfig(
@@ -151,7 +181,6 @@ namespace Ryujinx.Graphics.Shader.Translation
ThreadsPerInputPrimitive = 1;
OutputTopology = outputTopology;
MaxOutputVertices = maxOutputVertices;
- TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
}
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(header.Stage, gpuAccessor, options)
@@ -165,7 +194,6 @@ namespace Ryujinx.Graphics.Shader.Translation
OmapTargets = header.OmapTargets;
OmapSampleMask = header.OmapSampleMask;
OmapDepth = header.OmapDepth;
- TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
}