use crate::autointensity::AutoIntensityResources;
use crate::intermediate_texture::IntermediateTextureResources;
use crate::lut_texture::LutTextureResources;
use crate::uniform_buffer::UniformBufferResources;
use crate::waveform_resources::{WaveformMode, WaveformResources};
use wgpu::{Device, RenderPipeline, ShaderModule, TextureFormat};
#[derive(Debug)]
pub(crate) struct PipelineResources {
render_pipeline: RenderPipeline,
post_fx_pipeline: RenderPipeline,
decay_pipeline: RenderPipeline,
#[cfg(feature = "auto-intensity")]
auto_intensity_pipeline: wgpu::ComputePipeline,
}
impl PipelineResources {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
render_shader: &ShaderModule,
decay_shader: &ShaderModule,
post_fx_shader: &ShaderModule,
#[cfg(feature = "auto-intensity")] auto_intensity_shader: &ShaderModule,
device: &Device,
texture_format: &TextureFormat,
intermediate_texture_data: &IntermediateTextureResources,
lut_texture_data: &LutTextureResources,
uniform_data: &UniformBufferResources,
waveform_resources: &WaveformResources,
auto_intensity_data: &AutoIntensityResources,
) -> PipelineResources {
let render_pipeline =
Self::create_render_pipeline(render_shader, device, uniform_data, waveform_resources);
let post_fx_pipeline = Self::create_postfx_pipeline(
post_fx_shader,
device,
texture_format,
intermediate_texture_data,
lut_texture_data,
uniform_data,
auto_intensity_data,
);
let decay_pipeline = Self::create_decay_pipeline(decay_shader, device, uniform_data);
#[cfg(feature = "auto-intensity")]
let auto_intensity_pipeline = Self::create_auto_intensity_pipeline(
auto_intensity_shader,
device,
intermediate_texture_data,
auto_intensity_data,
);
PipelineResources {
render_pipeline,
post_fx_pipeline,
decay_pipeline,
#[cfg(feature = "auto-intensity")]
auto_intensity_pipeline,
}
}
#[cfg(feature = "auto-intensity")]
fn create_auto_intensity_pipeline(
auto_intensity_shader: &ShaderModule,
device: &Device,
intermediate_texture_data: &IntermediateTextureResources,
auto_intensity_data: &AutoIntensityResources,
) -> wgpu::ComputePipeline {
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Auto Intensity Pipeline"),
layout: Some(
&device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Auto Intensity Compute Pipeline Layout"),
bind_group_layouts: &[
intermediate_texture_data.bind_group_layout(),
auto_intensity_data.bind_group_layout_compute(),
],
push_constant_ranges: &[],
}),
),
module: auto_intensity_shader,
entry_point: Some("main"),
cache: None,
compilation_options: Default::default(),
})
}
fn create_postfx_pipeline(
post_fx_shader: &ShaderModule,
device: &Device,
texture_format: &TextureFormat,
intermediate_texture_data: &IntermediateTextureResources,
lut_texture_data: &LutTextureResources,
uniform_data: &UniformBufferResources,
auto_intensity_data: &AutoIntensityResources,
) -> RenderPipeline {
let bind_group_layouts = &[
intermediate_texture_data.bind_group_layout(),
lut_texture_data.bind_group_layout(),
auto_intensity_data.bind_group_layout_fragment(),
uniform_data.bind_group_layout(),
];
let postfx_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Post-processing Layout"),
bind_group_layouts,
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Post-processing pipeline"),
layout: Some(&postfx_pipeline_layout),
vertex: wgpu::VertexState {
module: post_fx_shader,
entry_point: Some("postfx_vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: post_fx_shader,
entry_point: Some("postfx_fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: *texture_format,
blend: Some(wgpu::BlendState {
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
fn create_render_pipeline(
render_shader: &ShaderModule,
device: &Device,
uniform_data: &UniformBufferResources,
waveform_resources: &WaveformResources,
) -> RenderPipeline {
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Pipeline Layout"),
bind_group_layouts: &[uniform_data.bind_group_layout()],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: render_shader,
entry_point: Some(match waveform_resources.mode() {
WaveformMode::YT => "vs_yt_main",
WaveformMode::XY => "vs_xy_main",
}),
buffers: &[waveform_resources.buffer_layout()],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: render_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: TextureFormat::R16Float,
blend: Some(wgpu::BlendState {
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
pub(crate) fn render_pipeline(&self) -> &RenderPipeline {
&self.render_pipeline
}
#[cfg(feature = "auto-intensity")]
pub(crate) fn auto_intensity_pipeline(&self) -> &wgpu::ComputePipeline {
&self.auto_intensity_pipeline
}
pub(crate) fn post_fx_pipeline(&self) -> &RenderPipeline {
&self.post_fx_pipeline
}
pub(crate) fn decay_pipeline(&self) -> &RenderPipeline {
&self.decay_pipeline
}
fn create_decay_pipeline(
decay_shader: &ShaderModule,
device: &Device,
uniform_data: &UniformBufferResources,
) -> RenderPipeline {
let decay_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Decay Pipeline Layout"),
bind_group_layouts: &[uniform_data.bind_group_layout()],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Decay pipeline"),
layout: Some(&decay_pipeline_layout),
vertex: wgpu::VertexState {
module: decay_shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: decay_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: TextureFormat::R16Float,
blend: Some(wgpu::BlendState {
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::Zero,
dst_factor: wgpu::BlendFactor::SrcAlpha,
operation: wgpu::BlendOperation::Add,
},
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::Zero,
dst_factor: wgpu::BlendFactor::SrcAlpha,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
})
}
}