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: "main",
171 buffers: &[],
172 },
173 primitive: wgpu::PrimitiveState {
174 topology: wgpu::PrimitiveTopology::TriangleList,
175 strip_index_format: None,
176 front_face: wgpu::FrontFace::Ccw,
177 cull_mode: None,
178 unclipped_depth: false,
179 polygon_mode: wgpu::PolygonMode::Fill,
180 conservative: false,
181 },
182 depth_stencil: None,
183 multisample: wgpu::MultisampleState {
184 count: 1,
185 mask: !0,
186 alpha_to_coverage_enabled: false,
187 },
188 fragment: Some(wgpu::FragmentState {
189 module: fs_module,
190 entry_point: "main",
191 targets: &[Some(wgpu::ColorTargetState {
192 format: target_format,
193 blend,
194 write_mask: wgpu::ColorWrites::ALL,
195 })],
196 }),
197 multiview: None,
198 })
199 };
200
201 let downsample_filtered_pipeline = create_pipeline(
202 "Bloom downsample filtered pipeline",
203 downsample_filtered_fs_module,
204 None,
205 );
206 let downsample_pipeline =
207 create_pipeline("Bloom downsample pipeline", downsample_fs_module, None);
208 let upsample_pipeline = create_pipeline(
209 "Bloom upsample pipeline",
210 upsample_fs_module,
211 (!bloom_config.uniform_blur).then_some(wgpu::BlendState {
212 color: wgpu::BlendComponent {
213 src_factor: wgpu::BlendFactor::One,
214 dst_factor: wgpu::BlendFactor::One,
215 operation: wgpu::BlendOperation::Add,
216 },
217 alpha: wgpu::BlendComponent::REPLACE,
219 }),
220 );
221
222 Self {
223 downsample_filtered: downsample_filtered_pipeline,
224 downsample: downsample_pipeline,
225 upsample: upsample_pipeline,
226 }
227 }
228}