forked from Mirror/Ryujinx
7527c5b906
* Avoid clearning alpha channel by handle when presenting Previous code was binding then blitting while the framebuffer was bound and then clearing the alpha channel by its handle. This ended up triggering a bug since AMD driver 21.4.1 ending up clearing the whole framebuffer as a result. New code fix this weird logic by applying the clear on the bound framebuffer. Close #2236. * Address rip's comments * Fix AMD being broken once again
174 lines
5.3 KiB
C#
174 lines
5.3 KiB
C#
using OpenTK.Graphics.OpenGL;
|
|
using Ryujinx.Graphics.GAL;
|
|
using Ryujinx.Graphics.OpenGL.Image;
|
|
using System;
|
|
|
|
namespace Ryujinx.Graphics.OpenGL
|
|
{
|
|
class Window : IWindow, IDisposable
|
|
{
|
|
private readonly Renderer _renderer;
|
|
|
|
private int _width;
|
|
private int _height;
|
|
|
|
private int _copyFramebufferHandle;
|
|
|
|
internal BackgroundContextWorker BackgroundContext { get; private set; }
|
|
|
|
public Window(Renderer renderer)
|
|
{
|
|
_renderer = renderer;
|
|
}
|
|
|
|
public void Present(ITexture texture, ImageCrop crop)
|
|
{
|
|
GL.Disable(EnableCap.FramebufferSrgb);
|
|
|
|
CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop);
|
|
|
|
GL.Enable(EnableCap.FramebufferSrgb);
|
|
}
|
|
|
|
public void SetSize(int width, int height)
|
|
{
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
|
|
private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop)
|
|
{
|
|
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
|
|
|
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
|
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
|
|
|
|
TextureView viewConverted = view.Format.IsBgra8() ? _renderer.TextureCopy.BgraSwap(view) : view;
|
|
|
|
GL.FramebufferTexture(
|
|
FramebufferTarget.ReadFramebuffer,
|
|
FramebufferAttachment.ColorAttachment0,
|
|
viewConverted.Handle,
|
|
0);
|
|
|
|
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
|
|
|
GL.Disable(EnableCap.RasterizerDiscard);
|
|
GL.Disable(IndexedEnableCap.ScissorTest, 0);
|
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
|
|
|
int srcX0, srcX1, srcY0, srcY1;
|
|
float scale = view.ScaleFactor;
|
|
|
|
if (crop.Left == 0 && crop.Right == 0)
|
|
{
|
|
srcX0 = 0;
|
|
srcX1 = (int)(view.Width / scale);
|
|
}
|
|
else
|
|
{
|
|
srcX0 = crop.Left;
|
|
srcX1 = crop.Right;
|
|
}
|
|
|
|
if (crop.Top == 0 && crop.Bottom == 0)
|
|
{
|
|
srcY0 = 0;
|
|
srcY1 = (int)(view.Height / scale);
|
|
}
|
|
else
|
|
{
|
|
srcY0 = crop.Top;
|
|
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 = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _height * crop.AspectRatioX / (_width * crop.AspectRatioY));
|
|
float ratioY = crop.IsStretched ? 1.0f : MathF.Min(1.0f, _width * crop.AspectRatioY / (_height * crop.AspectRatioX));
|
|
|
|
int dstWidth = (int)(_width * ratioX);
|
|
int dstHeight = (int)(_height * ratioY);
|
|
|
|
int dstPaddingX = (_width - dstWidth) / 2;
|
|
int dstPaddingY = (_height - dstHeight) / 2;
|
|
|
|
int dstX0 = crop.FlipX ? _width - dstPaddingX : dstPaddingX;
|
|
int dstX1 = crop.FlipX ? dstPaddingX : _width - dstPaddingX;
|
|
|
|
int dstY0 = crop.FlipY ? dstPaddingY : _height - dstPaddingY;
|
|
int dstY1 = crop.FlipY ? _height - dstPaddingY : dstPaddingY;
|
|
|
|
GL.BlitFramebuffer(
|
|
srcX0,
|
|
srcY0,
|
|
srcX1,
|
|
srcY1,
|
|
dstX0,
|
|
dstY0,
|
|
dstX1,
|
|
dstY1,
|
|
ClearBufferMask.ColorBufferBit,
|
|
BlitFramebufferFilter.Linear);
|
|
|
|
// Remove Alpha channel
|
|
GL.ColorMask(false, false, false, true);
|
|
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
|
|
|
for (int i = 0; i < Constants.MaxRenderTargets; i++)
|
|
{
|
|
((Pipeline)_renderer.Pipeline).RestoreComponentMask(i);
|
|
}
|
|
|
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
|
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
|
|
|
|
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
|
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
|
|
|
if (viewConverted != view)
|
|
{
|
|
viewConverted.Dispose();
|
|
}
|
|
}
|
|
|
|
private int GetCopyFramebufferHandleLazy()
|
|
{
|
|
int handle = _copyFramebufferHandle;
|
|
|
|
if (handle == 0)
|
|
{
|
|
handle = GL.GenFramebuffer();
|
|
|
|
_copyFramebufferHandle = handle;
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
|
{
|
|
BackgroundContext = new BackgroundContextWorker(baseContext);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
BackgroundContext.Dispose();
|
|
|
|
if (_copyFramebufferHandle != 0)
|
|
{
|
|
GL.DeleteFramebuffer(_copyFramebufferHandle);
|
|
|
|
_copyFramebufferHandle = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|