iced_wgpu/
color.rs

1use std::borrow::Cow;
2
3use wgpu::util::DeviceExt;
4
5pub fn convert(
6    device: &wgpu::Device,
7    encoder: &mut wgpu::CommandEncoder,
8    source: wgpu::Texture,
9    format: wgpu::TextureFormat,
10) -> wgpu::Texture {
11    if source.format() == format {
12        return source;
13    }
14
15    let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
16        label: Some("iced_wgpu.offscreen.sampler"),
17        ..wgpu::SamplerDescriptor::default()
18    });
19
20    #[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
21    #[repr(C)]
22    struct Ratio {
23        u: f32,
24        v: f32,
25    }
26
27    let ratio = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
28        label: Some("iced-wgpu::triangle::msaa ratio"),
29        contents: bytemuck::bytes_of(&Ratio { u: 1.0, v: 1.0 }),
30        usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,
31    });
32
33    let constant_layout =
34        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
35            label: Some("iced_wgpu.offscreen.blit.sampler_layout"),
36            entries: &[
37                wgpu::BindGroupLayoutEntry {
38                    binding: 0,
39                    visibility: wgpu::ShaderStages::FRAGMENT,
40                    ty: wgpu::BindingType::Sampler(
41                        wgpu::SamplerBindingType::NonFiltering,
42                    ),
43                    count: None,
44                },
45                wgpu::BindGroupLayoutEntry {
46                    binding: 1,
47                    visibility: wgpu::ShaderStages::VERTEX,
48                    ty: wgpu::BindingType::Buffer {
49                        ty: wgpu::BufferBindingType::Uniform,
50                        has_dynamic_offset: false,
51                        min_binding_size: None,
52                    },
53                    count: None,
54                },
55            ],
56        });
57
58    let constant_bind_group =
59        device.create_bind_group(&wgpu::BindGroupDescriptor {
60            label: Some("iced_wgpu.offscreen.sampler.bind_group"),
61            layout: &constant_layout,
62            entries: &[
63                wgpu::BindGroupEntry {
64                    binding: 0,
65                    resource: wgpu::BindingResource::Sampler(&sampler),
66                },
67                wgpu::BindGroupEntry {
68                    binding: 1,
69                    resource: ratio.as_entire_binding(),
70                },
71            ],
72        });
73
74    let texture_layout =
75        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
76            label: Some("iced_wgpu.offscreen.blit.texture_layout"),
77            entries: &[wgpu::BindGroupLayoutEntry {
78                binding: 0,
79                visibility: wgpu::ShaderStages::FRAGMENT,
80                ty: wgpu::BindingType::Texture {
81                    sample_type: wgpu::TextureSampleType::Float {
82                        filterable: false,
83                    },
84                    view_dimension: wgpu::TextureViewDimension::D2,
85                    multisampled: false,
86                },
87                count: None,
88            }],
89        });
90
91    let pipeline_layout =
92        device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
93            label: Some("iced_wgpu.offscreen.blit.pipeline_layout"),
94            bind_group_layouts: &[&constant_layout, &texture_layout],
95            push_constant_ranges: &[],
96        });
97
98    let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
99        label: Some("iced_wgpu.offscreen.blit.shader"),
100        source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!(
101            "shader/blit.wgsl"
102        ))),
103    });
104
105    let pipeline =
106        device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
107            label: Some("iced_wgpu.offscreen.blit.pipeline"),
108            layout: Some(&pipeline_layout),
109            vertex: wgpu::VertexState {
110                module: &shader,
111                entry_point: Some("vs_main"),
112                buffers: &[],
113                compilation_options: wgpu::PipelineCompilationOptions::default(
114                ),
115            },
116            fragment: Some(wgpu::FragmentState {
117                module: &shader,
118                entry_point: Some("fs_main"),
119                targets: &[Some(wgpu::ColorTargetState {
120                    format,
121                    blend: Some(wgpu::BlendState {
122                        color: wgpu::BlendComponent {
123                            src_factor: wgpu::BlendFactor::SrcAlpha,
124                            dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
125                            operation: wgpu::BlendOperation::Add,
126                        },
127                        alpha: wgpu::BlendComponent {
128                            src_factor: wgpu::BlendFactor::One,
129                            dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
130                            operation: wgpu::BlendOperation::Add,
131                        },
132                    }),
133                    write_mask: wgpu::ColorWrites::ALL,
134                })],
135                compilation_options: wgpu::PipelineCompilationOptions::default(
136                ),
137            }),
138            primitive: wgpu::PrimitiveState {
139                topology: wgpu::PrimitiveTopology::TriangleList,
140                front_face: wgpu::FrontFace::Cw,
141                ..wgpu::PrimitiveState::default()
142            },
143            depth_stencil: None,
144            multisample: wgpu::MultisampleState::default(),
145            multiview: None,
146            cache: None,
147        });
148
149    let texture = device.create_texture(&wgpu::TextureDescriptor {
150        label: Some("iced_wgpu.offscreen.conversion.source_texture"),
151        size: source.size(),
152        mip_level_count: 1,
153        sample_count: 1,
154        dimension: wgpu::TextureDimension::D2,
155        format,
156        usage: wgpu::TextureUsages::RENDER_ATTACHMENT
157            | wgpu::TextureUsages::COPY_SRC,
158        view_formats: &[],
159    });
160
161    let view = &texture.create_view(&wgpu::TextureViewDescriptor::default());
162
163    let texture_bind_group =
164        device.create_bind_group(&wgpu::BindGroupDescriptor {
165            label: Some("iced_wgpu.offscreen.blit.texture_bind_group"),
166            layout: &texture_layout,
167            entries: &[wgpu::BindGroupEntry {
168                binding: 0,
169                resource: wgpu::BindingResource::TextureView(
170                    &source
171                        .create_view(&wgpu::TextureViewDescriptor::default()),
172                ),
173            }],
174        });
175
176    let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
177        label: Some("iced_wgpu.offscreen.blit.render_pass"),
178        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
179            view,
180            resolve_target: None,
181            ops: wgpu::Operations {
182                load: wgpu::LoadOp::Load,
183                store: wgpu::StoreOp::Store,
184            },
185        })],
186        depth_stencil_attachment: None,
187        timestamp_writes: None,
188        occlusion_query_set: None,
189    });
190
191    pass.set_pipeline(&pipeline);
192    pass.set_bind_group(0, &constant_bind_group, &[]);
193    pass.set_bind_group(1, &texture_bind_group, &[]);
194    pass.draw(0..6, 0..1);
195
196    texture
197}