Skip to content

Commit

Permalink
Batch Rendering changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Terria-K committed Jan 21, 2025
1 parent 893da04 commit 8081d1f
Show file tree
Hide file tree
Showing 40 changed files with 365 additions and 488 deletions.
2 changes: 1 addition & 1 deletion Riateu/Core/GameApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private void InternalRender()
RenderTarget backbuffer = cmdBuf.AcquireSwapchainTarget(MainWindow);
if (backbuffer != null)
{
scene.Render(backbuffer);
scene.Render(cmdBuf, backbuffer);
}

Time.Draw();
Expand Down
34 changes: 9 additions & 25 deletions Riateu/Core/GameContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@ public static class GameContext
/// <summary>
/// The default material for basic rendering.
/// </summary>
public static Material DefaultMaterial;
public static Material BatchMaterial;
/// <summary>
/// A rendering material that uses R8G8B8A8 format.
/// </summary>
public static Material DepthMaterial;

public static Shader SpriteBatchShader;
public static Shader MSDFShader;
/// <summary>
/// A compute pipeline used for <see cref="Riateu.Graphics.Batch"/> to work.
/// </summary>
public static ComputePipeline SpriteBatchPipeline;

internal static void Init(GraphicsDevice device, Window mainWindow)
{
Expand All @@ -40,12 +37,13 @@ internal static void Init(GraphicsDevice device, Window mainWindow)
SamplerCount = 1
});

var positionTextureColor = Resources.PositionTextureColor;
using var ms1 = new MemoryStream(positionTextureColor);
Shader vertexPSC = new Shader(device, ms1, "main", new ShaderCreateInfo {
var spriteBatchShader = Resources.SpriteBatchShader;
using var ms1 = new MemoryStream(spriteBatchShader);
SpriteBatchShader = new Shader(device, ms1, "main", new ShaderCreateInfo {
ShaderStage = ShaderStage.Vertex,
ShaderFormat = GraphicsDevice.BackendShaderFormat,
UniformBufferCount = 1
UniformBufferCount = 1,
StorageBufferCount = 1
});

var textureFragment = Resources.Texture;
Expand All @@ -56,7 +54,7 @@ internal static void Init(GraphicsDevice device, Window mainWindow)
SamplerCount = 1
});

