diff options
Diffstat (limited to 'Ryujinx.Graphics.OpenGL')
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureBase.cs | 11 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs | 8 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureCopyUnscaled.cs | 11 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs | 42 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Image/TextureView.cs | 15 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Pipeline.cs | 84 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Program.cs | 6 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Renderer.cs | 4 | ||||
| -rw-r--r-- | Ryujinx.Graphics.OpenGL/Window.cs | 13 |
9 files changed, 157 insertions, 37 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs index a4209ea1..dfb81642 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs @@ -1,5 +1,6 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Graphics.GAL; +using System; namespace Ryujinx.Graphics.OpenGL.Image { @@ -9,15 +10,19 @@ namespace Ryujinx.Graphics.OpenGL.Image protected TextureCreateInfo Info { get; } - public int Width => Info.Width; - public int Height => Info.Height; + public int Width { get; } + public int Height { get; } + public float ScaleFactor { get; } public Target Target => Info.Target; public Format Format => Info.Format; - public TextureBase(TextureCreateInfo info) + public TextureBase(TextureCreateInfo info, float scaleFactor = 1f) { Info = info; + Width = (int)Math.Ceiling(Info.Width * scaleFactor); + Height = (int)Math.Ceiling(Info.Height * scaleFactor); + ScaleFactor = scaleFactor; Handle = GL.GenTexture(); } diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs index db9ff41c..e89d5614 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs @@ -33,6 +33,11 @@ namespace Ryujinx.Graphics.OpenGL.Image ClearBufferMask mask = GetMask(src.Format); + if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInteger()) + { + linearFilter = false; + } + BlitFramebufferFilter filter = linearFilter ? BlitFramebufferFilter.Linear : BlitFramebufferFilter.Nearest; @@ -55,6 +60,9 @@ namespace Ryujinx.Graphics.OpenGL.Image mask, filter); + Attach(FramebufferTarget.ReadFramebuffer, src.Format, 0); + Attach(FramebufferTarget.DrawFramebuffer, dst.Format, 0); + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureCopyUnscaled.cs b/Ryujinx.Graphics.OpenGL/Image/TextureCopyUnscaled.cs index 28401138..02ae3b58 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureCopyUnscaled.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureCopyUnscaled.cs @@ -15,15 +15,16 @@ namespace Ryujinx.Graphics.OpenGL.Image int srcLayer, int dstLayer, int srcLevel, - int dstLevel) + int dstLevel, + float scaleFactor = 1f) { - int srcWidth = srcInfo.Width; - int srcHeight = srcInfo.Height; + int srcWidth = (int)Math.Ceiling(srcInfo.Width * scaleFactor); + int srcHeight = (int)Math.Ceiling(srcInfo.Height * scaleFactor); int srcDepth = srcInfo.GetDepthOrLayers(); int srcLevels = srcInfo.Levels; - int dstWidth = dstInfo.Width; - int dstHeight = dstInfo.Height; + int dstWidth = (int)Math.Ceiling(dstInfo.Width * scaleFactor); + int dstHeight = (int)Math.Ceiling(dstInfo.Height * scaleFactor); int dstDepth = dstInfo.GetDepthOrLayers(); int dstLevels = dstInfo.Levels; diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs b/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs index baf8e65d..4fc0a77f 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureStorage.cs @@ -1,12 +1,14 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; +using System; namespace Ryujinx.Graphics.OpenGL.Image { class TextureStorage { public int Handle { get; private set; } + public float ScaleFactor { get; private set; } public TextureCreateInfo Info { get; } @@ -14,12 +16,13 @@ namespace Ryujinx.Graphics.OpenGL.Image private int _viewsCount; - public TextureStorage(Renderer renderer, TextureCreateInfo info) + public TextureStorage(Renderer renderer, TextureCreateInfo info, float scaleFactor) { _renderer = renderer; Info = info; Handle = GL.GenTexture(); + ScaleFactor = scaleFactor; CreateImmutableStorage(); } @@ -32,6 +35,9 @@ namespace Ryujinx.Graphics.OpenGL.Image GL.BindTexture(target, Handle); + int width = (int)Math.Ceiling(Info.Width * ScaleFactor); + int height = (int)Math.Ceiling(Info.Height * ScaleFactor); + FormatInfo format = FormatTable.GetFormatInfo(Info.Format); SizedInternalFormat internalFormat; @@ -52,7 +58,7 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget1d.Texture1D, Info.Levels, internalFormat, - Info.Width); + width); break; case Target.Texture1DArray: @@ -60,8 +66,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget2d.Texture1DArray, Info.Levels, internalFormat, - Info.Width, - Info.Height); + width, + height); break; case Target.Texture2D: @@ -69,8 +75,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget2d.Texture2D, Info.Levels, internalFormat, - Info.Width, - Info.Height); + width, + height); break; case Target.Texture2DArray: @@ -78,8 +84,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget3d.Texture2DArray, Info.Levels, internalFormat, - Info.Width, - Info.Height, + width, + height, Info.Depth); break; @@ -88,8 +94,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTargetMultisample2d.Texture2DMultisample, Info.Samples, internalFormat, - Info.Width, - Info.Height, + width, + height, true); break; @@ -98,8 +104,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTargetMultisample3d.Texture2DMultisampleArray, Info.Samples, internalFormat, - Info.Width, - Info.Height, + width, + height, Info.Depth, true); break; @@ -109,8 +115,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget3d.Texture3D, Info.Levels, internalFormat, - Info.Width, - Info.Height, + width, + height, Info.Depth); break; @@ -119,8 +125,8 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureTarget2d.TextureCubeMap, Info.Levels, internalFormat, - Info.Width, - Info.Height); + width, + height); break; case Target.CubemapArray: @@ -128,8 +134,8 @@ namespace Ryujinx.Graphics.OpenGL.Image (TextureTarget3d)All.TextureCubeMapArray, Info.Levels, internalFormat, - Info.Width, - Info.Height, + width, + height, Info.Depth); break; diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs index 0b24a296..02353ffa 100644 --- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs +++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.OpenGL.Image TextureStorage parent, TextureCreateInfo info, int firstLayer, - int firstLevel) : base(info) + int firstLevel) : base(info, parent.ScaleFactor) { _renderer = renderer; _parent = parent; @@ -101,7 +101,7 @@ namespace Ryujinx.Graphics.OpenGL.Image // So we emulate that here with a texture copy (see the first CopyTo overload). // However right now it only does a single copy right after the view is created, // so it doesn't work for all cases. - TextureView emulatedView = (TextureView)_renderer.CreateTexture(info); + TextureView emulatedView = (TextureView)_renderer.CreateTexture(info, ScaleFactor); emulatedView._emulatedViewParent = this; @@ -122,10 +122,10 @@ namespace Ryujinx.Graphics.OpenGL.Image { if (_incompatibleFormatView == null) { - _incompatibleFormatView = (TextureView)_renderer.CreateTexture(Info); + _incompatibleFormatView = (TextureView)_renderer.CreateTexture(Info, ScaleFactor); } - TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView.Info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0); + TextureCopyUnscaled.Copy(_parent.Info, _incompatibleFormatView.Info, _parent.Handle, _incompatibleFormatView.Handle, FirstLayer, 0, FirstLevel, 0, ScaleFactor); return _incompatibleFormatView.Handle; } @@ -137,7 +137,7 @@ namespace Ryujinx.Graphics.OpenGL.Image { if (_incompatibleFormatView != null) { - TextureCopyUnscaled.Copy(_incompatibleFormatView.Info, _parent.Info, _incompatibleFormatView.Handle, _parent.Handle, 0, FirstLayer, 0, FirstLevel); + TextureCopyUnscaled.Copy(_incompatibleFormatView.Info, _parent.Info, _incompatibleFormatView.Handle, _parent.Handle, 0, FirstLayer, 0, FirstLevel, ScaleFactor); } } @@ -145,7 +145,7 @@ namespace Ryujinx.Graphics.OpenGL.Image { TextureView destinationView = (TextureView)destination; - TextureCopyUnscaled.Copy(Info, destinationView.Info, Handle, destinationView.Handle, 0, firstLayer, 0, firstLevel); + TextureCopyUnscaled.Copy(Info, destinationView.Info, Handle, destinationView.Handle, 0, firstLayer, 0, firstLevel, ScaleFactor); if (destinationView._emulatedViewParent != null) { @@ -157,7 +157,8 @@ namespace Ryujinx.Graphics.OpenGL.Image 0, destinationView.FirstLayer, 0, - destinationView.FirstLevel); + destinationView.FirstLevel, + ScaleFactor); } } diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs index 6c511e09..62e5394e 100644 --- a/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -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; + } + } + } } } diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs index fe14e9a9..8b4f6e24 100644 --- a/Ryujinx.Graphics.OpenGL/Program.cs +++ b/Ryujinx.Graphics.OpenGL/Program.cs @@ -21,6 +21,9 @@ namespace Ryujinx.Graphics.OpenGL public int Handle { get; private set; } + public int FragmentRenderScaleUniform { get; } + public int ComputeRenderScaleUniform { get; } + public bool IsLinked { get; private set; } private int[] _ubBindingPoints; @@ -162,6 +165,9 @@ namespace Ryujinx.Graphics.OpenGL imageUnit++; } } + + FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale"); + ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale"); } public void Bind() diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs index 49dba9cc..cf90f81f 100644 --- a/Ryujinx.Graphics.OpenGL/Renderer.cs +++ b/Ryujinx.Graphics.OpenGL/Renderer.cs @@ -54,9 +54,9 @@ namespace Ryujinx.Graphics.OpenGL return new Sampler(info); } - public ITexture CreateTexture(TextureCreateInfo info) + public ITexture CreateTexture(TextureCreateInfo info, float scaleFactor) { - return info.Target == Target.TextureBuffer ? new TextureBuffer(info) : new TextureStorage(this, info).CreateDefaultView(); + return info.Target == Target.TextureBuffer ? new TextureBuffer(info) : new TextureStorage(this, info, scaleFactor).CreateDefaultView(); } public void DeleteBuffer(BufferHandle buffer) diff --git a/Ryujinx.Graphics.OpenGL/Window.cs b/Ryujinx.Graphics.OpenGL/Window.cs index 6da9e715..b7dc3784 100644 --- a/Ryujinx.Graphics.OpenGL/Window.cs +++ b/Ryujinx.Graphics.OpenGL/Window.cs @@ -65,11 +65,12 @@ namespace Ryujinx.Graphics.OpenGL GL.Clear(ClearBufferMask.ColorBufferBit); int srcX0, srcX1, srcY0, srcY1; + float scale = view.ScaleFactor; if (crop.Left == 0 && crop.Right == 0) { srcX0 = 0; - srcX1 = view.Width; + srcX1 = (int)(view.Width / scale); } else { @@ -80,7 +81,7 @@ namespace Ryujinx.Graphics.OpenGL if (crop.Top == 0 && crop.Bottom == 0) { srcY0 = 0; - srcY1 = view.Height; + srcY1 = (int)(view.Height / scale); } else { @@ -88,6 +89,14 @@ namespace Ryujinx.Graphics.OpenGL srcY1 = crop.Bottom; } + if (scale != 1f) + { + srcX0 = (int)(srcX0 * scale); + srcY0 = (int)(srcY0 * scale); + srcX1 = (int)Math.Ceiling(srcX1 * scale); + srcY1 = (int)Math.Ceiling(srcY1 * scale); + } + float ratioX = MathF.Min(1f, (_height * (float)NativeWidth) / ((float)NativeHeight * _width)); float ratioY = MathF.Min(1f, (_width * (float)NativeHeight) / ((float)NativeWidth * _height)); |
