6634d3ef87
Removes a bug introduced in v1.2.3: the DLSS clip-space jitter block was emitted into every vertex shader and read the Position output before writing it. Reading an unwritten output is undefined, so vertex positions could come out as garbage - whole 3D passes landing nowhere (the green screen reported on GYLT, Ghostbusters, Blair Witch and others) and the black block artifacts in Xenoblade Chronicles 2's motion-blur pass, which had been mistaken for a long-standing emulation defect and worked around by disabling the effect. With jitter off - how this fork ships - the vertex epilogue is now identical to the base emulator again, and the motion blur no longer needs to be disabled. CodeGenVersion bumped so existing shader caches are rebuilt. Also adds a DLSS sharpening slider (0-100, off by default) and an experimental advanced motion stack checkbox (off by default).
242 lines
6.7 KiB
C#
242 lines
6.7 KiB
C#
using OpenTK.Graphics.OpenGL;
|
|
using Ryujinx.Graphics.GAL;
|
|
using Ryujinx.Graphics.OpenGL.Image;
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Ryujinx.Graphics.OpenGL
|
|
{
|
|
class Framebuffer : IDisposable
|
|
{
|
|
public int Handle { get; private set; }
|
|
private int _clearFbHandle;
|
|
private bool _clearFbInitialized;
|
|
|
|
private FramebufferAttachment _lastDsAttachment;
|
|
|
|
private readonly TextureView[] _colors;
|
|
private TextureView _depthStencil;
|
|
|
|
private int _colorsCount;
|
|
private bool _dualSourceBlend;
|
|
|
|
public Framebuffer()
|
|
{
|
|
Handle = GL.GenFramebuffer();
|
|
_clearFbHandle = GL.GenFramebuffer();
|
|
|
|
_colors = new TextureView[8];
|
|
}
|
|
|
|
public int Bind()
|
|
{
|
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);
|
|
return Handle;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
// [GLDUMP] (journal 216) zero-alloc accessors for the GL-side chain dump probe.
|
|
public TextureView MvppGetColor(int index)
|
|
{
|
|
return (uint)index < (uint)_colors.Length ? _colors[index] : null;
|
|
}
|
|
|
|
public void AttachColor(int index, TextureView color)
|
|
{
|
|
if (_colors[index] == color)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0 + index;
|
|
|
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, attachment, color?.Handle ?? 0, 0);
|
|
|
|
_colors[index] = color;
|
|
}
|
|
|
|
public void AttachDepthStencil(TextureView depthStencil)
|
|
{
|
|
// Detach the last depth/stencil buffer if there is any.
|
|
if (_lastDsAttachment != 0)
|
|
{
|
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, _lastDsAttachment, 0, 0);
|
|
}
|
|
|
|
if (depthStencil != null)
|
|
{
|
|
FramebufferAttachment attachment = GetAttachment(depthStencil.Format);
|
|
|
|
GL.FramebufferTexture(
|
|
FramebufferTarget.Framebuffer,
|
|
attachment,
|
|
depthStencil.Handle,
|
|
0);
|
|
|
|
_lastDsAttachment = attachment;
|
|
}
|
|
else
|
|
{
|
|
_lastDsAttachment = 0;
|
|
}
|
|
|
|
_depthStencil = depthStencil;
|
|
}
|
|
|
|
public void SetDualSourceBlend(bool enable)
|
|
{
|
|
bool oldEnable = _dualSourceBlend;
|
|
|
|
_dualSourceBlend = enable;
|
|
|
|
// When dual source blend is used,
|
|
// we can only have one draw buffer.
|
|
if (enable)
|
|
{
|
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
|
}
|
|
else if (oldEnable)
|
|
{
|
|
SetDrawBuffersImpl(_colorsCount);
|
|
}
|
|
}
|
|
|
|
public void SetDrawBuffers(int colorsCount)
|
|
{
|
|
if (_colorsCount != colorsCount && !_dualSourceBlend)
|
|
{
|
|
SetDrawBuffersImpl(colorsCount);
|
|
}
|
|
|
|
_colorsCount = colorsCount;
|
|
}
|
|
|
|
private static void SetDrawBuffersImpl(int colorsCount)
|
|
{
|
|
DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[colorsCount];
|
|
|
|
for (int index = 0; index < colorsCount; index++)
|
|
{
|
|
drawBuffers[index] = DrawBuffersEnum.ColorAttachment0 + index;
|
|
}
|
|
|
|
GL.DrawBuffers(colorsCount, drawBuffers);
|
|
}
|
|
|
|
private static FramebufferAttachment GetAttachment(Format format)
|
|
{
|
|
if (FormatTable.IsPackedDepthStencil(format))
|
|
{
|
|
return FramebufferAttachment.DepthStencilAttachment;
|
|
}
|
|
else if (FormatTable.IsDepthOnly(format))
|
|
{
|
|
return FramebufferAttachment.DepthAttachment;
|
|
}
|
|
else
|
|
{
|
|
return FramebufferAttachment.StencilAttachment;
|
|
}
|
|
}
|
|
|
|
public int GetColorLayerCount(int index)
|
|
{
|
|
return _colors[index]?.Info.GetDepthOrLayers() ?? 0;
|
|
}
|
|
|
|
public int GetDepthStencilLayerCount()
|
|
{
|
|
return _depthStencil?.Info.GetDepthOrLayers() ?? 0;
|
|
}
|
|
|
|
public void AttachColorLayerForClear(int index, int layer)
|
|
{
|
|
TextureView color = _colors[index];
|
|
|
|
if (!IsLayered(color))
|
|
{
|
|
return;
|
|
}
|
|
|
|
BindClearFb();
|
|
GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, color.Handle, 0, layer);
|
|
}
|
|
|
|
public void DetachColorLayerForClear(int index)
|
|
{
|
|
TextureView color = _colors[index];
|
|
|
|
if (!IsLayered(color))
|
|
{
|
|
return;
|
|
}
|
|
|
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, 0, 0);
|
|
Bind();
|
|
}
|
|
|
|
public void AttachDepthStencilLayerForClear(int layer)
|
|
{
|
|
TextureView depthStencil = _depthStencil;
|
|
|
|
if (!IsLayered(depthStencil))
|
|
{
|
|
return;
|
|
}
|
|
|
|
BindClearFb();
|
|
GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), depthStencil.Handle, 0, layer);
|
|
}
|
|
|
|
public void DetachDepthStencilLayerForClear()
|
|
{
|
|
TextureView depthStencil = _depthStencil;
|
|
|
|
if (!IsLayered(depthStencil))
|
|
{
|
|
return;
|
|
}
|
|
|
|
GL.FramebufferTexture(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), 0, 0);
|
|
Bind();
|
|
}
|
|
|
|
private void BindClearFb()
|
|
{
|
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _clearFbHandle);
|
|
|
|
if (!_clearFbInitialized)
|
|
{
|
|
SetDrawBuffersImpl(Constants.MaxRenderTargets);
|
|
_clearFbInitialized = true;
|
|
}
|
|
}
|
|
|
|
private static bool IsLayered(TextureView view)
|
|
{
|
|
return view != null &&
|
|
view.Target != Target.Texture1D &&
|
|
view.Target != Target.Texture2D &&
|
|
view.Target != Target.Texture2DMultisample &&
|
|
view.Target != Target.TextureBuffer;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Handle != 0)
|
|
{
|
|
GL.DeleteFramebuffer(Handle);
|
|
|
|
Handle = 0;
|
|
}
|
|
|
|
if (_clearFbHandle != 0)
|
|
{
|
|
GL.DeleteFramebuffer(_clearFbHandle);
|
|
|
|
_clearFbHandle = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|