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