Implement Zero-Configuration Resolution Scaling (#1365)

* Initial implementation of Render Target Scaling

Works with most games I have. No GUI option right now, it is hardcoded.

Missing handling for texelFetch operation.

* Realtime Configuration, refactoring.

* texelFetch scaling on fragment shader (WIP)

* Improve Shader-Side changes.

* Fix potential crash when no color/depth bound

* Workaround random uses of textures in compute.

This was blacklisting textures in a few games despite causing no bugs. Will eventually add full support so this doesn't break anything.

* Fix scales oscillating when changing between non-native scales.

* Scaled textures on compute, cleanup, lazier uniform update.

* Cleanup.

* Fix stupidity

* Address Thog Feedback.

* Cover most of GDK's feedback (two comments remain)

* Fix bad rename

* Move IsDepthStencil to FormatExtensions, add docs.

* Fix default config, square texture detection.

* Three final fixes:

- Nearest copy when texture is integer format.
- Texture2D -> Texture3D copy correctly blacklists the texture before trying an unscaled copy (caused driver error)
- Discount small textures.

* Remove scale threshold.

Not needed right now - we'll see if we run into problems.

* All CPU modification blacklists scale.

* Fix comment.
This commit is contained in:
riperiperi 2020-07-07 03:41:07 +01:00 committed by GitHub
parent 43b78ae157
commit 484eb645ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1163 additions and 131 deletions

View file

@ -31,7 +31,12 @@ namespace Ryujinx.Graphics.OpenGL
private int _boundDrawFramebuffer;
private int _boundReadFramebuffer;
private float[] _fpRenderScale = new float[33];
private float[] _cpRenderScale = new float[32];
private TextureBase _unit0Texture;
private TextureBase _rtColor0Texture;
private TextureBase _rtDepthTexture;
private ClipOrigin _clipOrigin;
private ClipDepthMode _clipDepthMode;
@ -54,6 +59,16 @@ 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;
}
}
public void Barrier()
@ -685,6 +700,8 @@ namespace Ryujinx.Graphics.OpenGL
{
_program = (Program)program;
_program.Bind();
SetRenderTargetScale(_fpRenderScale[0]);
}
public void SetRasterizerDiscard(bool discard)
@ -701,6 +718,16 @@ namespace Ryujinx.Graphics.OpenGL
_rasterizerDiscard = discard;
}
public void SetRenderTargetScale(float scale)
{
_fpRenderScale[0] = scale;
if (_program != null && _program.FragmentRenderScaleUniform != -1)
{
GL.Uniform1(_program.FragmentRenderScaleUniform, 1, _fpRenderScale); // Just the first element.
}
}
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
{
for (int index = 0; index < componentMasks.Length; index++)
@ -715,6 +742,9 @@ namespace Ryujinx.Graphics.OpenGL
{
EnsureFramebuffer();
_rtColor0Texture = (TextureBase)colors[0];
_rtDepthTexture = (TextureBase)depthStencil;
for (int index = 0; index < colors.Length; index++)
{
TextureView color = (TextureView)colors[index];
@ -826,6 +856,37 @@ namespace Ryujinx.Graphics.OpenGL
{
((TextureBase)texture).Bind(unit);
}
// Update scale factor for bound textures.
switch (stage)
{
case ShaderStage.Fragment:
if (_program.FragmentRenderScaleUniform != -1)
{
// Only update and send sampled texture scales if the shader uses them.
bool interpolate = false;
float scale = texture.ScaleFactor;
if (scale != 1)
{
TextureBase activeTarget = _rtColor0Texture ?? _rtDepthTexture;
if (activeTarget != null && activeTarget.Width / (float)texture.Width == activeTarget.Height / (float)texture.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)
interpolate = true;
}
}
_fpRenderScale[index + 1] = interpolate ? -scale : scale;
}
break;
case ShaderStage.Compute:
_cpRenderScale[index] = texture.ScaleFactor;
break;
}
}
}
@ -1089,5 +1150,28 @@ namespace Ryujinx.Graphics.OpenGL
_framebuffer?.Dispose();
_vertexArray?.Dispose();
}
public void UpdateRenderScale(ShaderStage stage, int textureCount)
{
if (_program != null)
{
switch (stage)
{
case ShaderStage.Fragment:
if (_program.FragmentRenderScaleUniform != -1)
{
GL.Uniform1(_program.FragmentRenderScaleUniform, textureCount + 1, _fpRenderScale);
}
break;
case ShaderStage.Compute:
if (_program.ComputeRenderScaleUniform != -1)
{
GL.Uniform1(_program.ComputeRenderScaleUniform, textureCount, _cpRenderScale);
}
break;
}
}
}
}
}