aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Image
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2020-11-02 19:53:23 +0000
committerGitHub <noreply@github.com>2020-11-02 16:53:23 -0300
commite1da7df2075f45ac3d19538f7781115978282100 (patch)
treed46ae3ffedd2886adba64f1044b699f99b13f795 /Ryujinx.Graphics.Gpu/Image
parent11a7c99764ed4e6c575c877c69ca627645702a42 (diff)
Support res scale on images, correctly blacklist for SUST, move logic out of backend. (#1657)
* Support res scale on images, correctly blacklist for SUST, move logic out of backend. * Fix Typo
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image')
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs121
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureManager.cs9
2 files changed, 111 insertions, 19 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index e70b0933..08c4082e 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -41,6 +41,9 @@ namespace Ryujinx.Graphics.Gpu.Image
private bool _rebind;
+ private float[] _scales;
+ private bool _scaleChanged;
+
/// <summary>
/// Constructs a new instance of the texture bindings manager.
/// </summary>
@@ -60,6 +63,13 @@ namespace Ryujinx.Graphics.Gpu.Image
_textureState = new TextureStatePerStage[stages][];
_imageState = new TextureStatePerStage[stages][];
+
+ _scales = new float[64];
+
+ for (int i = 0; i < 64; i++)
+ {
+ _scales[i] = 1f;
+ }
}
/// <summary>
@@ -132,6 +142,81 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Updates the texture scale for a given texture or image.
+ /// </summary>
+ /// <param name="texture">Start GPU virtual address of the pool</param>
+ /// <param name="binding">The related texture binding</param>
+ /// <param name="index">The texture/image binding index</param>
+ /// <param name="stage">The active shader stage</param>
+ /// <returns>True if the given texture has become blacklisted, indicating that its host texture may have changed.</returns>
+ private bool UpdateScale(Texture texture, TextureBindingInfo binding, int index, ShaderStage stage)
+ {
+ float result = 1f;
+ bool changed = false;
+
+ if ((binding.Flags & TextureUsageFlags.NeedsScaleValue) != 0 && texture != null)
+ {
+ _scaleChanged |= true;
+
+ switch (stage)
+ {
+ case ShaderStage.Fragment:
+ if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
+ {
+ changed |= texture.ScaleMode != TextureScaleMode.Blacklisted;
+ texture.BlacklistScale();
+ break;
+ }
+
+ float scale = texture.ScaleFactor;
+
+ TextureManager manager = _context.Methods.TextureManager;
+
+ if (scale != 1)
+ {
+ Texture activeTarget = manager.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;
+
+ case ShaderStage.Compute:
+ if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
+ {
+ changed |= texture.ScaleMode != TextureScaleMode.Blacklisted;
+ texture.BlacklistScale();
+ }
+
+ result = texture.ScaleFactor;
+ break;
+ }
+ }
+
+ _scales[index] = result;
+ return changed;
+ }
+
+ /// <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)
+ {
+ if (_scaleChanged)
+ {
+ _context.Renderer.Pipeline.UpdateRenderScale(stage, _scales, _textureBindings[stageIndex]?.Length ?? 0, _imageBindings[stageIndex]?.Length ?? 0);
+ }
+ }
+
+ /// <summary>
/// Ensures that the bindings are visible to the host GPU.
/// Note: this actually performs the binding using the host graphics API.
/// </summary>
@@ -145,6 +230,8 @@ namespace Ryujinx.Graphics.Gpu.Image
{
CommitTextureBindings(texturePool, ShaderStage.Compute, 0);
CommitImageBindings (texturePool, ShaderStage.Compute, 0);
+
+ CommitRenderScale(ShaderStage.Compute, 0);
}
else
{
@@ -154,6 +241,8 @@ namespace Ryujinx.Graphics.Gpu.Image
CommitTextureBindings(texturePool, stage, stageIndex);
CommitImageBindings (texturePool, stage, stageIndex);
+
+ CommitRenderScale(stage, stageIndex);
}
}
@@ -174,8 +263,6 @@ namespace Ryujinx.Graphics.Gpu.Image
return;
}
- bool changed = false;
-
for (int index = 0; index < _textureBindings[stageIndex].Length; index++)
{
TextureBindingInfo binding = _textureBindings[stageIndex][index];
@@ -218,20 +305,18 @@ namespace Ryujinx.Graphics.Gpu.Image
Texture texture = pool.Get(textureId);
- if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
- {
- texture?.BlacklistScale();
- }
-
ITexture hostTexture = texture?.GetTargetTexture(binding.Target);
if (_textureState[stageIndex][index].Texture != hostTexture || _rebind)
{
+ if (UpdateScale(texture, binding, index, stage))
+ {
+ hostTexture = texture?.GetTargetTexture(binding.Target);
+ }
+
_textureState[stageIndex][index].Texture = hostTexture;
_context.Renderer.Pipeline.SetTexture(index, stage, hostTexture);
-
- changed = true;
}
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
@@ -253,11 +338,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_context.Renderer.Pipeline.SetSampler(index, stage, hostSampler);
}
}
-
- if (changed)
- {
- _context.Renderer.Pipeline.UpdateRenderScale(stage, _textureBindings[stageIndex].Length);
- }
}
/// <summary>
@@ -274,6 +354,9 @@ namespace Ryujinx.Graphics.Gpu.Image
return;
}
+ // Scales for images appear after the texture ones.
+ int baseScaleIndex = _textureBindings[stageIndex]?.Length ?? 0;
+
for (int index = 0; index < _imageBindings[stageIndex].Length; index++)
{
TextureBindingInfo binding = _imageBindings[stageIndex][index];
@@ -283,11 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Image
Texture texture = pool.Get(textureId);
- if ((binding.Flags & TextureUsageFlags.ResScaleUnsupported) != 0)
- {
- texture?.BlacklistScale();
- }
-
ITexture hostTexture = texture?.GetTargetTexture(binding.Target);
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
@@ -300,6 +378,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
{
+ if (UpdateScale(texture, binding, baseScaleIndex + index, stage))
+ {
+ hostTexture = texture?.GetTargetTexture(binding.Target);
+ }
+
_imageState[stageIndex][index].Texture = hostTexture;
Format format = binding.Format;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 7588258f..08398cb6 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -195,6 +195,15 @@ namespace Ryujinx.Graphics.Gpu.Image
}
/// <summary>
+ /// Gets the first available bound colour target, or the depth stencil target if not present.
+ /// </summary>
+ /// <returns>The first bound colour target, otherwise the depth stencil target</returns>
+ public Texture GetAnyRenderTarget()
+ {
+ return _rtColors[0] ?? _rtDepthStencil;
+ }
+
+ /// <summary>
/// Updates the Render Target scale, given the currently bound render targets.
/// This will update scale to match the configured scale, scale textures that are eligible but not scaled,
/// and propagate blacklisted status from one texture to the ones bound with it.