diff options
Diffstat (limited to 'wgpu/src/image/atlas.rs')
-rw-r--r-- | wgpu/src/image/atlas.rs | 92 |
1 files changed, 61 insertions, 31 deletions
diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 86a5ff49..660ebe44 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -28,8 +28,8 @@ impl Atlas { }; let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some("iced_wgpu::image texture atlas"), size: extent, - array_layer_count: 2, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, @@ -39,12 +39,15 @@ impl Atlas { | wgpu::TextureUsage::SAMPLED, }); - let texture_view = texture.create_default_view(); + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor { + dimension: Some(wgpu::TextureViewDimension::D2Array), + ..Default::default() + }); Atlas { texture, texture_view, - layers: vec![Layer::Empty, Layer::Empty], + layers: vec![Layer::Empty], } } @@ -56,17 +59,16 @@ impl Atlas { self.layers.len() } - pub fn upload<C>( + pub fn upload( &mut self, width: u32, height: u32, - data: &[C], + data: &[u8], device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, - ) -> Option<Entry> - where - C: Copy + 'static, - { + ) -> Option<Entry> { + use wgpu::util::DeviceExt; + let entry = { let current_size = self.layers.len(); let entry = self.allocate(width, height)?; @@ -80,9 +82,31 @@ impl Atlas { log::info!("Allocated atlas entry: {:?}", entry); - let buffer = device - .create_buffer_mapped(data.len(), wgpu::BufferUsage::COPY_SRC) - .fill_from_slice(data); + // It is a webgpu requirement that: + // BufferCopyView.layout.bytes_per_row % wgpu::COPY_BYTES_PER_ROW_ALIGNMENT == 0 + // So we calculate padded_width by rounding width up to the next + // multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT. + let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT; + let padding = (align - (4 * width) % align) % align; + let padded_width = (4 * width + padding) as usize; + let padded_data_size = padded_width * height as usize; + + let mut padded_data = vec![0; padded_data_size]; + + for row in 0..height as usize { + let offset = row * padded_width; + + padded_data[offset..offset + 4 * width as usize].copy_from_slice( + &data[row * 4 * width as usize..(row + 1) * 4 * width as usize], + ) + } + + let buffer = + device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("iced_wgpu::image staging buffer"), + contents: &padded_data, + usage: wgpu::BufferUsage::COPY_SRC, + }); match &entry { Entry::Contiguous(allocation) => { @@ -90,6 +114,7 @@ impl Atlas { &buffer, width, height, + padding, 0, &allocation, encoder, @@ -98,12 +123,13 @@ impl Atlas { Entry::Fragmented { fragments, .. } => { for fragment in fragments { let (x, y) = fragment.position; - let offset = (y * width + x) as usize * 4; + let offset = (y * padded_width as u32 + 4 * x) as usize; self.upload_allocation( &buffer, width, height, + padding, offset, &fragment.allocation, encoder, @@ -256,6 +282,7 @@ impl Atlas { buffer: &wgpu::Buffer, image_width: u32, image_height: u32, + padding: u32, offset: usize, allocation: &Allocation, encoder: &mut wgpu::CommandEncoder, @@ -273,18 +300,19 @@ impl Atlas { encoder.copy_buffer_to_texture( wgpu::BufferCopyView { buffer, - offset: offset as u64, - row_pitch: 4 * image_width, - image_height, + layout: wgpu::TextureDataLayout { + offset: offset as u64, + bytes_per_row: 4 * image_width + padding, + rows_per_image: image_height, + }, }, wgpu::TextureCopyView { texture: &self.texture, - array_layer: layer as u32, mip_level: 0, origin: wgpu::Origin3d { - x: x as f32, - y: y as f32, - z: 0.0, + x, + y, + z: layer as u32, }, }, extent, @@ -302,12 +330,12 @@ impl Atlas { } let new_texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some("iced_wgpu::image texture atlas"), size: wgpu::Extent3d { width: SIZE, height: SIZE, - depth: 1, + depth: self.layers.len() as u32, }, - array_layer_count: self.layers.len() as u32, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, @@ -329,22 +357,20 @@ impl Atlas { encoder.copy_texture_to_texture( wgpu::TextureCopyView { texture: &self.texture, - array_layer: i as u32, mip_level: 0, origin: wgpu::Origin3d { - x: 0.0, - y: 0.0, - z: 0.0, + x: 0, + y: 0, + z: i as u32, }, }, wgpu::TextureCopyView { texture: &new_texture, - array_layer: i as u32, mip_level: 0, origin: wgpu::Origin3d { - x: 0.0, - y: 0.0, - z: 0.0, + x: 0, + y: 0, + z: i as u32, }, }, wgpu::Extent3d { @@ -356,6 +382,10 @@ impl Atlas { } self.texture = new_texture; - self.texture_view = self.texture.create_default_view(); + self.texture_view = + self.texture.create_view(&wgpu::TextureViewDescriptor { + dimension: Some(wgpu::TextureViewDimension::D2Array), + ..Default::default() + }); } } |