Support Array/3D depth-stencil render target, and single layer clears (#3400)
* Support Array/3D depth-stencil render target, and single layer clears * Alignment
This commit is contained in:
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user