mirror of https://github.com/sotrh/learn-wgpu
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.2 KiB
Rust
159 lines
5.2 KiB
Rust
use wgpu::Operations;
|
|
|
|
use crate::{create_render_pipeline, texture};
|
|
|
|
/// Owns the render texture and controls tonemapping
|
|
pub struct HdrPipeline {
|
|
pipeline: wgpu::RenderPipeline,
|
|
bind_group: wgpu::BindGroup,
|
|
texture: texture::Texture,
|
|
width: u32,
|
|
height: u32,
|
|
format: wgpu::TextureFormat,
|
|
layout: wgpu::BindGroupLayout,
|
|
}
|
|
|
|
impl HdrPipeline {
|
|
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self {
|
|
let width = config.width;
|
|
let height = config.height;
|
|
|
|
// We could use `Rgba32Float`, but that requires some extra
|
|
// features to be enabled.
|
|
let format = wgpu::TextureFormat::Rgba16Float;
|
|
|
|
let texture = texture::Texture::create_2d_texture(
|
|
device,
|
|
width,
|
|
height,
|
|
format,
|
|
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
wgpu::FilterMode::Nearest,
|
|
Some("Hdr::texture"),
|
|
);
|
|
|
|
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
label: Some("Hdr::layout"),
|
|
entries: &[
|
|
wgpu::BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
ty: wgpu::BindingType::Texture {
|
|
// The Rgba16Float format cannot be filtered
|
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
view_dimension: wgpu::TextureViewDimension::D2,
|
|
multisampled: false,
|
|
},
|
|
count: None,
|
|
},
|
|
wgpu::BindGroupLayoutEntry {
|
|
binding: 1,
|
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
|
count: None,
|
|
},
|
|
],
|
|
});
|
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
label: Some("Hdr::bind_group"),
|
|
layout: &layout,
|
|
entries: &[
|
|
wgpu::BindGroupEntry {
|
|
binding: 0,
|
|
resource: wgpu::BindingResource::TextureView(&texture.view),
|
|
},
|
|
wgpu::BindGroupEntry {
|
|
binding: 1,
|
|
resource: wgpu::BindingResource::Sampler(&texture.sampler),
|
|
},
|
|
],
|
|
});
|
|
|
|
let shader = wgpu::include_wgsl!("hdr.wgsl");
|
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: None,
|
|
bind_group_layouts: &[&layout],
|
|
push_constant_ranges: &[],
|
|
});
|
|
|
|
let pipeline = create_render_pipeline(
|
|
device,
|
|
&pipeline_layout,
|
|
config.format,
|
|
None,
|
|
&[],
|
|
wgpu::PrimitiveTopology::TriangleList,
|
|
shader,
|
|
);
|
|
|
|
Self {
|
|
pipeline,
|
|
bind_group,
|
|
layout,
|
|
texture,
|
|
width,
|
|
height,
|
|
format,
|
|
}
|
|
}
|
|
|
|
/// Resize the HDR texture
|
|
pub fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) {
|
|
self.texture = texture::Texture::create_2d_texture(
|
|
device,
|
|
width,
|
|
height,
|
|
wgpu::TextureFormat::Rgba16Float,
|
|
wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
wgpu::FilterMode::Nearest,
|
|
Some("Hdr::texture"),
|
|
);
|
|
self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
label: Some("Hdr::bind_group"),
|
|
layout: &self.layout,
|
|
entries: &[
|
|
wgpu::BindGroupEntry {
|
|
binding: 0,
|
|
resource: wgpu::BindingResource::TextureView(&self.texture.view),
|
|
},
|
|
wgpu::BindGroupEntry {
|
|
binding: 1,
|
|
resource: wgpu::BindingResource::Sampler(&self.texture.sampler),
|
|
},
|
|
],
|
|
});
|
|
self.width = width;
|
|
self.height = height;
|
|
}
|
|
|
|
/// Exposes the HDR texture
|
|
pub fn view(&self) -> &wgpu::TextureView {
|
|
&self.texture.view
|
|
}
|
|
|
|
/// The format of the HDR texture
|
|
pub fn format(&self) -> wgpu::TextureFormat {
|
|
self.format
|
|
}
|
|
|
|
/// This renders the internal HDR texture to the [TextureView]
|
|
/// supplied as parameter.
|
|
pub fn process(&self, encoder: &mut wgpu::CommandEncoder, output: &wgpu::TextureView) {
|
|
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
label: Some("Hdr::process"),
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
view: &output,
|
|
resolve_target: None,
|
|
ops: Operations {
|
|
load: wgpu::LoadOp::Load,
|
|
store: true,
|
|
},
|
|
})],
|
|
depth_stencil_attachment: None,
|
|
});
|
|
pass.set_pipeline(&self.pipeline);
|
|
pass.set_bind_group(0, &self.bind_group, &[]);
|
|
pass.draw(0..3, 0..1);
|
|
}
|
|
}
|