diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs index 96ccfb28..bb3a8dca 100644 --- a/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/Ryujinx.Graphics.GAL/IPipeline.cs @@ -68,8 +68,7 @@ namespace Ryujinx.Graphics.GAL void SetSampler(int binding, ISampler sampler); - void SetScissorEnable(int index, bool enable); - void SetScissor(int index, int x, int y, int width, int height); + void SetScissor(int index, bool enable, int x, int y, int width, int height); void SetStencilTest(StencilTestDescriptor stencilTest); diff --git a/Ryujinx.Graphics.GAL/VertexAttribDescriptor.cs b/Ryujinx.Graphics.GAL/VertexAttribDescriptor.cs index 1547658e..b3248b62 100644 --- a/Ryujinx.Graphics.GAL/VertexAttribDescriptor.cs +++ b/Ryujinx.Graphics.GAL/VertexAttribDescriptor.cs @@ -1,6 +1,8 @@ +using System; + namespace Ryujinx.Graphics.GAL { - public struct VertexAttribDescriptor + public struct VertexAttribDescriptor : IEquatable { public int BufferIndex { get; } public int Offset { get; } @@ -16,5 +18,23 @@ namespace Ryujinx.Graphics.GAL IsZero = isZero; Format = format; } + + public override bool Equals(object obj) + { + return obj is VertexAttribDescriptor other && Equals(other); + } + + public bool Equals(VertexAttribDescriptor other) + { + return BufferIndex == other.BufferIndex && + Offset == other.Offset && + IsZero == other.IsZero && + Format == other.Format; + } + + public override int GetHashCode() + { + return HashCode.Combine(BufferIndex, Offset, IsZero, Format); + } } } diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index d6bd5110..a41fd541 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -436,8 +436,6 @@ namespace Ryujinx.Graphics.Gpu.Engine bool enable = scissor.Enable && (scissor.X1 != 0 || scissor.Y1 != 0 || scissor.X2 != 0xffff || scissor.Y2 != 0xffff); - _context.Renderer.Pipeline.SetScissorEnable(index, enable); - if (enable) { int x = scissor.X1; @@ -454,7 +452,11 @@ namespace Ryujinx.Graphics.Gpu.Engine height = (int)Math.Ceiling(height * scale); } - _context.Renderer.Pipeline.SetScissor(index, x, y, width, height); + _context.Renderer.Pipeline.SetScissor(index, true, x, y, width, height); + } + else + { + _context.Renderer.Pipeline.SetScissor(index, false, 0, 0, 0, 0); } } } diff --git a/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/Ryujinx.Graphics.OpenGL/Framebuffer.cs index 015b0ec0..66bf892b 100644 --- a/Ryujinx.Graphics.OpenGL/Framebuffer.cs +++ b/Ryujinx.Graphics.OpenGL/Framebuffer.cs @@ -2,6 +2,7 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL.Image; using System; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.OpenGL { @@ -29,21 +30,27 @@ namespace Ryujinx.Graphics.OpenGL return Handle; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AttachColor(int index, TextureView color) { + if (_colors[index] == color) + { + return; + } + FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index; if (HwCapabilities.Vendor == HwCapabilities.GpuVendor.Amd || HwCapabilities.Vendor == HwCapabilities.GpuVendor.Intel) { GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.GetIncompatibleFormatViewHandle() ?? 0, 0); - - _colors[index] = color; } else { GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.Handle ?? 0, 0); } + + _colors[index] = color; } public void AttachDepthStencil(TextureView depthStencil) diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index b6a34e9c..f42187bd 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.OpenGL private readonly uint[] _componentMasks; - private bool _scissor0Enable = false; + private uint _scissorEnables; private bool _tfEnabled; private TransformFeedbackPrimitiveType _tfTopology; @@ -883,25 +883,27 @@ namespace Ryujinx.Graphics.OpenGL ((Sampler)sampler).Bind(binding); } - public void SetScissorEnable(int index, bool enable) + public void SetScissor(int index, bool enable, int x, int y, int width, int height) { - if (enable) + uint mask = 1u << index; + + if (!enable) { + if ((_scissorEnables & mask) != 0) + { + _scissorEnables &= ~mask; + GL.Disable(IndexedEnableCap.ScissorTest, index); + } + + return; + } + + if ((_scissorEnables & mask) == 0) + { + _scissorEnables |= mask; GL.Enable(IndexedEnableCap.ScissorTest, index); } - else - { - GL.Disable(IndexedEnableCap.ScissorTest, index); - } - if (index == 0) - { - _scissor0Enable = enable; - } - } - - public void SetScissor(int index, int x, int y, int width, int height) - { GL.ScissorIndexed(index, x, y, width, height); } @@ -1241,7 +1243,7 @@ namespace Ryujinx.Graphics.OpenGL public void RestoreScissor0Enable() { - if (_scissor0Enable) + if ((_scissorEnables & 1u) != 0) { GL.Enable(IndexedEnableCap.ScissorTest, 0); } diff --git a/Ryujinx.Graphics.OpenGL/VertexArray.cs b/Ryujinx.Graphics.OpenGL/VertexArray.cs index 64c6a821..17703cd1 100644 --- a/Ryujinx.Graphics.OpenGL/VertexArray.cs +++ b/Ryujinx.Graphics.OpenGL/VertexArray.cs @@ -1,6 +1,7 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.GAL; using System; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.OpenGL { @@ -16,6 +17,9 @@ namespace Ryujinx.Graphics.OpenGL private int _vertexAttribsCount; private int _vertexBuffersCount; + private uint _vertexAttribsInUse; + private uint _vertexBuffersInUse; + public VertexArray() { Handle = GL.GenVertexArray(); @@ -31,30 +35,30 @@ namespace Ryujinx.Graphics.OpenGL public void SetVertexBuffers(ReadOnlySpan vertexBuffers) { - int bindingIndex = 0; - - for (int index = 0; index < vertexBuffers.Length; index++) + int bindingIndex; + for (bindingIndex = 0; bindingIndex < vertexBuffers.Length; bindingIndex++) { - VertexBufferDescriptor vb = vertexBuffers[index]; + VertexBufferDescriptor vb = vertexBuffers[bindingIndex]; if (vb.Buffer.Handle != BufferHandle.Null) { GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride); - GL.VertexBindingDivisor(bindingIndex, vb.Divisor); + _vertexBuffersInUse |= 1u << bindingIndex; } else { - GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0); + if ((_vertexBuffersInUse & (1u << bindingIndex)) != 0) + { + GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0); + _vertexBuffersInUse &= ~(1u << bindingIndex); + } } - _vertexBuffers[index] = vb; - - bindingIndex++; + _vertexBuffers[bindingIndex] = vb; } _vertexBuffersCount = bindingIndex; - _needsAttribsUpdate = true; } @@ -66,17 +70,22 @@ namespace Ryujinx.Graphics.OpenGL { VertexAttribDescriptor attrib = vertexAttribs[index]; + if (attrib.Equals(_vertexAttribs[index])) + { + continue; + } + FormatInfo fmtInfo = FormatTable.GetFormatInfo(attrib.Format); if (attrib.IsZero) { // Disabling the attribute causes the shader to read a constant value. // The value is configurable, but by default is a vector of (0, 0, 0, 1). - GL.DisableVertexAttribArray(index); + DisableVertexAttrib(index); } else { - GL.EnableVertexAttribArray(index); + EnableVertexAttrib(index); } int offset = attrib.Offset; @@ -107,7 +116,7 @@ namespace Ryujinx.Graphics.OpenGL for (; index < Constants.MaxVertexAttribs; index++) { - GL.DisableVertexAttribArray(index); + DisableVertexAttrib(index); } } @@ -122,29 +131,54 @@ namespace Ryujinx.Graphics.OpenGL { VertexAttribDescriptor attrib = _vertexAttribs[attribIndex]; - if ((uint)attrib.BufferIndex >= _vertexBuffersCount) + if (!attrib.IsZero) { - GL.DisableVertexAttribArray(attribIndex); + if ((uint)attrib.BufferIndex >= _vertexBuffersCount) + { + DisableVertexAttrib(attribIndex); + continue; + } - continue; - } + if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == BufferHandle.Null) + { + DisableVertexAttrib(attribIndex); + continue; + } - if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == BufferHandle.Null) - { - GL.DisableVertexAttribArray(attribIndex); - - continue; - } - - if (_needsAttribsUpdate && !attrib.IsZero) - { - GL.EnableVertexAttribArray(attribIndex); + if (_needsAttribsUpdate) + { + EnableVertexAttrib(attribIndex); + } } } _needsAttribsUpdate = false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnableVertexAttrib(int index) + { + uint mask = 1u << index; + + if ((_vertexAttribsInUse & mask) == 0) + { + _vertexAttribsInUse |= mask; + GL.EnableVertexAttribArray(index); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void DisableVertexAttrib(int index) + { + uint mask = 1u << index; + + if ((_vertexAttribsInUse & mask) != 0) + { + _vertexAttribsInUse &= ~mask; + GL.DisableVertexAttribArray(index); + } + } + public void Dispose() { if (Handle != 0)