1use alloc::borrow::ToOwned as _;
2
3use wgt::TextureDataOrder;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct BufferInitDescriptor<'a> {
8 pub label: crate::Label<'a>,
10 pub contents: &'a [u8],
12 pub usage: wgt::BufferUsages,
15}
16
17pub trait DeviceExt {
19 fn create_buffer_init(&self, desc: &BufferInitDescriptor<'_>) -> crate::Buffer;
21
22 fn create_texture_with_data(
31 &self,
32 queue: &crate::Queue,
33 desc: &crate::TextureDescriptor<'_>,
34 order: TextureDataOrder,
35 data: &[u8],
36 ) -> crate::Texture;
37}
38
39impl DeviceExt for crate::Device {
40 fn create_buffer_init(&self, descriptor: &BufferInitDescriptor<'_>) -> crate::Buffer {
41 if descriptor.contents.is_empty() {
43 let wgt_descriptor = crate::BufferDescriptor {
44 label: descriptor.label,
45 size: 0,
46 usage: descriptor.usage,
47 mapped_at_creation: false,
48 };
49
50 self.create_buffer(&wgt_descriptor)
51 } else {
52 let unpadded_size = descriptor.contents.len() as crate::BufferAddress;
53 let align_mask = crate::COPY_BUFFER_ALIGNMENT - 1;
58 let padded_size =
59 ((unpadded_size + align_mask) & !align_mask).max(crate::COPY_BUFFER_ALIGNMENT);
60
61 let wgt_descriptor = crate::BufferDescriptor {
62 label: descriptor.label,
63 size: padded_size,
64 usage: descriptor.usage,
65 mapped_at_creation: true,
66 };
67
68 let buffer = self.create_buffer(&wgt_descriptor);
69
70 buffer
71 .get_mapped_range_mut(..)
72 .expect("Failed to get mapped range for buffer created with mapped_at_creation")
73 .slice(..unpadded_size as usize)
74 .copy_from_slice(descriptor.contents);
75 buffer.unmap();
76
77 buffer
78 }
79 }
80
81 fn create_texture_with_data(
82 &self,
83 queue: &crate::Queue,
84 desc: &crate::TextureDescriptor<'_>,
85 order: TextureDataOrder,
86 data: &[u8],
87 ) -> crate::Texture {
88 let mut desc = desc.to_owned();
90 desc.usage |= crate::TextureUsages::COPY_DST;
91 let texture = self.create_texture(&desc);
92
93 let block_size = desc.format.block_copy_size(None).unwrap_or(4);
97 let (block_width, block_height) = desc.format.block_dimensions();
98 let layer_iterations = desc.array_layer_count();
99
100 let outer_iteration;
101 let inner_iteration;
102 match order {
103 TextureDataOrder::LayerMajor => {
104 outer_iteration = layer_iterations;
105 inner_iteration = desc.mip_level_count;
106 }
107 TextureDataOrder::MipMajor => {
108 outer_iteration = desc.mip_level_count;
109 inner_iteration = layer_iterations;
110 }
111 }
112
113 let mut binary_offset = 0;
114 for outer in 0..outer_iteration {
115 for inner in 0..inner_iteration {
116 let (layer, mip) = match order {
117 TextureDataOrder::LayerMajor => (outer, inner),
118 TextureDataOrder::MipMajor => (inner, outer),
119 };
120
121 let mut mip_size = desc.mip_level_size(mip).unwrap();
122 if desc.dimension != wgt::TextureDimension::D3 {
124 mip_size.depth_or_array_layers = 1;
125 }
126
127 let mip_physical = mip_size.physical_size(desc.format);
131
132 let width_blocks = mip_physical.width / block_width;
135 let height_blocks = mip_physical.height / block_height;
136
137 let bytes_per_row = width_blocks * block_size;
138 let data_size = bytes_per_row * height_blocks * mip_size.depth_or_array_layers;
139
140 let end_offset = binary_offset + data_size as usize;
141
142 queue.write_texture(
143 crate::TexelCopyTextureInfo {
144 texture: &texture,
145 mip_level: mip,
146 origin: crate::Origin3d {
147 x: 0,
148 y: 0,
149 z: layer,
150 },
151 aspect: wgt::TextureAspect::All,
152 },
153 &data[binary_offset..end_offset],
154 crate::TexelCopyBufferLayout {
155 offset: 0,
156 bytes_per_row: Some(bytes_per_row),
157 rows_per_image: Some(height_blocks),
158 },
159 mip_physical,
160 );
161
162 binary_offset = end_offset;
163 }
164 }
165
166 texture
167 }
168}