Allow copy destination to have a different scale from source (#1711)

* Allow copy destination to have a different scale from source

Will result in more scaled copy destinations, but allows scaling in some games that copy textures to the output framebuffer.

* Support copying multiple levels/layers

Uses glFramebufferTextureLayer to copy multiple layers, copies levels individually (and scales the regions).

Remove CopyArrayScaled, since the backend copy handles it now.
This commit is contained in:
riperiperi 2020-11-20 20:14:45 +00:00 committed by GitHub
parent cf7044e37b
commit 9493cdfe55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 99 additions and 98 deletions

View file

@ -34,38 +34,61 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle);
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
int layers = Math.Min(src.Info.GetLayers(), dst.Info.GetLayers());
ClearBufferMask mask = GetMask(src.Format);
if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInteger())
for (int level = 0; level < levels; level++)
{
linearFilter = false;
for (int layer = 0; layer < layers; layer++)
{
if (layers > 1)
{
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level, layer);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level, layer);
}
else
{
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level);
}
ClearBufferMask mask = GetMask(src.Format);
if ((mask & (ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit)) != 0 || src.Format.IsInteger())
{
linearFilter = false;
}
BlitFramebufferFilter filter = linearFilter
? BlitFramebufferFilter.Linear
: BlitFramebufferFilter.Nearest;
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.Disable(EnableCap.RasterizerDiscard);
GL.Disable(IndexedEnableCap.ScissorTest, 0);
GL.BlitFramebuffer(
srcRegion.X1,
srcRegion.Y1,
srcRegion.X2,
srcRegion.Y2,
dstRegion.X1,
dstRegion.Y1,
dstRegion.X2,
dstRegion.Y2,
mask,
filter);
}
if (level < levels - 1)
{
srcRegion = srcRegion.Reduce(1);
dstRegion = dstRegion.Reduce(1);
}
}
BlitFramebufferFilter filter = linearFilter
? BlitFramebufferFilter.Linear
: BlitFramebufferFilter.Nearest;
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.Disable(EnableCap.RasterizerDiscard);
GL.Disable(IndexedEnableCap.ScissorTest, 0);
GL.BlitFramebuffer(
srcRegion.X1,
srcRegion.Y1,
srcRegion.X2,
srcRegion.Y2,
dstRegion.X1,
dstRegion.Y1,
dstRegion.X2,
dstRegion.Y2,
mask,
filter);
Attach(FramebufferTarget.ReadFramebuffer, src.Format, 0);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, 0);
@ -191,26 +214,40 @@ namespace Ryujinx.Graphics.OpenGL.Image
}
}
private static void Attach(FramebufferTarget target, Format format, int handle)
private static FramebufferAttachment AttachmentForFormat(Format format)
{
if (format == Format.D24UnormS8Uint || format == Format.D32FloatS8Uint)
{
GL.FramebufferTexture(target, FramebufferAttachment.DepthStencilAttachment, handle, 0);
return FramebufferAttachment.DepthStencilAttachment;
}
else if (IsDepthOnly(format))
{
GL.FramebufferTexture(target, FramebufferAttachment.DepthAttachment, handle, 0);
return FramebufferAttachment.DepthAttachment;
}
else if (format == Format.S8Uint)
{
GL.FramebufferTexture(target, FramebufferAttachment.StencilAttachment, handle, 0);
return FramebufferAttachment.StencilAttachment;
}
else
{
GL.FramebufferTexture(target, FramebufferAttachment.ColorAttachment0, handle, 0);
return FramebufferAttachment.ColorAttachment0;
}
}
private static void Attach(FramebufferTarget target, Format format, int handle, int level = 0)
{
FramebufferAttachment attachment = AttachmentForFormat(format);
GL.FramebufferTexture(target, attachment, handle, level);
}
private static void Attach(FramebufferTarget target, Format format, int handle, int level, int layer)
{
FramebufferAttachment attachment = AttachmentForFormat(format);
GL.FramebufferTextureLayer(target, attachment, handle, level, layer);
}
private static ClearBufferMask GetMask(Format format)
{
if (format == Format.D24UnormS8Uint || format == Format.D32FloatS8Uint)