aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-09-25 19:55:30 -0300
committerAc_K <Acoustik666@gmail.com>2018-09-26 00:55:30 +0200
commit2562ca6c3fe6ef328e0926c9cbcd6bb52abb328f (patch)
treed4719ba44b7094cf4e8cf11db858b323644fd44a
parent7de7b559adc1924d3ff31cc58b281f70e468155f (diff)
Fix multiple rendertargets (#427)
* Simplify render target bindings * Implement multiple viewports * Pack glViewportIndexed calls into a single glViewportArray * Use ARB_viewport_array when available * Cache framebuffer attachments * Use get accessors in OGLExtension * Address feedback
-rw-r--r--Ryujinx.Graphics/Gal/IGalRenderTarget.cs10
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs37
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs247
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs2
-rw-r--r--Ryujinx.Graphics/GpuResourceManager.cs4
-rw-r--r--Ryujinx.Graphics/NvGpuEngine3d.cs24
-rw-r--r--Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs2
8 files changed, 179 insertions, 149 deletions
diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
index 7ccf0981..f941ccd5 100644
--- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
+++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs
@@ -2,15 +2,17 @@ namespace Ryujinx.Graphics.Gal
{
public interface IGalRenderTarget
{
- void BindColor(long Key, int Attachment, GalImage Image);
+ void Bind();
+
+ void BindColor(long Key, int Attachment);
void UnbindColor(int Attachment);
- void BindZeta(long Key, GalImage Image);
+ void BindZeta(long Key);
void UnbindZeta();
- void Set(long Key);
+ void Present(long Key);
void SetMap(int[] Map);
@@ -18,7 +20,7 @@ namespace Ryujinx.Graphics.Gal
void SetWindowSize(int Width, int Height);
- void SetViewport(int X, int Y, int Width, int Height);
+ void SetViewport(int Attachment, int X, int Y, int Width, int Height);
void Render();
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index 187d1eec..7f9e9fbe 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -225,7 +225,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
}
- if (OGLExtension.HasTextureMirrorClamp())
+ if (OGLExtension.TextureMirrorClamp)
{
switch (Wrap)
{
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
index 5ad42298..11daeb59 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
@@ -1,40 +1,17 @@
using OpenTK.Graphics.OpenGL;
+using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
static class OGLExtension
{
- private static bool Initialized = false;
+ private static Lazy<bool> s_EnhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
+ private static Lazy<bool> s_TextureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
+ private static Lazy<bool> s_ViewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
- private static bool EnhancedLayouts;
-
- private static bool TextureMirrorClamp;
-
- public static bool HasEnhancedLayouts()
- {
- EnsureInitialized();
-
- return EnhancedLayouts;
- }
-
- public static bool HasTextureMirrorClamp()
- {
- EnsureInitialized();
-
- return TextureMirrorClamp;
- }
-
- private static void EnsureInitialized()
- {
- if (Initialized)
- {
- return;
- }
-
- EnhancedLayouts = HasExtension("GL_ARB_enhanced_layouts");
-
- TextureMirrorClamp = HasExtension("GL_EXT_texture_mirror_clamp");
- }
+ public static bool EnhancedLayouts => s_EnhancedLayouts.Value;
+ public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value;
+ public static bool ViewportArray => s_ViewportArray.Value;
private static bool HasExtension(string Name)
{
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
index ff5dc1b8..78cf5d2f 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
@@ -22,16 +22,52 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
+ private class FrameBufferAttachments
+ {
+ public long[] Colors;
+ public long Zeta;
+
+ public int MapCount;
+ public DrawBuffersEnum[] Map;
+
+ public FrameBufferAttachments()
+ {
+ Colors = new long[RenderTargetsCount];
+
+ Map = new DrawBuffersEnum[RenderTargetsCount];
+ }
+
+ public void SetAndClear(FrameBufferAttachments Source)
+ {
+ Zeta = Source.Zeta;
+ MapCount = Source.MapCount;
+
+ Source.Zeta = 0;
+ Source.MapCount = 0;
+
+ for (int i = 0; i < RenderTargetsCount; i++)
+ {
+ Colors[i] = Source.Colors[i];
+ Map[i] = Source.Map[i];
+
+ Source.Colors[i] = 0;
+ Source.Map[i] = 0;
+ }
+ }
+ }
+
private const int NativeWidth = 1280;
private const int NativeHeight = 720;
+ private const int RenderTargetsCount = 8;
+
private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
private OGLTexture Texture;
private ImageHandler ReadTex;
- private Rect Viewport;
+ private float[] Viewports;
private Rect Window;
private bool FlipX;
@@ -50,138 +86,164 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private int SrcFb;
private int DstFb;
- //Holds current attachments, used to avoid unnecesary calls to OpenGL
- private int[] ColorAttachments;
-
- private int DepthAttachment;
- private int StencilAttachment;
+ private FrameBufferAttachments Attachments;
+ private FrameBufferAttachments OldAttachments;
private int CopyPBO;
public OGLRenderTarget(OGLTexture Texture)
{
- ColorAttachments = new int[8];
+ Attachments = new FrameBufferAttachments();
+
+ OldAttachments = new FrameBufferAttachments();
+
+ Viewports = new float[RenderTargetsCount * 4];
this.Texture = Texture;
}
- public void BindColor(long Key, int Attachment, GalImage Image)
+ public void Bind()
{
- if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
- {
- EnsureFrameBuffer();
-
- Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
- }
- else
+ if (DummyFrameBuffer == 0)
{
- UnbindColor(Attachment);
+ DummyFrameBuffer = GL.GenFramebuffer();
}
- }
- public void UnbindColor(int Attachment)
- {
- EnsureFrameBuffer();
+ GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
- Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
- }
+ ImageHandler CachedImage;
- public void BindZeta(long Key, GalImage Image)
- {
- if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
+ for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
{
- EnsureFrameBuffer();
+ if (Attachments.Colors[Attachment] == OldAttachments.Colors[Attachment])
+ {
+ continue;
+ }
+
+ int Handle = 0;
+
+ if (Attachments.Colors[Attachment] != 0 &&
+ Texture.TryGetImageHandler(Attachments.Colors[Attachment], out CachedImage))
+ {
+ Handle = CachedImage.Handle;
+ }
+
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.ColorAttachment0 + Attachment,
+ Handle,
+ 0);
+ }
- if (CachedImage.HasDepth && CachedImage.HasStencil)
+ if (Attachments.Zeta != OldAttachments.Zeta)
+ {
+ if (Attachments.Zeta != 0 && Texture.TryGetImageHandler(Attachments.Zeta, out CachedImage))
{
- if (DepthAttachment != CachedImage.Handle ||
- StencilAttachment != CachedImage.Handle)
+ if (CachedImage.HasDepth && CachedImage.HasStencil)
{
GL.FramebufferTexture(
FramebufferTarget.DrawFramebuffer,
FramebufferAttachment.DepthStencilAttachment,
CachedImage.Handle,
0);
-
- DepthAttachment = CachedImage.Handle;
- StencilAttachment = CachedImage.Handle;
}
- }
- else if (CachedImage.HasDepth)
- {
- Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
-
- Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
- }
- else if (CachedImage.HasStencil)
- {
- Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
+ else if (CachedImage.HasDepth)
+ {
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.DepthAttachment,
+ CachedImage.Handle,
+ 0);
- Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.StencilAttachment,
+ 0,
+ 0);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
}
else
{
- throw new InvalidOperationException();
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.DepthStencilAttachment,
+ 0,
+ 0);
}
}
+
+ if (OGLExtension.ViewportArray)
+ {
+ GL.ViewportArray(0, 8, Viewports);
+ }
else
{
- UnbindZeta();
+ GL.Viewport(
+ (int)Viewports[0],
+ (int)Viewports[1],
+ (int)Viewports[2],
+ (int)Viewports[3]);
}
- }
- private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
- {
- if (OldHandle != NewHandle)
+ if (Attachments.MapCount > 1)
{
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FbAttachment,
- NewHandle,
- 0);
-
- OldHandle = NewHandle;
+ GL.DrawBuffers(Attachments.MapCount, Attachments.Map);
}
+ else if (Attachments.MapCount == 1)
+ {
+ GL.DrawBuffer((DrawBufferMode)Attachments.Map[0]);
+ }
+ else
+ {
+ GL.DrawBuffer(DrawBufferMode.None);
+ }
+
+ OldAttachments.SetAndClear(Attachments);
}
- public void UnbindZeta()
+ public void BindColor(long Key, int Attachment)
{
- EnsureFrameBuffer();
+ Attachments.Colors[Attachment] = Key;
+ }
- if (DepthAttachment != 0 || StencilAttachment != 0)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthStencilAttachment,
- 0,
- 0);
+ public void UnbindColor(int Attachment)
+ {
+ Attachments.Colors[Attachment] = 0;
+ }
- DepthAttachment = 0;
- StencilAttachment = 0;
- }
+ public void BindZeta(long Key)
+ {
+ Attachments.Zeta = Key;
+ }
+
+ public void UnbindZeta()
+ {
+ Attachments.Zeta = 0;
}
- public void Set(long Key)
+ public void Present(long Key)
{
Texture.TryGetImageHandler(Key, out ReadTex);
}
public void SetMap(int[] Map)
{
- if (Map != null && Map.Length > 0)
+ if (Map != null)
{
- DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
+ Attachments.MapCount = Map.Length;
- for (int i = 0; i < Map.Length; i++)
+ for (int Attachment = 0; Attachment < Attachments.MapCount; Attachment++)
{
- Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
+ Attachments.Map[Attachment] = DrawBuffersEnum.ColorAttachment0 + Map[Attachment];
}
-
- GL.DrawBuffers(Mode.Length, Mode);
}
else
{
- GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
+ Attachments.MapCount = 0;
}
}
@@ -201,20 +263,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Window = new Rect(0, 0, Width, Height);
}
- public void SetViewport(int X, int Y, int Width, int Height)
+ public void SetViewport(int Attachment, int X, int Y, int Width, int Height)
{
- Viewport = new Rect(X, Y, Width, Height);
-
- SetViewport(Viewport);
- }
+ int Offset = Attachment * 4;
- private void SetViewport(Rect Viewport)
- {
- GL.Viewport(
- Viewport.X,
- Viewport.Y,
- Viewport.Width,
- Viewport.Height);
+ Viewports[Offset + 0] = X;
+ Viewports[Offset + 1] = Y;
+ Viewports[Offset + 2] = Width;
+ Viewports[Offset + 3] = Height;
}
public void Render()
@@ -276,7 +332,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
- GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
GL.Clear(ClearBufferMask.ColorBufferBit);
@@ -285,8 +340,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
DstX0, DstY0, DstX1, DstY1,
ClearBufferMask.ColorBufferBit,
BlitFramebufferFilter.Linear);
-
- EnsureFrameBuffer();
}
public void Copy(
@@ -343,8 +396,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.Clear(Mask);
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
-
- EnsureFrameBuffer();
}
}
@@ -419,15 +470,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
}
-
- private void EnsureFrameBuffer()
- {
- if (DummyFrameBuffer == 0)
- {
- DummyFrameBuffer = GL.GenFramebuffer();
- }
-
- GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
- }
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
index 73d37b87..efcb7e34 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -133,7 +133,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
//Enhanced layouts are required for Geometry shaders
//skip this stage if current driver has no ARB_enhanced_layouts
- if (!OGLExtension.HasEnhancedLayouts())
+ if (!OGLExtension.EnhancedLayouts)
{
return;
}
diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs
index 0a8d2014..71390a83 100644
--- a/Ryujinx.Graphics/GpuResourceManager.cs
+++ b/Ryujinx.Graphics/GpuResourceManager.cs
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
}
- Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage);
+ Gpu.Renderer.RenderTarget.BindColor(Position, Attachment);
}
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage)
@@ -60,7 +60,7 @@ namespace Ryujinx.Graphics
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
}
- Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage);
+ Gpu.Renderer.RenderTarget.BindZeta(Position);
}
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1)
diff --git a/Ryujinx.Graphics/NvGpuEngine3d.cs b/Ryujinx.Graphics/NvGpuEngine3d.cs
index b19f3063..22c09377 100644
--- a/Ryujinx.Graphics/NvGpuEngine3d.cs
+++ b/Ryujinx.Graphics/NvGpuEngine3d.cs
@@ -100,7 +100,10 @@ namespace Ryujinx.Graphics
SetAlphaBlending(State);
SetPrimitiveRestart(State);
- SetFrameBuffer(Vmm, 0);
+ for (int FbIndex = 0; FbIndex < 8; FbIndex++)
+ {
+ SetFrameBuffer(Vmm, FbIndex);
+ }
SetZeta(Vmm);
@@ -154,6 +157,10 @@ namespace Ryujinx.Graphics
SetZeta(Vmm);
+ SetRenderTargets();
+
+ Gpu.Renderer.RenderTarget.Bind();
+
Gpu.Renderer.Rasterizer.ClearBuffers(
Flags,
FbIndex,
@@ -204,7 +211,7 @@ namespace Ryujinx.Graphics
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
- Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH);
+ Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH);
}
private void SetFrameBuffer(GalPipelineState State)
@@ -426,14 +433,15 @@ namespace Ryujinx.Graphics
private void SetRenderTargets()
{
- bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData);
+ //Commercial games do not seem to
+ //bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData);
- if (SeparateFragData)
- {
- uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
+ uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
- uint Count = Control & 0xf;
+ uint Count = Control & 0xf;
+ if (Count > 0)
+ {
int[] Map = new int[Count];
for (int i = 0; i < Count; i++)
@@ -702,6 +710,8 @@ namespace Ryujinx.Graphics
Gpu.Renderer.Pipeline.Bind(State);
+ Gpu.Renderer.RenderTarget.Bind();
+
if (IndexCount != 0)
{
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
index c5f38211..191537b1 100644
--- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs
@@ -328,7 +328,7 @@ namespace Ryujinx.HLE.HOS.Services.Android
Context.Device.Gpu.ResourceManager.SendTexture(Vmm, FbAddr, Image);
Renderer.RenderTarget.SetTransform(FlipX, FlipY, Top, Left, Right, Bottom);
- Renderer.RenderTarget.Set(FbAddr);
+ Renderer.RenderTarget.Present(FbAddr);
ReleaseBuffer(Slot);
});