diff options
author | 2024-04-05 00:40:39 +0200 | |
---|---|---|
committer | 2024-04-05 00:40:39 +0200 | |
commit | 394e599c3a096b036aabdd6f850c4a7c518d44fa (patch) | |
tree | be925d4f26d7f1e30a289297ccf50ce968d6e86c /wgpu/src | |
parent | cc05cb9be4a1de5f0427f93ce64e658be0703f8b (diff) | |
download | iced-394e599c3a096b036aabdd6f850c4a7c518d44fa.tar.gz iced-394e599c3a096b036aabdd6f850c4a7c518d44fa.tar.bz2 iced-394e599c3a096b036aabdd6f850c4a7c518d44fa.zip |
Fix layer transformations
Diffstat (limited to 'wgpu/src')
-rw-r--r-- | wgpu/src/geometry.rs | 39 | ||||
-rw-r--r-- | wgpu/src/layer.rs | 65 | ||||
-rw-r--r-- | wgpu/src/lib.rs | 158 | ||||
-rw-r--r-- | wgpu/src/text.rs | 36 | ||||
-rw-r--r-- | wgpu/src/triangle.rs | 72 |
5 files changed, 206 insertions, 164 deletions
diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index d153c764..611e81f1 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -106,23 +106,28 @@ impl Frame { .buffers .stack .into_iter() - .map(|buffer| match buffer { - Buffer::Solid(buffer) => Mesh::Solid { - buffers: mesh::Indexed { - vertices: buffer.vertices, - indices: buffer.indices, - }, - transformation: Transformation::IDENTITY, - size: self.size, - }, - Buffer::Gradient(buffer) => Mesh::Gradient { - buffers: mesh::Indexed { - vertices: buffer.vertices, - indices: buffer.indices, - }, - transformation: Transformation::IDENTITY, - size: self.size, - }, + .filter_map(|buffer| match buffer { + Buffer::Solid(buffer) if !buffer.indices.is_empty() => { + Some(Mesh::Solid { + buffers: mesh::Indexed { + vertices: buffer.vertices, + indices: buffer.indices, + }, + transformation: Transformation::IDENTITY, + size: self.size, + }) + } + Buffer::Gradient(buffer) if !buffer.indices.is_empty() => { + Some(Mesh::Gradient { + buffers: mesh::Indexed { + vertices: buffer.vertices, + indices: buffer.indices, + }, + transformation: Transformation::IDENTITY, + size: self.size, + }) + } + _ => None, }) .collect(); diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 5c23669a..1c9638b0 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -13,17 +13,17 @@ use std::rc::Rc; pub enum Layer<'a> { Live(&'a Live), - Cached(cell::Ref<'a, Cached>), + Cached(Transformation, cell::Ref<'a, Cached>), } pub enum LayerMut<'a> { Live(&'a mut Live), - Cached(cell::RefMut<'a, Cached>), + Cached(Transformation, cell::RefMut<'a, Cached>), } pub struct Stack { live: Vec<Live>, - cached: Vec<Rc<RefCell<Cached>>>, + cached: Vec<(Transformation, Rc<RefCell<Cached>>)>, order: Vec<Kind>, transformations: Vec<Transformation>, previous: Vec<usize>, @@ -92,7 +92,7 @@ impl Stack { position, color, clip_bounds, - transformation: self.transformations.last().copied().unwrap(), + transformation: self.transformation(), }; self.live[self.current].text.push(paragraph); @@ -178,36 +178,31 @@ impl Stack { } pub fn draw_cached_layer(&mut self, layer: &Rc<RefCell<Cached>>) { - { - let mut layer = layer.borrow_mut(); - layer.transformation = self.transformation() * layer.transformation; - } - - self.cached.push(layer.clone()); + self.cached.push((self.transformation(), layer.clone())); self.order.push(Kind::Cache); } pub fn push_clip(&mut self, bounds: Option<Rectangle>) { - self.previous.push(self.current); - self.order.push(Kind::Live); - - self.current = self.live_count; - self.live_count += 1; - - let bounds = bounds.map(|bounds| bounds * self.transformation()); - - if self.current == self.live.len() { - self.live.push(Live { - bounds, - ..Live::default() - }); - } else { - self.live[self.current].bounds = bounds; - } + // self.previous.push(self.current); + // self.order.push(Kind::Live); + + // self.current = self.live_count; + // self.live_count += 1; + + // let bounds = bounds.map(|bounds| bounds * self.transformation()); + + // if self.current == self.live.len() { + // self.live.push(Live { + // bounds, + // ..Live::default() + // }); + // } else { + // self.live[self.current].bounds = bounds; + // } } pub fn pop_clip(&mut self) { - self.current = self.previous.pop().unwrap(); + // self.current = self.previous.pop().unwrap(); } pub fn push_transformation(&mut self, transformation: Transformation) { @@ -224,13 +219,17 @@ impl Stack { } pub fn iter_mut(&mut self) -> impl Iterator<Item = LayerMut<'_>> { + dbg!(self.order.len()); let mut live = self.live.iter_mut(); let mut cached = self.cached.iter_mut(); self.order.iter().map(move |kind| match kind { Kind::Live => LayerMut::Live(live.next().unwrap()), Kind::Cache => { - LayerMut::Cached(cached.next().unwrap().borrow_mut()) + let (transformation, layer) = cached.next().unwrap(); + let layer = layer.borrow_mut(); + + LayerMut::Cached(*transformation * layer.transformation, layer) } }) } @@ -241,7 +240,12 @@ impl Stack { self.order.iter().map(move |kind| match kind { Kind::Live => Layer::Live(live.next().unwrap()), - Kind::Cache => Layer::Cached(cached.next().unwrap().borrow()), + Kind::Cache => { + let (transformation, layer) = cached.next().unwrap(); + let layer = layer.borrow(); + + Layer::Cached(*transformation * layer.transformation, layer) + } }) } @@ -288,7 +292,6 @@ impl Live { Cached { bounds: self.bounds, transformation: self.transformation, - last_transformation: None, quads: quad::Cache::Staged(self.quads), meshes: triangle::Cache::Staged(self.meshes), text: text::Cache::Staged(self.text), @@ -301,7 +304,6 @@ impl Live { pub struct Cached { pub bounds: Option<Rectangle>, pub transformation: Transformation, - pub last_transformation: Option<Transformation>, pub quads: quad::Cache, pub meshes: triangle::Cache, pub text: text::Cache, @@ -311,7 +313,6 @@ pub struct Cached { impl Cached { pub fn update(&mut self, live: Live) { self.bounds = live.bounds; - self.transformation = live.transformation; self.quads.update(live.quads); self.meshes.update(live.meshes); diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 2d023d8b..4705cfa0 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -116,32 +116,10 @@ impl Renderer { viewport: &Viewport, overlay: &[T], ) { - let target_size = viewport.physical_size(); - let scale_factor = viewport.scale_factor() as f32; - let transformation = viewport.projection(); - self.draw_overlay(overlay, viewport); - self.prepare( - engine, - device, - queue, - format, - encoder, - scale_factor, - target_size, - transformation, - ); - - self.render( - engine, - device, - encoder, - frame, - clear_color, - scale_factor, - target_size, - ); + self.prepare(engine, device, queue, format, encoder, viewport); + self.render(engine, device, encoder, frame, clear_color, viewport); } fn prepare( @@ -151,10 +129,10 @@ impl Renderer { queue: &wgpu::Queue, _format: wgpu::TextureFormat, encoder: &mut wgpu::CommandEncoder, - scale_factor: f32, - target_size: Size<u32>, - transformation: Transformation, + viewport: &Viewport, ) { + let scale_factor = viewport.scale_factor() as f32; + for layer in self.layers.iter_mut() { match layer { LayerMut::Live(live) => { @@ -164,7 +142,7 @@ impl Renderer { encoder, &mut engine.staging_belt, &live.quads, - transformation, + viewport.projection(), scale_factor, ); } @@ -175,7 +153,7 @@ impl Renderer { encoder, &mut engine.staging_belt, &live.meshes, - transformation + viewport.projection() * Transformation::scale(scale_factor), ); } @@ -187,10 +165,11 @@ impl Renderer { encoder, &live.text, live.bounds.unwrap_or(Rectangle::with_size( - Size::INFINITY, + viewport.logical_size(), )), - scale_factor, - target_size, + live.transformation + * Transformation::scale(scale_factor), + viewport.physical_size(), ); } @@ -201,38 +180,46 @@ impl Renderer { encoder, &mut engine.staging_belt, &live.images, - transformation, + viewport.projection(), scale_factor, ); } } - LayerMut::Cached(mut cached) => { + LayerMut::Cached(layer_transformation, mut cached) => { if !cached.quads.is_empty() { engine.quad_pipeline.prepare_cache( device, encoder, &mut engine.staging_belt, &mut cached.quads, - transformation, + viewport.projection(), scale_factor, ); } if !cached.meshes.is_empty() { + let transformation = + Transformation::scale(scale_factor) + * layer_transformation; + engine.triangle_pipeline.prepare_cache( device, encoder, &mut engine.staging_belt, &mut cached.meshes, - transformation - * Transformation::scale(scale_factor), + viewport.projection(), + transformation, ); } if !cached.text.is_empty() { - let bounds = cached - .bounds - .unwrap_or(Rectangle::with_size(Size::INFINITY)); + let bounds = cached.bounds.unwrap_or( + Rectangle::with_size(viewport.logical_size()), + ); + + let transformation = + Transformation::scale(scale_factor) + * layer_transformation; engine.text_pipeline.prepare_cache( device, @@ -240,8 +227,8 @@ impl Renderer { encoder, &mut cached.text, bounds, - scale_factor, - target_size, + transformation, + viewport.physical_size(), ); } @@ -252,7 +239,7 @@ impl Renderer { encoder, &mut engine.staging_belt, &cached.images, - transformation, + viewport.projection(), scale_factor, ); } @@ -268,8 +255,7 @@ impl Renderer { encoder: &mut wgpu::CommandEncoder, frame: &wgpu::TextureView, clear_color: Option<Color>, - scale_factor: f32, - target_size: Size<u32>, + viewport: &Viewport, ) { use std::mem::ManuallyDrop; @@ -312,22 +298,37 @@ impl Renderer { let mut image_layer = 0; // TODO: Can we avoid collecting here? + let scale_factor = viewport.scale_factor() as f32; + let screen_bounds = Rectangle::with_size(viewport.logical_size()); + let physical_bounds = Rectangle::<f32>::from(Rectangle::with_size( + viewport.physical_size(), + )); + let layers: Vec<_> = self.layers.iter().collect(); let mut i = 0; + // println!("RENDER"); + while i < layers.len() { match layers[i] { Layer::Live(live) => { - let bounds = live - .bounds - .map(|bounds| bounds * scale_factor) + let layer_transformation = + Transformation::scale(scale_factor) + * live.transformation; + + let layer_bounds = live.bounds.unwrap_or(screen_bounds); + + let Some(physical_bounds) = physical_bounds + .intersection(&(layer_bounds * layer_transformation)) .map(Rectangle::snap) - .unwrap_or(Rectangle::with_size(target_size)); + else { + continue; + }; if !live.quads.is_empty() { engine.quad_pipeline.render_batch( quad_layer, - bounds, + physical_bounds, &live.quads, &mut render_pass, ); @@ -336,6 +337,7 @@ impl Renderer { } if !live.meshes.is_empty() { + // println!("LIVE PASS"); let _ = ManuallyDrop::into_inner(render_pass); engine.triangle_pipeline.render_batch( @@ -343,10 +345,10 @@ impl Renderer { encoder, frame, mesh_layer, - target_size, + viewport.physical_size(), &live.meshes, - bounds, - scale_factor, + physical_bounds, + &layer_transformation, ); mesh_layer += 1; @@ -375,7 +377,7 @@ impl Renderer { if !live.text.is_empty() { engine.text_pipeline.render_batch( text_layer, - bounds, + physical_bounds, &mut render_pass, ); @@ -386,7 +388,7 @@ impl Renderer { if !live.images.is_empty() { engine.image_pipeline.render( image_layer, - bounds, + physical_bounds, &mut render_pass, ); @@ -395,25 +397,35 @@ impl Renderer { i += 1; } - Layer::Cached(_) => { + Layer::Cached(_, _) => { let group_len = layers[i..] .iter() .position(|layer| matches!(layer, Layer::Live(_))) - .unwrap_or(layers.len()); - - let group = layers[i..i + group_len].iter().map(|layer| { - let Layer::Cached(cached) = layer else { - unreachable!() - }; - - let bounds = cached - .bounds - .map(|bounds| bounds * scale_factor) - .map(Rectangle::snap) - .unwrap_or(Rectangle::with_size(target_size)); - - (cached, bounds) - }); + .unwrap_or(layers.len() - i); + + let group = + layers[i..i + group_len].iter().filter_map(|layer| { + let Layer::Cached(transformation, cached) = layer + else { + unreachable!() + }; + + let physical_bounds = cached + .bounds + .and_then(|bounds| { + physical_bounds.intersection( + &(bounds + * *transformation + * Transformation::scale( + scale_factor, + )), + ) + }) + .unwrap_or(physical_bounds) + .snap(); + + Some((cached, physical_bounds)) + }); for (cached, bounds) in group.clone() { if !cached.quads.is_empty() { @@ -430,17 +442,17 @@ impl Renderer { .any(|(cached, _)| !cached.meshes.is_empty()); if group_has_meshes { + // println!("CACHE PASS"); let _ = ManuallyDrop::into_inner(render_pass); engine.triangle_pipeline.render_cache_group( device, encoder, frame, - target_size, + viewport.physical_size(), group.clone().map(|(cached, bounds)| { (&cached.meshes, bounds) }), - scale_factor, ); render_pass = diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 016ac92a..e0a5355c 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -26,7 +26,7 @@ pub enum Cache { renderer: glyphon::TextRenderer, atlas: Option<glyphon::TextAtlas>, buffer_cache: Option<BufferCache>, - scale_factor: f32, + transformation: Transformation, target_size: Size<u32>, needs_reupload: bool, }, @@ -95,7 +95,7 @@ impl Pipeline { encoder: &mut wgpu::CommandEncoder, sections: &Batch, layer_bounds: Rectangle, - scale_factor: f32, + layer_transformation: Transformation, target_size: Size<u32>, ) { if self.renderers.len() <= self.prepare_layer { @@ -117,7 +117,7 @@ impl Pipeline { &mut self.cache, sections, layer_bounds, - scale_factor, + layer_transformation, target_size, ); @@ -140,7 +140,7 @@ impl Pipeline { encoder: &mut wgpu::CommandEncoder, cache: &mut Cache, layer_bounds: Rectangle, - new_scale_factor: f32, + new_transformation: Transformation, new_target_size: Size<u32>, ) { match cache { @@ -186,7 +186,7 @@ impl Pipeline { buffer_cache.as_mut().unwrap_or(&mut self.cache), &batch, layer_bounds, - new_scale_factor, + new_transformation, new_target_size, ); @@ -196,7 +196,7 @@ impl Pipeline { renderer, atlas, buffer_cache, - scale_factor: new_scale_factor, + transformation: new_transformation, target_size: new_target_size, } } @@ -206,13 +206,13 @@ impl Pipeline { renderer, atlas, buffer_cache, - scale_factor, + transformation, target_size, } => { if *needs_reupload || atlas.is_none() || buffer_cache.is_none() - || new_scale_factor != *scale_factor + || new_transformation != *transformation || new_target_size != *target_size { let _ = prepare( @@ -224,11 +224,11 @@ impl Pipeline { buffer_cache.as_mut().unwrap_or(&mut self.cache), batch, layer_bounds, - *scale_factor, - *target_size, + new_transformation, + new_target_size, ); - *scale_factor = new_scale_factor; + *transformation = new_transformation; *target_size = new_target_size; } } @@ -297,7 +297,7 @@ fn prepare( buffer_cache: &mut BufferCache, sections: &Batch, layer_bounds: Rectangle, - scale_factor: f32, + layer_transformation: Transformation, target_size: Size<u32>, ) -> Result<(), glyphon::PrepareError> { let mut font_system = font_system().write().expect("Write font system"); @@ -349,7 +349,7 @@ fn prepare( }) .collect(); - let layer_bounds = layer_bounds * scale_factor; + let layer_bounds = layer_bounds * layer_transformation; let text_areas = sections.iter().zip(allocations.iter()).filter_map( |(section, allocation)| { @@ -456,7 +456,7 @@ fn prepare( } }; - let bounds = bounds * transformation * scale_factor; + let bounds = bounds * transformation * layer_transformation; let left = match horizontal_alignment { alignment::Horizontal::Left => bounds.x, @@ -470,14 +470,16 @@ fn prepare( alignment::Vertical::Bottom => bounds.y - bounds.height, }; - let clip_bounds = layer_bounds - .intersection(&(clip_bounds * transformation * scale_factor))?; + let clip_bounds = layer_bounds.intersection( + &(clip_bounds * transformation * layer_transformation), + )?; Some(glyphon::TextArea { buffer, left, top, - scale: scale_factor * transformation.scale_factor(), + scale: transformation.scale_factor() + * layer_transformation.scale_factor(), bounds: glyphon::TextBounds { left: clip_bounds.x as i32, top: clip_bounds.y as i32, diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index be7bb867..3a184da2 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -68,8 +68,11 @@ impl Pipeline { encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, cache: &mut Cache, - transformation: Transformation, + new_projection: Transformation, + new_transformation: Transformation, ) { + let new_projection = new_projection * new_transformation; + match cache { Cache::Staged(_) => { let Cache::Staged(batch) = @@ -86,21 +89,25 @@ impl Pipeline { &self.solid, &self.gradient, &batch, - transformation, + new_projection, ); *cache = Cache::Uploaded { layer, batch, + transformation: new_transformation, + projection: new_projection, needs_reupload: false, } } Cache::Uploaded { batch, layer, + transformation, + projection, needs_reupload, } => { - if *needs_reupload { + if *needs_reupload || new_projection != *projection { layer.prepare( device, encoder, @@ -108,9 +115,11 @@ impl Pipeline { &self.solid, &self.gradient, batch, - transformation, + new_projection, ); + *transformation = new_transformation; + *projection = new_projection; *needs_reupload = false; } } @@ -126,7 +135,7 @@ impl Pipeline { target_size: Size<u32>, meshes: &Batch, bounds: Rectangle<u32>, - scale_factor: f32, + transformation: &Transformation, ) { Self::render( device, @@ -136,8 +145,12 @@ impl Pipeline { &self.solid, &self.gradient, target_size, - std::iter::once((&self.layers[layer], meshes, bounds)), - scale_factor, + std::iter::once(( + &self.layers[layer], + meshes, + transformation, + bounds, + )), ); } @@ -150,9 +163,14 @@ impl Pipeline { target_size: Size<u32>, cache: &Cache, bounds: Rectangle<u32>, - scale_factor: f32, ) { - let Cache::Uploaded { batch, layer, .. } = cache else { + let Cache::Uploaded { + batch, + layer, + transformation, + .. + } = cache + else { return; }; @@ -164,8 +182,7 @@ impl Pipeline { &self.solid, &self.gradient, target_size, - std::iter::once((layer, batch, bounds)), - scale_factor, + std::iter::once((layer, batch, transformation, bounds)), ); } @@ -176,11 +193,16 @@ impl Pipeline { target: &wgpu::TextureView, target_size: Size<u32>, group: impl Iterator<Item = (&'a Cache, Rectangle<u32>)>, - scale_factor: f32, ) { let group = group.filter_map(|(cache, bounds)| { - if let Cache::Uploaded { batch, layer, .. } = cache { - Some((layer, batch, bounds)) + if let Cache::Uploaded { + batch, + layer, + transformation, + .. + } = cache + { + Some((layer, batch, transformation, bounds)) } else { None } @@ -195,7 +217,6 @@ impl Pipeline { &self.gradient, target_size, group, - scale_factor, ); } @@ -207,8 +228,9 @@ impl Pipeline { solid: &solid::Pipeline, gradient: &gradient::Pipeline, target_size: Size<u32>, - group: impl Iterator<Item = (&'a Layer, &'a Batch, Rectangle<u32>)>, - scale_factor: f32, + group: impl Iterator< + Item = (&'a Layer, &'a Batch, &'a Transformation, Rectangle<u32>), + >, ) { { let (attachment, resolve_target, load) = if let Some(blit) = @@ -244,13 +266,13 @@ impl Pipeline { occlusion_query_set: None, }); - for (layer, meshes, bounds) in group { + for (layer, meshes, transformation, bounds) in group { layer.render( solid, gradient, meshes, bounds, - scale_factor, + *transformation, &mut render_pass, ); } @@ -272,6 +294,8 @@ pub enum Cache { Uploaded { batch: Batch, layer: Layer, + transformation: Transformation, + projection: Transformation, needs_reupload: bool, }, } @@ -390,6 +414,7 @@ impl Layer { for mesh in meshes { let indices = mesh.indices(); + let uniforms = Uniforms::new(transformation * mesh.transformation()); @@ -448,7 +473,7 @@ impl Layer { gradient: &'a gradient::Pipeline, meshes: &Batch, layer_bounds: Rectangle<u32>, - scale_factor: f32, + transformation: Transformation, render_pass: &mut wgpu::RenderPass<'a>, ) { let mut num_solids = 0; @@ -457,15 +482,12 @@ impl Layer { for (index, mesh) in meshes.iter().enumerate() { let Some(clip_bounds) = Rectangle::<f32>::from(layer_bounds) - .intersection(&(mesh.clip_bounds() * scale_factor)) - .map(Rectangle::snap) + .intersection(&(mesh.clip_bounds() * transformation)) else { continue; }; - if clip_bounds.width < 1 || clip_bounds.height < 1 { - continue; - } + let clip_bounds = clip_bounds.snap(); render_pass.set_scissor_rect( clip_bounds.x, |