aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-08-11 16:33:43 -0300
committerGitHub <noreply@github.com>2021-08-11 21:33:43 +0200
commit0f6ec446ea3be41b1c22aa5c3870bd7a6c595d1f (patch)
treee441560dbdd560e9a020bb4b7606d3cd0698da02
parentb5b7e23fc41e7045f9e803d6926e98ec7d049f0c (diff)
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
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs4
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs16
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs193
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs2
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs122
-rw-r--r--Ryujinx.Graphics.OpenGL/Program.cs14
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs75
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs7
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_cp.glsl4
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl4
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs20
-rw-r--r--Ryujinx.Graphics.Shader/SupportBuffer.cs18
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs6
13 files changed, 264 insertions, 221 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index 760ad2ed..b2f9d5cb 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<BufferRange> buffers);
+ void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers);
void SetTexture(int binding, ITexture texture);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
- void SetUniformBuffers(ReadOnlySpan<BufferRange> buffers);
+ void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> 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 4ff084e9..d9484cf6 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 eccc2ca3..855a444f 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
/// </summary>
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<BufferTextureBinding> _bufferTextures;
+ private readonly BufferRange[] _ranges;
/// <summary>
/// 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<BufferTextureBinding>();
+
+ _ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
}
@@ -288,7 +284,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
{
_cpStorageBuffers.SetBindings(descriptors);
- _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
}
/// <summary>
@@ -303,22 +298,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Sets the total number of storage buffer bindings used.
- /// </summary>
- /// <param name="count">Number of storage buffer bindings used</param>
- public void SetGraphicsStorageBufferBindingsCount(int count)
- {
- _gpStorageBufferBindings = count;
- }
-
- /// <summary>
/// Sets the binding points for the uniform buffers bound on the compute pipeline.
/// </summary>
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
{
_cpUniformBuffers.SetBindings(descriptors);
- _cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
}
/// <summary>
@@ -334,15 +319,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Sets the total number of uniform buffer bindings used.
- /// </summary>
- /// <param name="count">Number of uniform buffer bindings used</param>
- public void SetGraphicsUniformBufferBindingsCount(int count)
- {
- _gpUniformBufferBindings = count;
- }
-
- /// <summary>
/// Gets a bit mask indicating which compute uniform buffers are currently bound.
/// </summary>
/// <returns>Mask where each bit set indicates a bound constant buffer</returns>
@@ -381,7 +357,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
return mask;
}
-
/// <summary>
/// Gets the address of the compute uniform buffer currently bound at the given index.
/// </summary>
@@ -409,46 +384,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
public void CommitComputeBindings()
{
- int sCount = _cpStorageBufferBindings;
-
- Span<BufferRange> 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<BufferRange> 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);
- }
- }
+ var bufferCache = _channel.MemoryManager.Physical.BufferCache;
- _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
/// </summary>
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
/// <summary>
/// Bind respective buffer bindings on the host API.
/// </summary>
- /// <param name="bindings">Bindings to bind</param>
- /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param>
- private void BindBuffers(BuffersPerStage[] bindings, bool isStorage)
+ /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
+ /// <param name="bindings">Buffer memory ranges to bind</param>
+ /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
{
- int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings;
+ int rangesFirst = 0;
+ int rangesCount = 0;
- Span<BufferRange> ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count];
+ Span<BufferRange> 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);
+ }
+ }
+
+ /// <summary>
+ /// Bind respective buffer bindings on the host API.
+ /// </summary>
+ /// <param name="bufferCache">Buffer cache holding the buffers for the specified ranges</param>
+ /// <param name="buffers">Buffer memory ranges to bind</param>
+ /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
+ {
+ int rangesFirst = 0;
+ int rangesCount = 0;
+
+ Span<BufferRange> 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);
+ }
+ }
+
+ /// <summary>
+ /// Bind respective buffer bindings on the host API.
+ /// </summary>
+ /// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
+ /// <param name="first">First binding point</param>
+ /// <param name="count">Number of bindings</param>
+ /// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SetHostBuffers(ReadOnlySpan<BufferRange> 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 754449fb..db5a3bff 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- 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 948a8b89..9c39f719 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<T>
+ {
+ public T X;
+ public T Y;
+ public T Z;
+ public T W;
+ }
+
+ private Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
+ private Vector4<float>[] _renderScale = new Vector4<float>[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<float> { X = 0f, Y = 0f, Z = 0f, W = 0f };
+ new Span<Vector4<float>>(_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<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1); // Just the first element.
}
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> 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<Vector4<int>>(SupportBuffer.FragmentIsBgraOffset, _fpIsBgra, SupportBuffer.FragmentIsBgraCount);
+ }
TextureView depthStencilView = (TextureView)depthStencil;
@@ -965,9 +967,9 @@ namespace Ryujinx.Graphics.OpenGL
_stencilFrontMask = stencilTest.FrontMask;
}
- public void SetStorageBuffers(ReadOnlySpan<BufferRange> buffers)
+ public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> 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<BufferRange> buffers)
+ public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> 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<BufferRange> buffers, bool isStorage)
+ private void SetBuffers(int first, ReadOnlySpan<BufferRange> 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;
}
- }
- public void UpdateRenderScale(ShaderStage stage, float[] scales, int textureCount, int imageCount)
- {
- if (_program != null)
+ bool changed = false;
+
+ for (int index = 0; index < textureCount + imageCount; index++)
{
- switch (stage)
+ if (_renderScale[1 + index].X != scales[index])
{
- 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;
+ _renderScale[1 + index].X = scales[index];
+ changed = true;
}
}
+
+ if (changed)
+ {
+ SetSupportBufferData<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1 + textureCount + imageCount);
+ }
+ }
+
+ private void SetSupportBufferData<T>(int offset, ReadOnlySpan<T> data, int count) where T : unmanaged
+ {
+ if (_supportBuffer == BufferHandle.Null)
+ {
+ _supportBuffer = Buffer.Create(SupportBuffer.RequiredSize);
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, Unsafe.As<BufferHandle, int>(ref _supportBuffer));
+ }
+
+ Buffer.SetData(_supportBuffer, offset, MemoryMarshal.Cast<T, byte>(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 decc75b1..785f2f00 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 e1f49065..478ae497 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)
+ bool isFragment = context.Config.Stage == ShaderStage.Fragment;
+
+ if (isFragment || context.Config.Stage == ShaderStage.Compute)
{
- if (context.Config.Stage == ShaderStage.Fragment)
+ if (isFragment && context.Config.GpuAccessor.QueryEarlyZForce())
+ {
+ context.AppendLine("layout(early_fragment_tests) in;");
+ context.AppendLine();
+ }
+
+ if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0)
{
- if (context.Config.GpuAccessor.QueryEarlyZForce())
+ string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+
+ int scaleElements = context.Config.GetTextureDescriptors().Length + context.Config.GetImageDescriptors().Length;
+
+ if (isFragment)
{
- context.AppendLine("layout(early_fragment_tests) in;");
- context.AppendLine();
+ scaleElements++; // Also includes render target scale, for gl_FragCoord.
}
- context.AppendLine($"uniform bool {DefaultNames.IsBgraName}[8];");
- context.AppendLine();
- }
+ DeclareSupportUniformBlock(context, isFragment, scaleElements);
- if (DeclareRenderScale(context))
+ if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
+ {
+ AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
+ context.AppendLine();
+ }
+ }
+ else if (isFragment)
{
- context.AppendLine();
+ 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.
- }
+ return;
+ }
- context.AppendLine($"uniform float {stage}_renderScale[{scaleElements}];");
+ context.AppendLine($"layout (binding = 0, std140) uniform {DefaultNames.SupportBlockName}");
+ context.EnterScope();
- if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
- {
- context.AppendLine();
- AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
- }
+ if (isFragment)
+ {
+ context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
+ context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
+ }
+ else
+ {
+ context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];");
+ }
- return true;
+ if (scaleElements != 0)
+ {
+ context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{scaleElements}];");
}
- return false;
+ 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 cd9ca96e..eaf1050c 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 abc3f428..4ebade5e 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 c13e2368..5def1390 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 03d28256..03fbb8a4 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<AstOperand, string> _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 00000000..78f24401
--- /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 18f4725d..6751d7ea 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++;