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
This commit is contained in:
parent
b5b7e23fc4
commit
0f6ec446ea
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
@ -302,15 +297,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_gpStorageBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@ -318,7 +304,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_cpUniformBuffers.SetBindings(descriptors);
|
||||
_cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -333,15 +318,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_gpUniformBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@ -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;
|
||||
var bufferCache = _channel.MemoryManager.Physical.BufferCache;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
_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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1 + textureCount + imageCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateRenderScale(ShaderStage stage, float[] scales, int textureCount, int imageCount)
|
||||
private void SetSupportBufferData<T>(int offset, ReadOnlySpan<T> 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<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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
}
|
||||
|
18
Ryujinx.Graphics.Shader/SupportBuffer.cs
Normal file
18
Ryujinx.Graphics.Shader/SupportBuffer.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user