blob: 4a69710ba2a8196d2c7ace9e6236ed2d00f681df [file] [log] [blame]
Corentin Wallez4a9ef4e2018-07-18 11:40:26 +02001// Copyright 2017 The Dawn Authors
Corentin Wallezf07e3bd2017-04-20 14:38:20 -04002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Corentin Wallez9347e8f2017-06-19 13:15:13 -040015#include "SampleUtils.h"
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040016
Corentin Wallezf6840402018-07-18 14:00:56 +020017#include "utils/DawnHelpers.h"
Corentin Wallez134e0802017-07-17 17:13:57 -040018#include "utils/SystemUtils.h"
Corentin Wallez5ee7afd2017-06-19 13:09:41 -040019
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040020#include <array>
21#include <cstring>
22#include <random>
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040023
24#include <glm/glm.hpp>
25
Corentin Wallez4828d922018-07-18 13:45:46 +020026dawn::Device device;
27dawn::Queue queue;
28dawn::SwapChain swapchain;
29dawn::TextureView depthStencilView;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040030
Corentin Wallez4828d922018-07-18 13:45:46 +020031dawn::Buffer modelBuffer;
32std::array<dawn::Buffer, 2> particleBuffers;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040033
Corentin Wallez4828d922018-07-18 13:45:46 +020034dawn::RenderPipeline renderPipeline;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040035
Corentin Wallez4828d922018-07-18 13:45:46 +020036dawn::Buffer updateParams;
37dawn::ComputePipeline updatePipeline;
38std::array<dawn::BindGroup, 2> updateBGs;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040039
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040040size_t pingpong = 0;
41
42static const uint32_t kNumParticles = 1000;
43
44struct Particle {
45 glm::vec2 pos;
46 glm::vec2 vel;
47};
48
49struct SimParams {
50 float deltaT;
51 float rule1Distance;
52 float rule2Distance;
53 float rule3Distance;
54 float rule1Scale;
55 float rule2Scale;
56 float rule3Scale;
57 int particleCount;
58};
59
60void initBuffers() {
61 glm::vec2 model[3] = {
62 {-0.01, -0.02},
63 {0.01, -0.02},
64 {0.00, 0.02},
65 };
Corentin Wallez4828d922018-07-18 13:45:46 +020066 modelBuffer = utils::CreateBufferFromData(device, model, sizeof(model), dawn::BufferUsageBit::Vertex);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040067
Corentin Wallez83e779d2017-07-10 21:44:06 -040068 SimParams params = { 0.04f, 0.1f, 0.025f, 0.025f, 0.02f, 0.05f, 0.005f, kNumParticles };
Corentin Wallez4828d922018-07-18 13:45:46 +020069 updateParams = utils::CreateBufferFromData(device, &params, sizeof(params), dawn::BufferUsageBit::Uniform);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040070
71 std::vector<Particle> initialParticles(kNumParticles);
72 {
73 std::mt19937 generator;
74 std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
75 for (auto& p : initialParticles)
76 {
77 p.pos = glm::vec2(dist(generator), dist(generator));
78 p.vel = glm::vec2(dist(generator), dist(generator)) * 0.1f;
79 }
80 }
81
Kai Ninomiya78c8b832017-07-21 17:00:22 -070082 for (size_t i = 0; i < 2; i++) {
Corentin Wallez82b65732018-08-22 15:37:29 +020083 dawn::BufferDescriptor descriptor;
84 descriptor.size = sizeof(Particle) * kNumParticles;
85 descriptor.usage = dawn::BufferUsageBit::TransferDst | dawn::BufferUsageBit::Vertex | dawn::BufferUsageBit::Storage;
86 particleBuffers[i] = device.CreateBuffer(&descriptor);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040087
88 particleBuffers[i].SetSubData(0,
Stephen Whitee5ae3272018-02-04 11:07:02 -050089 sizeof(Particle) * kNumParticles,
90 reinterpret_cast<uint8_t*>(initialParticles.data()));
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040091 }
92}
93
94void initRender() {
Corentin Wallez4828d922018-07-18 13:45:46 +020095 dawn::ShaderModule vsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040096 #version 450
97 layout(location = 0) in vec2 a_particlePos;
98 layout(location = 1) in vec2 a_particleVel;
99 layout(location = 2) in vec2 a_pos;
100 void main() {
101 float angle = -atan(a_particleVel.x, a_particleVel.y);
102 vec2 pos = vec2(a_pos.x * cos(angle) - a_pos.y * sin(angle),
103 a_pos.x * sin(angle) + a_pos.y * cos(angle));
104 gl_Position = vec4(pos + a_particlePos, 0, 1);
105 }
106 )");
107
Corentin Wallez4828d922018-07-18 13:45:46 +0200108 dawn::ShaderModule fsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400109 #version 450
Corentin Wallezb6fb5f32017-08-29 13:37:45 -0400110 layout(location = 0) out vec4 fragColor;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400111 void main() {
112 fragColor = vec4(1.0);
113 }
114 )");
115
Corentin Wallez4828d922018-07-18 13:45:46 +0200116 dawn::InputState inputState = device.CreateInputStateBuilder()
117 .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32, offsetof(Particle, pos))
118 .SetAttribute(1, 0, dawn::VertexFormat::FloatR32G32, offsetof(Particle, vel))
119 .SetInput(0, sizeof(Particle), dawn::InputStepMode::Instance)
120 .SetAttribute(2, 1, dawn::VertexFormat::FloatR32G32, 0)
121 .SetInput(1, sizeof(glm::vec2), dawn::InputStepMode::Vertex)
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400122 .GetResult();
123
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700124 depthStencilView = CreateDefaultDepthStencilView(device);
125
Corentin Wallez66ff4472017-07-14 11:32:57 -0400126 renderPipeline = device.CreateRenderPipelineBuilder()
Corentin Wallez6f7749c2018-05-02 18:10:13 -0400127 .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
Corentin Wallez4828d922018-07-18 13:45:46 +0200128 .SetDepthStencilAttachmentFormat(dawn::TextureFormat::D32FloatS8Uint)
129 .SetStage(dawn::ShaderStage::Vertex, vsModule, "main")
130 .SetStage(dawn::ShaderStage::Fragment, fsModule, "main")
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400131 .SetInputState(inputState)
132 .GetResult();
133}
134
135void initSim() {
Corentin Wallez4828d922018-07-18 13:45:46 +0200136 dawn::ShaderModule module = utils::CreateShaderModule(device, dawn::ShaderStage::Compute, R"(
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400137 #version 450
138
139 struct Particle {
140 vec2 pos;
141 vec2 vel;
142 };
143
144 layout(std140, set = 0, binding = 0) uniform SimParams {
145 float deltaT;
146 float rule1Distance;
147 float rule2Distance;
148 float rule3Distance;
149 float rule1Scale;
150 float rule2Scale;
151 float rule3Scale;
152 int particleCount;
153 } params;
154
155 layout(std140, set = 0, binding = 1) buffer ParticlesA {
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700156 Particle particles[1000];
157 } particlesA;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400158
159 layout(std140, set = 0, binding = 2) buffer ParticlesB {
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700160 Particle particles[1000];
161 } particlesB;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400162
163 void main() {
164 // https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
165
166 uint index = gl_GlobalInvocationID.x;
167 if (index >= params.particleCount) { return; }
168
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700169 vec2 vPos = particlesA.particles[index].pos;
170 vec2 vVel = particlesA.particles[index].vel;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400171
172 vec2 cMass = vec2(0.0, 0.0);
173 vec2 cVel = vec2(0.0, 0.0);
174 vec2 colVel = vec2(0.0, 0.0);
175 int cMassCount = 0;
176 int cVelCount = 0;
177
178 vec2 pos;
179 vec2 vel;
180 for (int i = 0; i < params.particleCount; ++i) {
181 if (i == index) { continue; }
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700182 pos = particlesA.particles[i].pos.xy;
183 vel = particlesA.particles[i].vel.xy;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400184
185 if (distance(pos, vPos) < params.rule1Distance) {
186 cMass += pos;
187 cMassCount++;
188 }
189 if (distance(pos, vPos) < params.rule2Distance) {
190 colVel -= (pos - vPos);
191 }
192 if (distance(pos, vPos) < params.rule3Distance) {
193 cVel += vel;
194 cVelCount++;
195 }
196 }
197 if (cMassCount > 0) {
198 cMass = cMass / cMassCount - vPos;
199 }
200 if (cVelCount > 0) {
201 cVel = cVel / cVelCount;
202 }
203
204 vVel += cMass * params.rule1Scale + colVel * params.rule2Scale + cVel * params.rule3Scale;
205
206 // clamp velocity for a more pleasing simulation.
207 vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);
208
209 // kinematic update
210 vPos += vVel * params.deltaT;
211
212 // Wrap around boundary
213 if (vPos.x < -1.0) vPos.x = 1.0;
214 if (vPos.x > 1.0) vPos.x = -1.0;
215 if (vPos.y < -1.0) vPos.y = 1.0;
216 if (vPos.y > 1.0) vPos.y = -1.0;
217
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700218 particlesB.particles[index].pos = vPos;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400219
220 // Write back
Kai Ninomiya7883e7e2018-07-10 11:01:28 -0700221 particlesB.particles[index].vel = vVel;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400222 }
223 )");
224
Kai Ninomiya234becf2018-07-10 12:23:50 -0700225 auto bgl = utils::MakeBindGroupLayout(
226 device, {
Corentin Wallez4828d922018-07-18 13:45:46 +0200227 {0, dawn::ShaderStageBit::Compute, dawn::BindingType::UniformBuffer},
228 {1, dawn::ShaderStageBit::Compute, dawn::BindingType::StorageBuffer},
229 {2, dawn::ShaderStageBit::Compute, dawn::BindingType::StorageBuffer},
Kai Ninomiya234becf2018-07-10 12:23:50 -0700230 });
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400231
Corentin Wallez4828d922018-07-18 13:45:46 +0200232 dawn::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, &bgl);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400233
Corentin Wallez8e335a52018-08-27 23:12:56 +0200234 dawn::ComputePipelineDescriptor csDesc;
235 csDesc.module = module.Clone();
236 csDesc.entryPoint = "main";
237 csDesc.layout = pl.Clone();
238 updatePipeline = device.CreateComputePipeline(&csDesc);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400239
Corentin Wallez4828d922018-07-18 13:45:46 +0200240 dawn::BufferView updateParamsView = updateParams.CreateBufferViewBuilder()
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400241 .SetExtent(0, sizeof(SimParams))
242 .GetResult();
243
Corentin Wallez4828d922018-07-18 13:45:46 +0200244 std::array<dawn::BufferView, 2> views;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400245 for (uint32_t i = 0; i < 2; ++i) {
246 views[i] = particleBuffers[i].CreateBufferViewBuilder()
247 .SetExtent(0, kNumParticles * sizeof(Particle))
248 .GetResult();
249 }
250
251 for (uint32_t i = 0; i < 2; ++i) {
252 updateBGs[i] = device.CreateBindGroupBuilder()
253 .SetLayout(bgl)
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400254 .SetBufferViews(0, 1, &updateParamsView)
255 .SetBufferViews(1, 1, &views[i])
256 .SetBufferViews(2, 1, &views[(i + 1) % 2])
257 .GetResult();
258 }
259}
260
Corentin Wallez4828d922018-07-18 13:45:46 +0200261dawn::CommandBuffer createCommandBuffer(const dawn::RenderPassDescriptor& renderPass, size_t i) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400262 static const uint32_t zeroOffsets[1] = {0};
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700263 auto& bufferDst = particleBuffers[(i + 1) % 2];
264 return device.CreateCommandBufferBuilder()
265 .BeginComputePass()
266 .SetComputePipeline(updatePipeline)
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700267 .SetBindGroup(0, updateBGs[i])
268 .Dispatch(kNumParticles, 1, 1)
269 .EndComputePass()
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400270
Corentin Wallez6f7749c2018-05-02 18:10:13 -0400271 .BeginRenderPass(renderPass)
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700272 .SetRenderPipeline(renderPipeline)
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700273 .SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
274 .SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
275 .DrawArrays(3, kNumParticles, 0, 0)
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700276 .EndRenderPass()
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400277
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700278 .GetResult();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400279}
280
281void init() {
Corentin Wallez39039fa2018-07-18 14:06:10 +0200282 device = CreateCppDawnDevice();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400283
Corentin Wallezb703def2018-06-14 20:26:27 -0400284 queue = device.CreateQueue();
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700285 swapchain = GetSwapChain(device);
Corentin Wallez2e31e8f2017-09-21 12:54:53 -0400286 swapchain.Configure(GetPreferredSwapChainTextureFormat(),
Corentin Wallez4828d922018-07-18 13:45:46 +0200287 dawn::TextureUsageBit::OutputAttachment, 640, 480);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400288
289 initBuffers();
290 initRender();
291 initSim();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400292}
293
294void frame() {
Corentin Wallez4828d922018-07-18 13:45:46 +0200295 dawn::Texture backbuffer;
296 dawn::RenderPassDescriptor renderPass;
Corentin Wallez8d6b5d22018-05-11 13:04:44 -0400297 GetNextRenderPassDescriptor(device, swapchain, depthStencilView, &backbuffer, &renderPass);
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700298
Corentin Wallez4828d922018-07-18 13:45:46 +0200299 dawn::CommandBuffer commandBuffer = createCommandBuffer(renderPass, pingpong);
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700300 queue.Submit(1, &commandBuffer);
Kai Ninomiyac16a67a2017-07-27 18:30:57 -0700301 swapchain.Present(backbuffer);
302 DoFlush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400303
304 pingpong = (pingpong + 1) % 2;
305}
306
307int main(int argc, const char* argv[]) {
Corentin Wallez9347e8f2017-06-19 13:15:13 -0400308 if (!InitSample(argc, argv)) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400309 return 1;
310 }
311 init();
312
313 while (!ShouldQuit()) {
314 frame();
Corentin Wallez134e0802017-07-17 17:13:57 -0400315 utils::USleep(16000);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400316 }
317
318 // TODO release stuff
319}