compute sprite batch
parent
f17e9851f3
commit
041b52ed44
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
#version 450
|
||||
|
||||
layout (local_size_x = 8) in;
|
||||
layout (set = 1, binding = 0) buffer outBuffer
|
||||
layout (set = 1, binding = 0) writeonly buffer outBuffer
|
||||
{
|
||||
uint squares[];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
#version 450
|
||||
|
||||
struct SpriteComputeData
|
||||
{
|
||||
vec3 position;
|
||||
float rotation;
|
||||
vec2 scale;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
struct SpriteVertex
|
||||
{
|
||||
vec4 position;
|
||||
vec2 texcoord;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
|
||||
layout (std430, set = 0, binding = 0) readonly buffer inBuffer
|
||||
{
|
||||
SpriteComputeData computeData[];
|
||||
};
|
||||
layout (std430, set = 1, binding = 0) writeonly buffer outBuffer
|
||||
{
|
||||
SpriteVertex vertexData[];
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
uint n = gl_GlobalInvocationID.x;
|
||||
|
||||
SpriteComputeData currentSpriteData = computeData[n];
|
||||
|
||||
mat4 Scale = mat4(
|
||||
currentSpriteData.scale.x, 0, 0, 0,
|
||||
0, currentSpriteData.scale.y, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
|
||||
float c = cos(currentSpriteData.rotation);
|
||||
float s = sin(currentSpriteData.rotation);
|
||||
|
||||
mat4 Rotation = mat4(
|
||||
c, s, 0, 0,
|
||||
-s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
|
||||
mat4 Translation = mat4(
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
currentSpriteData.position.x, currentSpriteData.position.y, currentSpriteData.position.z, 1
|
||||
);
|
||||
|
||||
mat4 Model = Translation * Rotation * Scale;
|
||||
|
||||
vec4 topLeft = vec4(0, 0, 0, 1);
|
||||
vec4 topRight = vec4(1, 0, 0, 1);
|
||||
vec4 bottomLeft = vec4(0, 1, 0, 1);
|
||||
vec4 bottomRight = vec4(1, 1, 0, 1);
|
||||
|
||||
vertexData[n*4] .position = Model * topLeft;
|
||||
vertexData[n*4+1].position = Model * topRight;
|
||||
vertexData[n*4+2].position = Model * bottomLeft;
|
||||
vertexData[n*4+3].position = Model * bottomRight;
|
||||
|
||||
vertexData[n*4] .texcoord = vec2(0, 0);
|
||||
vertexData[n*4+1].texcoord = vec2(1, 0);
|
||||
vertexData[n*4+2].texcoord = vec2(0, 1);
|
||||
vertexData[n*4+3].texcoord = vec2(1, 1);
|
||||
|
||||
vertexData[n*4] .color = currentSpriteData.color;
|
||||
vertexData[n*4+1].color = currentSpriteData.color;
|
||||
vertexData[n*4+2].color = currentSpriteData.color;
|
||||
vertexData[n*4+3].color = currentSpriteData.color;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec2 TexCoord;
|
||||
layout (location = 1) in vec4 Color;
|
||||
|
||||
layout (location = 0) out vec4 FragColor;
|
||||
|
||||
layout(set = 2, binding = 0) uniform sampler2D Sampler;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = Color * texture(Sampler, TexCoord);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec4 Position;
|
||||
layout (location = 1) in vec2 TexCoord;
|
||||
layout (location = 2) in vec4 Color;
|
||||
|
||||
layout (location = 0) out vec2 outTexCoord;
|
||||
layout (location = 1) out vec4 outColor;
|
||||
|
||||
layout (set = 1, binding = 0) uniform UniformBlock
|
||||
{
|
||||
mat4x4 MatrixTransform;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
outTexCoord = TexCoord;
|
||||
outColor = Color;
|
||||
gl_Position = MatrixTransform * Position;
|
||||
}
|
|
@ -14,10 +14,12 @@ public struct PositionVertex : IVertexType
|
|||
Position = position;
|
||||
}
|
||||
|
||||
public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[1]
|
||||
{
|
||||
public static VertexElementFormat[] Formats { get; } =
|
||||
[
|
||||
VertexElementFormat.Vector3
|
||||
};
|
||||
];
|
||||
|
||||
public static uint[] Offsets { get; } = [ 0 ];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -37,11 +39,17 @@ public struct PositionColorVertex : IVertexType
|
|||
Color = color;
|
||||
}
|
||||
|
||||
public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[2]
|
||||
{
|
||||
public static VertexElementFormat[] Formats { get; } =
|
||||
[
|
||||
VertexElementFormat.Vector3,
|
||||
VertexElementFormat.Color
|
||||
};
|
||||
];
|
||||
|
||||
public static uint[] Offsets { get; } =
|
||||
[
|
||||
0,
|
||||
12
|
||||
];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -67,8 +75,41 @@ public struct PositionTextureVertex : IVertexType
|
|||
VertexElementFormat.Vector2
|
||||
};
|
||||
|
||||
public static uint[] Offsets { get; } =
|
||||
[
|
||||
0,
|
||||
12
|
||||
];
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Position + " | " + TexCoord;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 48)]
|
||||
struct PositionTextureColorVertex : IVertexType
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public Vector4 Position;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public Vector2 TexCoord;
|
||||
|
||||
[FieldOffset(32)]
|
||||
public Vector4 Color;
|
||||
|
||||
public static VertexElementFormat[] Formats { get; } =
|
||||
[
|
||||
VertexElementFormat.Vector4,
|
||||
VertexElementFormat.Vector2,
|
||||
VertexElementFormat.Vector4
|
||||
];
|
||||
|
||||
public static uint[] Offsets { get; } =
|
||||
[
|
||||
0,
|
||||
16,
|
||||
32
|
||||
];
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using MoonWorks;
|
||||
using MoonWorks.Graphics;
|
||||
using MoonWorks.Input;
|
||||
using MoonWorks.Math.Float;
|
||||
using Buffer = MoonWorks.Graphics.Buffer;
|
||||
|
||||
namespace MoonWorksGraphicsTests;
|
||||
|
||||
class ComputeSpriteBatchExample : Example
|
||||
{
|
||||
ComputePipeline ComputePipeline;
|
||||
GraphicsPipeline RenderPipeline;
|
||||
Sampler Sampler;
|
||||
Texture SpriteTexture;
|
||||
TransferBuffer SpriteComputeTransferBuffer;
|
||||
Buffer SpriteComputeBuffer;
|
||||
Buffer SpriteVertexBuffer;
|
||||
Buffer SpriteIndexBuffer;
|
||||
|
||||
const int MAX_SPRITE_COUNT = 8192;
|
||||
|
||||
Random Random = new Random();
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 48)]
|
||||
struct ComputeSpriteData
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public Vector3 Position;
|
||||
|
||||
[FieldOffset(12)]
|
||||
public float Rotation;
|
||||
|
||||
[FieldOffset(16)]
|
||||
public Vector2 Size;
|
||||
|
||||
[FieldOffset(32)]
|
||||
public Vector4 Color;
|
||||
}
|
||||
|
||||
public override unsafe void Init(Window window, GraphicsDevice graphicsDevice, Inputs inputs)
|
||||
{
|
||||
Window = window;
|
||||
GraphicsDevice = graphicsDevice;
|
||||
|
||||
Window.SetTitle("ComputeSpriteBatch");
|
||||
|
||||
Shader vertShader = new Shader(
|
||||
GraphicsDevice,
|
||||
TestUtils.GetShaderPath("TexturedQuadColorWithMatrix.vert"),
|
||||
"main",
|
||||
new ShaderCreateInfo
|
||||
{
|
||||
ShaderStage = ShaderStage.Vertex,
|
||||
ShaderFormat = ShaderFormat.SPIRV,
|
||||
UniformBufferCount = 1
|
||||
}
|
||||
);
|
||||
|
||||
Shader fragShader = new Shader(
|
||||
GraphicsDevice,
|
||||
TestUtils.GetShaderPath("TexturedQuadColor.frag"),
|
||||
"main",
|
||||
new ShaderCreateInfo
|
||||
{
|
||||
ShaderStage = ShaderStage.Fragment,
|
||||
ShaderFormat = ShaderFormat.SPIRV,
|
||||
SamplerCount = 1
|
||||
}
|
||||
);
|
||||
|
||||
GraphicsPipelineCreateInfo renderPipelineCreateInfo = TestUtils.GetStandardGraphicsPipelineCreateInfo(
|
||||
Window.SwapchainFormat,
|
||||
vertShader,
|
||||
fragShader
|
||||
);
|
||||
renderPipelineCreateInfo.VertexInputState = VertexInputState.CreateSingleBinding<PositionTextureColorVertex>();
|
||||
|
||||
RenderPipeline = new GraphicsPipeline(GraphicsDevice, renderPipelineCreateInfo);
|
||||
|
||||
ComputePipeline = new ComputePipeline(
|
||||
GraphicsDevice,
|
||||
TestUtils.GetShaderPath("SpriteBatch.comp"),
|
||||
"main",
|
||||
new ComputePipelineCreateInfo
|
||||
{
|
||||
ShaderFormat = ShaderFormat.SPIRV,
|
||||
ReadOnlyStorageBufferCount = 1,
|
||||
ReadWriteStorageBufferCount = 1,
|
||||
ThreadCountX = 64,
|
||||
ThreadCountY = 1,
|
||||
ThreadCountZ = 1
|
||||
}
|
||||
);
|
||||
|
||||
Sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp);
|
||||
|
||||
// Create and populate the sprite texture
|
||||
var resourceUploader = new ResourceUploader(GraphicsDevice);
|
||||
|
||||
SpriteTexture = resourceUploader.CreateTexture2DFromCompressed(TestUtils.GetTexturePath("ravioli.png"));
|
||||
|
||||
resourceUploader.Upload();
|
||||
resourceUploader.Dispose();
|
||||
|
||||
SpriteComputeTransferBuffer = TransferBuffer.Create<ComputeSpriteData>(
|
||||
GraphicsDevice,
|
||||
TransferUsage.Buffer,
|
||||
TransferBufferMapFlags.Write,
|
||||
MAX_SPRITE_COUNT
|
||||
);
|
||||
|
||||
SpriteComputeBuffer = Buffer.Create<ComputeSpriteData>(
|
||||
GraphicsDevice,
|
||||
BufferUsageFlags.ComputeStorageRead,
|
||||
MAX_SPRITE_COUNT
|
||||
);
|
||||
|
||||
SpriteVertexBuffer = Buffer.Create<PositionTextureColorVertex>(
|
||||
GraphicsDevice,
|
||||
BufferUsageFlags.ComputeStorageWrite | BufferUsageFlags.Vertex,
|
||||
MAX_SPRITE_COUNT * 4
|
||||
);
|
||||
|
||||
SpriteIndexBuffer = Buffer.Create<uint>(
|
||||
GraphicsDevice,
|
||||
BufferUsageFlags.Index,
|
||||
MAX_SPRITE_COUNT * 6
|
||||
);
|
||||
|
||||
TransferBuffer spriteIndexTransferBuffer = TransferBuffer.Create<uint>(
|
||||
GraphicsDevice,
|
||||
TransferUsage.Buffer,
|
||||
TransferBufferMapFlags.Write,
|
||||
MAX_SPRITE_COUNT * 6
|
||||
);
|
||||
|
||||
spriteIndexTransferBuffer.Map(false, out byte* mapPointer);
|
||||
uint *indexPointer = (uint*) mapPointer;
|
||||
|
||||
for (uint i = 0, j = 0; i < MAX_SPRITE_COUNT * 6; i += 6, j += 4)
|
||||
{
|
||||
indexPointer[i] = j;
|
||||
indexPointer[i + 1] = j + 1;
|
||||
indexPointer[i + 2] = j + 2;
|
||||
indexPointer[i + 3] = j + 3;
|
||||
indexPointer[i + 4] = j + 2;
|
||||
indexPointer[i + 5] = j + 1;
|
||||
}
|
||||
spriteIndexTransferBuffer.Unmap();
|
||||
|
||||
var cmdbuf = GraphicsDevice.AcquireCommandBuffer();
|
||||
var copyPass = cmdbuf.BeginCopyPass();
|
||||
copyPass.UploadToBuffer(spriteIndexTransferBuffer, SpriteIndexBuffer, false);
|
||||
cmdbuf.EndCopyPass(copyPass);
|
||||
GraphicsDevice.Submit(cmdbuf);
|
||||
}
|
||||
|
||||
public override void Update(TimeSpan delta)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override unsafe void Draw(double alpha)
|
||||
{
|
||||
Matrix4x4 cameraMatrix =
|
||||
Matrix4x4.CreateOrthographicOffCenter(
|
||||
0,
|
||||
640,
|
||||
480,
|
||||
0,
|
||||
0,
|
||||
-1f
|
||||
);
|
||||
|
||||
CommandBuffer cmdbuf = GraphicsDevice.AcquireCommandBuffer();
|
||||
Texture swapchainTexture = cmdbuf.AcquireSwapchainTexture(Window);
|
||||
if (swapchainTexture != null)
|
||||
{
|
||||
// Build sprite compute transfer
|
||||
SpriteComputeTransferBuffer.Map(true, out byte* mapPointer);
|
||||
ComputeSpriteData *dataPointer = (ComputeSpriteData*) mapPointer;
|
||||
|
||||
for (var i = 0; i < MAX_SPRITE_COUNT; i += 1)
|
||||
{
|
||||
dataPointer[i] = new ComputeSpriteData
|
||||
{
|
||||
Position = new Vector3(Random.Next(640), Random.Next(480), 0),
|
||||
Rotation = (float) (Random.NextDouble() * System.Math.PI * 2),
|
||||
Size = new Vector2(32, 32),
|
||||
Color = new Vector4(1f, 1f, 1f, 1f)
|
||||
};
|
||||
}
|
||||
SpriteComputeTransferBuffer.Unmap();
|
||||
|
||||
// Upload compute data to buffer
|
||||
var copyPass = cmdbuf.BeginCopyPass();
|
||||
copyPass.UploadToBuffer(SpriteComputeTransferBuffer, SpriteComputeBuffer, true);
|
||||
cmdbuf.EndCopyPass(copyPass);
|
||||
|
||||
// Set up compute pass to build sprite vertex buffer
|
||||
var computePass = cmdbuf.BeginComputePass(new StorageBufferReadWriteBinding
|
||||
{
|
||||
Buffer = SpriteVertexBuffer,
|
||||
Cycle = true
|
||||
});
|
||||
|
||||
computePass.BindComputePipeline(ComputePipeline);
|
||||
computePass.BindStorageBuffer(SpriteComputeBuffer);
|
||||
computePass.Dispatch(MAX_SPRITE_COUNT / 64, 1, 1);
|
||||
|
||||
cmdbuf.EndComputePass(computePass);
|
||||
|
||||
// Render sprites using vertex buffer
|
||||
var renderPass = cmdbuf.BeginRenderPass(
|
||||
new ColorAttachmentInfo(swapchainTexture, false, Color.Black)
|
||||
);
|
||||
|
||||
renderPass.BindGraphicsPipeline(RenderPipeline);
|
||||
renderPass.BindVertexBuffer(SpriteVertexBuffer);
|
||||
renderPass.BindIndexBuffer(SpriteIndexBuffer, IndexElementSize.ThirtyTwo);
|
||||
renderPass.BindFragmentSampler(new TextureSamplerBinding(SpriteTexture, Sampler));
|
||||
renderPass.PushVertexUniformData(cameraMatrix);
|
||||
renderPass.DrawIndexedPrimitives(0, 0, MAX_SPRITE_COUNT * 2);
|
||||
|
||||
cmdbuf.EndRenderPass(renderPass);
|
||||
}
|
||||
|
||||
GraphicsDevice.Submit(cmdbuf);
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
ComputePipeline.Dispose();
|
||||
RenderPipeline.Dispose();
|
||||
Sampler.Dispose();
|
||||
SpriteTexture.Dispose();
|
||||
SpriteComputeTransferBuffer.Dispose();
|
||||
SpriteComputeBuffer.Dispose();
|
||||
SpriteVertexBuffer.Dispose();
|
||||
SpriteIndexBuffer.Dispose();
|
||||
}
|
||||
}
|
|
@ -17,45 +17,6 @@
|
|||
<ProjectReference Include="..\MoonWorks\MoonWorks.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- TODO: remove this once examples are fully converted -->
|
||||
<PropertyGroup>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);Examples\**\*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Examples\Example.cs" />
|
||||
<Compile Include="Examples\BasicComputeExample.cs" />
|
||||
<Compile Include="Examples\BasicStencilExample.cs" />
|
||||
<Compile Include="Examples\BasicTriangleExample.cs" />
|
||||
<Compile Include="Examples\ClearScreenExample.cs" />
|
||||
<Compile Include="Examples\ClearScreen_MultiWindowExample.cs" />
|
||||
<Compile Include="Examples\CompressedTexturesExample.cs" />
|
||||
<Compile Include="Examples\ComputeUniformsExample.cs" />
|
||||
<Compile Include="Examples\CopyTextureExample.cs" />
|
||||
<Compile Include="Examples\CubeExample.cs" />
|
||||
<Compile Include="Examples\CullFaceExample.cs" />
|
||||
<Compile Include="Examples\DepthMSAAExample.cs" />
|
||||
<Compile Include="Examples\DrawIndirectExample.cs" />
|
||||
<Compile Include="Examples\GetBufferDataExample.cs" />
|
||||
<Compile Include="Examples\InstancingAndOffsetsExample.cs" />
|
||||
<Compile Include="Examples\MSAACubeExample.cs" />
|
||||
<Compile Include="Examples\MSAAExample.cs" />
|
||||
<Compile Include="Examples\RenderTexture2DArrayExample.cs" />
|
||||
<Compile Include="Examples\RenderTexture2DExample.cs" />
|
||||
<Compile Include="Examples\RenderTextureCubeExample.cs" />
|
||||
<Compile Include="Examples\RenderTextureMipmapsExample.cs" />
|
||||
<Compile Include="Examples\StoreLoadExample.cs" />
|
||||
<Compile Include="Examples\Texture3DCopyExample.cs" />
|
||||
<Compile Include="Examples\Texture3DExample.cs" />
|
||||
<Compile Include="Examples\TexturedAnimatedQuadExample.cs" />
|
||||
<Compile Include="Examples\TexturedQuadExample.cs" />
|
||||
<Compile Include="Examples\TextureMipmapsExample.cs" />
|
||||
<Compile Include="Examples\TriangleVertexBufferExample.cs" />
|
||||
<Compile Include="Examples\VertexSamplerExample.cs" />
|
||||
<Compile Include="Examples\VideoPlayerExample.cs" />
|
||||
<Compile Include="Examples\WindowResizingExample.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project=".\CopyMoonlibs.targets" />
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -37,7 +37,8 @@ class Program : Game
|
|||
new TriangleVertexBufferExample(),
|
||||
new VertexSamplerExample(),
|
||||
new VideoPlayerExample(),
|
||||
new WindowResizingExample()
|
||||
new WindowResizingExample(),
|
||||
new ComputeSpriteBatchExample()
|
||||
];
|
||||
|
||||
int ExampleIndex = 0;
|
||||
|
|
Loading…
Reference in New Issue