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