initial commit
						commit
						accf424699
					
				|  | @ -0,0 +1 @@ | ||||||
|  | moonlibs/**/* filter=lfs diff=lfs merge=lfs -text | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | bin/ | ||||||
|  | obj/ | ||||||
|  | .vscode/ | ||||||
|  | .vs/ | ||||||
|  | Properties/ | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | [submodule "lib/MoonWorks"] | ||||||
|  | 	path = lib/MoonWorks | ||||||
|  | 	url = https://gitea.moonside.games/MoonsideGames/MoonWorks.git | ||||||
|  | @ -0,0 +1,38 @@ | ||||||
|  | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|  | 
 | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <OutputType>Exe</OutputType> | ||||||
|  |     <TargetFramework>net5.0</TargetFramework> | ||||||
|  |     <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||||
|  |   </PropertyGroup> | ||||||
|  | 
 | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <DefaultItemExcludes>$(DefaultItemExcludes);lib\**\*</DefaultItemExcludes> | ||||||
|  |   </PropertyGroup> | ||||||
|  | 
 | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="lib\MoonWorks\MoonWorks.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  | 
 | ||||||
|  |   <ItemGroup> | ||||||
|  |     <Content Include="Content\**\*.*"> | ||||||
|  |       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||||
|  |     </Content> | ||||||
|  |   </ItemGroup> | ||||||
|  | 
 | ||||||
|  | 	<ItemGroup> | ||||||
|  | 		<Content Include=".\moonlibs\windows\**\*.*" Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true' AND '$(Platform)' != 'x86'"> | ||||||
|  | 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||||
|  | 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|  | 		</Content> | ||||||
|  | 		<Content Include=".\moonlibs\osx\**\*.*" Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'" > | ||||||
|  | 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||||
|  | 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|  | 		</Content> | ||||||
|  | 		<Content Include=".\moonlibs\lib64\**\*.*" Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'" > | ||||||
|  | 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||||
|  | 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|  | 		</Content> | ||||||
|  | 	</ItemGroup> | ||||||
|  | 
 | ||||||
|  | </Project> | ||||||
|  | @ -0,0 +1,34 @@ | ||||||
|  |  | ||||||
|  | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||||
|  | # Visual Studio Version 16 | ||||||
|  | VisualStudioVersion = 16.0.30114.105 | ||||||
|  | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
|  | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonWorksComputeSpriteBatch", "MoonWorksComputeSpriteBatch.csproj", "{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}" | ||||||
|  | EndProject | ||||||
|  | Global | ||||||
|  | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
|  | 		Debug|Any CPU = Debug|Any CPU | ||||||
|  | 		Debug|x64 = Debug|x64 | ||||||
|  | 		Debug|x86 = Debug|x86 | ||||||
|  | 		Release|Any CPU = Release|Any CPU | ||||||
|  | 		Release|x64 = Release|x64 | ||||||
|  | 		Release|x86 = Release|x86 | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(SolutionProperties) = preSolution | ||||||
|  | 		HideSolutionNode = FALSE | ||||||
|  | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|x64.Build.0 = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Debug|x86.Build.0 = Debug|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|x64.ActiveCfg = Release|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|x64.Build.0 = Release|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|x86.ActiveCfg = Release|Any CPU | ||||||
|  | 		{1AAA8AA3-3376-4369-A9CB-1F10A51DDE07}.Release|x86.Build.0 = Release|Any CPU | ||||||
|  | 	EndGlobalSection | ||||||
|  | EndGlobal | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | Subproject commit 8022cd101124163306329913c918e379fd57aebf | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | #version 450 | ||||||
|  | 
 | ||||||
|  | layout(set = 1, binding = 0) uniform sampler2D uniformTexture; | ||||||
|  | 
 | ||||||
|  | layout(location = 0) in vec2 fragCoord; | ||||||
|  | layout(location = 0) out vec4 fragColor; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     fragColor = texture(uniformTexture, fragCoord); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | #version 450 | ||||||
|  | 
 | ||||||
