ori_wgpu/
blit.rs

1use wgpu::{
2    include_wgsl, AddressMode, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
3    BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendState,
4    ColorTargetState, ColorWrites, CommandEncoder, Device, FilterMode, FragmentState,
5    MultisampleState, Operations, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor,
6    RenderPipeline, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, TextureFormat,
7    TextureSampleType, TextureView, TextureViewDimension, VertexState,
8};
9
10pub struct BlitPipeline {
11    pub source_bind_group_layout: BindGroupLayout,
12    pub sampler: Sampler,
13    pub pipeline: RenderPipeline,
14}
15
16impl BlitPipeline {
17    pub fn new(device: &Device, format: TextureFormat) -> Self {
18        let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
19            label: Some("Blit Source Bind Group Layout"),
20            entries: &[
21                BindGroupLayoutEntry {
22                    binding: 0,
23                    visibility: ShaderStages::FRAGMENT,
24                    ty: BindingType::Texture {
25                        sample_type: TextureSampleType::Float { filterable: true },
26                        view_dimension: TextureViewDimension::D2,
27                        multisampled: false,
28                    },
29                    count: None,
30                },
31                BindGroupLayoutEntry {
32                    binding: 1,
33                    visibility: ShaderStages::FRAGMENT,
34                    ty: BindingType::Sampler(SamplerBindingType::Filtering),
35                    count: None,
36                },
37            ],
38        });
39
40        let sampler = device.create_sampler(&SamplerDescriptor {
41            label: Some("Blit Sampler"),
42            address_mode_u: AddressMode::ClampToEdge,
43            address_mode_v: AddressMode::ClampToEdge,
44            address_mode_w: AddressMode::ClampToEdge,
45            mag_filter: FilterMode::Linear,
46            min_filter: FilterMode::Linear,
47            ..Default::default()
48        });
49
50        let shader = device.create_shader_module(include_wgsl!("blit.wgsl"));
51
52        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
53            label: Some("Blit Pipeline"),
54            layout: Some(
55                &device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
56                    label: Some("Blit Pipeline Layout"),
57                    bind_group_layouts: &[&bind_group_layout],
58                    push_constant_ranges: &[],
59                }),
60            ),
61            vertex: VertexState {
62                module: &shader,
63                entry_point: "vertex",
64                buffers: &[],
65            },
66            fragment: Some(FragmentState {
67                module: &shader,
68                entry_point: "fragment",
69                targets: &[Some(ColorTargetState {
70                    format,
71                    blend: Some(BlendState::REPLACE),
72                    write_mask: ColorWrites::ALL,
73                })],
74            }),
75            primitive: PrimitiveState::default(),
76            multisample: MultisampleState {
77                count: 4,
78                ..Default::default()
79            },
80            depth_stencil: None,
81            multiview: None,
82        });
83
84        Self {
85            source_bind_group_layout: bind_group_layout,
86            sampler,
87            pipeline,
88        }
89    }
90
91    pub fn blit(
92        &self,
93        device: &Device,
94        encoder: &mut CommandEncoder,
95        source: &TextureView,
96        target: &TextureView,
97    ) {
98        let bind_group = device.create_bind_group(&BindGroupDescriptor {
99            label: Some("Blit Source Bind Group"),
100            layout: &self.source_bind_group_layout,
101            entries: &[
102                BindGroupEntry {
103                    binding: 0,
104                    resource: BindingResource::TextureView(source),
105                },
106                BindGroupEntry {
107                    binding: 1,
108                    resource: BindingResource::Sampler(&self.sampler),
109                },
110            ],
111        });
112
113        let mut render_pass = encoder.begin_render_pass(&RenderPassDescriptor {
114            label: Some("Blit Render Pass"),
115            color_attachments: &[Some(RenderPassColorAttachment {
116                view: target,
117                resolve_target: None,
118                ops: Operations {
119                    load: wgpu::LoadOp::Load,
120                    store: true,
121                },
122            })],
123            depth_stencil_attachment: None,
124        });
125
126        render_pass.set_pipeline(&self.pipeline);
127        render_pass.set_bind_group(0, &bind_group, &[]);
128        render_pass.draw(0..6, 0..1);
129    }
130}