veloren_voxygen/render/pipelines/
bloom.rs1use super::super::{BloomConfig, Consts};
6use bytemuck::{Pod, Zeroable};
7use vek::*;
8
9pub const NUM_SIZES: usize = 5;
47
48pub struct BindGroup {
49 pub(in super::super) bind_group: wgpu::BindGroup,
50}
51
52#[repr(C)]
53#[derive(Copy, Clone, Debug, Zeroable, Pod)]
54pub struct Locals {
55 halfpixel: [f32; 2],
56}
57
58impl Locals {
59 pub fn new(source_texture_resolution: Vec2<f32>) -> Self {
60 Self {
61 halfpixel: source_texture_resolution.map(|e| 0.5 / e).into_array(),
62 }
63 }
64}
65
66pub struct BloomLayout {
67 pub layout: wgpu::BindGroupLayout,
68}
69
70impl BloomLayout {
71 pub fn new(device: &wgpu::Device) -> Self {
72 Self {
73 layout: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
74 label: None,
75 entries: &[
76 wgpu::BindGroupLayoutEntry {
78 binding: 0,
79 visibility: wgpu::ShaderStages::FRAGMENT,
80 ty: wgpu::BindingType::Texture {
81 sample_type: wgpu::TextureSampleType::Float { filterable: true },
82 view_dimension: wgpu::TextureViewDimension::D2,
83 multisampled: false,
84 },
85 count: None,
86 },
87 wgpu::BindGroupLayoutEntry {
88 binding: 1,
89 visibility: wgpu::ShaderStages::FRAGMENT,
90 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
91 count: None,
92 },
93 wgpu::BindGroupLayoutEntry {
95 binding: 2,
96 visibility: wgpu::ShaderStages::FRAGMENT,
97 ty: wgpu::BindingType::Buffer {
98 ty: wgpu::BufferBindingType::Uniform,
99 has_dynamic_offset: false,
100 min_binding_size: None,
101 },
102 count: None,
103 },
104 ],
105 }),
106 }
107 }
108
109 pub fn bind(
110 &self,
111 device: &wgpu::Device,
112 src_color: &wgpu::TextureView,
113 sampler: &wgpu::Sampler,
114 half_pixel: Consts<Locals>,
115 ) -> BindGroup {
116 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
117 label: None,
118 layout: &self.layout,
119 entries: &[
120 wgpu::BindGroupEntry {
121 binding: 0,
122 resource: wgpu::BindingResource::TextureView(src_color),
123 },
124 wgpu::BindGroupEntry {
125 binding: 1,
126 resource: wgpu::BindingResource::Sampler(sampler),
127 },
128 wgpu::BindGroupEntry {
129 binding: 2,
130 resource: half_pixel.buf().as_entire_binding(),
131 },
132 ],
133 });
134
135 BindGroup { bind_group }
136 }
137}
138
139pub struct BloomPipelines {
140 pub downsample_filtered: wgpu::RenderPipeline,
141 pub downsample: wgpu::RenderPipeline,
142 pub upsample: wgpu::RenderPipeline,
143}
144
145impl BloomPipelines {
146 pub fn new(
147 device: &wgpu::Device,
148 vs_module: &wgpu::ShaderModule,
149 downsample_filtered_fs_module: &wgpu::ShaderModule,
150 downsample_fs_module: &wgpu::ShaderModule,
151 upsample_fs_module: &wgpu::ShaderModule,
152 target_format: wgpu::TextureFormat,
153 layout: &BloomLayout,
154 bloom_config: &BloomConfig,
155 ) -> Self {
156 common_base::span!(_guard, "BloomPipelines::new");
157 let render_pipeline_layout =
158 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
159 label: Some("Bloom pipelines layout"),
160 push_constant_ranges: &[],
161 bind_group_layouts: &[&layout.layout],
162 });
163
164 let create_pipeline = |label, fs_module, blend| {
165 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
166 label: Some(label),
167 layout: Some(&render_pipeline_layout),
168 vertex: wgpu::VertexState {
169 module: vs_module,
170 entry_point: Some("main"),
171 buffers: &[],
172 compilation_options: Default::default(),
173 },
174 primitive: wgpu::PrimitiveState {
175 topology: wgpu::PrimitiveTopology::TriangleList,
176 strip_index_format: None,
177 front_face: wgpu::FrontFace::Ccw,
178 cull_mode: None,
179 unclipped_depth: false,
180 polygon_mode: wgpu::PolygonMode::Fill,
181 conservative: false,
182 },
183 depth_stencil: None,
184 multisample: wgpu::MultisampleState {
185 count: 1,
186 mask: !0,
187 alpha_to_coverage_enabled: false,
188 },
189 fragment: Some(wgpu::FragmentState {
190 module: fs_module,
191 entry_point: Some("main"),
192 targets: &[Some(wgpu::ColorTargetState {
193 format: target_format,
194 blend,
195 write_mask: wgpu::ColorWrites::ALL,
196 })],
197 compilation_options: Default::default(),
198 }),
199 multiview: None,
200 cache: None,
201 })
202 };
203
204 let downsample_filtered_pipeline = create_pipeline(
205 "Bloom downsample filtered pipeline",
206 downsample_filtered_fs_module,
207 None,
208 );
209 let downsample_pipeline =
210 create_pipeline("Bloom downsample pipeline", downsample_fs_module, None);
211 let upsample_pipeline = create_pipeline(
212 "Bloom upsample pipeline",
213 upsample_fs_module,
214 (!bloom_config.uniform_blur).then_some(wgpu::BlendState {
215 color: wgpu::BlendComponent {
216 src_factor: wgpu::BlendFactor::One,
217 dst_factor: wgpu::BlendFactor::One,
218 operation: wgpu::BlendOperation::Add,
219 },
220 alpha: wgpu::BlendComponent::REPLACE,
222 }),
223 );
224
225 Self {
226 downsample_filtered: downsample_filtered_pipeline,
227 downsample: downsample_pipeline,
228 upsample: upsample_pipeline,
229 }
230 }
231}