aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs2
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs14
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs4
-rw-r--r--Ryujinx.Graphics.GAL/SupportBufferUpdater.cs93
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs90
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs2
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs58
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs2
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs31
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs1
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl2
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl20
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs6
-rw-r--r--Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj5
-rw-r--r--Ryujinx.Graphics.Shader/ShaderStage.cs13
-rw-r--r--Ryujinx.Graphics.Shader/SupportBuffer.cs53
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs2
17 files changed, 286 insertions, 112 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index b7da2c21..c02f84d4 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -104,6 +104,6 @@ namespace Ryujinx.Graphics.GAL
bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual);
void EndHostConditionalRendering();
- void UpdateRenderScale(ShaderStage stage, ReadOnlySpan<float> scales, int textureCount, int imageCount);
+ void UpdateRenderScale(ReadOnlySpan<float> scales, int totalCount, int fragmentCount);
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
index fafb52a8..7e1e66b2 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
@@ -6,22 +6,20 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
struct UpdateRenderScaleCommand : IGALCommand
{
public CommandType CommandType => CommandType.UpdateRenderScale;
- private ShaderStage _stage;
private SpanRef<float> _scales;
- private int _textureCount;
- private int _imageCount;
+ private int _totalCount;
+ private int _fragmentCount;
- public void Set(ShaderStage stage, SpanRef<float> scales, int textureCount, int imageCount)
+ public void Set(SpanRef<float> scales, int totalCount, int fragmentCount)
{
- _stage = stage;
_scales = scales;
- _textureCount = textureCount;
- _imageCount = imageCount;
+ _totalCount = totalCount;
+ _fragmentCount = fragmentCount;
}
public static void Run(ref UpdateRenderScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
- renderer.Pipeline.UpdateRenderScale(command._stage, command._scales.Get(threaded), command._textureCount, command._imageCount);
+ renderer.Pipeline.UpdateRenderScale(command._scales.Get(threaded), command._totalCount, command._fragmentCount);
command._scales.Dispose(threaded);
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index 63a29b1b..6dc8ef38 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -353,9 +353,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return false;
}
- public void UpdateRenderScale(ShaderStage stage, ReadOnlySpan<float> scales, int textureCount, int imageCount)
+ public void UpdateRenderScale(ReadOnlySpan<float> scales, int totalCount, int fragmentCount)
{
- _renderer.New<UpdateRenderScaleCommand>().Set(stage, _renderer.CopySpan(scales.Slice(0, textureCount + imageCount)), textureCount, imageCount);
+ _renderer.New<UpdateRenderScaleCommand>().Set(_renderer.CopySpan(scales.Slice(0, totalCount)), totalCount, fragmentCount);
_renderer.QueueCommand();
}
}
diff --git a/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
new file mode 100644
index 00000000..cb24bdd7
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/SupportBufferUpdater.cs
@@ -0,0 +1,93 @@
+using Ryujinx.Graphics.Shader;
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.GAL
+{
+ public class SupportBufferUpdater : IDisposable
+ {
+ public SupportBuffer Data;
+ public BufferHandle Handle;
+
+ private IRenderer _renderer;
+ private int _startOffset = -1;
+ private int _endOffset = -1;
+
+ public SupportBufferUpdater(IRenderer renderer)
+ {
+ _renderer = renderer;
+ Handle = renderer.CreateBuffer(SupportBuffer.RequiredSize);
+ }
+
+ private void MarkDirty(int startOffset, int byteSize)
+ {
+ int endOffset = startOffset + byteSize;
+
+ if (_startOffset == -1)
+ {
+ _startOffset = startOffset;
+ _endOffset = endOffset;
+ }
+ else
+ {
+ if (startOffset < _startOffset)
+ {
+ _startOffset = startOffset;
+ }
+
+ if (endOffset > _endOffset)
+ {
+ _endOffset = endOffset;
+ }
+ }
+ }
+
+ public void UpdateFragmentRenderScaleCount(int count)
+ {
+ if (Data.FragmentRenderScaleCount.X != count)
+ {
+ Data.FragmentRenderScaleCount.X = count;
+
+ MarkDirty(SupportBuffer.FragmentRenderScaleCountOffset, sizeof(int));
+ }
+ }
+
+ private void UpdateGenericField<T>(int baseOffset, ReadOnlySpan<T> data, Span<T> target, int offset, int count) where T : unmanaged
+ {
+ data.Slice(0, count).CopyTo(target.Slice(offset));
+
+ int elemSize = Unsafe.SizeOf<T>();
+
+ MarkDirty(baseOffset + offset * elemSize, count * elemSize);
+ }
+
+ public void UpdateRenderScale(ReadOnlySpan<Vector4<float>> data, int offset, int count)
+ {
+ UpdateGenericField(SupportBuffer.GraphicsRenderScaleOffset, data, Data.RenderScale.ToSpan(), offset, count);
+ }
+
+ public void UpdateFragmentIsBgra(ReadOnlySpan<Vector4<int>> data, int offset, int count)
+ {
+ UpdateGenericField(SupportBuffer.FragmentIsBgraOffset, data, Data.FragmentIsBgra.ToSpan(), offset, count);
+ }
+
+ public void Commit()
+ {
+ if (_startOffset != -1)
+ {
+ ReadOnlySpan<byte> data = MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref Data, 1));
+
+ _renderer.SetBufferData(Handle, _startOffset, data.Slice(_startOffset, _endOffset - _startOffset));
+
+ _startOffset = -1;
+ _endOffset = -1;
+ }
+ }
+
+ public void Dispose()
+ {
+ _renderer.DeleteBuffer(Handle);
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index dea918cd..97a9eee4 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -232,42 +232,44 @@ namespace Ryujinx.Graphics.Gpu.Image
if ((binding.Flags & TextureUsageFlags.NeedsScaleValue) != 0 && texture != null)
{
- switch (stage)
+ if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
{
- case ShaderStage.Fragment:
- if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
- {
- changed |= texture.ScaleMode != TextureScaleMode.Blacklisted;
- texture.BlacklistScale();
- break;
- }
-
- float scale = texture.ScaleFactor;
-
- if (scale != 1)
- {
- Texture activeTarget = _channel.TextureManager.GetAnyRenderTarget();
+ changed = texture.ScaleMode != TextureScaleMode.Blacklisted;
+ texture.BlacklistScale();
+ }
+ else
+ {
+ switch (stage)
+ {
+ case ShaderStage.Fragment:
+ float scale = texture.ScaleFactor;
- if (activeTarget != null && activeTarget.Info.Width / (float)texture.Info.Width == activeTarget.Info.Height / (float)texture.Info.Height)
+ if (scale != 1)
{
- // If the texture's size is a multiple of the sampler size, enable interpolation using gl_FragCoord. (helps "invent" new integer values between scaled pixels)
- result = -scale;
- break;
+ Texture activeTarget = _channel.TextureManager.GetAnyRenderTarget();
+
+ if (activeTarget != null && (activeTarget.Info.Width / (float)texture.Info.Width) == (activeTarget.Info.Height / (float)texture.Info.Height))
+ {
+ // If the texture's size is a multiple of the sampler size, enable interpolation using gl_FragCoord. (helps "invent" new integer values between scaled pixels)
+ result = -scale;
+ break;
+ }
}
- }
- result = scale;
- break;
+ result = scale;
+ break;
- case ShaderStage.Compute:
- if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
- {
- changed |= texture.ScaleMode != TextureScaleMode.Blacklisted;
- texture.BlacklistScale();
- }
+ case ShaderStage.Vertex:
+ int fragmentIndex = (int)ShaderStage.Fragment - 1;
+ index += _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
+
+ result = texture.ScaleFactor;
+ break;
- result = texture.ScaleFactor;
- break;
+ case ShaderStage.Compute:
+ result = texture.ScaleFactor;
+ break;
+ }
}
}
@@ -284,13 +286,29 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Uploads texture and image scales to the backend when they are used.
/// </summary>
- /// <param name="stage">Current shader stage</param>
- /// <param name="stageIndex">Shader stage index</param>
- private void CommitRenderScale(ShaderStage stage, int stageIndex)
+ private void CommitRenderScale()
{
if (_scaleChanged)
{
- _context.Renderer.Pipeline.UpdateRenderScale(stage, _scales, _textureBindingsCount[stageIndex], _imageBindingsCount[stageIndex]);
+ int fragmentTotal = 0;
+ int total;
+
+ if (!_isCompute)
+ {
+ int fragmentIndex = (int)ShaderStage.Fragment - 1;
+ fragmentTotal = _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
+
+ int vertexIndex = (int)ShaderStage.Vertex - 1;
+ int vertexTotal = _textureBindingsCount[vertexIndex] + _imageBindingsCount[vertexIndex];
+
+ total = fragmentTotal + vertexTotal;
+ }
+ else
+ {
+ total = _textureBindingsCount[0] + _imageBindingsCount[0];
+ }
+
+ _context.Renderer.Pipeline.UpdateRenderScale(_scales, total, fragmentTotal);
_scaleChanged = false;
}
@@ -312,8 +330,6 @@ namespace Ryujinx.Graphics.Gpu.Image
{
CommitTextureBindings(texturePool, ShaderStage.Compute, 0);
CommitImageBindings (texturePool, ShaderStage.Compute, 0);
-
- CommitRenderScale(ShaderStage.Compute, 0);
}
else
{
@@ -323,11 +339,11 @@ namespace Ryujinx.Graphics.Gpu.Image
CommitTextureBindings(texturePool, stage, stageIndex);
CommitImageBindings (texturePool, stage, stageIndex);
-
- CommitRenderScale(stage, stageIndex);
}
}
+ CommitRenderScale();
+
_rebind = false;
}
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 32a1e4bd..acd65621 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,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 = 2885;
+ private const ulong ShaderCodeGenVersion = 2764;
// Progress reporting helpers
private volatile int _shaderCount;
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index aafc4db8..6d6e0745 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -43,16 +43,9 @@ namespace Ryujinx.Graphics.OpenGL
private CounterQueueEvent _activeConditionalRender;
- 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 int _fragmentScaleCount;
private TextureBase _unit0Texture;
private Sampler _unit0Sampler;
@@ -68,7 +61,7 @@ namespace Ryujinx.Graphics.OpenGL
private bool _tfEnabled;
private TransformFeedbackPrimitiveType _tfTopology;
- private BufferHandle _supportBuffer;
+ private SupportBufferUpdater _supportBuffer;
private readonly BufferHandle[] _tfbs;
private readonly BufferRange[] _tfbTargets;
@@ -95,13 +88,13 @@ namespace Ryujinx.Graphics.OpenGL
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
}
- public void Initialize()
+ public void Initialize(Renderer renderer)
{
- _supportBuffer = Buffer.Create(SupportBuffer.RequiredSize);
- GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, Unsafe.As<BufferHandle, int>(ref _supportBuffer));
+ _supportBuffer = new SupportBufferUpdater(renderer);
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, Unsafe.As<BufferHandle, int>(ref _supportBuffer.Handle));
- SetSupportBufferData<Vector4<int>>(SupportBuffer.FragmentIsBgraOffset, _fpIsBgra, SupportBuffer.FragmentIsBgraCount);
- SetSupportBufferData<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, SupportBuffer.RenderScaleMaxCount);
+ _supportBuffer.UpdateFragmentIsBgra(_fpIsBgra, 0, SupportBuffer.FragmentIsBgraCount);
+ _supportBuffer.UpdateRenderScale(_renderScale, 0, SupportBuffer.RenderScaleMaxCount);
}
public void Barrier()
@@ -558,6 +551,8 @@ namespace Ryujinx.Graphics.OpenGL
{
if (texture is TextureView view && sampler is Sampler samp)
{
+ _supportBuffer.Commit();
+
if (HwCapabilities.SupportsDrawTexture)
{
GL.NV.DrawTexture(
@@ -1038,7 +1033,7 @@ namespace Ryujinx.Graphics.OpenGL
public void SetRenderTargetScale(float scale)
{
_renderScale[0].X = scale;
- SetSupportBufferData<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1); // Just the first element.
+ _supportBuffer.UpdateRenderScale(_renderScale, 0, 1); // Just the first element.
}
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
@@ -1076,7 +1071,7 @@ namespace Ryujinx.Graphics.OpenGL
if (isBgraChanged)
{
- SetSupportBufferData<Vector4<int>>(SupportBuffer.FragmentIsBgraOffset, _fpIsBgra, SupportBuffer.FragmentIsBgraCount);
+ _supportBuffer.UpdateFragmentIsBgra(_fpIsBgra, 0, SupportBuffer.FragmentIsBgraCount);
}
TextureView depthStencilView = (TextureView)depthStencil;
@@ -1384,16 +1379,11 @@ namespace Ryujinx.Graphics.OpenGL
return (_boundDrawFramebuffer, _boundReadFramebuffer);
}
- public void UpdateRenderScale(ShaderStage stage, ReadOnlySpan<float> scales, int textureCount, int imageCount)
+ public void UpdateRenderScale(ReadOnlySpan<float> scales, int totalCount, int fragmentCount)
{
- if (stage != ShaderStage.Compute && stage != ShaderStage.Fragment)
- {
- return;
- }
-
bool changed = false;
- for (int index = 0; index < textureCount + imageCount; index++)
+ for (int index = 0; index < totalCount; index++)
{
if (_renderScale[1 + index].X != scales[index])
{
@@ -1402,20 +1392,23 @@ namespace Ryujinx.Graphics.OpenGL
}
}
- if (changed)
+ // Only update fragment count if there are scales after it for the vertex stage.
+ if (fragmentCount != totalCount && fragmentCount != _fragmentScaleCount)
{
- SetSupportBufferData<Vector4<float>>(SupportBuffer.FragmentRenderScaleOffset, _renderScale, 1 + textureCount + imageCount);
+ _fragmentScaleCount = fragmentCount;
+ _supportBuffer.UpdateFragmentRenderScaleCount(_fragmentScaleCount);
}
- }
- private void SetSupportBufferData<T>(int offset, ReadOnlySpan<T> data, int count) where T : unmanaged
- {
- Buffer.SetData(_supportBuffer, offset, MemoryMarshal.Cast<T, byte>(data.Slice(0, count)));
+ if (changed)
+ {
+ _supportBuffer.UpdateRenderScale(_renderScale, 0, 1 + totalCount);
+ }
}
private void PrepareForDispatch()
{
_unit0Texture?.Bind(0);
+ _supportBuffer.Commit();
}
private void PreDraw()
@@ -1424,6 +1417,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.Validate();
_unit0Texture?.Bind(0);
+ _supportBuffer.Commit();
}
private void PostDraw()
@@ -1521,11 +1515,7 @@ namespace Ryujinx.Graphics.OpenGL
public void Dispose()
{
- if (_supportBuffer != BufferHandle.Null)
- {
- Buffer.Delete(_supportBuffer);
- _supportBuffer = BufferHandle.Null;
- }
+ _supportBuffer?.Dispose();
for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
{
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 0c16ec5a..7806157d 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -151,7 +151,7 @@ namespace Ryujinx.Graphics.OpenGL
GL.Arb.MaxShaderCompilerThreads(Math.Min(Environment.ProcessorCount, 8));
}
- _pipeline.Initialize();
+ _pipeline.Initialize(this);
_counters.Initialize();
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 7dcd1671..d8956567 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -208,7 +208,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
bool isFragment = context.Config.Stage == ShaderStage.Fragment;
- if (isFragment || context.Config.Stage == ShaderStage.Compute)
+ if (isFragment || context.Config.Stage == ShaderStage.Compute || context.Config.Stage == ShaderStage.Vertex)
{
if (isFragment && context.Config.GpuAccessor.QueryEarlyZForce())
{
@@ -227,7 +227,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
scaleElements++; // Also includes render target scale, for gl_FragCoord.
}
- DeclareSupportUniformBlock(context, isFragment, scaleElements);
+ DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling))
{
@@ -237,7 +237,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
else if (isFragment)
{
- DeclareSupportUniformBlock(context, true, 0);
+ DeclareSupportUniformBlock(context, context.Config.Stage, 0);
}
}
@@ -591,8 +591,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine($"patch out vec4 {name};");
}
- private static void DeclareSupportUniformBlock(CodeGenContext context, bool isFragment, int scaleElements)
+ private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
{
+ bool isFragment = stage == ShaderStage.Fragment;
if (!isFragment && scaleElements == 0)
{
return;
@@ -601,20 +602,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
context.AppendLine($"layout (binding = 0, std140) uniform {DefaultNames.SupportBlockName}");
context.EnterScope();
- if (isFragment)
+ switch (stage)
{
- context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
- context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
- }
- else
- {
- context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];");
+ case ShaderStage.Fragment:
+ case ShaderStage.Vertex:
+ context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
+ context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
+ context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};");
+ break;
+ case ShaderStage.Compute:
+ context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];");
+ break;
}
- if (scaleElements != 0)
- {
- context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{scaleElements}];");
- }
+ context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{SupportBuffer.RenderScaleMaxCount}];");
context.LeaveScope(";");
context.AppendLine();
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
index 47350408..76203522 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
@@ -18,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string SupportBlockName = "support_block";
public const string SupportBlockAlphaTestName = "s_alpha_test";
public const string SupportBlockIsBgraName = "s_is_bgra";
+ public const string SupportBlockFragmentScaleCount = "s_frag_scale_count";
public const string SupportBlockRenderScaleName = "s_render_scale";
public const string BlockSuffix = "block";
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl
index 5def1390..6c670f91 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_fp.glsl
@@ -7,7 +7,7 @@
}
if (scale < 0.0) // If less than 0, try interpolate between texels by using the screen position.
{
- return ivec2(vec2(inputVec) * (-scale) + mod(gl_FragCoord.xy, -scale));
+ return ivec2(vec2(inputVec) * (-scale) + mod(gl_FragCoord.xy, 0.0 - scale));
}
else
{
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl
new file mode 100644
index 00000000..19eb119d
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_vp.glsl
@@ -0,0 +1,20 @@
+ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
+{
+ float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
+ if (scale == 1.0)
+ {
+ return inputVec;
+ }
+
+ return ivec2(vec2(inputVec) * scale);
+}
+
+int Helper_TextureSizeUnscale(int size, int samplerIndex)
+{
+ float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
+ if (scale == 1.0)
+ {
+ return size;
+ }
+ return int(float(size) / scale);
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index abca03aa..164de7bb 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
string ApplyScaling(string vector)
{
- if ((context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) &&
+ if ((context.Config.Stage.SupportsRenderScale()) &&
texOp.Inst == Instruction.ImageLoad &&
!isBindless &&
!isIndexed)
@@ -621,7 +621,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
if (intCoords)
{
- if ((context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) &&
+ if ((context.Config.Stage.SupportsRenderScale()) &&
!isBindless &&
!isIndexed)
{
@@ -770,7 +770,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
string texCall = $"textureSize({samplerName}, {lodExpr}){GetMask(texOp.Index)}";
- if ((context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) &&
+ if (context.Config.Stage.SupportsRenderScale() &&
!isBindless &&
!isIndexed)
{
diff --git a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
index c604902f..81cc0caf 100644
--- a/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
+++ b/Ryujinx.Graphics.Shader/Ryujinx.Graphics.Shader.csproj
@@ -5,6 +5,10 @@
</PropertyGroup>
<ItemGroup>
+ <None Remove="CodeGen\Glsl\HelperFunctions\TexelFetchScale_vp.glsl" />
+ </ItemGroup>
+
+ <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
</ItemGroup>
@@ -20,6 +24,7 @@
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreSharedSmallInt.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreStorageSmallInt.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\SwizzleAdd.glsl" />
+ <EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_vp.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_fp.glsl" />
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_cp.glsl" />
</ItemGroup>
diff --git a/Ryujinx.Graphics.Shader/ShaderStage.cs b/Ryujinx.Graphics.Shader/ShaderStage.cs
index 63e3b068..f16fe328 100644
--- a/Ryujinx.Graphics.Shader/ShaderStage.cs
+++ b/Ryujinx.Graphics.Shader/ShaderStage.cs
@@ -11,4 +11,17 @@ namespace Ryujinx.Graphics.Shader
Count
}
+
+ public static class ShaderStageExtensions
+ {
+ /// <summary>
+ /// Checks if the shader stage supports render scale.
+ /// </summary>
+ /// <param name="stage">Shader stage</param>
+ /// <returns>True if the shader stage supports render scale, false otherwise</returns>
+ public static bool SupportsRenderScale(this ShaderStage stage)
+ {
+ return stage == ShaderStage.Vertex || stage == ShaderStage.Fragment || stage == ShaderStage.Compute;
+ }
+ }
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/SupportBuffer.cs b/Ryujinx.Graphics.Shader/SupportBuffer.cs
index f76d2c92..47a47ea6 100644
--- a/Ryujinx.Graphics.Shader/SupportBuffer.cs
+++ b/Ryujinx.Graphics.Shader/SupportBuffer.cs
@@ -1,18 +1,55 @@
+using Ryujinx.Common.Memory;
+using System.Runtime.CompilerServices;
+
namespace Ryujinx.Graphics.Shader
{
- public static class SupportBuffer
+ public struct Vector4<T>
{
- public const int FieldSize = 16; // Each field takes 16 bytes on default layout, even bool.
+ public T X;
+ public T Y;
+ public T Z;
+ public T W;
+ }
- 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
+ public struct SupportBuffer
+ {
+ public static int FieldSize;
+ public static int RequiredSize;
+
+ public static int FragmentAlphaTestOffset;
+ public static int FragmentIsBgraOffset;
+ public static int FragmentRenderScaleCountOffset;
+ public static int GraphicsRenderScaleOffset;
+ public static int ComputeRenderScaleOffset;
+ public const int FragmentIsBgraCount = 8;
// One for the render target, 32 for the textures, and 8 for the images.
public const int RenderScaleMaxCount = 1 + 32 + 8;
- public const int RequiredSize = FragmentRenderScaleOffset + RenderScaleMaxCount * FieldSize;
+ private static int OffsetOf<T>(ref SupportBuffer storage, ref T target)
+ {
+ return (int)Unsafe.ByteOffset(ref Unsafe.As<SupportBuffer, T>(ref storage), ref target);
+ }
+
+ static SupportBuffer()
+ {
+ FieldSize = Unsafe.SizeOf<Vector4<float>>();
+ RequiredSize = Unsafe.SizeOf<SupportBuffer>();
+
+ SupportBuffer instance = new SupportBuffer();
+
+ FragmentAlphaTestOffset = OffsetOf(ref instance, ref instance.FragmentAlphaTest);
+ FragmentIsBgraOffset = OffsetOf(ref instance, ref instance.FragmentIsBgra);
+ FragmentRenderScaleCountOffset = OffsetOf(ref instance, ref instance.FragmentRenderScaleCount);
+ GraphicsRenderScaleOffset = OffsetOf(ref instance, ref instance.RenderScale);
+ ComputeRenderScaleOffset = GraphicsRenderScaleOffset + FieldSize;
+ }
+
+ public Vector4<int> FragmentAlphaTest;
+ public Array8<Vector4<int>> FragmentIsBgra;
+ public Vector4<int> FragmentRenderScaleCount;
+
+ // Render scale max count: 1 + 32 + 8. First scale is fragment output scale, others are textures/image inputs.
+ public Array41<Vector4<float>> RenderScale;
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index df14a5ed..9d5a4070 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -413,7 +413,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{
usageFlags |= TextureUsageFlags.NeedsScaleValue;
- var canScale = (Stage == ShaderStage.Fragment || Stage == ShaderStage.Compute) && !isIndexed && !write && dimensions == 2;
+ var canScale = Stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2;
if (!canScale)
{