aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-06-14 13:30:39 -0300
committerGitHub <noreply@github.com>2022-06-14 13:30:39 -0300
commit851f56b08a0c3b420f91143b6c6c007b429174a8 (patch)
treed4f331d1de9f4715a22abdc9b1b90b5ce5a3b4ae
parentb1bd6a50b5341f444ceb31bbb0fb64f685828d75 (diff)
Support Array/3D depth-stencil render target, and single layer clears (#3400)1.1.147
* Support Array/3D depth-stencil render target, and single layer clears * Alignment
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs3
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs6
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs6
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs8
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs5
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureCache.cs23
-rw-r--r--Ryujinx.Graphics.OpenGL/Framebuffer.cs116
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs12
10 files changed, 157 insertions, 34 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index aec096e7..83afcaa3 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -10,9 +10,10 @@ namespace Ryujinx.Graphics.GAL
void ClearBuffer(BufferHandle destination, int offset, int size, uint value);
- void ClearRenderTargetColor(int index, uint componentMask, ColorF color);
+ void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color);
void ClearRenderTargetDepthStencil(
+ int layer,
float depthValue,
bool depthMask,
int stencilValue,
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
index 57509f1c..cde69e7b 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
@@ -4,19 +4,21 @@
{
public CommandType CommandType => CommandType.ClearRenderTargetColor;
private int _index;
+ private int _layer;
private uint _componentMask;
private ColorF _color;
- public void Set(int index, uint componentMask, ColorF color)
+ public void Set(int index, int layer, uint componentMask, ColorF color)
{
_index = index;
+ _layer = layer;
_componentMask = componentMask;
_color = color;
}
public static void Run(ref ClearRenderTargetColorCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
- renderer.Pipeline.ClearRenderTargetColor(command._index, command._componentMask, command._color);
+ renderer.Pipeline.ClearRenderTargetColor(command._index, command._layer, command._componentMask, command._color);
}
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
index 3692cd37..c5c76539 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
@@ -3,13 +3,15 @@
struct ClearRenderTargetDepthStencilCommand : IGALCommand
{
public CommandType CommandType => CommandType.ClearRenderTargetDepthStencil;
+ private int _layer;
private float _depthValue;
private bool _depthMask;
private int _stencilValue;
private int _stencilMask;
- public void Set(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+ public void Set(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
+ _layer = layer;
_depthValue = depthValue;
_depthMask = depthMask;
_stencilValue = stencilValue;
@@ -18,7 +20,7 @@
public static void Run(ref ClearRenderTargetDepthStencilCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
- renderer.Pipeline.ClearRenderTargetDepthStencil(command._depthValue, command._depthMask, command._stencilValue, command._stencilMask);
+ renderer.Pipeline.ClearRenderTargetDepthStencil(command._layer, command._depthValue, command._depthMask, command._stencilValue, command._stencilMask);
}
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index 010ee7e6..2a1f474a 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -40,15 +40,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand();
}
- public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
+ public void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color)
{
- _renderer.New<ClearRenderTargetColorCommand>().Set(index, componentMask, color);
+ _renderer.New<ClearRenderTargetColorCommand>().Set(index, layer, componentMask, color);
_renderer.QueueCommand();
}
- public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+ public void ClearRenderTargetDepthStencil(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
- _renderer.New<ClearRenderTargetDepthStencilCommand>().Set(depthValue, depthMask, stencilValue, stencilMask);
+ _renderer.New<ClearRenderTargetDepthStencilCommand>().Set(layer, depthValue, depthMask, stencilValue, stencilMask);
_renderer.QueueCommand();
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index ab371314..f90baf99 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -505,8 +505,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
int index = (argument >> 6) & 0xf;
+ int layer = (argument >> 10) & 0x3ff;
- engine.UpdateRenderTargetState(useControl: false, singleUse: index);
+ engine.UpdateRenderTargetState(useControl: false, layered: layer != 0, singleUse: index);
// If there is a mismatch on the host clip region and the one explicitly defined by the guest
// on the screen scissor state, then we need to force only one texture to be bound to avoid
@@ -581,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
ColorF color = new ColorF(clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha);
- _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
+ _context.Renderer.Pipeline.ClearRenderTargetColor(index, layer, componentMask, color);
}
if (clearDepth || clearStencil)
@@ -602,6 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
+ layer,
depthValue,
clearDepth,
stencilValue,
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index d0c3bc5a..f648479b 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -362,8 +362,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
/// </summary>
/// <param name="useControl">Use draw buffers information from render target control register</param>
+ /// <param name="layered">Indicates if the texture is layered</param>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
- public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
+ public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
{
var memoryManager = _channel.MemoryManager;
var rtControl = _state.State.RtControl;
@@ -399,7 +400,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
memoryManager,
colorState,
- _vtgWritesRtLayer,
+ _vtgWritesRtLayer || layered,
samplesInX,
samplesInY,
sizeHint);
@@ -433,6 +434,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
memoryManager,
dsState,
dsSize,
+ _vtgWritesRtLayer || layered,
samplesInX,
samplesInY,
sizeHint);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
index a2e8c64c..764ba239 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -131,10 +131,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
/// </summary>
/// <param name="useControl">Use draw buffers information from render target control register</param>
+ /// <param name="layered">Indicates if the texture is layered</param>
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
- public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
+ public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
{
- _stateUpdater.UpdateRenderTargetState(useControl, singleUse);
+ _stateUpdater.UpdateRenderTargetState(useControl, layered, singleUse);
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 04541057..ba863a1e 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -349,6 +349,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="dsState">Depth-stencil buffer texture to find or create</param>
/// <param name="size">Size of the depth-stencil texture</param>
+ /// <param name="layered">Indicates if the texture might be accessed with a non-zero layer index</param>
/// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
/// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
@@ -357,6 +358,7 @@ namespace Ryujinx.Graphics.Gpu.Image
MemoryManager memoryManager,
RtDepthStencilState dsState,
Size3D size,
+ bool layered,
int samplesInX,
int samplesInY,
Size sizeHint)
@@ -364,9 +366,24 @@ namespace Ryujinx.Graphics.Gpu.Image
int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
- Target target = (samplesInX | samplesInY) != 1
- ? Target.Texture2DMultisample
- : Target.Texture2D;
+ Target target;
+
+ if (dsState.MemoryLayout.UnpackIsTarget3D())
+ {
+ target = Target.Texture3D;
+ }
+ else if ((samplesInX | samplesInY) != 1)
+ {
+ target = size.Depth > 1 && layered
+ ? Target.Texture2DMultisampleArray
+ : Target.Texture2DMultisample;
+ }
+ else
+ {
+ target = size.Depth > 1 && layered
+ ? Target.Texture2DArray
+ : Target.Texture2D;
+ }
FormatInfo formatInfo = dsState.Format.Convert();
diff --git a/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
index da928b4c..dafa7672 100644
--- a/Ryujinx.Graphics.OpenGL/Framebuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
@@ -9,10 +9,13 @@ namespace Ryujinx.Graphics.OpenGL
class Framebuffer : IDisposable
{
public int Handle { get; private set; }
+ private int _clearFbHandle;
+ private bool _clearFbInitialized;
private FramebufferAttachment _lastDsAttachment;
private readonly TextureView[] _colors;
+ private TextureView _depthStencil;
private int _colorsCount;
private bool _dualSourceBlend;
@@ -20,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
public Framebuffer()
{
Handle = GL.GenFramebuffer();
+ _clearFbHandle = GL.GenFramebuffer();
_colors = new TextureView[8];
}
@@ -55,20 +59,7 @@ namespace Ryujinx.Graphics.OpenGL
if (depthStencil != null)
{
- FramebufferAttachment attachment;
-
- if (IsPackedDepthStencilFormat(depthStencil.Format))
- {
- attachment = FramebufferAttachment.DepthStencilAttachment;
- }
- else if (IsDepthOnlyFormat(depthStencil.Format))
- {
- attachment = FramebufferAttachment.DepthAttachment;
- }
- else
- {
- attachment = FramebufferAttachment.StencilAttachment;
- }
+ FramebufferAttachment attachment = GetAttachment(depthStencil.Format);
GL.FramebufferTexture(
FramebufferTarget.Framebuffer,
@@ -82,6 +73,8 @@ namespace Ryujinx.Graphics.OpenGL
{
_lastDsAttachment = 0;
}
+
+ _depthStencil = depthStencil;
}
public void SetDualSourceBlend(bool enable)
@@ -124,6 +117,22 @@ namespace Ryujinx.Graphics.OpenGL
GL.DrawBuffers(colorsCount, drawBuffers);
}
+ private static FramebufferAttachment GetAttachment(Format format)
+ {
+ if (IsPackedDepthStencilFormat(format))
+ {
+ return FramebufferAttachment.DepthStencilAttachment;
+ }
+ else if (IsDepthOnlyFormat(format))
+ {
+ return FramebufferAttachment.DepthAttachment;
+ }
+ else
+ {
+ return FramebufferAttachment.StencilAttachment;
+ }
+ }
+
private static bool IsPackedDepthStencilFormat(Format format)
{
return format == Format.D24UnormS8Uint ||
@@ -136,6 +145,78 @@ namespace Ryujinx.Graphics.OpenGL
return format == Format.D16Unorm || format == Format.D32Float;
}
+ public void AttachColorLayerForClear(int index, int layer)
+ {
+ TextureView color = _colors[index];
+
+ if (!IsLayered(color))
+ {
+ return;
+ }
+
+ BindClearFb();
+ GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, color.Handle, 0, layer);
+ }
+
+ public void DetachColorLayerForClear(int index)
+ {
+ TextureView color = _colors[index];
+
+ if (!IsLayered(color))
+ {
+ return;
+ }
+
+ GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, 0, 0);
+ Bind();
+ }
+
+ public void AttachDepthStencilLayerForClear(int layer)
+ {
+ TextureView depthStencil = _depthStencil;
+
+ if (!IsLayered(depthStencil))
+ {
+ return;
+ }
+
+ BindClearFb();
+ GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), depthStencil.Handle, 0, layer);
+ }
+
+ public void DetachDepthStencilLayerForClear()
+ {
+ TextureView depthStencil = _depthStencil;
+
+ if (!IsLayered(depthStencil))
+ {
+ return;
+ }
+
+ GL.FramebufferTexture(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), 0, 0);
+ Bind();
+ }
+
+ private void BindClearFb()
+ {
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, _clearFbHandle);
+
+ if (!_clearFbInitialized)
+ {
+ SetDrawBuffersImpl(Constants.MaxRenderTargets);
+ _clearFbInitialized = true;
+ }
+ }
+
+ private static bool IsLayered(TextureView view)
+ {
+ return view != null &&
+ view.Target != Target.Texture1D &&
+ view.Target != Target.Texture2D &&
+ view.Target != Target.Texture2DMultisample &&
+ view.Target != Target.TextureBuffer;
+ }
+
public void Dispose()
{
if (Handle != 0)
@@ -144,6 +225,13 @@ namespace Ryujinx.Graphics.OpenGL
Handle = 0;
}
+
+ if (_clearFbHandle != 0)
+ {
+ GL.DeleteFramebuffer(_clearFbHandle);
+
+ _clearFbHandle = 0;
+ }
}
}
}
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 637e4606..62d4dee9 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Clear(destination, offset, size, value);
}
- public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
+ public void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color)
{
GL.ColorMask(
index,
@@ -119,14 +119,18 @@ namespace Ryujinx.Graphics.OpenGL
(componentMask & 4) != 0,
(componentMask & 8) != 0);
+ _framebuffer.AttachColorLayerForClear(index, layer);
+
float[] colors = new float[] { color.Red, color.Green, color.Blue, color.Alpha };
GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Color, index, colors);
+ _framebuffer.DetachColorLayerForClear(index);
+
RestoreComponentMask(index);
}
- public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+ public void ClearRenderTargetDepthStencil(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
bool stencilMaskChanged =
stencilMask != 0 &&
@@ -144,6 +148,8 @@ namespace Ryujinx.Graphics.OpenGL
GL.DepthMask(depthMask);
}
+ _framebuffer.AttachDepthStencilLayerForClear(layer);
+
if (depthMask && stencilMask != 0)
{
GL.ClearBuffer(ClearBufferCombined.DepthStencil, 0, depthValue, stencilValue);
@@ -157,6 +163,8 @@ namespace Ryujinx.Graphics.OpenGL
GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Stencil, 0, ref stencilValue);
}
+ _framebuffer.DetachDepthStencilLayerForClear();
+
if (stencilMaskChanged)
{
GL.StencilMaskSeparate(StencilFace.Front, _stencilFrontMask);