From 0f6ec446ea3be41b1c22aa5c3870bd7a6c595d1f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 11 Aug 2021 16:33:43 -0300 Subject: [PATCH] Replace BGRA and scale uniforms with a uniform block (#2496) * Replace BGRA and scale uniforms with a uniform block * Setting the data again on program change is no longer needed * Optimize and resolve some warnings * Avoid redundant support buffer updates * Some optimizations to BindBuffers (now inlined) * Unify render scale arrays --- Ryujinx.Graphics.GAL/IPipeline.cs | 4 +- .../Engine/Threed/StateUpdater.cs | 16 -- Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 193 ++++++++++-------- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- Ryujinx.Graphics.OpenGL/Pipeline.cs | 122 ++++++----- Ryujinx.Graphics.OpenGL/Program.cs | 14 -- .../CodeGen/Glsl/Declarations.cs | 85 ++++---- .../CodeGen/Glsl/DefaultNames.cs | 7 +- .../HelperFunctions/TexelFetchScale_cp.glsl | 4 +- .../HelperFunctions/TexelFetchScale_fp.glsl | 4 +- .../CodeGen/Glsl/OperandManager.cs | 20 +- Ryujinx.Graphics.Shader/SupportBuffer.cs | 18 ++ .../Translation/TranslationCounts.cs | 6 + 13 files changed, 269 insertions(+), 226 deletions(-) create mode 100644 Ryujinx.Graphics.Shader/SupportBuffer.cs diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs index 760ad2edc..b2f9d5cbb 100644 --- a/Ryujinx.Graphics.GAL/IPipeline.cs +++ b/Ryujinx.Graphics.GAL/IPipeline.cs @@ -73,12 +73,12 @@ namespace Ryujinx.Graphics.GAL void SetStencilTest(StencilTestDescriptor stencilTest); - void SetStorageBuffers(ReadOnlySpan buffers); + void SetStorageBuffers(int first, ReadOnlySpan buffers); void SetTexture(int binding, ITexture texture); void SetTransformFeedbackBuffers(ReadOnlySpan buffers); - void SetUniformBuffers(ReadOnlySpan buffers); + void SetUniformBuffers(int first, ReadOnlySpan buffers); void SetUserClipDistance(int index, bool enableClip); diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 4ff084e94..d9484cf65 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -957,9 +957,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed UpdateUserClipState(); } - int storageBufferBindingsCount = 0; - int uniformBufferBindingsCount = 0; - for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgramInfo info = gs.Shaders[stage]?.Info; @@ -1015,21 +1012,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers); _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers); - - if (info.SBuffers.Count != 0) - { - storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1); - } - - if (info.CBuffers.Count != 0) - { - uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1); - } } - _channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount); - _channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount); - _context.Renderer.Pipeline.SetProgram(gs.HostProgram); } diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index eccc2ca36..855a444f9 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -5,7 +5,7 @@ using Ryujinx.Graphics.Shader; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Gpu.Memory { @@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Gpu.Memory /// class BufferManager { - private const int StackToHeapThreshold = 16; - private readonly GpuContext _context; private readonly GpuChannel _channel; @@ -23,6 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly VertexBuffer[] _vertexBuffers; private readonly BufferBounds[] _transformFeedbackBuffers; private readonly List _bufferTextures; + private readonly BufferRange[] _ranges; /// /// Holds shader stage buffer state and binding information. @@ -88,11 +87,6 @@ namespace Ryujinx.Graphics.Gpu.Memory private readonly BuffersPerStage[] _gpStorageBuffers; private readonly BuffersPerStage[] _gpUniformBuffers; - private int _cpStorageBufferBindings; - private int _cpUniformBufferBindings; - private int _gpStorageBufferBindings; - private int _gpUniformBufferBindings; - private bool _gpStorageBuffersDirty; private bool _gpUniformBuffersDirty; @@ -130,6 +124,8 @@ namespace Ryujinx.Graphics.Gpu.Memory } _bufferTextures = new List(); + + _ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages]; } @@ -288,7 +284,6 @@ namespace Ryujinx.Graphics.Gpu.Memory public void SetComputeStorageBufferBindings(ReadOnlyCollection descriptors) { _cpStorageBuffers.SetBindings(descriptors); - _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// @@ -302,15 +297,6 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpStorageBuffersDirty = true; } - /// - /// Sets the total number of storage buffer bindings used. - /// - /// Number of storage buffer bindings used - public void SetGraphicsStorageBufferBindingsCount(int count) - { - _gpStorageBufferBindings = count; - } - /// /// Sets the binding points for the uniform buffers bound on the compute pipeline. /// @@ -318,7 +304,6 @@ namespace Ryujinx.Graphics.Gpu.Memory public void SetComputeUniformBufferBindings(ReadOnlyCollection descriptors) { _cpUniformBuffers.SetBindings(descriptors); - _cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// @@ -333,15 +318,6 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpUniformBuffersDirty = true; } - /// - /// Sets the total number of uniform buffer bindings used. - /// - /// Number of uniform buffer bindings used - public void SetGraphicsUniformBufferBindingsCount(int count) - { - _gpUniformBufferBindings = count; - } - /// /// Gets a bit mask indicating which compute uniform buffers are currently bound. /// @@ -381,7 +357,6 @@ namespace Ryujinx.Graphics.Gpu.Memory return mask; } - /// /// Gets the address of the compute uniform buffer currently bound at the given index. /// @@ -409,46 +384,10 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public void CommitComputeBindings() { - int sCount = _cpStorageBufferBindings; + var bufferCache = _channel.MemoryManager.Physical.BufferCache; - Span sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount]; - - for (int index = 0; index < _cpStorageBuffers.Count; index++) - { - ref var bindingInfo = ref _cpStorageBuffers.Bindings[index]; - - BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot]; - - if (bounds.Address != 0) - { - // The storage buffer size is not reliable (it might be lower than the actual size), - // so we bind the entire buffer to allow otherwise out of range accesses to work. - sRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd( - bounds.Address, - bounds.Size, - bounds.Flags.HasFlag(BufferUsageFlags.Write)); - } - } - - _context.Renderer.Pipeline.SetStorageBuffers(sRanges); - - int uCount = _cpUniformBufferBindings; - - Span uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount]; - - for (int index = 0; index < _cpUniformBuffers.Count; index++) - { - ref var bindingInfo = ref _cpUniformBuffers.Bindings[index]; - - BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot]; - - if (bounds.Address != 0) - { - uRanges[bindingInfo.Binding] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size); - } - } - - _context.Renderer.Pipeline.SetUniformBuffers(uRanges); + BindBuffers(bufferCache, _cpStorageBuffers, isStorage: true); + BindBuffers(bufferCache, _cpUniformBuffers, isStorage: false); CommitBufferTextureBindings(); @@ -491,20 +430,22 @@ namespace Ryujinx.Graphics.Gpu.Memory /// public void CommitGraphicsBindings() { + var bufferCache = _channel.MemoryManager.Physical.BufferCache; + if (_indexBufferDirty || _rebind) { _indexBufferDirty = false; if (_indexBuffer.Address != 0) { - BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size); + BufferRange buffer = bufferCache.GetBufferRange(_indexBuffer.Address, _indexBuffer.Size); _context.Renderer.Pipeline.SetIndexBuffer(buffer, _indexBuffer.Type); } } else if (_indexBuffer.Address != 0) { - _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size); + bufferCache.SynchronizeBufferRange(_indexBuffer.Address, _indexBuffer.Size); } uint vbEnableMask = _vertexBuffersEnableMask; @@ -524,7 +465,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - BufferRange buffer = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(vb.Address, vb.Size); + BufferRange buffer = bufferCache.GetBufferRange(vb.Address, vb.Size); vertexBuffers[index] = new VertexBufferDescriptor(buffer, vb.Stride, vb.Divisor); } @@ -542,7 +483,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(vb.Address, vb.Size); + bufferCache.SynchronizeBufferRange(vb.Address, vb.Size); } } @@ -562,7 +503,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - tfbs[index] = _channel.MemoryManager.Physical.BufferCache.GetBufferRange(tfb.Address, tfb.Size); + tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size); } _context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs); @@ -578,7 +519,7 @@ namespace Ryujinx.Graphics.Gpu.Memory continue; } - _channel.MemoryManager.Physical.BufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size); + bufferCache.SynchronizeBufferRange(tfb.Address, tfb.Size); } } @@ -586,7 +527,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { _gpStorageBuffersDirty = false; - BindBuffers(_gpStorageBuffers, isStorage: true); + BindBuffers(bufferCache, _gpStorageBuffers, isStorage: true); } else { @@ -597,7 +538,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { _gpUniformBuffersDirty = false; - BindBuffers(_gpUniformBuffers, isStorage: false); + BindBuffers(bufferCache, _gpUniformBuffers, isStorage: false); } else { @@ -612,13 +553,16 @@ namespace Ryujinx.Graphics.Gpu.Memory /// /// Bind respective buffer bindings on the host API. /// - /// Bindings to bind - /// True to bind as storage buffer, false to bind as uniform buffers - private void BindBuffers(BuffersPerStage[] bindings, bool isStorage) + /// Buffer cache holding the buffers for the specified ranges + /// Buffer memory ranges to bind + /// True to bind as storage buffer, false to bind as uniform buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage) { - int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings; + int rangesFirst = 0; + int rangesCount = 0; - Span ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count]; + Span ranges = _ranges; for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) { @@ -633,20 +577,97 @@ namespace Ryujinx.Graphics.Gpu.Memory if (bounds.Address != 0) { var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); - ranges[bindingInfo.Binding] = isStorage - ? _channel.MemoryManager.Physical.BufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite) - : _channel.MemoryManager.Physical.BufferCache.GetBufferRange(bounds.Address, bounds.Size, isWrite); + var range = isStorage + ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite) + : bufferCache.GetBufferRange(bounds.Address, bounds.Size); + + if (rangesCount == 0) + { + rangesFirst = bindingInfo.Binding; + } + else if (bindingInfo.Binding != rangesFirst + rangesCount) + { + SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); + rangesFirst = bindingInfo.Binding; + rangesCount = 0; + } + + ranges[rangesCount++] = range; } } } + if (rangesCount != 0) + { + SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); + } + } + + /// + /// Bind respective buffer bindings on the host API. + /// + /// Buffer cache holding the buffers for the specified ranges + /// Buffer memory ranges to bind + /// True to bind as storage buffer, false to bind as uniform buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage) + { + int rangesFirst = 0; + int rangesCount = 0; + + Span ranges = _ranges; + + for (int index = 0; index < buffers.Count; index++) + { + ref var bindingInfo = ref buffers.Bindings[index]; + + BufferBounds bounds = buffers.Buffers[bindingInfo.Slot]; + + if (bounds.Address != 0) + { + var isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write); + var range = isStorage + ? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite) + : bufferCache.GetBufferRange(bounds.Address, bounds.Size); + + if (rangesCount == 0) + { + rangesFirst = bindingInfo.Binding; + } + else if (bindingInfo.Binding != rangesFirst + rangesCount) + { + SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); + rangesFirst = bindingInfo.Binding; + rangesCount = 0; + } + + ranges[rangesCount++] = range; + } + } + + if (rangesCount != 0) + { + SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage); + } + } + + /// + /// Bind respective buffer bindings on the host API. + /// + /// Host buffers to bind, with their offsets and sizes + /// First binding point + /// Number of bindings + /// Indicates if the buffers are storage or uniform buffers + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetHostBuffers(ReadOnlySpan ranges, int first, int count, bool isStorage) + { if (isStorage) { - _context.Renderer.Pipeline.SetStorageBuffers(ranges); + _context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count)); } else { - _context.Renderer.Pipeline.SetUniformBuffers(ranges); + _context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count)); } } diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 754449fbc..db5a3bff1 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Version of the codegen (to be changed when codegen or guest format change). /// - private const ulong ShaderCodeGenVersion = 2530; + private const ulong ShaderCodeGenVersion = 2494; // Progress reporting helpers private volatile int _shaderCount; diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 948a8b891..9c39f719c 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -5,6 +5,8 @@ using Ryujinx.Graphics.OpenGL.Image; using Ryujinx.Graphics.OpenGL.Queries; using Ryujinx.Graphics.Shader; using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Ryujinx.Graphics.OpenGL { @@ -31,9 +33,16 @@ namespace Ryujinx.Graphics.OpenGL private int _boundDrawFramebuffer; private int _boundReadFramebuffer; - private int[] _fpIsBgra = new int[8]; - private float[] _fpRenderScale = new float[65]; - private float[] _cpRenderScale = new float[64]; + private struct Vector4 + { + public T X; + public T Y; + public T Z; + public T W; + } + + private Vector4[] _fpIsBgra = new Vector4[SupportBuffer.FragmentIsBgraCount]; + private Vector4[] _renderScale = new Vector4[65]; private TextureBase _unit0Texture; @@ -48,6 +57,7 @@ namespace Ryujinx.Graphics.OpenGL private bool _tfEnabled; private TransformFeedbackPrimitiveType _tfTopology; + private BufferHandle _supportBuffer; private readonly BufferHandle[] _tfbs; private readonly BufferRange[] _tfbTargets; @@ -66,15 +76,8 @@ namespace Ryujinx.Graphics.OpenGL _componentMasks[index] = 0xf; } - for (int index = 0; index < _fpRenderScale.Length; index++) - { - _fpRenderScale[index] = 1f; - } - - for (int index = 0; index < _cpRenderScale.Length; index++) - { - _cpRenderScale[index] = 1f; - } + var v4Zero = new Vector4 { X = 0f, Y = 0f, Z = 0f, W = 0f }; + new Span>(_renderScale).Fill(v4Zero); _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers]; _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers]; @@ -823,9 +826,6 @@ namespace Ryujinx.Graphics.OpenGL { _program.Bind(); } - - UpdateFpIsBgra(); - SetRenderTargetScale(_fpRenderScale[0]); } public void SetRasterizerDiscard(bool discard) @@ -844,12 +844,8 @@ namespace Ryujinx.Graphics.OpenGL public void SetRenderTargetScale(float scale) { - _fpRenderScale[0] = scale; - - if (_program != null && _program.FragmentRenderScaleUniform != -1) - { - GL.Uniform1(_program.FragmentRenderScaleUniform, 1, _fpRenderScale); // Just the first element. - } + _renderScale[0].X = scale; + SetSupportBufferData>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1); // Just the first element. } public void SetRenderTargetColorMasks(ReadOnlySpan componentMasks) @@ -866,6 +862,8 @@ namespace Ryujinx.Graphics.OpenGL { EnsureFramebuffer(); + bool isBgraChanged = false; + for (int index = 0; index < colors.Length; index++) { TextureView color = (TextureView)colors[index]; @@ -874,15 +872,19 @@ namespace Ryujinx.Graphics.OpenGL int isBgra = color != null && color.Format.IsBgra8() ? 1 : 0; - if (_fpIsBgra[index] != isBgra) + if (_fpIsBgra[index].X != isBgra) { - _fpIsBgra[index] = isBgra; + _fpIsBgra[index].X = isBgra; + isBgraChanged = true; RestoreComponentMask(index); } } - UpdateFpIsBgra(); + if (isBgraChanged) + { + SetSupportBufferData>(SupportBuffer.FragmentIsBgraOffset, _fpIsBgra, SupportBuffer.FragmentIsBgraCount); + } TextureView depthStencilView = (TextureView)depthStencil; @@ -965,9 +967,9 @@ namespace Ryujinx.Graphics.OpenGL _stencilFrontMask = stencilTest.FrontMask; } - public void SetStorageBuffers(ReadOnlySpan buffers) + public void SetStorageBuffers(int first, ReadOnlySpan buffers) { - SetBuffers(buffers, isStorage: true); + SetBuffers(first, buffers, isStorage: true); } public void SetTexture(int binding, ITexture texture) @@ -1023,9 +1025,9 @@ namespace Ryujinx.Graphics.OpenGL } } - public void SetUniformBuffers(ReadOnlySpan buffers) + public void SetUniformBuffers(int first, ReadOnlySpan buffers) { - SetBuffers(buffers, isStorage: false); + SetBuffers(first, buffers, isStorage: false); } public void SetUserClipDistance(int index, bool enableClip) @@ -1103,7 +1105,7 @@ namespace Ryujinx.Graphics.OpenGL GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit); } - private void SetBuffers(ReadOnlySpan buffers, bool isStorage) + private void SetBuffers(int first, ReadOnlySpan buffers, bool isStorage) { BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer; @@ -1113,11 +1115,11 @@ namespace Ryujinx.Graphics.OpenGL if (buffer.Handle == BufferHandle.Null) { - GL.BindBufferRange(target, index, 0, IntPtr.Zero, 0); + GL.BindBufferRange(target, first + index, 0, IntPtr.Zero, 0); continue; } - GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size); + GL.BindBufferRange(target, first + index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size); } } @@ -1179,37 +1181,39 @@ namespace Ryujinx.Graphics.OpenGL return (_boundDrawFramebuffer, _boundReadFramebuffer); } - private void UpdateFpIsBgra() + public void UpdateRenderScale(ShaderStage stage, float[] scales, int textureCount, int imageCount) { - if (_program != null) + if (stage != ShaderStage.Compute && stage != ShaderStage.Fragment) { - GL.Uniform1(_program.FragmentIsBgraUniform, 8, _fpIsBgra); + return; + } + + bool changed = false; + + for (int index = 0; index < textureCount + imageCount; index++) + { + if (_renderScale[1 + index].X != scales[index]) + { + _renderScale[1 + index].X = scales[index]; + changed = true; + } + } + + if (changed) + { + SetSupportBufferData>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1 + textureCount + imageCount); } } - public void UpdateRenderScale(ShaderStage stage, float[] scales, int textureCount, int imageCount) + private void SetSupportBufferData(int offset, ReadOnlySpan data, int count) where T : unmanaged { - if (_program != null) + if (_supportBuffer == BufferHandle.Null) { - switch (stage) - { - case ShaderStage.Fragment: - if (_program.FragmentRenderScaleUniform != -1) - { - Array.Copy(scales, 0, _fpRenderScale, 1, textureCount + imageCount); - GL.Uniform1(_program.FragmentRenderScaleUniform, 1 + textureCount + imageCount, _fpRenderScale); - } - break; - - case ShaderStage.Compute: - if (_program.ComputeRenderScaleUniform != -1) - { - Array.Copy(scales, 0, _cpRenderScale, 0, textureCount + imageCount); - GL.Uniform1(_program.ComputeRenderScaleUniform, textureCount + imageCount, _cpRenderScale); - } - break; - } + _supportBuffer = Buffer.Create(SupportBuffer.RequiredSize); + GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, Unsafe.As(ref _supportBuffer)); } + + Buffer.SetData(_supportBuffer, offset, MemoryMarshal.Cast(data.Slice(0, count))); } private void PrepareForDispatch() @@ -1249,8 +1253,8 @@ namespace Ryujinx.Graphics.OpenGL public void RestoreComponentMask(int index) { // If the bound render target is bgra, swap the red and blue masks. - uint redMask = _fpIsBgra[index] == 0 ? 1u : 4u; - uint blueMask = _fpIsBgra[index] == 0 ? 4u : 1u; + uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u; + uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u; GL.ColorMask( index, @@ -1322,6 +1326,12 @@ namespace Ryujinx.Graphics.OpenGL public void Dispose() { + if (_supportBuffer != BufferHandle.Null) + { + Buffer.Delete(_supportBuffer); + _supportBuffer = BufferHandle.Null; + } + for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++) { if (_tfbs[i] != BufferHandle.Null) diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs index decc75b1e..785f2f005 100644 --- a/Ryujinx.Graphics.OpenGL/Program.cs +++ b/Ryujinx.Graphics.OpenGL/Program.cs @@ -13,10 +13,6 @@ namespace Ryujinx.Graphics.OpenGL { public int Handle { get; private set; } - public int FragmentIsBgraUniform { get; private set; } - public int FragmentRenderScaleUniform { get; private set; } - public int ComputeRenderScaleUniform { get; private set; } - public bool IsLinked { get @@ -30,7 +26,6 @@ namespace Ryujinx.Graphics.OpenGL } } - private bool _initialized; private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete; private IShader[] _shaders; @@ -117,15 +112,6 @@ namespace Ryujinx.Graphics.OpenGL public void Bind() { - if (!_initialized) - { - FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra"); - FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale"); - ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale"); - - _initialized = true; - } - GL.UseProgram(Handle); } diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index e1f49065c..478ae4973 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -1,9 +1,7 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.Translation; using System; -using System.Collections.Generic; using System.Linq; namespace Ryujinx.Graphics.Shader.CodeGen.Glsl @@ -159,23 +157,38 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl context.AppendLine(); } - if (context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) - { - if (context.Config.Stage == ShaderStage.Fragment) - { - if (context.Config.GpuAccessor.QueryEarlyZForce()) - { - context.AppendLine("layout(early_fragment_tests) in;"); - context.AppendLine(); - } + bool isFragment = context.Config.Stage == ShaderStage.Fragment; - context.AppendLine($"uniform bool {DefaultNames.IsBgraName}[8];"); + if (isFragment || context.Config.Stage == ShaderStage.Compute) + { + if (isFragment && context.Config.GpuAccessor.QueryEarlyZForce()) + { + context.AppendLine("layout(early_fragment_tests) in;"); context.AppendLine(); } - if (DeclareRenderScale(context)) + if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0) { - context.AppendLine(); + string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage); + + int scaleElements = context.Config.GetTextureDescriptors().Length + context.Config.GetImageDescriptors().Length; + + if (isFragment) + { + scaleElements++; // Also includes render target scale, for gl_FragCoord. + } + + DeclareSupportUniformBlock(context, isFragment, scaleElements); + + if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling)) + { + AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl"); + context.AppendLine(); + } + } + else if (isFragment) + { + DeclareSupportUniformBlock(context, true, 0); } } @@ -498,31 +511,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl } } - private static bool DeclareRenderScale(CodeGenContext context) + private static void DeclareSupportUniformBlock(CodeGenContext context, bool isFragment, int scaleElements) { - if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0) + if (!isFragment && scaleElements == 0) { - string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage); - - int scaleElements = context.Config.GetTextureDescriptors().Length + context.Config.GetImageDescriptors().Length; - - if (context.Config.Stage == ShaderStage.Fragment) - { - scaleElements++; // Also includes render target scale, for gl_FragCoord. - } - - context.AppendLine($"uniform float {stage}_renderScale[{scaleElements}];"); - - if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling)) - { - context.AppendLine(); - AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl"); - } - - return true; + return; } - return false; + context.AppendLine($"layout (binding = 0, std140) uniform {DefaultNames.SupportBlockName}"); + context.EnterScope(); + + if (isFragment) + { + context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};"); + context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];"); + } + else + { + context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];"); + } + + if (scaleElements != 0) + { + context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{scaleElements}];"); + } + + context.LeaveScope(";"); + context.AppendLine(); } private static void AppendHelperFunction(CodeGenContext context, string filename) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs index cd9ca96e5..eaf1050c1 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs @@ -14,6 +14,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl public const string DataName = "data"; + public const string SupportBlockName = "support_block"; + public const string SupportBlockAlphaTestName = "s_alpha_test"; + public const string SupportBlockIsBgraName = "s_is_bgra"; + public const string SupportBlockRenderScaleName = "s_render_scale"; + public const string BlockSuffix = "block"; public const string UniformNamePrefix = "c"; @@ -25,7 +30,5 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl public const string ArgumentNamePrefix = "a"; public const string UndefinedName = "undef"; - - public const string IsBgraName = "is_bgra"; } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl index abc3f4282..4ebade5e3 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl @@ -1,6 +1,6 @@ ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) { - float scale = cp_renderScale[samplerIndex]; + float scale = s_render_scale[samplerIndex]; if (scale == 1.0) { return inputVec; @@ -10,7 +10,7 @@ int Helper_TextureSizeUnscale(int size, int samplerIndex) { - float scale = cp_renderScale[samplerIndex]; + float scale = s_render_scale[samplerIndex]; if (scale == 1.0) { return size; diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl index c13e2368c..5def1390c 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl @@ -1,6 +1,6 @@ ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex) { - float scale = fp_renderScale[1 + samplerIndex]; + float scale = s_render_scale[1 + samplerIndex]; if (scale == 1.0) { return inputVec; @@ -17,7 +17,7 @@ int Helper_TextureSizeUnscale(int size, int samplerIndex) { - float scale = abs(fp_renderScale[1 + samplerIndex]); + float scale = abs(s_render_scale[1 + samplerIndex]); if (scale == 1.0) { return size; diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index 03d282564..03fbb8a41 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -68,14 +68,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { AttributeConsts.LtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLtMaskARB).x", VariableType.U32) }, // Support uniforms. - { AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.IsBgraName}[0]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.IsBgraName}[1]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.IsBgraName}[2]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.IsBgraName}[3]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.IsBgraName}[4]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.IsBgraName}[5]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.IsBgraName}[6]", VariableType.Bool) }, - { AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.IsBgraName}[7]", VariableType.Bool) } + { AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[0]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[1]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[2]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[3]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", VariableType.Bool) }, + { AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", VariableType.Bool) } }; private Dictionary _locals; @@ -194,8 +194,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl { switch (value & ~3) { - case AttributeConsts.PositionX: return "(gl_FragCoord.x / fp_renderScale[0])"; - case AttributeConsts.PositionY: return "(gl_FragCoord.y / fp_renderScale[0])"; + case AttributeConsts.PositionX: return $"(gl_FragCoord.x / {DefaultNames.SupportBlockRenderScaleName}[0])"; + case AttributeConsts.PositionY: return $"(gl_FragCoord.y / {DefaultNames.SupportBlockRenderScaleName}[0])"; case AttributeConsts.PositionZ: return "gl_FragCoord.z"; case AttributeConsts.PositionW: return "gl_FragCoord.w"; } diff --git a/Ryujinx.Graphics.Shader/SupportBuffer.cs b/Ryujinx.Graphics.Shader/SupportBuffer.cs new file mode 100644 index 000000000..78f244011 --- /dev/null +++ b/Ryujinx.Graphics.Shader/SupportBuffer.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.Graphics.Shader +{ + public static class SupportBuffer + { + public const int FieldSize = 16; // Each field takes 16 bytes on default layout, even bool. + + public const int FragmentAlphaTestOffset = 0; + public const int FragmentIsBgraOffset = FieldSize; + public const int FragmentIsBgraCount = 8; + public const int FragmentRenderScaleOffset = FragmentIsBgraOffset + FragmentIsBgraCount * FieldSize; + public const int ComputeRenderScaleOffset = FragmentRenderScaleOffset + FieldSize; // Skip first scale that is used for the render target + + // One for the render target, 32 for the textures, and 8 for the images. + private const int RenderScaleMaxCount = 1 + 32 + 8; + + public const int RequiredSize = FragmentRenderScaleOffset + RenderScaleMaxCount * FieldSize; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs b/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs index 18f4725d5..6751d7ea6 100644 --- a/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs +++ b/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs @@ -7,6 +7,12 @@ namespace Ryujinx.Graphics.Shader.Translation public int TexturesCount { get; private set; } public int ImagesCount { get; private set; } + public TranslationCounts() + { + // The first binding is reserved for the support buffer. + UniformBuffersCount = 1; + } + internal int IncrementUniformBuffersCount() { return UniformBuffersCount++;