aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.OpenGL/Image
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.OpenGL/Image')
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureBase.cs2
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureCopy.cs65
-rw-r--r--Ryujinx.Graphics.OpenGL/Image/TextureView.cs44
3 files changed, 98 insertions, 13 deletions
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBase.cs
index dfb81642..5f786dec 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 e89d5614..edfbec5f 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 02353ffa..2d50eba5 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();