mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-10-01 12:30:00 +02:00
Implement BGRA texture support (#1418)
* Implement BGRA texture support * Missing AppendLine * Remove empty lines * Address PR feedback
This commit is contained in:
parent
2678bf0010
commit
8dbcae1ff8
14 changed files with 232 additions and 61 deletions
|
@ -230,6 +230,25 @@ namespace Ryujinx.Graphics.GAL
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the texture format is a BGRA format with 8-bit components.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">Texture format</param>
|
||||||
|
/// <returns>True if the texture format is a BGRA format with 8-bit components, false otherwise</returns>
|
||||||
|
public static bool IsBgra8(this Format format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case Format.B8G8R8X8Unorm:
|
||||||
|
case Format.B8G8R8A8Unorm:
|
||||||
|
case Format.B8G8R8X8Srgb:
|
||||||
|
case Format.B8G8R8A8Srgb:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the texture format is a depth, stencil or depth-stencil format.
|
/// Checks if the texture format is a depth, stencil or depth-stencil format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -164,10 +164,10 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
Add(Format.B5G5R5X1Unorm, new FormatInfo(4, true, false, All.Rgb5, PixelFormat.Bgra, PixelType.UnsignedShort5551));
|
Add(Format.B5G5R5X1Unorm, new FormatInfo(4, true, false, All.Rgb5, PixelFormat.Bgra, PixelType.UnsignedShort5551));
|
||||||
Add(Format.B5G5R5A1Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Bgra, PixelType.UnsignedShort5551));
|
Add(Format.B5G5R5A1Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Bgra, PixelType.UnsignedShort5551));
|
||||||
Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Bgra, PixelType.UnsignedShort1555Reversed));
|
Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Bgra, PixelType.UnsignedShort1555Reversed));
|
||||||
Add(Format.B8G8R8X8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte));
|
Add(Format.B8G8R8X8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||||
Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte));
|
Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||||
Add(Format.B8G8R8X8Srgb, new FormatInfo(4, false, false, All.Srgb8, PixelFormat.BgraInteger, PixelType.UnsignedByte));
|
Add(Format.B8G8R8X8Srgb, new FormatInfo(4, false, false, All.Srgb8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||||
Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.BgraInteger, PixelType.UnsignedByte));
|
Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Add(Format format, FormatInfo info)
|
private static void Add(Format format, FormatInfo info)
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
{
|
{
|
||||||
public int Handle { get; protected set; }
|
public int Handle { get; protected set; }
|
||||||
|
|
||||||
protected TextureCreateInfo Info { get; }
|
public TextureCreateInfo Info { get; }
|
||||||
|
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
|
@ -11,6 +11,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
private int _srcFramebuffer;
|
private int _srcFramebuffer;
|
||||||
private int _dstFramebuffer;
|
private int _dstFramebuffer;
|
||||||
|
|
||||||
|
private int _copyPboHandle;
|
||||||
|
private int _copyPboSize;
|
||||||
|
|
||||||
public TextureCopy(Renderer renderer)
|
public TextureCopy(Renderer renderer)
|
||||||
{
|
{
|
||||||
_renderer = renderer;
|
_renderer = renderer;
|
||||||
|
@ -23,12 +26,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
Extents2D dstRegion,
|
Extents2D dstRegion,
|
||||||
bool linearFilter)
|
bool linearFilter)
|
||||||
{
|
{
|
||||||
|
TextureView srcConverted = src.Format.IsBgra8() != dst.Format.IsBgra8() ? BgraSwap(src) : src;
|
||||||
|
|
||||||
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
|
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
|
||||||
|
|
||||||
Attach(FramebufferTarget.ReadFramebuffer, src.Format, src.Handle);
|
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle);
|
||||||
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle);
|
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle);
|
||||||
|
|
||||||
ClearBufferMask mask = GetMask(src.Format);
|
ClearBufferMask mask = GetMask(src.Format);
|
||||||
|
@ -68,6 +73,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
|
|
||||||
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
||||||
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
||||||
|
|
||||||
|
if (srcConverted != src)
|
||||||
|
{
|
||||||
|
srcConverted.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Attach(FramebufferTarget target, Format format, int handle)
|
private static void Attach(FramebufferTarget target, Format format, int handle)
|
||||||
|
@ -117,6 +127,52 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
format == Format.D32Float;
|
format == Format.D32Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TextureView BgraSwap(TextureView from)
|
||||||
|
{
|
||||||
|
TextureView to = (TextureView)_renderer.CreateTexture(from.Info, 1f);
|
||||||
|
|
||||||
|
EnsurePbo(from);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPboHandle);
|
||||||
|
|
||||||
|
from.WriteToPbo(0, forceBgra: true);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
|
||||||
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPboHandle);
|
||||||
|
|
||||||
|
to.ReadFromPbo(0, _copyPboSize);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
|
||||||
|
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsurePbo(TextureView view)
|
||||||
|
{
|
||||||
|
int requiredSize = 0;
|
||||||
|
|
||||||
|
for (int level = 0; level < view.Info.Levels; level++)
|
||||||
|
{
|
||||||
|
requiredSize += view.Info.GetMipSize(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_copyPboSize < requiredSize && _copyPboHandle != 0)
|
||||||
|
{
|
||||||
|
GL.DeleteBuffer(_copyPboHandle);
|
||||||
|
|
||||||
|
_copyPboHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_copyPboHandle == 0)
|
||||||
|
{
|
||||||
|
_copyPboHandle = GL.GenBuffer();
|
||||||
|
_copyPboSize = requiredSize;
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPboHandle);
|
||||||
|
GL.BufferData(BufferTarget.PixelPackBuffer, requiredSize, IntPtr.Zero, BufferUsageHint.DynamicCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int GetSrcFramebufferLazy()
|
private int GetSrcFramebufferLazy()
|
||||||
{
|
{
|
||||||
if (_srcFramebuffer == 0)
|
if (_srcFramebuffer == 0)
|
||||||
|
@ -152,6 +208,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
|
|
||||||
_dstFramebuffer = 0;
|
_dstFramebuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_copyPboHandle != 0)
|
||||||
|
{
|
||||||
|
GL.DeleteBuffer(_copyPboHandle);
|
||||||
|
|
||||||
|
_copyPboHandle = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
(int)Info.SwizzleA.Convert()
|
(int)Info.SwizzleA.Convert()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Info.Format.IsBgra8())
|
||||||
|
{
|
||||||
|
// Swap B <-> R for BGRA formats, as OpenGL has no support for them
|
||||||
|
// and we need to manually swap the components on read/write on the GPU.
|
||||||
|
int temp = swizzleRgba[0];
|
||||||
|
swizzleRgba[0] = swizzleRgba[2];
|
||||||
|
swizzleRgba[2] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
|
GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
|
||||||
|
|
||||||
int maxLevel = Info.Levels - 1;
|
int maxLevel = Info.Levels - 1;
|
||||||
|
@ -189,7 +198,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteTo(IntPtr ptr)
|
public void WriteToPbo(int offset, bool forceBgra)
|
||||||
|
{
|
||||||
|
WriteTo(IntPtr.Zero + offset, forceBgra);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTo(IntPtr data, bool forceBgra = false)
|
||||||
{
|
{
|
||||||
TextureTarget target = Target.Convert();
|
TextureTarget target = Target.Convert();
|
||||||
|
|
||||||
|
@ -197,6 +211,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
|
|
||||||
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
|
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
|
||||||
|
|
||||||
|
PixelFormat pixelFormat = format.PixelFormat;
|
||||||
|
PixelType pixelType = format.PixelType;
|
||||||
|
|
||||||
|
if (forceBgra)
|
||||||
|
{
|
||||||
|
pixelFormat = PixelFormat.Bgra;
|
||||||
|
}
|
||||||
|
|
||||||
int faces = 1;
|
int faces = 1;
|
||||||
|
|
||||||
if (target == TextureTarget.TextureCubeMap)
|
if (target == TextureTarget.TextureCubeMap)
|
||||||
|
@ -214,20 +236,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
|
|
||||||
if (format.IsCompressed)
|
if (format.IsCompressed)
|
||||||
{
|
{
|
||||||
GL.GetCompressedTexImage(target + face, level, ptr + faceOffset);
|
GL.GetCompressedTexImage(target + face, level, data + faceOffset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL.GetTexImage(
|
GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
|
||||||
target + face,
|
|
||||||
level,
|
|
||||||
format.PixelFormat,
|
|
||||||
format.PixelType,
|
|
||||||
ptr + faceOffset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += Info.GetMipSize(level);
|
data += Info.GetMipSize(level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,12 +254,17 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = data)
|
fixed (byte* ptr = data)
|
||||||
{
|
{
|
||||||
SetData((IntPtr)ptr, data.Length);
|
ReadFrom((IntPtr)ptr, data.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetData(IntPtr data, int size)
|
public void ReadFromPbo(int offset, int size)
|
||||||
|
{
|
||||||
|
ReadFrom(IntPtr.Zero + offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadFrom(IntPtr data, int size)
|
||||||
{
|
{
|
||||||
TextureTarget target = Target.Convert();
|
TextureTarget target = Target.Convert();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
private int _boundDrawFramebuffer;
|
private int _boundDrawFramebuffer;
|
||||||
private int _boundReadFramebuffer;
|
private int _boundReadFramebuffer;
|
||||||
|
|
||||||
|
private int[] _fpIsBgra = new int[8];
|
||||||
private float[] _fpRenderScale = new float[33];
|
private float[] _fpRenderScale = new float[33];
|
||||||
private float[] _cpRenderScale = new float[32];
|
private float[] _cpRenderScale = new float[32];
|
||||||
|
|
||||||
|
@ -765,6 +766,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
_program.Bind();
|
_program.Bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateFpIsBgra();
|
||||||
SetRenderTargetScale(_fpRenderScale[0]);
|
SetRenderTargetScale(_fpRenderScale[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,12 +816,15 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
TextureView color = (TextureView)colors[index];
|
TextureView color = (TextureView)colors[index];
|
||||||
|
|
||||||
_framebuffer.AttachColor(index, color);
|
_framebuffer.AttachColor(index, color);
|
||||||
|
|
||||||
|
_fpIsBgra[index] = color != null && color.Format.IsBgra8() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateFpIsBgra();
|
||||||
|
|
||||||
TextureView depthStencilView = (TextureView)depthStencil;
|
TextureView depthStencilView = (TextureView)depthStencil;
|
||||||
|
|
||||||
_framebuffer.AttachDepthStencil(depthStencilView);
|
_framebuffer.AttachDepthStencil(depthStencilView);
|
||||||
|
|
||||||
_framebuffer.SetDrawBuffers(colors.Length);
|
_framebuffer.SetDrawBuffers(colors.Length);
|
||||||
|
|
||||||
_hasDepthBuffer = depthStencil != null && depthStencilView.Format != Format.S8Uint;
|
_hasDepthBuffer = depthStencil != null && depthStencilView.Format != Format.S8Uint;
|
||||||
|
@ -938,7 +943,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
if (activeTarget != null && activeTarget.Width / (float)texture.Width == activeTarget.Height / (float)texture.Height)
|
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)
|
// 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;
|
interpolate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1112,6 +1119,14 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
return (_boundDrawFramebuffer, _boundReadFramebuffer);
|
return (_boundDrawFramebuffer, _boundReadFramebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateFpIsBgra()
|
||||||
|
{
|
||||||
|
if (_program != null)
|
||||||
|
{
|
||||||
|
GL.Uniform1(_program.FragmentIsBgraUniform, 8, _fpIsBgra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateDepthTest()
|
private void UpdateDepthTest()
|
||||||
{
|
{
|
||||||
// Enabling depth operations is only valid when we have
|
// Enabling depth operations is only valid when we have
|
||||||
|
@ -1137,6 +1152,29 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void PrepareForDispatch()
|
private void PrepareForDispatch()
|
||||||
{
|
{
|
||||||
if (_unit0Texture != null)
|
if (_unit0Texture != null)
|
||||||
|
@ -1230,28 +1268,5 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
_framebuffer?.Dispose();
|
_framebuffer?.Dispose();
|
||||||
_vertexArray?.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
|
public int FragmentIsBgraUniform { get; }
|
||||||
public int FragmentRenderScaleUniform { get; }
|
public int FragmentRenderScaleUniform { get; }
|
||||||
public int ComputeRenderScaleUniform { get; }
|
public int ComputeRenderScaleUniform { get; }
|
||||||
|
|
||||||
|
@ -218,6 +219,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra");
|
||||||
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
|
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
|
||||||
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
|
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
|
||||||
|
|
||||||
|
TextureView viewConverted = view.Format.IsBgra8() ? _renderer.TextureCopy.BgraSwap(view) : view;
|
||||||
|
|
||||||
GL.FramebufferTexture(
|
GL.FramebufferTexture(
|
||||||
FramebufferTarget.ReadFramebuffer,
|
FramebufferTarget.ReadFramebuffer,
|
||||||
FramebufferAttachment.ColorAttachment0,
|
FramebufferAttachment.ColorAttachment0,
|
||||||
view.Handle,
|
viewConverted.Handle,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||||
|
@ -138,6 +140,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
|
||||||
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
|
||||||
|
|
||||||
|
if (viewConverted != view)
|
||||||
|
{
|
||||||
|
viewConverted.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetCopyFramebufferHandleLazy()
|
private int GetCopyFramebufferHandleLazy()
|
||||||
|
|
|
@ -139,6 +139,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
if (context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute)
|
if (context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute)
|
||||||
{
|
{
|
||||||
|
if (context.Config.Stage == ShaderStage.Fragment)
|
||||||
|
{
|
||||||
|
context.AppendLine($"uniform bool {DefaultNames.IsBgraName}[8];");
|
||||||
|
context.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
if (DeclareRenderScale(context))
|
if (DeclareRenderScale(context))
|
||||||
{
|
{
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
|
|
|
@ -23,5 +23,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
public const string SharedMemoryName = "shared_mem";
|
public const string SharedMemoryName = "shared_mem";
|
||||||
|
|
||||||
public const string UndefinedName = "undef";
|
public const string UndefinedName = "undef";
|
||||||
|
|
||||||
|
public const string IsBgraName = "is_bgra";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,6 +64,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{ AttributeConsts.GtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGtMaskARB).x", VariableType.U32) },
|
{ AttributeConsts.GtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGtMaskARB).x", VariableType.U32) },
|
||||||
{ AttributeConsts.LeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLeMaskARB).x", VariableType.U32) },
|
{ AttributeConsts.LeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLeMaskARB).x", VariableType.U32) },
|
||||||
{ AttributeConsts.LtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLtMaskARB).x", VariableType.U32) },
|
{ AttributeConsts.LtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLtMaskARB).x", VariableType.U32) },
|
||||||
|
|
||||||
|
// Support uniforms.
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.IsBgraName}[0]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.IsBgraName}[1]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.IsBgraName}[2]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.IsBgraName}[3]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.IsBgraName}[4]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.IsBgraName}[5]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.IsBgraName}[6]", VariableType.Bool) },
|
||||||
|
{ AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.IsBgraName}[7]", VariableType.Bool) }
|
||||||
};
|
};
|
||||||
|
|
||||||
private Dictionary<AstOperand, string> _locals;
|
private Dictionary<AstOperand, string> _locals;
|
||||||
|
@ -149,8 +159,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
||||||
|
|
||||||
if (value >= AttributeConsts.UserAttributeBase &&
|
if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||||
value < AttributeConsts.UserAttributeEnd)
|
|
||||||
{
|
{
|
||||||
value -= AttributeConsts.UserAttributeBase;
|
value -= AttributeConsts.UserAttributeBase;
|
||||||
|
|
||||||
|
@ -169,8 +178,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (value >= AttributeConsts.FragmentOutputColorBase &&
|
if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
|
||||||
value < AttributeConsts.FragmentOutputColorEnd)
|
|
||||||
{
|
{
|
||||||
value -= AttributeConsts.FragmentOutputColorBase;
|
value -= AttributeConsts.FragmentOutputColorBase;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
public const int FragmentOutputColorBase = 0x1000010;
|
public const int FragmentOutputColorBase = 0x1000010;
|
||||||
public const int FragmentOutputColorEnd = FragmentOutputColorBase + 8 * 16;
|
public const int FragmentOutputColorEnd = FragmentOutputColorBase + 8 * 16;
|
||||||
|
|
||||||
|
public const int FragmentOutputIsBgraBase = 0x1000100;
|
||||||
|
public const int FragmentOutputIsBgraEnd = FragmentOutputIsBgraBase + 8 * 4;
|
||||||
|
|
||||||
public const int ThreadIdX = 0x2000000;
|
public const int ThreadIdX = 0x2000000;
|
||||||
public const int ThreadIdY = 0x2000004;
|
public const int ThreadIdY = 0x2000004;
|
||||||
public const int ThreadIdZ = 0x2000008;
|
public const int ThreadIdZ = 0x2000008;
|
||||||
|
|
|
@ -115,22 +115,46 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
int regIndex = 0;
|
int regIndex = 0;
|
||||||
|
|
||||||
for (int attachment = 0; attachment < 8; attachment++)
|
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
|
||||||
{
|
{
|
||||||
OmapTarget target = Config.OmapTargets[attachment];
|
OmapTarget target = Config.OmapTargets[rtIndex];
|
||||||
|
|
||||||
for (int component = 0; component < 4; component++)
|
for (int component = 0; component < 4; component++)
|
||||||
{
|
{
|
||||||
if (target.ComponentEnabled(component))
|
if (!target.ComponentEnabled(component))
|
||||||
{
|
{
|
||||||
Operand dest = Attribute(AttributeConsts.FragmentOutputColorBase + attachment * 16 + component * 4);
|
continue;
|
||||||
|
|
||||||
Operand src = Register(regIndex, RegisterType.Gpr);
|
|
||||||
|
|
||||||
this.Copy(dest, src);
|
|
||||||
|
|
||||||
regIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16;
|
||||||
|
|
||||||
|
Operand src = Register(regIndex, RegisterType.Gpr);
|
||||||
|
|
||||||
|
// Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
|
||||||
|
if (component == 0 || component == 2)
|
||||||
|
{
|
||||||
|
Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);
|
||||||
|
|
||||||
|
Operand lblIsBgra = Label();
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
this.BranchIfTrue(lblIsBgra, isBgra);
|
||||||
|
|
||||||
|
this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
|
||||||
|
this.Branch(lblEnd);
|
||||||
|
|
||||||
|
MarkLabel(lblIsBgra);
|
||||||
|
|
||||||
|
this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src);
|
||||||
|
|
||||||
|
MarkLabel(lblEnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
|
||||||
|
}
|
||||||
|
|
||||||
|
regIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue