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