diff --git a/Ryujinx.Graphics.GAL/Format.cs b/Ryujinx.Graphics.GAL/Format.cs
index 19939c38a..a66673614 100644
--- a/Ryujinx.Graphics.GAL/Format.cs
+++ b/Ryujinx.Graphics.GAL/Format.cs
@@ -230,6 +230,25 @@ namespace Ryujinx.Graphics.GAL
return false;
}
+ ///
+ /// Checks if the texture format is a BGRA format with 8-bit components.
+ ///
+ /// Texture format
+ /// True if the texture format is a BGRA format with 8-bit components, false otherwise
+ 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;
+ }
+
///
/// Checks if the texture format is a depth, stencil or depth-stencil format.
///
diff --git a/Ryujinx.Graphics.OpenGL/FormatTable.cs b/Ryujinx.Graphics.OpenGL/FormatTable.cs
index b178553cd..4200ea7e0 100644
--- a/Ryujinx.Graphics.OpenGL/FormatTable.cs
+++ b/Ryujinx.Graphics.OpenGL/FormatTable.cs
@@ -164,10 +164,10 @@ namespace Ryujinx.Graphics.OpenGL
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.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.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte));
- Add(Format.B8G8R8X8Srgb, new FormatInfo(4, false, false, All.Srgb8, PixelFormat.BgraInteger, PixelType.UnsignedByte));
- Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.BgraInteger, 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.Rgba, 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.Rgba, PixelType.UnsignedByte));
}
private static void Add(Format format, FormatInfo info)
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs
index dfb81642c..5f786decc 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
public int Handle { get; protected set; }
- protected TextureCreateInfo Info { get; }
+ public TextureCreateInfo Info { get; }
public int Width { get; }
public int Height { get; }
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
index e89d5614c..edfbec5f8 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs
@@ -11,6 +11,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
private int _srcFramebuffer;
private int _dstFramebuffer;
+ private int _copyPboHandle;
+ private int _copyPboSize;
+
public TextureCopy(Renderer renderer)
{
_renderer = renderer;
@@ -23,12 +26,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
Extents2D dstRegion,
bool linearFilter)
{
+ TextureView srcConverted = src.Format.IsBgra8() != dst.Format.IsBgra8() ? BgraSwap(src) : src;
+
(int oldDrawFramebufferHandle, int oldReadFramebufferHandle) = ((Pipeline)_renderer.Pipeline).GetBoundFramebuffers();
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
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);
ClearBufferMask mask = GetMask(src.Format);
@@ -68,6 +73,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
+
+ if (srcConverted != src)
+ {
+ srcConverted.Dispose();
+ }
}
private static void Attach(FramebufferTarget target, Format format, int handle)
@@ -117,6 +127,52 @@ namespace Ryujinx.Graphics.OpenGL.Image
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()
{
if (_srcFramebuffer == 0)
@@ -152,6 +208,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
_dstFramebuffer = 0;
}
+
+ if (_copyPboHandle != 0)
+ {
+ GL.DeleteBuffer(_copyPboHandle);
+
+ _copyPboHandle = 0;
+ }
}
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
index 02353ffaa..2d50eba5e 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureView.cs
@@ -72,6 +72,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
(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);
int maxLevel = Info.Levels - 1;
@@ -189,7 +198,12 @@ namespace Ryujinx.Graphics.OpenGL.Image
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();
@@ -197,6 +211,14 @@ namespace Ryujinx.Graphics.OpenGL.Image
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
+ PixelFormat pixelFormat = format.PixelFormat;
+ PixelType pixelType = format.PixelType;
+
+ if (forceBgra)
+ {
+ pixelFormat = PixelFormat.Bgra;
+ }
+
int faces = 1;
if (target == TextureTarget.TextureCubeMap)
@@ -214,20 +236,15 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (format.IsCompressed)
{
- GL.GetCompressedTexImage(target + face, level, ptr + faceOffset);
+ GL.GetCompressedTexImage(target + face, level, data + faceOffset);
}
else
{
- GL.GetTexImage(
- target + face,
- level,
- format.PixelFormat,
- format.PixelType,
- ptr + faceOffset);
+ GL.GetTexImage(target + face, level, pixelFormat, pixelType, data + faceOffset);
}
}
- ptr += Info.GetMipSize(level);
+ data += Info.GetMipSize(level);
}
}
@@ -237,12 +254,17 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
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();
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 2016d8524..09ba9be0b 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -31,6 +31,7 @@ namespace Ryujinx.Graphics.OpenGL
private int _boundDrawFramebuffer;
private int _boundReadFramebuffer;
+ private int[] _fpIsBgra = new int[8];
private float[] _fpRenderScale = new float[33];
private float[] _cpRenderScale = new float[32];
@@ -722,12 +723,12 @@ namespace Ryujinx.Graphics.OpenGL
GL.Disable(EnableCap.ProgramPointSize);
}
- GL.PointParameter(origin == Origin.LowerLeft
- ? PointSpriteCoordOriginParameter.LowerLeft
+ GL.PointParameter(origin == Origin.LowerLeft
+ ? PointSpriteCoordOriginParameter.LowerLeft
: PointSpriteCoordOriginParameter.UpperLeft);
// Games seem to set point size to 0 which generates a GL_INVALID_VALUE
- // From the spec, GL_INVALID_VALUE is generated if size is less than or equal to 0.
+ // From the spec, GL_INVALID_VALUE is generated if size is less than or equal to 0.
GL.PointSize(Math.Max(float.Epsilon, size));
}
@@ -765,6 +766,7 @@ namespace Ryujinx.Graphics.OpenGL
_program.Bind();
}
+ UpdateFpIsBgra();
SetRenderTargetScale(_fpRenderScale[0]);
}
@@ -814,12 +816,15 @@ namespace Ryujinx.Graphics.OpenGL
TextureView color = (TextureView)colors[index];
_framebuffer.AttachColor(index, color);
+
+ _fpIsBgra[index] = color != null && color.Format.IsBgra8() ? 1 : 0;
}
+ UpdateFpIsBgra();
+
TextureView depthStencilView = (TextureView)depthStencil;
_framebuffer.AttachDepthStencil(depthStencilView);
-
_framebuffer.SetDrawBuffers(colors.Length);
_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 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;
}
}
@@ -1112,6 +1119,14 @@ namespace Ryujinx.Graphics.OpenGL
return (_boundDrawFramebuffer, _boundReadFramebuffer);
}
+ private void UpdateFpIsBgra()
+ {
+ if (_program != null)
+ {
+ GL.Uniform1(_program.FragmentIsBgraUniform, 8, _fpIsBgra);
+ }
+ }
+
private void UpdateDepthTest()
{
// 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()
{
if (_unit0Texture != null)
@@ -1230,28 +1268,5 @@ 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 a0f8eb015..06f05f67c 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -25,6 +25,7 @@ namespace Ryujinx.Graphics.OpenGL
public int Handle { get; private set; }
+ public int FragmentIsBgraUniform { get; }
public int FragmentRenderScaleUniform { 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");
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
}
diff --git a/Ryujinx.Graphics.OpenGL/Window.cs b/Ryujinx.Graphics.OpenGL/Window.cs
index b7dc37843..a2f4e4ce9 100644
--- a/Ryujinx.Graphics.OpenGL/Window.cs
+++ b/Ryujinx.Graphics.OpenGL/Window.cs
@@ -51,10 +51,12 @@ namespace Ryujinx.Graphics.OpenGL
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,
- view.Handle,
+ viewConverted.Handle,
0);
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
@@ -138,6 +140,11 @@ namespace Ryujinx.Graphics.OpenGL
((Pipeline)_renderer.Pipeline).RestoreScissor0Enable();
((Pipeline)_renderer.Pipeline).RestoreRasterizerDiscard();
+
+ if (viewConverted != view)
+ {
+ viewConverted.Dispose();
+ }
}
private int GetCopyFramebufferHandleLazy()
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index efd30143b..40e277e06 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -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.AppendLine($"uniform bool {DefaultNames.IsBgraName}[8];");
+ context.AppendLine();
+ }
+
if (DeclareRenderScale(context))
{
context.AppendLine();
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
index 4da38b2de..d1cf4636b 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/DefaultNames.cs
@@ -23,5 +23,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
public const string SharedMemoryName = "shared_mem";
public const string UndefinedName = "undef";
+
+ public const string IsBgraName = "is_bgra";
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 8801fc111..4ae9a00ac 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -64,6 +64,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{ AttributeConsts.GtMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupGtMaskARB).x", VariableType.U32) },
{ AttributeConsts.LeMask, new BuiltInAttribute("unpackUint2x32(gl_SubGroupLeMaskARB).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 _locals;
@@ -149,8 +159,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
char swzMask = GetSwizzleMask((value >> 2) & 3);
- if (value >= AttributeConsts.UserAttributeBase &&
- value < AttributeConsts.UserAttributeEnd)
+ if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
{
value -= AttributeConsts.UserAttributeBase;
@@ -169,8 +178,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
else
{
- if (value >= AttributeConsts.FragmentOutputColorBase &&
- value < AttributeConsts.FragmentOutputColorEnd)
+ if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
{
value -= AttributeConsts.FragmentOutputColorBase;
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
index 8ff37429a..c194b5c2e 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeConsts.cs
@@ -35,6 +35,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public const int FragmentOutputColorBase = 0x1000010;
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 ThreadIdY = 0x2000004;
public const int ThreadIdZ = 0x2000008;
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 39532a64f..9b26fa4a6 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -115,22 +115,46 @@ namespace Ryujinx.Graphics.Shader.Translation
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++)
{
- if (target.ComponentEnabled(component))
+ if (!target.ComponentEnabled(component))
{
- Operand dest = Attribute(AttributeConsts.FragmentOutputColorBase + attachment * 16 + component * 4);
-
- Operand src = Register(regIndex, RegisterType.Gpr);
-
- this.Copy(dest, src);
-
- regIndex++;
+ continue;
}
+
+ 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++;
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
index e1eb55ade..dbb05c772 100644
--- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs
@@ -247,7 +247,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
}
private void PostFrameBuffer(Layer layer, BufferItem item)
- {
+ {
int frameBufferWidth = item.GraphicBuffer.Object.Width;
int frameBufferHeight = item.GraphicBuffer.Object.Height;