use super::*;
impl GpuFluidSystem {
#[tracing::instrument(skip_all, level = "trace")]
pub fn compute_pass(
&self,
encoder: &mut wgpu::CommandEncoder,
queue: &wgpu::Queue,
update_grid: bool,
active_particles: u32,
) {
if active_particles == 0 {
return;
}
let workgroups_parts = active_particles.div_ceil(64);
tracing::trace!(
active_particles,
update_grid,
solver_iterations = 6,
"[GpuFluid] recording PBF solve"
);
queue.write_buffer(
&self.params_buffer,
28,
bytemuck::cast_slice(&[active_particles]),
);
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Predict Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_predict);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
if update_grid {
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Clear Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_clear);
cpass.dispatch_workgroups(self.total_cells.div_ceil(64), 1, 1);
}
let num_elements = active_particles.next_power_of_two();
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Hash Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_hash);
cpass.dispatch_workgroups(num_elements.div_ceil(64), 1, 1);
}
let mut offset_idx = 0;
let mut k = 2u32;
while k <= num_elements {
let mut j = k >> 1;
while j > 0 {
let offset = offset_idx * 256;
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Sort Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(
0,
&self.pipelines.compute_bind_group,
&[offset as wgpu::DynamicOffset],
);
cpass.set_pipeline(&self.pipelines.pipeline_sort);
cpass.dispatch_workgroups(num_elements.div_ceil(64), 1, 1);
offset_idx += 1;
j >>= 1;
}
k <<= 1;
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Offsets Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_offsets);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
}
for _ in 0..6 {
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Calc Lambda"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_calc_lambda);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Apply Delta P"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_apply_delta_p);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Compute Vorticity"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_compute_vorticity);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Update Velocity Pass"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_update_velocity);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Fluid Classify Particles"),
timestamp_writes: None,
});
cpass.set_bind_group(0, &self.pipelines.compute_bind_group, &[0]);
cpass.set_pipeline(&self.pipelines.pipeline_classify);
cpass.dispatch_workgroups(workgroups_parts, 1, 1);
}
}
pub fn render_pass<'a>(
&'a self,
_rpass: &mut wgpu::RenderPass<'a>,
_global_scene_bind_group: &'a wgpu::BindGroup,
) {
}
#[tracing::instrument(skip_all, level = "trace")]
pub fn render_ssfr(
&self,
encoder: &mut wgpu::CommandEncoder,
target_texture: &wgpu::Texture,
target_view: &wgpu::TextureView,
scene_depth_view: &wgpu::TextureView,
global_scene_bind_group: &wgpu::BindGroup,
active_particles: u32,
) {
if active_particles == 0 {
return;
}
tracing::trace!(
active_particles,
"[GpuFluid] recording screen-space fluid render (depth/blur/thickness/composite/foam)"
);
encoder.copy_texture_to_texture(
wgpu::TexelCopyTextureInfo {
texture: target_texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::TexelCopyTextureInfo {
texture: &self.opaque_bg_texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::Extent3d {
width: self.opaque_bg_texture.width(),
height: self.opaque_bg_texture.height(),
depth_or_array_layers: 1,
},
);
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("SSFR Depth"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.raw_depth_texture_view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_texture_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
rpass.set_pipeline(&self.pipelines.pipeline_depth);
rpass.set_bind_group(0, global_scene_bind_group, &[]);
rpass.set_bind_group(1, &self.ssfr_particle_bg, &[]);
rpass.draw(0..4, 0..active_particles);
}
{
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("SSFR Blur"),
timestamp_writes: None,
});
cpass.set_pipeline(&self.pipelines.pipeline_blur);
let target_width = target_texture.width();
let target_height = target_texture.height();
cpass.set_bind_group(0, &self.ssfr_blur_x_bg, &[]);
cpass.dispatch_workgroups(target_width.div_ceil(16), target_height.div_ceil(16), 1);
cpass.set_bind_group(0, &self.ssfr_blur_y_bg, &[]);
cpass.dispatch_workgroups(target_width.div_ceil(16), target_height.div_ceil(16), 1);
}
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("SSFR Thickness"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.thickness_texture_view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
rpass.set_pipeline(&self.pipelines.pipeline_thickness);
rpass.set_bind_group(0, global_scene_bind_group, &[]);
rpass.set_bind_group(1, &self.ssfr_particle_bg, &[]);
rpass.draw(0..4, 0..active_particles);
}
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("SSFR Composite"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: target_view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: scene_depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
rpass.set_pipeline(&self.pipelines.pipeline_composite);
rpass.set_bind_group(0, global_scene_bind_group, &[]);
rpass.set_bind_group(1, &self.ssfr_composite_bg, &[]);
rpass.draw(0..3, 0..1); }
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("SSFR Foam/Spray"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: target_view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: scene_depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
rpass.set_pipeline(&self.pipelines.pipeline_foam);
rpass.set_bind_group(0, global_scene_bind_group, &[]);
rpass.set_bind_group(1, &self.ssfr_particle_bg, &[]);
rpass.draw(0..4, 0..active_particles); }
}
}