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() +            });      }  }  | 
