public Configure(GpuDevice device, Settings settings, GpuBindGroupLayout bindGroupLayout, GpuBindGroupLayout dynamicBindGroupLayout, GpuBindGroupLayout timeBindGroupLayout, GpuRenderPipeline pipeline, GpuRenderPipeline dynamicPipeline, GpuBuffer vertexBuffer, GpuTextureFormat swapChainFormat) { Device = device; Settings = settings; Pipeline = pipeline; DynamicPipeline = dynamicPipeline; VertexBuffer = vertexBuffer; SwapChainFormat = swapChainFormat; UniformBuffer = Device.CreateBuffer(new GpuBufferDescriptor(Settings.NumTriangles * AlignedUniformBytes + sizeof(float), GpuBufferUsageFlags.Uniform | GpuBufferUsageFlags.CopyDst)); var uniformCpuBuffer = new Windows.Storage.Streams.Buffer(Settings.NumTriangles * AlignedUniformBytes) { Length = Settings.NumTriangles * AlignedUniformBytes }; using (var uniformCpuStream = uniformCpuBuffer.AsStream()) using (var uniformCpuWriter = new BinaryWriter(uniformCpuStream)) { var rand = new Random(); for (var i = 0; i < Settings.NumTriangles; ++i) { uniformCpuWriter.Seek((int)(i * AlignedUniformBytes), SeekOrigin.Begin); float scale = (float)(rand.NextDouble() * 0.2 + 0.2); //scale = 5; float offsetX = (float)(0.9 * 2 * (rand.NextDouble() - 0.5)); float offsetY = (float)(0.9 * 2 * (rand.NextDouble() - 0.5)); float scalar = (float)(rand.NextDouble() * 1.5 + 0.5); float scalarOffset = (float)(rand.NextDouble() * 10); uniformCpuWriter.Write(scale); //Scale uniformCpuWriter.Write(offsetX); //offsetX uniformCpuWriter.Write(offsetY); //offsetY uniformCpuWriter.Write(scalar); //scalar uniformCpuWriter.Write(scalarOffset); //scalar offset } } BindGroups = new GpuBindGroup[Settings.NumTriangles]; for (var i = 0; i < Settings.NumTriangles; ++i) { BindGroups[i] = Device.CreateBindGroup(new GpuBindGroupDescriptor(bindGroupLayout, new GpuBindGroupEntry[] { new GpuBindGroupEntry(0, new GpuBufferBinding(UniformBuffer, 6 * sizeof(float)) { Offset = (UInt64)(i * AlignedUniformBytes) }) })); } DynamicBindGroup = Device.CreateBindGroup(new GpuBindGroupDescriptor(dynamicBindGroupLayout, new GpuBindGroupEntry[] { new GpuBindGroupEntry(0, new GpuBufferBinding(UniformBuffer, 6 * sizeof(float))) })); TimeBindGroup = Device.CreateBindGroup(new GpuBindGroupDescriptor(timeBindGroupLayout, new GpuBindGroupEntry[] { new GpuBindGroupEntry(0, new GpuBufferBinding(UniformBuffer, sizeof(float)) { Offset = TimeOffset }) })); Device.DefaultQueue.WriteBuffer(UniformBuffer, 0, uniformCpuBuffer); var renderBundleEncoder = Device.CreateRenderBundleEncoder(new GpuRenderBundleEncoderDescriptor(new GpuTextureFormat[] { SwapChainFormat })); RecordRenderPass(renderBundleEncoder); RenderBundle = renderBundleEncoder.Finish(); UniformTimeCpuBuffer = new Windows.Storage.Streams.Buffer(sizeof(float)) { Length = sizeof(float) }; }
async Task Init() { var adapter = await Gpu.RequestAdapterAsync(); Device = await adapter.RequestDeviceAsync(); GpuShaderModule computeShader; using (var shaderFileStream = typeof(MainWindow).Assembly.GetManifestResourceStream("ComputeBoidsWpf.compute.hlsl")) using (var shaderStreamReader = new StreamReader(shaderFileStream)) { var shaderCode = await shaderStreamReader.ReadToEndAsync(); computeShader = Device.CreateShaderModule(new GpuShaderModuleDescriptor(GpuShaderSourceType.Hlsl, shaderCode)); } GpuShaderModule drawShader; using (var shaderFileStream = typeof(MainWindow).Assembly.GetManifestResourceStream("ComputeBoidsWpf.draw.hlsl")) using (var shaderStreamReader = new StreamReader(shaderFileStream)) { var shaderCode = await shaderStreamReader.ReadToEndAsync(); drawShader = Device.CreateShaderModule(new GpuShaderModuleDescriptor(GpuShaderSourceType.Hlsl, shaderCode)); } RenderPipeline = Device.CreateRenderPipeline(new GpuRenderPipelineDescriptor(new GpuVertexState(drawShader, "VSMain") { VertexBuffers = new GpuVertexBufferLayout[] { new GpuVertexBufferLayout(4 * 4, new GpuVertexAttribute[] { new GpuVertexAttribute() { Format = GpuVertexFormat.Float2, Offset = 0, ShaderLocation = 0 }, new GpuVertexAttribute() { Format = GpuVertexFormat.Float2, Offset = 2 * 4, ShaderLocation = 1 } }) { StepMode = GpuInputStepMode.Instance }, new GpuVertexBufferLayout(2 * 4, new GpuVertexAttribute[] { new GpuVertexAttribute() { Format = GpuVertexFormat.Float2, Offset = 0, ShaderLocation = 2 } }) } }) { Fragment = new GpuFragmentState(drawShader, "PSMain", new GpuColorTargetState[] { new GpuColorTargetState { Format = GpuTextureFormat.BGRA8UNorm, Blend = null, WriteMask = GpuColorWriteFlags.All } }), Primitive = new GpuPrimitiveState { Topology = GpuPrimitiveTopology.TriangleList, CullMode = GpuCullMode.None, FrontFace = GpuFrontFace.Ccw }, DepthStencilState = new GpuDepthStencilState(GpuTextureFormat.Depth24PlusStencil8) { DepthWriteEnabled = true, DepthCompare = GpuCompareFunction.Less, } }); var computeBindGroupLayout = Device.CreateBindGroupLayout(new GpuBindGroupLayoutDescriptor(new GpuBindGroupLayoutEntry[] { new GpuBindGroupLayoutEntry() { Binding = 0, Visibility = GpuShaderStageFlags.Compute, Buffer = new GpuBufferBindingLayout() { Type = GpuBufferBindingType.Uniform, HasDynamicOffset = false, MinBindingSize = (ulong)(SimParamData.Length * sizeof(float)) } }, new GpuBindGroupLayoutEntry() { Binding = 1, Visibility = GpuShaderStageFlags.Compute, Buffer = new GpuBufferBindingLayout() { Type = GpuBufferBindingType.ReadOnlyStorage, HasDynamicOffset = false, MinBindingSize = NumParticles * 16 } }, new GpuBindGroupLayoutEntry() { Binding = 2, Visibility = GpuShaderStageFlags.Compute, Buffer = new GpuBufferBindingLayout() { Type = GpuBufferBindingType.Storage, HasDynamicOffset = false, MinBindingSize = NumParticles * 16 } } })); ComputePipeline = Device.CreateComputePipeline(new GpuComputePipelineDescriptor(new GpuProgrammableStage(computeShader, "main")) { Layout = Device.CreatePipelineLayout(new GpuPipelineLayoutDescriptor() { BindGroupLayouts = new GpuBindGroupLayout[] { computeBindGroupLayout } }), }); VerticesBuffer = Device.CreateBuffer(new GpuBufferDescriptor((ulong)(sizeof(float) * VertexBufferData.Length), GpuBufferUsageFlags.Vertex) { MappedAtCreation = true }); using (var stream = VerticesBuffer.GetMappedRange().AsStream()) using (var binaryWriter = new BinaryWriter(stream)) { for (int i = 0; i < VertexBufferData.Length; ++i) { binaryWriter.Write(VertexBufferData[i]); } } VerticesBuffer.Unmap(); var simParamBuffer = Device.CreateBuffer(new GpuBufferDescriptor((ulong)(sizeof(float) * SimParamData.Length), GpuBufferUsageFlags.Uniform) { MappedAtCreation = true }); using (var stream = simParamBuffer.GetMappedRange().AsStream()) using (var writer = new BinaryWriter(stream)) { for (int i = 0; i < SimParamData.Length; ++i) { writer.Write(SimParamData[i]); } } simParamBuffer.Unmap(); float[] initialParticleData = new float[NumParticles * 4]; Random random = new Random(); for (var i = 0; i < NumParticles; ++i) { initialParticleData[4 * i + 0] = (float)(2 * (random.NextDouble() - 0.5f)); initialParticleData[4 * i + 1] = (float)(2 * (random.NextDouble() - 0.5f)); initialParticleData[4 * i + 2] = (float)(2 * (random.NextDouble() - 0.5f) * 0.1); initialParticleData[4 * i + 3] = (float)(2 * (random.NextDouble() - 0.5f) * 0.1); } Windows.Storage.Streams.Buffer initialParticleDataBuffer = new Windows.Storage.Streams.Buffer((uint)(sizeof(float) * initialParticleData.Length)) { Length = (uint)(sizeof(float) * initialParticleData.Length) }; using (var stream = initialParticleDataBuffer.AsStream()) using (var writer = new BinaryWriter(stream)) { for (int i = 0; i < initialParticleData.Length; ++i) { writer.Write(initialParticleData[i]); } } ParticleBuffers = new GpuBuffer[2]; for (int i = 0; i < 2; ++i) { ParticleBuffers[i] = Device.CreateBuffer(new GpuBufferDescriptor(initialParticleDataBuffer.Length, GpuBufferUsageFlags.Vertex | GpuBufferUsageFlags.Storage) { MappedAtCreation = true }); initialParticleDataBuffer.CopyTo(ParticleBuffers[i].GetMappedRange()); ParticleBuffers[i].Unmap(); } ParticleBindGroups = new GpuBindGroup[2]; for (var i = 0; i < 2; ++i) { ParticleBindGroups[i] = Device.CreateBindGroup(new GpuBindGroupDescriptor(computeBindGroupLayout, new GpuBindGroupEntry[] { new GpuBindGroupEntry(0, new GpuBufferBinding(simParamBuffer, simParamBuffer.Size)), new GpuBindGroupEntry(1, new GpuBufferBinding(ParticleBuffers[i], ParticleBuffers[i].Size)), new GpuBindGroupEntry(2, new GpuBufferBinding(ParticleBuffers[(i + 1) % 2], ParticleBuffers[(i + 1) % 2].Size)) })); } T = 0; }