diff options
Diffstat (limited to 'Ryujinx.Graphics.OpenGL')
-rw-r--r-- | Ryujinx.Graphics.OpenGL/EnumConversion.cs | 25 | ||||
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Pipeline.cs | 46 | ||||
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Program.cs | 54 | ||||
-rw-r--r-- | Ryujinx.Graphics.OpenGL/Renderer.cs | 4 |
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) |