use super::*;
impl ViewportRenderer {
pub(crate) fn render_frame_ldr(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
output_view: &wgpu::TextureView,
vp_idx: usize,
frame: &FrameData,
bg_colour: [f32; 4],
w: u32,
h: u32,
) -> wgpu::CommandBuffer {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("ldr_encoder"),
});
let use_dyn_res = self.current_render_scale < 1.0 - 0.001;
let needs_blur = self.has_backdrop_blur_shapes();
if use_dyn_res {
let sw = ((w as f32 * self.current_render_scale) as u32).max(1);
let sh = ((h as f32 * self.current_render_scale) as u32).max(1);
self.ensure_dyn_res_target(device, vp_idx, [sw, sh], [w.max(1), h.max(1)]);
}
if needs_blur && !use_dyn_res {
self.ensure_backdrop_blur_state(device, w.max(1), h.max(1));
}
{
let slot = &self.viewport_slots[vp_idx];
let slot_hdr = slot
.hdr
.as_ref()
.expect("HDR state missing in LDR path; ensure_viewport_hdr must have been called");
let camera_bg = &slot.camera_bind_group;
let grid_bg = &slot.grid_bind_group;
let (scene_colour_view, scene_depth_view): (&wgpu::TextureView, &wgpu::TextureView) =
if use_dyn_res {
let dr = slot.dyn_res.as_ref().unwrap();
(&dr.colour_view, &dr.depth_view)
} else if needs_blur {
let bs = self.backdrop_blur_state.as_ref().unwrap();
(&bs.intermediate_view, &slot_hdr.outline_depth_view)
} else {
(output_view, &slot_hdr.outline_depth_view)
};
let ts_writes = self.ts_query_set.as_ref().map(|qs| {
self.ts_written_mask.fetch_or(
1 << crate::renderer::GPU_TS_SCENE,
std::sync::atomic::Ordering::Relaxed,
);
wgpu::RenderPassTimestampWrites {
query_set: qs,
beginning_of_pass_write_index: Some(crate::renderer::GPU_TS_SCENE * 2),
end_of_pass_write_index: Some(crate::renderer::GPU_TS_SCENE * 2 + 1),
}
});
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("ldr_render_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: scene_colour_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: bg_colour[0] as f64,
g: bg_colour[1] as f64,
b: bg_colour[2] as f64,
a: bg_colour[3] as f64,
}),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: scene_depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: wgpu::StoreOp::Discard,
}),
stencil_ops: None,
}),
timestamp_writes: ts_writes,
occlusion_query_set: None,
});
emit_draw_calls!(
&self.resources,
&mut render_pass,
frame,
self.instancing.use_instancing,
&self.instancing.batches,
camera_bg,
grid_bg,
&self.compute_filter_results,
Some(slot),
&self.mesh_uniforms.wireframe_bind_groups,
&self.mesh_uniforms.bind_groups
);
emit_scivis_draw_calls!(
&self.resources,
&mut render_pass,
&self.point_cloud_gpu_data,
&self.glyph_gpu_data,
&self.polyline_gpu_data,
&self.volume_gpu_data,
&self.streamtube_gpu_data,
camera_bg,
&self.tube_gpu_data,
&self.image_slice_gpu_data,
&self.tensor_glyph_gpu_data,
&self.ribbon_gpu_data,
&self.volume_surface_slice_gpu_data,
&self.sprite_gpu_data,
&self.mesh_instance_gpu_data,
false
);
if !self.mesh_uniforms.tvm_wireframe_draws.is_empty() {
if let Some(ref tvm_bg) = self.mesh_uniforms.tvm_wireframe_bg {
render_pass.set_bind_group(0, camera_bg, &[]);
for mesh_id in &self.mesh_uniforms.tvm_wireframe_draws {
if let Some(mesh) = self.resources.mesh_store.get(*mesh_id) {
render_pass.set_pipeline(&self.resources.wireframe_pipeline);
render_pass.set_bind_group(
2,
&self.resources.deform.dummy_bind_group,
&[],
);
render_pass.set_bind_group(1, tvm_bg, &[]);
render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
render_pass.set_index_buffer(
mesh.edge_index_buffer.slice(..),
wgpu::IndexFormat::Uint32,
);
render_pass.draw_indexed(0..mesh.edge_index_count, 0, 0..1);
}
}
}
}
if !self.implicit_gpu_data.is_empty() {
if let Some(ref dual) = self.resources.implicit_pipeline {
render_pass.set_pipeline(dual.for_format(false));
render_pass.set_bind_group(0, camera_bg, &[]);
for gpu in &self.implicit_gpu_data {
render_pass.set_bind_group(1, &gpu.bind_group, &[]);
render_pass.draw(0..6, 0..1);
}
}
}
if !self.mc_gpu_data.is_empty() {
if let Some(ref dual) = self.resources.mc_surface_pipeline {
render_pass.set_pipeline(dual.for_format(false));
render_pass.set_bind_group(0, camera_bg, &[]);
for mc in &self.mc_gpu_data {
let vol = &self.resources.mc_volumes[mc.volume_idx];
render_pass.set_bind_group(1, &mc.render_bg, &[]);
for slab in &vol.slabs {
render_pass.set_vertex_buffer(0, slab.vertex_buf.slice(..));
render_pass.draw_indirect(&slab.indirect_buf, 0);
}
}
}
}
emit_outline_composite!(&self.resources, &mut render_pass, Some(slot));
if !self.screen_image_gpu_data.is_empty() {
if let Some(overlay_pipeline) = &self.resources.screen_image_pipeline {
let dc_pipeline = self.resources.screen_image_dc_pipeline.as_ref();
for gpu in &self.screen_image_gpu_data {
if let (Some(dc_bg), Some(dc_pipe)) = (&gpu.depth_bind_group, dc_pipeline) {
render_pass.set_pipeline(dc_pipe);
render_pass.set_bind_group(0, dc_bg, &[]);
} else {
render_pass.set_pipeline(overlay_pipeline);
render_pass.set_bind_group(0, &gpu.bind_group, &[]);
}
render_pass.draw(0..6, 0..1);
}
}
}
if !needs_blur {
emit_overlay_2d!(self, render_pass);
}
}
if needs_blur {
let spread = self
.overlay_shape_gpu_data
.as_ref()
.map(|d| d.max_blur_radius)
.unwrap_or(1.0);
let blur_bg = {
let source = if use_dyn_res {
&self.viewport_slots[vp_idx]
.dyn_res
.as_ref()
.unwrap()
.colour_view
} else {
&self.backdrop_blur_state.as_ref().unwrap().intermediate_view
};
self.run_backdrop_blur(&mut encoder, device, queue, source, spread)
};
let slot = &self.viewport_slots[vp_idx];
let slot_hdr = slot.hdr.as_ref().unwrap();
let overlay_colour_view: &wgpu::TextureView = if use_dyn_res {
&slot.dyn_res.as_ref().unwrap().colour_view
} else {
&self.backdrop_blur_state.as_ref().unwrap().intermediate_view
};
let overlay_depth_view: &wgpu::TextureView = if use_dyn_res {
&slot.dyn_res.as_ref().unwrap().depth_view
} else {
&slot_hdr.outline_depth_view
};
{
let mut overlay_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("ldr_overlay_blur_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: overlay_colour_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: overlay_depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Discard,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
});
self.draw_blur_shapes(&mut overlay_pass, &blur_bg);
emit_overlay_2d!(self, overlay_pass);
}
}
if !self.ts_data_ready && !self.ts_map_inflight {
if let (Some(qs), Some(res_buf), Some(stg_buf)) = (
self.ts_query_set.as_ref(),
self.ts_resolve_buf.as_ref(),
self.ts_staging_buf.as_ref(),
) {
let ts_count = 2 * crate::renderer::GPU_TS_SLOTS;
encoder.resolve_query_set(qs, 0..ts_count, res_buf, 0);
encoder.copy_buffer_to_buffer(res_buf, 0, stg_buf, 0, ts_count as u64 * 8);
self.ts_pending_mask = self
.ts_written_mask
.load(std::sync::atomic::Ordering::Relaxed);
self.ts_data_ready = true;
}
}
if use_dyn_res {
let upscale_bg = &self.viewport_slots[vp_idx]
.dyn_res
.as_ref()
.unwrap()
.upscale_bind_group;
let mut upscale_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("dyn_res_upscale_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: output_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
if let Some(pipeline) = &self.resources.dyn_res_upscale_pipeline {
upscale_pass.set_pipeline(pipeline);
upscale_pass.set_bind_group(0, upscale_bg, &[]);
upscale_pass.draw(0..3, 0..1);
}
} else if needs_blur {
let bs = self.backdrop_blur_state.as_ref().unwrap();
let blit_bgl = self.resources.dyn_res_upscale_bgl.as_ref().unwrap();
let blit_sampler = self.resources.dyn_res_linear_sampler.as_ref().unwrap();
let blit_bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("backdrop_blit_bg"),
layout: blit_bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&bs.intermediate_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(blit_sampler),
},
],
});
let mut blit_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("backdrop_blit_pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: output_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
if let Some(pipeline) = &self.resources.dyn_res_upscale_pipeline {
blit_pass.set_pipeline(pipeline);
blit_pass.set_bind_group(0, &blit_bg, &[]);
blit_pass.draw(0..3, 0..1);
}
}
return encoder.finish();
}
}