diff options
| author | riperiperi <rhy3756547@hotmail.com> | 2020-11-02 19:53:23 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-02 16:53:23 -0300 |
| commit | e1da7df2075f45ac3d19538f7781115978282100 (patch) | |
| tree | d46ae3ffedd2886adba64f1044b699f99b13f795 /Ryujinx.Graphics.Gpu/Image | |
| parent | 11a7c99764ed4e6c575c877c69ca627645702a42 (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.cs | 121 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 9 |
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. |
