Implement clear buffer (fast path) (#1902)

* Implement clear buffer (fast path)

* Remove blank line
This commit is contained in:
gdkchan 2021-01-12 18:50:54 -03:00 committed by GitHub
parent 68f6b79fd3
commit df820a72de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 125 additions and 5 deletions

View File

@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.GAL
void BeginTransformFeedback(PrimitiveTopology topology);
void ClearBuffer(BufferHandle destination, int offset, int size, uint value);
void ClearRenderTargetColor(int index, uint componentMask, ColorF color);
void ClearRenderTargetDepthStencil(

View File

@ -200,8 +200,24 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
else
{
// Buffer to buffer copy.
BufferManager.CopyBuffer(cbp.SrcAddress, cbp.DstAddress, (uint)size);
if (remap &&
swizzle.UnpackDstX() == BufferSwizzleComponent.ConstA &&
swizzle.UnpackDstY() == BufferSwizzleComponent.ConstA &&
swizzle.UnpackDstZ() == BufferSwizzleComponent.ConstA &&
swizzle.UnpackDstW() == BufferSwizzleComponent.ConstA &&
swizzle.UnpackSrcComponentsCount() == 1 &&
swizzle.UnpackDstComponentsCount() == 1 &&
swizzle.UnpackComponentSize() == 4)
{
// Fast path for clears when remap is enabled.
BufferManager.ClearBuffer(cbp.DstAddress, (uint)size * 4, state.Get<uint>(MethodOffset.CopyBufferConstA));
}
else
{
// TODO: Implement remap functionality.
// Buffer to buffer copy.
BufferManager.CopyBuffer(cbp.SrcAddress, cbp.DstAddress, (uint)size);
}
}
}
}

View File

@ -821,6 +821,28 @@ namespace Ryujinx.Graphics.Gpu.Memory
dstBuffer.Flush(dstAddress, size);
}
/// <summary>
/// Clears a buffer at a given address with the specified value.
/// </summary>
/// <remarks>
/// Both the address and size must be aligned to 4 bytes.
/// </remarks>
/// <param name="gpuVa">GPU virtual address of the region to clear</param>
/// <param name="size">Number of bytes to clear</param>
/// <param name="value">Value to be written into the buffer</param>
public void ClearBuffer(GpuVa gpuVa, ulong size, uint value)
{
ulong address = TranslateAndCreateBuffer(gpuVa.Pack(), size);
Buffer buffer = GetBuffer(address, size);
int offset = (int)(address - buffer.Address);
_context.Renderer.Pipeline.ClearBuffer(buffer.Handle, offset, (int)size, value);
buffer.Flush(address, size);
}
/// <summary>
/// Gets a buffer sub-range for a given memory range.
/// </summary>

View File

@ -0,0 +1,16 @@
namespace Ryujinx.Graphics.Gpu.State
{
/// <summary>
/// Buffer swizzle component.
/// </summary>
enum BufferSwizzleComponent
{
SrcX,
SrcY,
SrcZ,
SrcW,
ConstA,
ConstB,
NoWrite
}
}

View File

@ -9,6 +9,42 @@ namespace Ryujinx.Graphics.Gpu.State
public uint Swizzle;
#pragma warning restore CS0649
/// <summary>
/// Unpacks the source for the buffer destination vector X component.
/// </summary>
/// <returns>Destination component</returns>
public BufferSwizzleComponent UnpackDstX()
{
return (BufferSwizzleComponent)(Swizzle & 7);
}
/// <summary>
/// Unpacks the source for the buffer destination vector Y component.
/// </summary>
/// <returns>Destination component</returns>
public BufferSwizzleComponent UnpackDstY()
{
return (BufferSwizzleComponent)((Swizzle >> 4) & 7);
}
/// <summary>
/// Unpacks the source for the buffer destination vector Z component.
/// </summary>
/// <returns>Destination component</returns>
public BufferSwizzleComponent UnpackDstZ()
{
return (BufferSwizzleComponent)((Swizzle >> 8) & 7);
}
/// <summary>
/// Unpacks the source for the buffer destination vector W component.
/// </summary>
/// <returns>Destination component</returns>
public BufferSwizzleComponent UnpackDstW()
{
return (BufferSwizzleComponent)((Swizzle >> 12) & 7);
}
/// <summary>
/// Unpacks the size of each vector component of the copy.
/// </summary>

View File

@ -23,6 +23,8 @@ namespace Ryujinx.Graphics.Gpu.State
TfBufferState = 0xe0,
CopyBufferParams = 0x100,
TfState = 0x1c0,
CopyBufferConstA = 0x1c0,
CopyBufferConstB = 0x1c1,
CopyBufferSwizzle = 0x1c2,
CopyBufferDstTexture = 0x1c3,
CopyBufferSrcTexture = 0x1ca,

View File

@ -6,6 +6,27 @@ namespace Ryujinx.Graphics.OpenGL
{
static class Buffer
{
public static void Clear(BufferHandle destination, int offset, int size, uint value)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
unsafe
{
uint* valueArr = stackalloc uint[1];
valueArr[0] = value;
GL.ClearBufferSubData(
BufferTarget.CopyWriteBuffer,
PixelInternalFormat.Rgba8ui,
(IntPtr)offset,
(IntPtr)size,
PixelFormat.RgbaInteger,
PixelType.UnsignedByte,
(IntPtr)valueArr);
}
}
public static BufferHandle Create()
{
return Handle.FromInt32<BufferHandle>(GL.GenBuffer());

View File

@ -91,6 +91,11 @@ namespace Ryujinx.Graphics.OpenGL
_tfEnabled = true;
}
public void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
{
Buffer.Clear(destination, offset, size, value);
}
public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
{
GL.ColorMask(
@ -102,7 +107,7 @@ namespace Ryujinx.Graphics.OpenGL
float[] colors = new float[] { color.Red, color.Green, color.Blue, color.Alpha };
GL.ClearBuffer(ClearBuffer.Color, index, colors);
GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Color, index, colors);
RestoreComponentMask(index);
@ -133,11 +138,11 @@ namespace Ryujinx.Graphics.OpenGL
}
else if (depthMask)
{
GL.ClearBuffer(ClearBuffer.Depth, 0, ref depthValue);
GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Depth, 0, ref depthValue);
}
else if (stencilMask != 0)
{
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencilValue);
GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Stencil, 0, ref stencilValue);
}
if (stencilMaskChanged)