|  | layout(location = 0) in vec3 inPosition; | ||||||
|  | layout(location = 1) in vec2 inTexCoord; | ||||||
|  | 
 | ||||||
|  | layout(location = 0) out vec2 fragCoord; | ||||||
|  | 
 | ||||||
|  | layout(set = 2, binding = 0) uniform UBO | ||||||
|  | { | ||||||
|  |     mat4 viewProjection; | ||||||
|  | } ubo; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  | 	gl_Position = ubo.viewProjection * vec4(inPosition, 1.0); | ||||||
|  | 	fragCoord = inTexCoord; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,44 @@ | ||||||
|  | #version 450 | ||||||
|  | 
 | ||||||
|  | struct Vertex | ||||||
|  | { | ||||||
|  |     vec3 position; | ||||||
|  |     vec2 texcoord; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Binding 0: vertices | ||||||
|  | layout(set = 0, binding = 0) buffer Vertices | ||||||
|  | { | ||||||
|  |     Vertex vertices[ ]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Binding 1: transform matrices | ||||||
|  | layout(set = 0, binding = 1) buffer Transforms | ||||||
|  | { | ||||||
|  |     mat4 transforms[ ]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout(set = 2, binding = 0) uniform UBO | ||||||
|  | { | ||||||
|  |     uint vertexCount; | ||||||
|  | } ubo; | ||||||
|  | 
 | ||||||
|  | layout (local_size_x = 256) in; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     // Current buffer index | ||||||
|  |     uint index = gl_GlobalInvocationID.x; | ||||||
|  | 
 | ||||||
|  |     // Don't write past particle count | ||||||
|  |     if (index >= ubo.vertexCount) | ||||||
|  |     { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint transformIndex = index / 4; | ||||||
|  |     mat4 transform = transforms[transformIndex]; | ||||||
|  |     vec4 position = vec4(vertices[index].position, 1.0); | ||||||
|  | 
 | ||||||
|  |     vertices[index].position = vec3(transform * position); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | using MoonWorks.Math; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     [StructLayout(LayoutKind.Sequential)] | ||||||
|  |     public struct CameraUniforms | ||||||
|  |     { | ||||||
|  |         public Matrix4x4 viewProjectionMatrix; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | using MoonWorks.Window; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     class Program | ||||||
|  |     { | ||||||
|  |         static void Main(string[] args) | ||||||
|  |         { | ||||||
|  |             WindowCreateInfo windowCreateInfo = new WindowCreateInfo | ||||||
|  |             { | ||||||
|  |                 WindowTitle = "Compute Sprite Batch", | ||||||
|  |                 WindowWidth = 1280, | ||||||
|  |                 WindowHeight = 720, | ||||||
|  |                 ScreenMode = ScreenMode.Windowed | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             TestGame game = new TestGame(windowCreateInfo, MoonWorks.Graphics.PresentMode.FIFO, 60, true); | ||||||
|  |             game.Run(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,18 @@ | ||||||
|  | using MoonWorks.Graphics; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     public struct Sprite | ||||||
|  |     { | ||||||
|  |         public Rect Texcoord { get; } | ||||||
|  |         public uint Width { get; } | ||||||
|  |         public uint Height { get; } | ||||||
|  | 
 | ||||||
|  |         public Sprite(Rect texcoord, uint width, uint height) | ||||||
|  |         { | ||||||
|  |             Texcoord = texcoord; | ||||||
|  |             Width = width; | ||||||
|  |             Height = height; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,173 @@ | ||||||
|  | using System.IO; | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | using MoonWorks.Graphics; | ||||||
|  | using MoonWorks.Math; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     [StructLayout(LayoutKind.Sequential)] | ||||||
|  |     public struct SpriteBatchUniforms | ||||||
|  |     { | ||||||
|  |         public uint VertexCount { get; set; } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class SpriteBatch | ||||||
|  |     { | ||||||
|  |         private const int MAX_SPRITES = 16384; | ||||||
|  |         private const int MAX_VERTICES = MAX_SPRITES * 4; | ||||||
|  |         private const int MAX_INDICES = MAX_SPRITES * 6; | ||||||
|  |         private const int MAX_MATRICES = MAX_SPRITES; | ||||||
|  | 
 | ||||||
|  |         private static ComputePipeline ComputePipeline = null; | ||||||
|  | 
 | ||||||
|  |         private Buffer VertexBuffer { get; } | ||||||
|  |         private Buffer IndexBuffer { get; } | ||||||
|  |         private Buffer TransformBuffer { get; } | ||||||
|  | 
 | ||||||
|  |         private readonly VertexPositionTexcoord[] Vertices; | ||||||
|  |         private static readonly short[] Indices = GenerateIndexArray(); | ||||||
|  |         private readonly Matrix4x4[] Transforms; | ||||||
|  | 
 | ||||||
|  |         private Texture CurrentTexture { get; set; } | ||||||
|  |         private Sampler CurrentSampler { get; set; } | ||||||
|  |         private uint VertexCount { get; set; } | ||||||
|  |         private uint TransformCount { get; set; } | ||||||
|  | 
 | ||||||
|  |         public SpriteBatch(GraphicsDevice graphicsDevice) | ||||||
|  |         { | ||||||
|  |             if (ComputePipeline == null) | ||||||
|  |             { | ||||||
|  |                 var computeShaderModule = new ShaderModule(graphicsDevice, Path.Combine(System.Environment.CurrentDirectory, "Content", "spritebatch.comp.spv")); | ||||||
|  | 
 | ||||||
|  |                 var computeShaderState = new ShaderStageState | ||||||
|  |                 { | ||||||
|  |                     ShaderModule = computeShaderModule, | ||||||
|  |                     EntryPointName = "main", | ||||||
|  |                     UniformBufferSize = (uint) Marshal.SizeOf<SpriteBatchUniforms>() | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 ComputePipeline = new ComputePipeline(graphicsDevice, computeShaderState, 2, 0); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Vertices = new VertexPositionTexcoord[MAX_VERTICES]; | ||||||
|  |             VertexBuffer = new Buffer( | ||||||
|  |                 graphicsDevice, | ||||||
|  |                 BufferUsageFlags.Vertex | BufferUsageFlags.Compute, | ||||||
|  |                 (uint)(MAX_VERTICES * Marshal.SizeOf<VertexPositionTexcoord>()) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             IndexBuffer = new Buffer( | ||||||
|  |                 graphicsDevice, | ||||||
|  |                 BufferUsageFlags.Index | BufferUsageFlags.Compute, | ||||||
|  |                 MAX_INDICES * sizeof(short) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             Transforms = new Matrix4x4[MAX_MATRICES]; | ||||||
|  |             TransformBuffer = new Buffer( | ||||||
|  |                 graphicsDevice, | ||||||
|  |                 BufferUsageFlags.Compute, | ||||||
|  |                 (uint)(MAX_MATRICES * Marshal.SizeOf<Matrix4x4>()) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             var commandBuffer = graphicsDevice.AcquireCommandBuffer(); | ||||||
|  |             commandBuffer.SetBufferData(IndexBuffer, Indices); | ||||||
|  |             graphicsDevice.Submit(commandBuffer); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Start(Texture texture, Sampler sampler) | ||||||
|  |         { | ||||||
|  |             TransformCount = 0; | ||||||
|  |             VertexCount = 0; | ||||||
|  |             CurrentTexture = texture; | ||||||
|  |             CurrentSampler = sampler; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Add(Sprite sprite, Matrix4x4 transform) | ||||||
|  |         { | ||||||
|  |             Vertices[VertexCount].position.X = 0; | ||||||
|  |             Vertices[VertexCount].position.Y = 0; | ||||||
|  |             Vertices[VertexCount].texcoord.X = sprite.Texcoord.X; | ||||||
|  |             Vertices[VertexCount].texcoord.Y = sprite.Texcoord.Y; | ||||||
|  | 
 | ||||||
|  |             Vertices[VertexCount + 1].position.X = sprite.Width; | ||||||
|  |             Vertices[VertexCount + 1].position.Y = 0; | ||||||
|  |             Vertices[VertexCount + 1].texcoord.X = sprite.Texcoord.X + sprite.Texcoord.W; | ||||||
|  |             Vertices[VertexCount + 1].texcoord.Y = sprite.Texcoord.Y; | ||||||
|  | 
 | ||||||
|  |             Vertices[VertexCount + 2].position.X = 0; | ||||||
|  |             Vertices[VertexCount + 2].position.Y = sprite.Height; | ||||||
|  |             Vertices[VertexCount + 2].texcoord.X = sprite.Texcoord.X; | ||||||
|  |             Vertices[VertexCount + 2].texcoord.Y = sprite.Texcoord.Y + sprite.Texcoord.H; | ||||||
|  | 
 | ||||||
|  |             Vertices[VertexCount + 3].position.X = sprite.Width; | ||||||
|  |             Vertices[VertexCount + 3].position.Y = sprite.Height; | ||||||
|  |             Vertices[VertexCount + 3].texcoord.X = sprite.Texcoord.X + sprite.Texcoord.W; | ||||||
|  |             Vertices[VertexCount + 3].texcoord.Y = sprite.Texcoord.Y + sprite.Texcoord.H; | ||||||
|  | 
 | ||||||
|  |             VertexCount += 4; | ||||||
|  | 
 | ||||||
|  |             Transforms[TransformCount] = transform; | ||||||
|  |             TransformCount += 1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Flush( | ||||||
|  |             CommandBuffer commandBuffer, | ||||||
|  |             RenderPass renderPass, | ||||||
|  |             Framebuffer framebuffer, | ||||||
|  |             Rect renderArea, | ||||||
|  |             GraphicsPipeline graphicsPipeline, | ||||||
|  |             CameraUniforms cameraUniforms | ||||||
|  |         ) { | ||||||
|  |             if (VertexCount == 0) | ||||||
|  |             { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             commandBuffer.SetBufferData(VertexBuffer, Vertices, 0, 0, VertexCount); | ||||||
|  |             commandBuffer.SetBufferData(TransformBuffer, Transforms, 0, 0, TransformCount); | ||||||
|  | 
 | ||||||
|  |             commandBuffer.BindComputePipeline(ComputePipeline); | ||||||
|  |             commandBuffer.BindComputeBuffers(VertexBuffer, TransformBuffer); | ||||||
|  |             var offset = commandBuffer.PushComputeShaderUniforms(new SpriteBatchUniforms | ||||||
|  |             { | ||||||
|  |                 VertexCount = VertexCount | ||||||
|  |             }); | ||||||
|  |             commandBuffer.DispatchCompute(VertexCount / 256, 1, 1, offset); | ||||||
|  | 
 | ||||||
|  |             commandBuffer.BeginRenderPass(renderPass, framebuffer, renderArea, Vector4.Zero); | ||||||
|  |             commandBuffer.BindGraphicsPipeline(graphicsPipeline); | ||||||
|  |             commandBuffer.BindVertexBuffers(VertexBuffer); | ||||||
|  |             commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.Sixteen); | ||||||
|  |             commandBuffer.BindFragmentSamplers(new TextureSamplerBinding { Texture = CurrentTexture, Sampler = CurrentSampler }); | ||||||
|  |             offset = commandBuffer.PushVertexShaderUniforms(cameraUniforms); | ||||||
|  | 
 | ||||||
|  |             commandBuffer.DrawIndexedPrimitives( | ||||||
|  |                 0, | ||||||
|  |                 0, | ||||||
|  |                 VertexCount / 2, | ||||||
|  |                 offset, | ||||||
|  |                 0 | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             commandBuffer.EndRenderPass(); | ||||||
|  | 
 | ||||||
|  |             VertexCount = 0; | ||||||
|  |             TransformCount = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private static short[] GenerateIndexArray() | ||||||
|  |         { | ||||||
|  |             var result = new short[MAX_INDICES]; | ||||||
|  |             for (int i = 0, j = 0; i < MAX_INDICES; i += 6, j += 4) | ||||||
|  |             { | ||||||
|  |                 result[i] = (short)j; | ||||||
|  |                 result[i + 1] = (short)(j + 1); | ||||||
|  |                 result[i + 2] = (short)(j + 2); | ||||||
|  |                 result[i + 3] = (short)(j + 2); | ||||||
|  |                 result[i + 4] = (short)(j + 1); | ||||||
|  |                 result[i + 5] = (short)(j + 3); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,237 @@ | ||||||
|  | using System; | ||||||
|  | using System.IO; | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | using MoonWorks; | ||||||
|  | using MoonWorks.Graphics; | ||||||
|  | using MoonWorks.Math; | ||||||
|  | using MoonWorks.Window; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     public class TestGame : Game | ||||||
|  |     { | ||||||
|  |         private RenderPass mainRenderPass; | ||||||
|  |         private RenderTarget mainColorTarget; | ||||||
|  |         private Framebuffer mainFramebuffer; | ||||||
|  |         private Rect mainRenderArea; | ||||||
|  | 
 | ||||||
|  |         private GraphicsPipeline spritePipeline; | ||||||
|  | 
 | ||||||
|  |         private SpriteBatch spriteBatch; | ||||||
|  | 
 | ||||||
|  |         private Texture whitePixel; | ||||||
|  |         private Sampler sampler; | ||||||
|  | 
 | ||||||
|  |         private const int SPRITECOUNT = 8092; | ||||||
|  |         private Vector3[] positions = new Vector3[SPRITECOUNT]; | ||||||
|  | 
 | ||||||
|  |         private uint windowWidth; | ||||||
|  |         private uint windowHeight; | ||||||
|  | 
 | ||||||
|  |         private Random random = new Random(); | ||||||
|  | 
 | ||||||
|  |         public TestGame(WindowCreateInfo windowCreateInfo, PresentMode presentMode, int targetTimestep = 60, bool debugMode = false) : base(windowCreateInfo, presentMode, targetTimestep, debugMode) | ||||||
|  |         { | ||||||
|  |             windowWidth = windowCreateInfo.WindowWidth; | ||||||
|  |             windowHeight = windowCreateInfo.WindowHeight; | ||||||
|  | 
 | ||||||
|  |             var vertexShaderModule = new ShaderModule(GraphicsDevice, Path.Combine(Environment.CurrentDirectory, "Content", "sprite.vert.spv")); | ||||||
|  |             var fragmentShaderModule = new ShaderModule(GraphicsDevice, Path.Combine(Environment.CurrentDirectory, "Content", "sprite.frag.spv")); | ||||||
|  | 
 | ||||||
|  |             ColorTargetDescription colorTargetDescription = new ColorTargetDescription | ||||||
|  |             { | ||||||
|  |                 Format = TextureFormat.R8G8B8A8, | ||||||
|  |                 MultisampleCount = SampleCount.One, | ||||||
|  |                 LoadOp = LoadOp.Clear, | ||||||
|  |                 StoreOp = StoreOp.Store | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             mainRenderPass = new RenderPass(GraphicsDevice, colorTargetDescription); | ||||||
|  | 
 | ||||||
|  |             mainColorTarget = RenderTarget.CreateBackedRenderTarget( | ||||||
|  |                 GraphicsDevice, | ||||||
|  |                 windowWidth, | ||||||
|  |                 windowHeight, | ||||||
|  |                 TextureFormat.R8G8B8A8, | ||||||
|  |                 false | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             mainFramebuffer = new Framebuffer( | ||||||
|  |                 GraphicsDevice, | ||||||
|  |                 windowWidth, | ||||||
|  |                 windowHeight, | ||||||
|  |                 mainRenderPass, | ||||||
|  |                 null, | ||||||
|  |                 mainColorTarget | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             mainRenderArea = new Rect | ||||||
|  |             { | ||||||
|  |                 X = 0, | ||||||
|  |                 Y = 0, | ||||||
|  |                 W = (int) windowWidth, | ||||||
|  |                 H = (int) windowHeight | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             /* Pipeline */ | ||||||
|  | 
 | ||||||
|  |             ColorTargetBlendState[] colorTargetBlendStates = new ColorTargetBlendState[1] | ||||||
|  |             { | ||||||
|  |                 ColorTargetBlendState.None | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             ColorBlendState colorBlendState = new ColorBlendState | ||||||
|  |             { | ||||||
|  |                 LogicOpEnable = false, | ||||||
|  |                 LogicOp = LogicOp.NoOp, | ||||||
|  |                 BlendConstants = new BlendConstants(), | ||||||
|  |                 ColorTargetBlendStates = colorTargetBlendStates | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             DepthStencilState depthStencilState = DepthStencilState.Disable; | ||||||
|  | 
 | ||||||
|  |             ShaderStageState vertexShaderState = new ShaderStageState | ||||||
|  |             { | ||||||
|  |                 ShaderModule = vertexShaderModule, | ||||||
|  |                 EntryPointName = "main", | ||||||
|  |                 UniformBufferSize = (uint) Marshal.SizeOf<CameraUniforms>() | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             ShaderStageState fragmentShaderState = new ShaderStageState | ||||||
|  |             { | ||||||
|  |                 ShaderModule = fragmentShaderModule, | ||||||
|  |                 EntryPointName = "main", | ||||||
|  |                 UniformBufferSize = 0 | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             MultisampleState multisampleState = MultisampleState.None; | ||||||
|  | 
 | ||||||
|  |             GraphicsPipelineLayoutInfo pipelineLayoutInfo = new GraphicsPipelineLayoutInfo | ||||||
|  |             { | ||||||
|  |                 VertexSamplerBindingCount = 0, | ||||||
|  |                 FragmentSamplerBindingCount = 1 | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             RasterizerState rasterizerState = RasterizerState.CCW_CullNone; | ||||||
|  | 
 | ||||||
|  |             var vertexBindings = new VertexBinding[1] | ||||||
|  |             { | ||||||
|  |                 new VertexBinding | ||||||
|  |                 { | ||||||
|  |                     Binding = 0, | ||||||
|  |                     InputRate = VertexInputRate.Vertex, | ||||||
|  |                     Stride = (uint) Marshal.SizeOf<VertexPositionTexcoord>() | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             var vertexAttributes = new VertexAttribute[2] | ||||||
|  |             { | ||||||
|  |                 new VertexAttribute | ||||||
|  |                 { | ||||||
|  |                     Binding = 0, | ||||||
|  |                     Location = 0, | ||||||
|  |                     Format = VertexElementFormat.Vector3, | ||||||
|  |                     Offset = 0 | ||||||
|  |                 }, | ||||||
|  |                 new VertexAttribute | ||||||
|  |                 { | ||||||
|  |                     Binding = 0, | ||||||
|  |                     Location = 1, | ||||||
|  |                     Format = VertexElementFormat.Vector2, | ||||||
|  |                     Offset = (uint) Marshal.OffsetOf<VertexPositionTexcoord>("texcoord") | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             VertexInputState vertexInputState = new VertexInputState | ||||||
|  |             { | ||||||
|  |                 VertexBindings = vertexBindings, | ||||||
|  |                 VertexAttributes = vertexAttributes | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             var viewports = new Viewport[1] | ||||||
|  |             { | ||||||
|  |                 new Viewport | ||||||
|  |                 { | ||||||
|  |                     X = 0, | ||||||
|  |                     Y = 0, | ||||||
|  |                     W = windowWidth, | ||||||
|  |                     H = windowHeight, | ||||||
|  |                     MinDepth = 0, | ||||||
|  |                     MaxDepth = 1 | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             var scissors = new Rect[1] | ||||||
|  |             { | ||||||
|  |                 new Rect | ||||||
|  |                 { | ||||||
|  |                     X = 0, | ||||||
|  |                     Y = 0, | ||||||
|  |                     W = (int) windowWidth, | ||||||
|  |                     H = (int) windowHeight | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             ViewportState viewportState = new ViewportState | ||||||
|  |             { | ||||||
|  |                 Viewports = viewports, | ||||||
|  |                 Scissors = scissors | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             var graphicsPipelineCreateInfo = new GraphicsPipelineCreateInfo | ||||||
|  |             { | ||||||
|  |                 ColorBlendState = colorBlendState, | ||||||
|  |                 DepthStencilState = depthStencilState, | ||||||
|  |                 VertexShaderState = vertexShaderState, | ||||||
|  |                 FragmentShaderState = fragmentShaderState, | ||||||
|  |                 MultisampleState = multisampleState, | ||||||
|  |                 PipelineLayoutInfo = pipelineLayoutInfo, | ||||||
|  |                 RasterizerState = rasterizerState, | ||||||
|  |                 PrimitiveType = PrimitiveType.TriangleList, | ||||||
|  |                 VertexInputState = vertexInputState, | ||||||
|  |                 ViewportState = viewportState, | ||||||
|  |                 RenderPass = mainRenderPass | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             spritePipeline = new GraphicsPipeline(GraphicsDevice, graphicsPipelineCreateInfo); | ||||||
|  | 
 | ||||||
|  |             spriteBatch = new SpriteBatch(GraphicsDevice); | ||||||
|  | 
 | ||||||
|  |             whitePixel = Texture.CreateTexture2D(GraphicsDevice, 1, 1, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler); | ||||||
|  | 
 | ||||||
|  |             var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); | ||||||
|  |             commandBuffer.SetTextureData(whitePixel, new Color[] { Color.White }); | ||||||
|  |             GraphicsDevice.Submit(commandBuffer); | ||||||
|  | 
 | ||||||
|  |             sampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointWrap); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override void Update(TimeSpan dt) | ||||||
|  |         { | ||||||
|  |             for (var i = 0; i < SPRITECOUNT; i += 1) | ||||||
|  |             { | ||||||
|  |                 positions[i].X = (float) (random.NextDouble() * windowWidth) - 64; | ||||||
|  |                 positions[i].Y = (float) (random.NextDouble() * windowHeight) - 64; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override void Draw(TimeSpan dt, double alpha) | ||||||
|  |         { | ||||||
|  |             var commandBuffer = GraphicsDevice.AcquireCommandBuffer(); | ||||||
|  | 
 | ||||||
|  |             var viewProjection = Matrix4x4.CreateLookAt(new Vector3(windowWidth / 2, windowHeight / 2, 1), new Vector3(windowWidth / 2, windowHeight / 2, 0), Vector3.Up) * Matrix4x4.CreateOrthographic(windowWidth, windowHeight, 0.1f, 1000); | ||||||
|  |             spriteBatch.Start(whitePixel, sampler); | ||||||
|  | 
 | ||||||
|  |             for (var i = 0; i < SPRITECOUNT; i += 1) | ||||||
|  |             { | ||||||
|  |                 var transform = Matrix4x4.CreateTranslation(positions[i]); | ||||||
|  |                 spriteBatch.Add(new Sprite(new Rect { X = 0, Y = 0, W = 0, H = 0 }, 128, 128), transform); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             spriteBatch.Flush(commandBuffer, mainRenderPass, mainFramebuffer, mainRenderArea, spritePipeline, new CameraUniforms { viewProjectionMatrix = viewProjection }); | ||||||
|  | 
 | ||||||
|  |             commandBuffer.QueuePresent(mainColorTarget.TextureSlice, Filter.Nearest); | ||||||
|  |             GraphicsDevice.Submit(commandBuffer); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | using MoonWorks.Math; | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | 
 | ||||||
|  | namespace MoonWorksComputeSpriteBatch | ||||||
|  | { | ||||||
|  |     // SPIR-V requires vectors to not cross 16-byte boundaries | ||||||
|  |     [StructLayout(LayoutKind.Explicit, Size=32)] | ||||||
|  |     public struct VertexPositionTexcoord | ||||||
|  |     { | ||||||
|  |         [FieldOffset(0)] | ||||||
|  |         public Vector3 position; | ||||||
|  |         [FieldOffset(16)] | ||||||
|  |         public Vector2 texcoord; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue