aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.OpenGL')
-rw-r--r--Ryujinx.Graphics.OpenGL/EnumConversion.cs25
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs46
-rw-r--r--Ryujinx.Graphics.OpenGL/Program.cs54
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs4
4 files changed, 123 insertions, 6 deletions
diff --git a/Ryujinx.Graphics.OpenGL/EnumConversion.cs b/Ryujinx.Graphics.OpenGL/EnumConversion.cs
index a4bd39cc..09860be3 100644
--- a/Ryujinx.Graphics.OpenGL/EnumConversion.cs
+++ b/Ryujinx.Graphics.OpenGL/EnumConversion.cs
@@ -331,6 +331,31 @@ namespace Ryujinx.Graphics.OpenGL
return PrimitiveType.Points;
}
+ public static TransformFeedbackPrimitiveType ConvertToTfType(this PrimitiveTopology topology)
+ {
+ switch (topology)
+ {
+ case PrimitiveTopology.Points:
+ return TransformFeedbackPrimitiveType.Points;
+ case PrimitiveTopology.Lines:
+ case PrimitiveTopology.LineLoop:
+ case PrimitiveTopology.LineStrip:
+ case PrimitiveTopology.LinesAdjacency:
+ case PrimitiveTopology.LineStripAdjacency:
+ return TransformFeedbackPrimitiveType.Lines;
+ case PrimitiveTopology.Triangles:
+ case PrimitiveTopology.TriangleStrip:
+ case PrimitiveTopology.TriangleFan:
+ case PrimitiveTopology.TrianglesAdjacency:
+ case PrimitiveTopology.TriangleStripAdjacency:
+ return TransformFeedbackPrimitiveType.Triangles;
+ }
+
+ Logger.PrintDebug(LogClass.Gpu, $"Invalid {nameof(PrimitiveTopology)} enum value: {topology}.");
+
+ return TransformFeedbackPrimitiveType.Points;
+ }
+
public static OpenTK.Graphics.OpenGL.StencilOp Convert(this GAL.StencilOp op)
{
switch (op)
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 9623c826..7537b44f 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -45,6 +45,8 @@ namespace Ryujinx.Graphics.OpenGL
private bool _scissor0Enable = false;
+ private bool _tfEnabled;
+
ColorF _blendConstant = new ColorF(0, 0, 0, 0);
internal Pipeline()
@@ -76,6 +78,12 @@ namespace Ryujinx.Graphics.OpenGL
GL.MemoryBarrier(MemoryBarrierFlags.AllBarrierBits);
}
+ public void BeginTransformFeedback(PrimitiveTopology topology)
+ {
+ GL.BeginTransformFeedback(topology.ConvertToTfType());
+ _tfEnabled = true;
+ }
+
public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
{
GL.ColorMask(
@@ -512,6 +520,12 @@ namespace Ryujinx.Graphics.OpenGL
}
}
+ public void EndTransformFeedback()
+ {
+ GL.EndTransformFeedback();
+ _tfEnabled = false;
+ }
+
public void SetBlendState(int index, BlendDescriptor blend)
{
if (!blend.Enable)
@@ -713,7 +727,17 @@ namespace Ryujinx.Graphics.OpenGL
public void SetProgram(IProgram program)
{
_program = (Program)program;
- _program.Bind();
+
+ if (_tfEnabled)
+ {
+ GL.PauseTransformFeedback();
+ _program.Bind();
+ GL.ResumeTransformFeedback();
+ }
+ else
+ {
+ _program.Bind();
+ }
SetRenderTargetScale(_fpRenderScale[0]);
}
@@ -904,6 +928,22 @@ namespace Ryujinx.Graphics.OpenGL
}
}
+ public void SetTransformFeedbackBuffer(int index, BufferRange buffer)
+ {
+ const BufferRangeTarget target = BufferRangeTarget.TransformFeedbackBuffer;
+
+ if (_tfEnabled)
+ {
+ GL.PauseTransformFeedback();
+ GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
+ GL.ResumeTransformFeedback();
+ }
+ else
+ {
+ GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
+ }
+ }
+
public void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer)
{
SetBuffer(index, stage, buffer, isStorage: false);
@@ -1132,7 +1172,7 @@ namespace Ryujinx.Graphics.OpenGL
{
// If the event has been flushed, then just use the values on the CPU.
// The query object may already be repurposed for another draw (eg. begin + end).
- return false;
+ return false;
}
if (compare == 0 && evt.Type == QueryTarget.SamplesPassed && evt.ClearCounter)
@@ -1145,7 +1185,7 @@ namespace Ryujinx.Graphics.OpenGL
// The GPU will flush the queries to CPU and evaluate the condition there instead.
GL.Flush(); // The thread will be stalled manually flushing the counter, so flush GL commands now.
- return false;
+ return false;
}
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index 8b4f6e24..a0f8eb01 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -2,6 +2,10 @@ using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
+using Ryujinx.Graphics.Shader.CodeGen.Glsl;
+using System;
+using System.Collections.Generic;
+using System.Linq;
namespace Ryujinx.Graphics.OpenGL
{
@@ -31,7 +35,7 @@ namespace Ryujinx.Graphics.OpenGL
private int[] _textureUnits;
private int[] _imageUnits;
- public Program(IShader[] shaders)
+ public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
{
_ubBindingPoints = new int[UbsPerStage * ShaderStages];
_sbBindingPoints = new int[SbsPerStage * ShaderStages];
@@ -67,6 +71,54 @@ namespace Ryujinx.Graphics.OpenGL
GL.AttachShader(Handle, shaderHandle);
}
+ if (transformFeedbackDescriptors != null)
+ {
+ List<string> varyings = new List<string>();
+
+ int cbi = 0;
+
+ foreach (var tfd in transformFeedbackDescriptors.OrderBy(x => x.BufferIndex))
+ {
+ if (tfd.VaryingLocations.Length == 0)
+ {
+ continue;
+ }
+
+ while (cbi < tfd.BufferIndex)
+ {
+ varyings.Add("gl_NextBuffer");
+
+ cbi++;
+ }
+
+ int stride = Math.Min(128 * 4, (tfd.Stride + 3) & ~3);
+
+ int j = 0;
+
+ for (; j < tfd.VaryingLocations.Length && j * 4 < stride; j++)
+ {
+ byte location = tfd.VaryingLocations[j];
+
+ varyings.Add(Varying.GetName(location) ?? "gl_SkipComponents1");
+
+ j += Varying.GetSize(location) - 1;
+ }
+
+ int feedbackBytes = j * 4;
+
+ while (feedbackBytes < stride)
+ {
+ int bytes = Math.Min(16, stride - feedbackBytes);
+
+ varyings.Add($"gl_SkipComponents{(bytes / 4)}");
+
+ feedbackBytes += bytes;
+ }
+ }
+
+ GL.TransformFeedbackVaryings(Handle, varyings.Count, varyings.ToArray(), TransformFeedbackMode.InterleavedAttribs);
+ }
+
GL.LinkProgram(Handle);
for (int index = 0; index < shaders.Length; index++)
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index cf90f81f..49324637 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -44,9 +44,9 @@ namespace Ryujinx.Graphics.OpenGL
return Buffer.Create(size);
}
- public IProgram CreateProgram(IShader[] shaders)
+ public IProgram CreateProgram(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
{
- return new Program(shaders);
+ return new Program(shaders, transformFeedbackDescriptors);
}
public ISampler CreateSampler(SamplerCreateInfo info)