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}