DefaultMaterial = new Material(device, GraphicsPipeline.CreateBuilder(vertexPSC, fragmentPSC)
BatchMaterial = new Material(device, GraphicsPipeline.CreateBuilder(SpriteBatchShader, fragmentPSC)
.SetAttachmentInfo(new GraphicsPipelineAttachmentInfo(
new ColorAttachmentDescription(mainWindow.SwapchainFormat,
ColorTargetBlendState.AlphaBlend)
Expand All @@ -66,11 +64,10 @@ internal static void Init(GraphicsDevice device, Window mainWindow)
.SetPrimitiveType(PrimitiveType.TriangleList)
.SetRasterizerState(RasterizerState.CCW_CullNone)

.AddVertexInputState<PositionTextureColorVertex>()
.Build(device)
);

DepthMaterial = new Material(device, GraphicsPipeline.CreateBuilder(vertexPSC, fragmentPSC)
DepthMaterial = new Material(device, GraphicsPipeline.CreateBuilder(SpriteBatchShader, fragmentPSC)
.SetAttachmentInfo(new GraphicsPipelineAttachmentInfo(
TextureFormat.D24_UNORM,
new ColorAttachmentDescription(mainWindow.SwapchainFormat, ColorTargetBlendState.AlphaBlend)
Expand All @@ -80,20 +77,7 @@ internal static void Init(GraphicsDevice device, Window mainWindow)
.SetPrimitiveType(PrimitiveType.TriangleList)
.SetRasterizerState(RasterizerState.CCW_CullNone)

.AddVertexInputState<PositionTextureColorVertex>()
.Build(device)
);

var spriteBatchShader = Resources.SpriteBatchShader;
using var comp1 = new MemoryStream(spriteBatchShader);
SpriteBatchPipeline = new ComputePipeline(device, comp1, "main", new ComputePipelineCreateInfo
{
ShaderFormat = GraphicsDevice.BackendShaderFormat,
ReadWriteStorageBufferCount = 1,
ReadOnlyStorageBufferCount = 1,
ThreadCountX = 64,
ThreadCountY = 1,
ThreadCountZ = 1
});
}
}
3 changes: 2 additions & 1 deletion Riateu/Core/GameLoop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public GameLoop(GameApp gameApp)
/// <summary>
/// A method that called during the draw loop. Do your draw calls here.
/// </summary>
/// <param name="commandBuffer">A commandBuffer for sending draw commands to the GPU</param>///
/// <param name="swapchainTarget">A swapchainTarget target to be used for drawing inside of a window</param>
public abstract void Render(RenderTarget swapchainTarget);
public abstract void Render(CommandBuffer commandBuffer, RenderTarget swapchainTarget);
}
145 changes: 47 additions & 98 deletions Riateu/Core/Graphics/Batch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,11 @@ public class Batch : System.IDisposable
private bool flushed;
private uint onQueue;

private StructuredBuffer<PositionTextureColorVertex> vertexBuffer;
private StructuredBuffer<uint> indexBuffer;
private StructuredBuffer<BatchData> computeBuffer;
private TransferBuffer transferComputeBuffer;
private StructuredBuffer<BatchData> batchBuffer;
private TransferBuffer transferBatchBuffer;
private BatchQueue[] queues = new BatchQueue[InitialMaxQueues];

public StructuredBuffer<PositionTextureColorVertex> VertexBuffer => vertexBuffer;
public StructuredBuffer<uint> IndexBuffer => indexBuffer;
public StructuredBuffer<BatchData> ComputeBuffer => computeBuffer;
public StructuredBuffer<BatchData> BatchBuffer => batchBuffer;

#if DEBUG
private bool DEBUG_begin;
Expand Down Expand Up @@ -58,17 +54,9 @@ public Batch(GraphicsDevice device, int width, int height)
{
this.device = device;

vertexBuffer = new StructuredBuffer<PositionTextureColorVertex>(device,
BufferUsageFlags.Vertex
| BufferUsageFlags.ComputeStorageRead
| BufferUsageFlags.ComputeStorageWrite, MaxTextures * 4);
vertexBuffer.Name = "BatchVertexBuffer";
indexBuffer = GenerateIndexArray(device, MaxTextures * 6);
indexBuffer.Name = "BatchIndexBuffer";

transferComputeBuffer = TransferBuffer.Create<BatchData>(device, TransferBufferUsage.Upload, MaxTextures);
computeBuffer = new StructuredBuffer<BatchData>(device, BufferUsageFlags.ComputeStorageRead | BufferUsageFlags.Vertex, MaxTextures);
computeBuffer.Name = "BatchComputeBuffer";
transferBatchBuffer = TransferBuffer.Create<BatchData>(device, TransferBufferUsage.Upload, MaxTextures);
batchBuffer = new StructuredBuffer<BatchData>(device, BufferUsageFlags.ComputeStorageRead | BufferUsageFlags.Vertex, MaxTextures);
batchBuffer.Name = "BatchComputeBuffer";

var view = Matrix4x4.CreateTranslation(0, 0, 0);
var projection = Matrix4x4.CreateOrthographicOffCenter(0, width, height, 0, -1, 1);
Expand Down Expand Up @@ -109,7 +97,7 @@ private static StructuredBuffer<uint> GenerateIndexArray(GraphicsDevice device,
/// <param name="sampler">A sampler to used for the texture</param>
public void Begin(Texture texture, Sampler sampler)
{
Begin(texture, sampler, GameContext.DefaultMaterial, Matrix);
Begin(texture, sampler, GameContext.BatchMaterial, Matrix);
}

/// <summary>
Expand All @@ -120,7 +108,7 @@ public void Begin(Texture texture, Sampler sampler)
/// <param name="transform">A transformation matrix</param>
public void Begin(Texture texture, Sampler sampler, Matrix4x4 transform)
{
Begin(texture, sampler, GameContext.DefaultMaterial, transform);
Begin(texture, sampler, GameContext.BatchMaterial, transform);
}

/// <summary>
Expand Down Expand Up @@ -168,7 +156,7 @@ public void Begin(Texture texture, Sampler sampler, Material material, Matrix4x4
Offset = vertexIndex,
Matrix = transform
};
transferComputeBuffer.Map(true);
transferBatchBuffer.Map(true);
}

/// <summary>
Expand All @@ -181,61 +169,43 @@ public void End()
DEBUG_begin = false;

#endif
transferComputeBuffer.Unmap();
transferBatchBuffer.Unmap();

if (vertexIndex == 0)
{
return;
}

var offset = queues[onQueue].Offset;
queues[onQueue].Count = vertexIndex - offset;
var count = vertexIndex - offset;
queues[onQueue].Count = count;

onQueue++;
}

/// <inheritdoc/>
private void BindUniformMatrix(in Matrix4x4 matrix)
{
device.DeviceCommandBuffer().PushVertexUniformData(matrix, 0);
}

public void Flush()
public void Flush(CommandBuffer commandBuffer)
{
#if DEBUG
if (DEBUG_isFlushed)
{
Logger.Warn("The state has been flushed, yet has been flushed again. Avoid doing this everytime as it cost performance.");
}
AssertBegin();
DEBUG_isFlushed = true;
#endif
flushed = true;
CommandBuffer cmdBuf = device.AcquireCommandBuffer();

CopyPass copyPass = cmdBuf.BeginCopyPass();
copyPass.UploadToBuffer(transferComputeBuffer, computeBuffer, true);

cmdBuf.EndCopyPass(copyPass);
CopyPass copyPass = commandBuffer.BeginCopyPass();
copyPass.UploadToBuffer(transferBatchBuffer, batchBuffer, true);
commandBuffer.EndCopyPass(copyPass);
}

ComputePass computePass = cmdBuf.BeginComputePass(new StorageBufferReadWriteBinding
{
Buffer = vertexBuffer,
Cycle = true
});
uint workgroupSize = (vertexIndex + 64 - 1) / 64;
computePass.BindComputePipeline(GameContext.SpriteBatchPipeline);
computePass.BindStorageBuffer(computeBuffer);
computePass.Dispatch(workgroupSize, 1, 1);

cmdBuf.EndComputePass(computePass);
device.Submit(cmdBuf);
/// <inheritdoc/>
private void BindUniformMatrix(in Matrix4x4 matrix)
{
device.DeviceCommandBuffer().PushVertexUniformData(matrix, 0);
}

/// <inheritdoc/>
public void Render(RenderPass renderPass)
{
#if DEBUG
AssertRender();
AssertIsFlushed();
DEBUG_isFlushed = false;
DEBUG_begin = false;
#endif
Expand All @@ -245,10 +215,6 @@ public void Render(RenderPass renderPass)
{
return;
}
if (!flushed)
{
Flush();
}

ref var start = ref MemoryMarshal.GetArrayDataReference(queues);
ref var end = ref Unsafe.Add(ref start, onQueue);
Expand All @@ -257,38 +223,27 @@ public void Render(RenderPass renderPass)
{
BindUniformMatrix(start.Matrix);
renderPass.BindGraphicsPipeline(start.Material.ShaderPipeline);
renderPass.BindVertexBuffer(vertexBuffer);
renderPass.BindIndexBuffer(indexBuffer, IndexElementSize.ThirtyTwoBit);
renderPass.BindStorageVertexBuffer(batchBuffer);
renderPass.BindFragmentSampler(start.Binding);
start.Material.BindUniforms(new UniformBinder());
renderPass.DrawIndexedPrimitives(start.Count * 6u, 1, 0u, (int)(start.Offset * 4u), 0u);
renderPass.DrawPrimitives(start.Count * 6u, 1, start.Offset * 6);

start = ref Unsafe.Add(ref start, 1);
}
}

internal void ResizeBuffer()
{
transferComputeBuffer.Unmap();
transferBatchBuffer.Unmap();
uint maxTextures = (uint)(currentMaxTexture += 2048);

indexBuffer.Dispose();
indexBuffer = GenerateIndexArray(device, (uint)(maxTextures * 6));

vertexBuffer.Dispose();
vertexBuffer = new StructuredBuffer<PositionTextureColorVertex>(
device,
BufferUsageFlags.Vertex
| BufferUsageFlags.ComputeStorageRead
| BufferUsageFlags.ComputeStorageWrite, maxTextures * 4);
transferBatchBuffer.Dispose();
transferBatchBuffer = TransferBuffer.Create<BatchData>(device, TransferBufferUsage.Upload, maxTextures);

transferComputeBuffer.Dispose();
transferComputeBuffer = TransferBuffer.Create<BatchData>(device, TransferBufferUsage.Upload, maxTextures);

computeBuffer.Dispose();
computeBuffer = new StructuredBuffer<BatchData>(device, BufferUsageFlags.ComputeStorageRead, maxTextures);
batchBuffer.Dispose();
batchBuffer = new StructuredBuffer<BatchData>(device, BufferUsageFlags.ComputeStorageRead, maxTextures);
currentMaxTexture = maxTextures;
transferComputeBuffer.Map(true);
transferBatchBuffer.Map(true);
}

/// <summary>
Expand All @@ -301,8 +256,8 @@ protected virtual void Dispose(bool disposing)
{
if (disposing)
{
vertexBuffer.Dispose();
indexBuffer.Dispose();
batchBuffer.Dispose();
transferBatchBuffer.Dispose();
}

IsDisposed = true;
Expand Down Expand Up @@ -411,16 +366,14 @@ public unsafe void Draw(TextureQuad quad, Vector2 position, Color color, Vector2
{
ResizeBuffer();
}
var datas = transferComputeBuffer.MappedTouch<BatchData>();
var datas = transferBatchBuffer.MappedTouch<BatchData>();
datas[(int)vertexIndex] = new BatchData
{
Position = position,
Scale = scale,
Origin = origin,
Position = new Vector3(position, layerDepth),
Scale = new Vector2(quad.Source.Width, quad.Source.Height) * scale,
Origin = origin * scale,
UV = quad.UV,
Dimension = new Vector2(quad.Source.Width, quad.Source.Height),
Rotation = rotation,
Depth = layerDepth,
Color = color.ToVector4(),
};

Expand Down Expand Up @@ -466,7 +419,7 @@ public void Draw(SpriteFont font, string text, Vector2 position, Color color, Ve
_ => throw new NotImplementedException()
};

font.Draw(transferComputeBuffer.MappedTouch<BatchData>(), ref vertexIndex, text, position, justify, color, scale, layerDepth);
font.Draw(transferBatchBuffer.MappedTouch<BatchData>(), ref vertexIndex, text, position, justify, color, scale, layerDepth);
}

#if DEBUG
Expand Down Expand Up @@ -511,25 +464,21 @@ private struct BatchQueue
public Matrix4x4 Matrix;
}

[StructLayout(LayoutKind.Explicit, Size = 96)]
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct BatchData
{
[FieldOffset(0)]
public Vector2 Position;
[FieldOffset(8)]
public Vector2 Scale;
[FieldOffset(16)]
public Vector2 Origin;
[FieldOffset(24)]
public UV UV;
[FieldOffset(56)]
public Vector2 Dimension;
[FieldOffset(64)]
[FieldOffset(32)]
public Vector3 Position;
[FieldOffset(44)]
public float Rotation;
[FieldOffset(68)]
public float Depth;
[FieldOffset(80)]
[FieldOffset(48)]
public Vector4 Color;
[FieldOffset(64)]
public Vector2 Scale;
[FieldOffset(72)]
public Vector2 Origin;
}
}

Expand Down
Loading

0 comments on commit 8081d1f

Please sign in to comment.