summaryrefslogtreecommitdiffstats
path: root/wgpu/src/image/atlas.rs
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/image/atlas.rs')
-rw-r--r--wgpu/src/image/atlas.rs215
1 files changed, 103 insertions, 112 deletions
diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs
index 82504147..39b6e5d2 100644
--- a/wgpu/src/image/atlas.rs
+++ b/wgpu/src/image/atlas.rs
@@ -12,8 +12,7 @@ use allocator::Allocator;
pub const SIZE: u32 = 2048;
-use iced_graphics::image;
-use iced_graphics::Size;
+use crate::core::Size;
use std::num::NonZeroU32;
@@ -39,10 +38,10 @@ impl Atlas {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
- view_formats: &[],
usage: wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING,
+ view_formats: &[],
});
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
@@ -65,6 +64,97 @@ impl Atlas {
self.layers.len()
}
+ pub fn upload(
+ &mut self,
+ device: &wgpu::Device,
+ queue: &wgpu::Queue,
+ encoder: &mut wgpu::CommandEncoder,
+ width: u32,
+ height: u32,
+ data: &[u8],
+ ) -> Option<Entry> {
+ let entry = {
+ let current_size = self.layers.len();
+ let entry = self.allocate(width, height)?;
+
+ // We grow the internal texture after allocating if necessary
+ let new_layers = self.layers.len() - current_size;
+ self.grow(new_layers, device, encoder);
+
+ entry
+ };
+
+ log::info!("Allocated atlas entry: {:?}", entry);
+
+ // 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],
+ )
+ }
+
+ match &entry {
+ Entry::Contiguous(allocation) => {
+ self.upload_allocation(
+ &padded_data,
+ width,
+ height,
+ padding,
+ 0,
+ allocation,
+ queue,
+ );
+ }
+ Entry::Fragmented { fragments, .. } => {
+ for fragment in fragments {
+ let (x, y) = fragment.position;
+ let offset = (y * padded_width as u32 + 4 * x) as usize;
+
+ self.upload_allocation(
+ &padded_data,
+ width,
+ height,
+ padding,
+ offset,
+ &fragment.allocation,
+ queue,
+ );
+ }
+ }
+ }
+
+ log::info!("Current atlas: {:?}", self);
+
+ Some(entry)
+ }
+
+ pub fn remove(&mut self, entry: &Entry) {
+ log::info!("Removing atlas entry: {:?}", entry);
+
+ match entry {
+ Entry::Contiguous(allocation) => {
+ self.deallocate(allocation);
+ }
+ Entry::Fragmented { fragments, .. } => {
+ for fragment in fragments {
+ self.deallocate(&fragment.allocation);
+ }
+ }
+ }
+ }
+
fn allocate(&mut self, width: u32, height: u32) -> Option<Entry> {
// Allocate one layer if texture fits perfectly
if width == SIZE && height == SIZE {
@@ -186,13 +276,13 @@ impl Atlas {
fn upload_allocation(
&mut self,
- buffer: &wgpu::Buffer,
+ data: &[u8],
image_width: u32,
image_height: u32,
padding: u32,
offset: usize,
allocation: &Allocation,
- encoder: &mut wgpu::CommandEncoder,
+ queue: &wgpu::Queue,
) {
let (x, y) = allocation.position();
let Size { width, height } = allocation.size();
@@ -204,15 +294,7 @@ impl Atlas {
depth_or_array_layers: 1,
};
- encoder.copy_buffer_to_texture(
- wgpu::ImageCopyBuffer {
- buffer,
- layout: wgpu::ImageDataLayout {
- offset: offset as u64,
- bytes_per_row: NonZeroU32::new(4 * image_width + padding),
- rows_per_image: NonZeroU32::new(image_height),
- },
- },
+ queue.write_texture(
wgpu::ImageCopyTexture {
texture: &self.texture,
mip_level: 0,
@@ -223,6 +305,12 @@ impl Atlas {
},
aspect: wgpu::TextureAspect::default(),
},
+ data,
+ wgpu::ImageDataLayout {
+ offset: offset as u64,
+ bytes_per_row: NonZeroU32::new(4 * image_width + padding),
+ rows_per_image: NonZeroU32::new(image_height),
+ },
extent,
);
}
@@ -248,10 +336,10 @@ impl Atlas {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
- view_formats: &[],
usage: wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::TEXTURE_BINDING,
+ view_formats: &[],
});
let amount_to_copy = self.layers.len() - amount;
@@ -300,100 +388,3 @@ impl Atlas {
});
}
}
-
-impl image::Storage for Atlas {
- type Entry = Entry;
- type State<'a> = (&'a wgpu::Device, &'a mut wgpu::CommandEncoder);
-
- fn upload(
- &mut self,
- width: u32,
- height: u32,
- data: &[u8],
- (device, encoder): &mut Self::State<'_>,
- ) -> Option<Self::Entry> {
- use wgpu::util::DeviceExt;
-
- let entry = {
- let current_size = self.layers.len();
- let entry = self.allocate(width, height)?;
-
- // We grow the internal texture after allocating if necessary
- let new_layers = self.layers.len() - current_size;
- self.grow(new_layers, device, encoder);
-
- entry
- };
-
- log::info!("Allocated atlas entry: {:?}", entry);
-
- // 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::BufferUsages::COPY_SRC,
- });
-
- match &entry {
- Entry::Contiguous(allocation) => {
- self.upload_allocation(
- &buffer, width, height, padding, 0, allocation, encoder,
- );
- }
- Entry::Fragmented { fragments, .. } => {
- for fragment in fragments {
- let (x, y) = fragment.position;
- let offset = (y * padded_width as u32 + 4 * x) as usize;
-
- self.upload_allocation(
- &buffer,
- width,
- height,
- padding,
- offset,
- &fragment.allocation,
- encoder,
- );
- }
- }
- }
-
- log::info!("Current atlas: {:?}", self);
-
- Some(entry)
- }
-
- fn remove(&mut self, entry: &Entry, _: &mut Self::State<'_>) {
- log::info!("Removing atlas entry: {:?}", entry);
-
- match entry {
- Entry::Contiguous(allocation) => {
- self.deallocate(allocation);
- }
- Entry::Fragmented { fragments, .. } => {
- for fragment in fragments {
- self.deallocate(&fragment.allocation);
- }
- }
- }
- }
-}