63 std::uint32_t step_size;
66 bool operator==(Sample
const& rhs)
const
68 return step_size == rhs.step_size && offset == rhs.offset;
71 bool operator!=(Sample
const& rhs)
const {
return !(*
this == rhs); }
85 float node_half_length;
87 bool operator==(Uniform
const& rhs)
const
91 rhs.projection == projection &&
94 rhs.near_clip == near_clip &&
95 rhs.far_clip == far_clip &&
96 rhs.sample == sample &&
98 rhs.node_center == node_center &&
99 rhs.node_half_length == node_half_length;
103 bool operator!=(Uniform
const& rhs)
const {
return !(*
this == rhs); }
106 static_assert(
sizeof(Uniform) % 16 == 0);
114 static_assert(
sizeof(Hit) % 16 == 0);
129 void init(WGPUDevice device, WGPUTextureFormat texture_format)
override
131 map_.gpuInit(device);
133 compute_bind_group_layout_ = createBindGroupLayout(map_.gpuDevice(), texture_format);
134 compute_pipeline_layout_ =
135 createPipelineLayout(map_.gpuDevice(), compute_bind_group_layout_);
136 compute_pipeline_ = createComputePipeline(map_.gpuDevice(), compute_pipeline_layout_);
139 compute::createBuffer(map_.gpuDevice(),
sizeof(uniform_),
140 WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
false);
143 void release()
override
145 if (
nullptr != compute_bind_group_) {
146 wgpuBindGroupRelease(compute_bind_group_);
147 compute_bind_group_ =
nullptr;
149 if (
nullptr != compute_pipeline_layout_) {
150 wgpuPipelineLayoutRelease(compute_pipeline_layout_);
151 compute_pipeline_layout_ =
nullptr;
153 if (
nullptr != compute_bind_group_layout_) {
154 wgpuBindGroupLayoutRelease(compute_bind_group_layout_);
155 compute_bind_group_layout_ =
nullptr;
160 if (
nullptr != compute_pipeline_) {
161 wgpuComputePipelineRelease(compute_pipeline_);
162 compute_pipeline_ =
nullptr;
166 void update(WGPUDevice device, WGPUCommandEncoder encoder,
167 WGPUTextureView render_texture, WGPUTextureView depth_texture,
168 Camera const& camera)
override
170 Uniform uniform = createUniform(map_, camera);
175 map_.gpuUpdateBuffers();
177 if (uniform_ != uniform) {
179 hits_node_.resize(uniform.dim.x * uniform.dim.y);
180 hits_depth_.resize(uniform.dim.x * uniform.dim.y);
182 if (
nullptr != hits_staging_buffer_) {
183 wgpuBufferRelease(hits_staging_buffer_);
186 if (
nullptr != hits_storage_buffer_) {
187 wgpuBufferRelease(hits_storage_buffer_);
190 if (
nullptr != compute_bind_group_) {
191 wgpuBindGroupRelease(compute_bind_group_);
204 compute_bind_group_ = createBindGroup(device);
207 WGPUComputePassEncoder compute_pass_encoder =
208 wgpuCommandEncoderBeginComputePass(encoder,
nullptr);
210 wgpuComputePassEncoderSetPipeline(compute_pass_encoder, compute_pipeline_);
211 wgpuComputePassEncoderSetBindGroup(compute_pass_encoder, 0, compute_bind_group_, 0,
214 std::uint32_t invocation_count_x = uniform.dim.x / uniform_.sample.step_size;
215 std::uint32_t invocation_count_y = uniform.dim.y / uniform_.sample.step_size;
218 std::uint32_t workgroup_size_x = 8;
219 std::uint32_t workgroup_size_y = 4;
220 std::uint32_t workgroup_count_x =
221 (invocation_count_x + workgroup_size_x - 1) / workgroup_size_x;
222 std::uint32_t workgroup_count_y =
223 (invocation_count_y + workgroup_size_y - 1) / workgroup_size_y;
225 wgpuComputePassEncoderDispatchWorkgroups(compute_pass_encoder, workgroup_count_x,
226 workgroup_count_y, 1);
228 wgpuComputePassEncoderEnd(compute_pass_encoder);
229 wgpuComputePassEncoderRelease(compute_pass_encoder);
235 WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(encoder,
nullptr);
236 assert(command_buffer);
238 wgpuQueueSubmit(map_.gpuQueue(), 1, &command_buffer);
253 wgpuBufferUnmap(hits_staging_buffer_);
254 wgpuCommandBufferRelease(command_buffer);
258 void onGui()
override
266 [[nodiscard]] WGPUBindGroupLayout createBindGroupLayout(
267 WGPUDevice device, WGPUTextureFormat )
269 std::array<WGPUBindGroupLayoutEntry, 4> binding_layout{};
272 compute::setDefault(binding_layout[0]);
273 binding_layout[0].binding = 0;
274 binding_layout[0].visibility = WGPUShaderStage_Compute;
275 binding_layout[0].buffer.type = WGPUBufferBindingType_Storage;
278 compute::setDefault(binding_layout[1]);
279 binding_layout[1].binding = 1;
280 binding_layout[1].visibility = WGPUShaderStage_Compute;
281 binding_layout[1].buffer.type = WGPUBufferBindingType_Uniform;
282 binding_layout[1].buffer.minBindingSize =
sizeof(uniform_);
285 compute::setDefault(binding_layout[2]);
286 binding_layout[2].binding = 2;
287 binding_layout[2].visibility = WGPUShaderStage_Compute;
288 binding_layout[2].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
291 compute::setDefault(binding_layout[3]);
292 binding_layout[3].binding = 3;
293 binding_layout[3].visibility = WGPUShaderStage_Compute;
294 binding_layout[3].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
297 WGPUBindGroupLayoutDescriptor bind_group_layout_desc{};
298 bind_group_layout_desc.label =
"";
299 bind_group_layout_desc.nextInChain =
nullptr;
300 bind_group_layout_desc.entryCount = binding_layout.size();
301 bind_group_layout_desc.entries = binding_layout.data();
303 return wgpuDeviceCreateBindGroupLayout(device, &bind_group_layout_desc);
306 [[nodiscard]] WGPUPipelineLayout createPipelineLayout(
307 WGPUDevice device, WGPUBindGroupLayout bind_group_layout)
309 WGPUPipelineLayoutDescriptor desc{};
310 desc.nextInChain =
nullptr;
311 desc.bindGroupLayoutCount = 1;
312 desc.bindGroupLayouts = &bind_group_layout;
313 return wgpuDeviceCreatePipelineLayout(device, &desc);
316 [[nodiscard]] WGPUComputePipeline createComputePipeline(
317 WGPUDevice device, WGPUPipelineLayout pipeline_layout)
319 WGPUShaderModule shader_module;
322 compute::loadShaderModule(device, UFOVIZ_SHADER_DIR
"/map_ray_trace_2d.wgsl");
325 compute::loadShaderModule(device, UFOVIZ_SHADER_DIR
"/map_ray_trace_3d.wgsl");
328 compute::loadShaderModule(device, UFOVIZ_SHADER_DIR
"/map_ray_trace_4d.wgsl");
330 static_assert(dependent_false_v<Map>,
"Non-supported number of dimensions");
333 if (
nullptr == shader_module) {
334 std::cerr <<
"Could not load shader!" << std::endl;
338 WGPUComputePipelineDescriptor desc{};
339 desc.nextInChain =
nullptr;
340 desc.compute.constantCount = 0;
341 desc.compute.constants =
nullptr;
342 desc.compute.entryPoint =
"main";
343 desc.compute.module = shader_module;
344 desc.layout = pipeline_layout;
346 WGPUComputePipeline pipeline = wgpuDeviceCreateComputePipeline(device, &desc);
348 wgpuShaderModuleRelease(shader_module);
353 [[nodiscard]] WGPUBindGroup createBindGroup(WGPUDevice device)
356 std::array<WGPUBindGroupEntry, 4> binding{};
359 binding[0].nextInChain =
nullptr;
360 binding[0].binding = 0;
361 binding[0].buffer = hits_storage_buffer_;
362 binding[0].offset = 0;
367 binding[1].nextInChain =
nullptr;
368 binding[1].binding = 1;
369 binding[1].buffer = uniform_buffer_;
370 binding[1].offset = 0;
371 binding[1].size =
sizeof(uniform_);
374 binding[2].nextInChain =
nullptr;
375 binding[2].binding = 2;
376 binding[2].buffer = map_.gpuTreeBuffer();
378 binding[2].size = map_.gpuTreeBufferSize();
381 binding[3].nextInChain =
nullptr;
382 binding[3].binding = 3;
383 binding[3].buffer = map_.gpuOccupancyBuffer();
385 binding[3].size = map_.gpuOccupancyBufferSize();
388 WGPUBindGroupDescriptor desc{};
389 desc.nextInChain =
nullptr;
390 desc.layout = compute_bind_group_layout_;
391 desc.entryCount = binding.size();
392 desc.entries = binding.data();
393 return wgpuDeviceCreateBindGroup(device, &desc);
396 [[nodiscard]]
static Uniform createUniform(
Map const& map,
Camera const& camera)
399 uniform.projection =
inverse(camera.projection());
400 uniform.view =
inverse(camera.view());
401 uniform.dim =
Vec2u(camera.cols, camera.rows);
402 uniform.near_clip = camera.near_clip;
403 uniform.far_clip = camera.far_clip;
404 uniform.node = map.
index();
405 uniform.node_center = map.
center(uniform.node);
413 WGPUBindGroupLayout compute_bind_group_layout_ =
nullptr;
414 WGPUPipelineLayout compute_pipeline_layout_ =
nullptr;
415 WGPUComputePipeline compute_pipeline_ =
nullptr;
416 WGPUBindGroup compute_bind_group_ =
nullptr;
418 WGPUBuffer hits_staging_buffer_ =
nullptr;
419 WGPUBuffer hits_storage_buffer_ =
nullptr;
420 WGPUBuffer uniform_buffer_ =
nullptr;
422 WGPUTexture texture_ =
nullptr;
423 WGPUTextureView texture_view_ =
nullptr;
427 std::vector<TreeIndex> hits_node_;
428 std::vector<float> hits_depth_;