Fix layer transformations

This commit is contained in:
Héctor Ramón Jiménez 2024-04-05 00:40:39 +02:00
parent cc05cb9be4
commit 394e599c3a
No known key found for this signature in database
GPG key ID: 4C07CEC81AFA161F
6 changed files with 203 additions and 161 deletions

View file

@ -106,23 +106,28 @@ impl Frame {
.buffers .buffers
.stack .stack
.into_iter() .into_iter()
.map(|buffer| match buffer { .filter_map(|buffer| match buffer {
Buffer::Solid(buffer) => Mesh::Solid { Buffer::Solid(buffer) if !buffer.indices.is_empty() => {
buffers: mesh::Indexed { Some(Mesh::Solid {
vertices: buffer.vertices, buffers: mesh::Indexed {
indices: buffer.indices, vertices: buffer.vertices,
}, indices: buffer.indices,
transformation: Transformation::IDENTITY, },
size: self.size, transformation: Transformation::IDENTITY,
}, size: self.size,
Buffer::Gradient(buffer) => Mesh::Gradient { })
buffers: mesh::Indexed { }
vertices: buffer.vertices, Buffer::Gradient(buffer) if !buffer.indices.is_empty() => {
indices: buffer.indices, Some(Mesh::Gradient {
}, buffers: mesh::Indexed {
transformation: Transformation::IDENTITY, vertices: buffer.vertices,
size: self.size, indices: buffer.indices,
}, },
transformation: Transformation::IDENTITY,
size: self.size,
})
}
_ => None,
}) })
.collect(); .collect();

View file

@ -13,17 +13,17 @@ use std::rc::Rc;
pub enum Layer<'a> { pub enum Layer<'a> {
Live(&'a Live), Live(&'a Live),
Cached(cell::Ref<'a, Cached>), Cached(Transformation, cell::Ref<'a, Cached>),
} }
pub enum LayerMut<'a> { pub enum LayerMut<'a> {
Live(&'a mut Live), Live(&'a mut Live),
Cached(cell::RefMut<'a, Cached>), Cached(Transformation, cell::RefMut<'a, Cached>),
} }
pub struct Stack { pub struct Stack {
live: Vec<Live>, live: Vec<Live>,
cached: Vec<Rc<RefCell<Cached>>>, cached: Vec<(Transformation, Rc<RefCell<Cached>>)>,
order: Vec<Kind>, order: Vec<Kind>,
transformations: Vec<Transformation>, transformations: Vec<Transformation>,
previous: Vec<usize>, previous: Vec<usize>,
@ -92,7 +92,7 @@ impl Stack {
position, position,
color, color,
clip_bounds, clip_bounds,
transformation: self.transformations.last().copied().unwrap(), transformation: self.transformation(),
}; };
self.live[self.current].text.push(paragraph); self.live[self.current].text.push(paragraph);
@ -178,36 +178,31 @@ impl Stack {
} }
pub fn draw_cached_layer(&mut self, layer: &Rc<RefCell<Cached>>) { pub fn draw_cached_layer(&mut self, layer: &Rc<RefCell<Cached>>) {
{ self.cached.push((self.transformation(), layer.clone()));
let mut layer = layer.borrow_mut();
layer.transformation = self.transformation() * layer.transformation;
}
self.cached.push(layer.clone());
self.order.push(Kind::Cache); self.order.push(Kind::Cache);
} }
pub fn push_clip(&mut self, bounds: Option<Rectangle>) { pub fn push_clip(&mut self, bounds: Option<Rectangle>) {
self.previous.push(self.current); // self.previous.push(self.current);
self.order.push(Kind::Live); // self.order.push(Kind::Live);
self.current = self.live_count; // self.current = self.live_count;
self.live_count += 1; // self.live_count += 1;
let bounds = bounds.map(|bounds| bounds * self.transformation()); // let bounds = bounds.map(|bounds| bounds * self.transformation());
if self.current == self.live.len() { // if self.current == self.live.len() {
self.live.push(Live { // self.live.push(Live {
bounds, // bounds,
..Live::default() // ..Live::default()
}); // });
} else { // } else {
self.live[self.current].bounds = bounds; // self.live[self.current].bounds = bounds;
} // }
} }
pub fn pop_clip(&mut self) { 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) { pub fn push_transformation(&mut self, transformation: Transformation) {
@ -224,13 +219,17 @@ impl Stack {
} }
pub fn iter_mut(&mut self) -> impl Iterator<Item = LayerMut<'_>> { pub fn iter_mut(&mut self) -> impl Iterator<Item = LayerMut<'_>> {
dbg!(self.order.len());
let mut live = self.live.iter_mut(); let mut live = self.live.iter_mut();
let mut cached = self.cached.iter_mut(); let mut cached = self.cached.iter_mut();
self.order.iter().map(move |kind| match kind { self.order.iter().map(move |kind| match kind {
Kind::Live => LayerMut::Live(live.next().unwrap()), Kind::Live => LayerMut::Live(live.next().unwrap()),
Kind::Cache => { 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 { self.order.iter().map(move |kind| match kind {
Kind::Live => Layer::Live(live.next().unwrap()), 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 { Cached {
bounds: self.bounds, bounds: self.bounds,
transformation: self.transformation, transformation: self.transformation,
last_transformation: None,
quads: quad::Cache::Staged(self.quads), quads: quad::Cache::Staged(self.quads),
meshes: triangle::Cache::Staged(self.meshes), meshes: triangle::Cache::Staged(self.meshes),
text: text::Cache::Staged(self.text), text: text::Cache::Staged(self.text),
@ -301,7 +304,6 @@ impl Live {
pub struct Cached { pub struct Cached {
pub bounds: Option<Rectangle>, pub bounds: Option<Rectangle>,
pub transformation: Transformation, pub transformation: Transformation,
pub last_transformation: Option<Transformation>,
pub quads: quad::Cache, pub quads: quad::Cache,
pub meshes: triangle::Cache, pub meshes: triangle::Cache,
pub text: text::Cache, pub text: text::Cache,
@ -311,7 +313,6 @@ pub struct Cached {
impl Cached { impl Cached {
pub fn update(&mut self, live: Live) { pub fn update(&mut self, live: Live) {
self.bounds = live.bounds; self.bounds = live.bounds;
self.transformation = live.transformation;
self.quads.update(live.quads); self.quads.update(live.quads);
self.meshes.update(live.meshes); self.meshes.update(live.meshes);

View file

@ -116,32 +116,10 @@ impl Renderer {
viewport: &Viewport, viewport: &Viewport,
overlay: &[T], 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.draw_overlay(overlay, viewport);
self.prepare( self.prepare(engine, device, queue, format, encoder, viewport);
engine, self.render(engine, device, encoder, frame, clear_color, viewport);
device,
queue,
format,
encoder,
scale_factor,
target_size,
transformation,
);
self.render(
engine,
device,
encoder,
frame,
clear_color,
scale_factor,
target_size,
);
} }
fn prepare( fn prepare(
@ -151,10 +129,10 @@ impl Renderer {
queue: &wgpu::Queue, queue: &wgpu::Queue,
_format: wgpu::TextureFormat, _format: wgpu::TextureFormat,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
scale_factor: f32, viewport: &Viewport,
target_size: Size<u32>,
transformation: Transformation,
) { ) {
let scale_factor = viewport.scale_factor() as f32;
for layer in self.layers.iter_mut() { for layer in self.layers.iter_mut() {
match layer { match layer {
LayerMut::Live(live) => { LayerMut::Live(live) => {
@ -164,7 +142,7 @@ impl Renderer {
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&live.quads, &live.quads,
transformation, viewport.projection(),
scale_factor, scale_factor,
); );
} }
@ -175,7 +153,7 @@ impl Renderer {
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&live.meshes, &live.meshes,
transformation viewport.projection()
* Transformation::scale(scale_factor), * Transformation::scale(scale_factor),
); );
} }
@ -187,10 +165,11 @@ impl Renderer {
encoder, encoder,
&live.text, &live.text,
live.bounds.unwrap_or(Rectangle::with_size( live.bounds.unwrap_or(Rectangle::with_size(
Size::INFINITY, viewport.logical_size(),
)), )),
scale_factor, live.transformation
target_size, * Transformation::scale(scale_factor),
viewport.physical_size(),
); );
} }
@ -201,38 +180,46 @@ impl Renderer {
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&live.images, &live.images,
transformation, viewport.projection(),
scale_factor, scale_factor,
); );
} }
} }
LayerMut::Cached(mut cached) => { LayerMut::Cached(layer_transformation, mut cached) => {
if !cached.quads.is_empty() { if !cached.quads.is_empty() {
engine.quad_pipeline.prepare_cache( engine.quad_pipeline.prepare_cache(
device, device,
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&mut cached.quads, &mut cached.quads,
transformation, viewport.projection(),
scale_factor, scale_factor,
); );
} }
if !cached.meshes.is_empty() { if !cached.meshes.is_empty() {
let transformation =
Transformation::scale(scale_factor)
* layer_transformation;
engine.triangle_pipeline.prepare_cache( engine.triangle_pipeline.prepare_cache(
device, device,
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&mut cached.meshes, &mut cached.meshes,
transformation viewport.projection(),
* Transformation::scale(scale_factor), transformation,
); );
} }
if !cached.text.is_empty() { if !cached.text.is_empty() {
let bounds = cached let bounds = cached.bounds.unwrap_or(
.bounds Rectangle::with_size(viewport.logical_size()),
.unwrap_or(Rectangle::with_size(Size::INFINITY)); );
let transformation =
Transformation::scale(scale_factor)
* layer_transformation;
engine.text_pipeline.prepare_cache( engine.text_pipeline.prepare_cache(
device, device,
@ -240,8 +227,8 @@ impl Renderer {
encoder, encoder,
&mut cached.text, &mut cached.text,
bounds, bounds,
scale_factor, transformation,
target_size, viewport.physical_size(),
); );
} }
@ -252,7 +239,7 @@ impl Renderer {
encoder, encoder,
&mut engine.staging_belt, &mut engine.staging_belt,
&cached.images, &cached.images,
transformation, viewport.projection(),
scale_factor, scale_factor,
); );
} }
@ -268,8 +255,7 @@ impl Renderer {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
frame: &wgpu::TextureView, frame: &wgpu::TextureView,
clear_color: Option<Color>, clear_color: Option<Color>,
scale_factor: f32, viewport: &Viewport,
target_size: Size<u32>,
) { ) {
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@ -312,22 +298,37 @@ impl Renderer {
let mut image_layer = 0; let mut image_layer = 0;
// TODO: Can we avoid collecting here? // 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 layers: Vec<_> = self.layers.iter().collect();
let mut i = 0; let mut i = 0;
// println!("RENDER");
while i < layers.len() { while i < layers.len() {
match layers[i] { match layers[i] {
Layer::Live(live) => { Layer::Live(live) => {
let bounds = live let layer_transformation =
.bounds Transformation::scale(scale_factor)
.map(|bounds| bounds * 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) .map(Rectangle::snap)
.unwrap_or(Rectangle::with_size(target_size)); else {
continue;
};
if !live.quads.is_empty() { if !live.quads.is_empty() {
engine.quad_pipeline.render_batch( engine.quad_pipeline.render_batch(
quad_layer, quad_layer,
bounds, physical_bounds,
&live.quads, &live.quads,
&mut render_pass, &mut render_pass,
); );
@ -336,6 +337,7 @@ impl Renderer {
} }
if !live.meshes.is_empty() { if !live.meshes.is_empty() {
// println!("LIVE PASS");
let _ = ManuallyDrop::into_inner(render_pass); let _ = ManuallyDrop::into_inner(render_pass);
engine.triangle_pipeline.render_batch( engine.triangle_pipeline.render_batch(
@ -343,10 +345,10 @@ impl Renderer {
encoder, encoder,
frame, frame,
mesh_layer, mesh_layer,
target_size, viewport.physical_size(),
&live.meshes, &live.meshes,
bounds, physical_bounds,
scale_factor, &layer_transformation,
); );
mesh_layer += 1; mesh_layer += 1;
@ -375,7 +377,7 @@ impl Renderer {
if !live.text.is_empty() { if !live.text.is_empty() {
engine.text_pipeline.render_batch( engine.text_pipeline.render_batch(
text_layer, text_layer,
bounds, physical_bounds,
&mut render_pass, &mut render_pass,
); );
@ -386,7 +388,7 @@ impl Renderer {
if !live.images.is_empty() { if !live.images.is_empty() {
engine.image_pipeline.render( engine.image_pipeline.render(
image_layer, image_layer,
bounds, physical_bounds,
&mut render_pass, &mut render_pass,
); );
@ -395,25 +397,35 @@ impl Renderer {
i += 1; i += 1;
} }
Layer::Cached(_) => { Layer::Cached(_, _) => {
let group_len = layers[i..] let group_len = layers[i..]
.iter() .iter()
.position(|layer| matches!(layer, Layer::Live(_))) .position(|layer| matches!(layer, Layer::Live(_)))
.unwrap_or(layers.len()); .unwrap_or(layers.len() - i);
let group = layers[i..i + group_len].iter().map(|layer| { let group =
let Layer::Cached(cached) = layer else { layers[i..i + group_len].iter().filter_map(|layer| {
unreachable!() let Layer::Cached(transformation, cached) = layer
}; else {
unreachable!()
};
let bounds = cached let physical_bounds = cached
.bounds .bounds
.map(|bounds| bounds * scale_factor) .and_then(|bounds| {
.map(Rectangle::snap) physical_bounds.intersection(
.unwrap_or(Rectangle::with_size(target_size)); &(bounds
* *transformation
* Transformation::scale(
scale_factor,
)),
)
})
.unwrap_or(physical_bounds)
.snap();
(cached, bounds) Some((cached, physical_bounds))
}); });
for (cached, bounds) in group.clone() { for (cached, bounds) in group.clone() {
if !cached.quads.is_empty() { if !cached.quads.is_empty() {
@ -430,17 +442,17 @@ impl Renderer {
.any(|(cached, _)| !cached.meshes.is_empty()); .any(|(cached, _)| !cached.meshes.is_empty());
if group_has_meshes { if group_has_meshes {
// println!("CACHE PASS");
let _ = ManuallyDrop::into_inner(render_pass); let _ = ManuallyDrop::into_inner(render_pass);
engine.triangle_pipeline.render_cache_group( engine.triangle_pipeline.render_cache_group(
device, device,
encoder, encoder,
frame, frame,
target_size, viewport.physical_size(),
group.clone().map(|(cached, bounds)| { group.clone().map(|(cached, bounds)| {
(&cached.meshes, bounds) (&cached.meshes, bounds)
}), }),
scale_factor,
); );
render_pass = render_pass =

View file

@ -26,7 +26,7 @@ pub enum Cache {
renderer: glyphon::TextRenderer, renderer: glyphon::TextRenderer,
atlas: Option<glyphon::TextAtlas>, atlas: Option<glyphon::TextAtlas>,
buffer_cache: Option<BufferCache>, buffer_cache: Option<BufferCache>,
scale_factor: f32, transformation: Transformation,
target_size: Size<u32>, target_size: Size<u32>,
needs_reupload: bool, needs_reupload: bool,
}, },
@ -95,7 +95,7 @@ impl Pipeline {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
sections: &Batch, sections: &Batch,
layer_bounds: Rectangle, layer_bounds: Rectangle,
scale_factor: f32, layer_transformation: Transformation,
target_size: Size<u32>, target_size: Size<u32>,
) { ) {
if self.renderers.len() <= self.prepare_layer { if self.renderers.len() <= self.prepare_layer {
@ -117,7 +117,7 @@ impl Pipeline {
&mut self.cache, &mut self.cache,
sections, sections,
layer_bounds, layer_bounds,
scale_factor, layer_transformation,
target_size, target_size,
); );
@ -140,7 +140,7 @@ impl Pipeline {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
cache: &mut Cache, cache: &mut Cache,
layer_bounds: Rectangle, layer_bounds: Rectangle,
new_scale_factor: f32, new_transformation: Transformation,
new_target_size: Size<u32>, new_target_size: Size<u32>,
) { ) {
match cache { match cache {
@ -186,7 +186,7 @@ impl Pipeline {
buffer_cache.as_mut().unwrap_or(&mut self.cache), buffer_cache.as_mut().unwrap_or(&mut self.cache),
&batch, &batch,
layer_bounds, layer_bounds,
new_scale_factor, new_transformation,
new_target_size, new_target_size,
); );
@ -196,7 +196,7 @@ impl Pipeline {
renderer, renderer,
atlas, atlas,
buffer_cache, buffer_cache,
scale_factor: new_scale_factor, transformation: new_transformation,
target_size: new_target_size, target_size: new_target_size,
} }
} }
@ -206,13 +206,13 @@ impl Pipeline {
renderer, renderer,
atlas, atlas,
buffer_cache, buffer_cache,
scale_factor, transformation,
target_size, target_size,
} => { } => {
if *needs_reupload if *needs_reupload
|| atlas.is_none() || atlas.is_none()
|| buffer_cache.is_none() || buffer_cache.is_none()
|| new_scale_factor != *scale_factor || new_transformation != *transformation
|| new_target_size != *target_size || new_target_size != *target_size
{ {
let _ = prepare( let _ = prepare(
@ -224,11 +224,11 @@ impl Pipeline {
buffer_cache.as_mut().unwrap_or(&mut self.cache), buffer_cache.as_mut().unwrap_or(&mut self.cache),
batch, batch,
layer_bounds, layer_bounds,
*scale_factor, new_transformation,
*target_size, new_target_size,
); );
*scale_factor = new_scale_factor; *transformation = new_transformation;
*target_size = new_target_size; *target_size = new_target_size;
} }
} }
@ -297,7 +297,7 @@ fn prepare(
buffer_cache: &mut BufferCache, buffer_cache: &mut BufferCache,
sections: &Batch, sections: &Batch,
layer_bounds: Rectangle, layer_bounds: Rectangle,
scale_factor: f32, layer_transformation: Transformation,
target_size: Size<u32>, target_size: Size<u32>,
) -> Result<(), glyphon::PrepareError> { ) -> Result<(), glyphon::PrepareError> {
let mut font_system = font_system().write().expect("Write font system"); let mut font_system = font_system().write().expect("Write font system");
@ -349,7 +349,7 @@ fn prepare(
}) })
.collect(); .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( let text_areas = sections.iter().zip(allocations.iter()).filter_map(
|(section, allocation)| { |(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 { let left = match horizontal_alignment {
alignment::Horizontal::Left => bounds.x, alignment::Horizontal::Left => bounds.x,
@ -470,14 +470,16 @@ fn prepare(
alignment::Vertical::Bottom => bounds.y - bounds.height, alignment::Vertical::Bottom => bounds.y - bounds.height,
}; };
let clip_bounds = layer_bounds let clip_bounds = layer_bounds.intersection(
.intersection(&(clip_bounds * transformation * scale_factor))?; &(clip_bounds * transformation * layer_transformation),
)?;
Some(glyphon::TextArea { Some(glyphon::TextArea {
buffer, buffer,
left, left,
top, top,
scale: scale_factor * transformation.scale_factor(), scale: transformation.scale_factor()
* layer_transformation.scale_factor(),
bounds: glyphon::TextBounds { bounds: glyphon::TextBounds {
left: clip_bounds.x as i32, left: clip_bounds.x as i32,
top: clip_bounds.y as i32, top: clip_bounds.y as i32,

View file

@ -68,8 +68,11 @@ impl Pipeline {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt, belt: &mut wgpu::util::StagingBelt,
cache: &mut Cache, cache: &mut Cache,
transformation: Transformation, new_projection: Transformation,
new_transformation: Transformation,
) { ) {
let new_projection = new_projection * new_transformation;
match cache { match cache {
Cache::Staged(_) => { Cache::Staged(_) => {
let Cache::Staged(batch) = let Cache::Staged(batch) =
@ -86,21 +89,25 @@ impl Pipeline {
&self.solid, &self.solid,
&self.gradient, &self.gradient,
&batch, &batch,
transformation, new_projection,
); );
*cache = Cache::Uploaded { *cache = Cache::Uploaded {
layer, layer,
batch, batch,
transformation: new_transformation,
projection: new_projection,
needs_reupload: false, needs_reupload: false,
} }
} }
Cache::Uploaded { Cache::Uploaded {
batch, batch,
layer, layer,
transformation,
projection,
needs_reupload, needs_reupload,
} => { } => {
if *needs_reupload { if *needs_reupload || new_projection != *projection {
layer.prepare( layer.prepare(
device, device,
encoder, encoder,
@ -108,9 +115,11 @@ impl Pipeline {
&self.solid, &self.solid,
&self.gradient, &self.gradient,
batch, batch,
transformation, new_projection,
); );
*transformation = new_transformation;
*projection = new_projection;
*needs_reupload = false; *needs_reupload = false;
} }
} }
@ -126,7 +135,7 @@ impl Pipeline {
target_size: Size<u32>, target_size: Size<u32>,
meshes: &Batch, meshes: &Batch,
bounds: Rectangle<u32>, bounds: Rectangle<u32>,
scale_factor: f32, transformation: &Transformation,
) { ) {
Self::render( Self::render(
device, device,
@ -136,8 +145,12 @@ impl Pipeline {
&self.solid, &self.solid,
&self.gradient, &self.gradient,
target_size, target_size,
std::iter::once((&self.layers[layer], meshes, bounds)), std::iter::once((
scale_factor, &self.layers[layer],
meshes,
transformation,
bounds,
)),
); );
} }
@ -150,9 +163,14 @@ impl Pipeline {
target_size: Size<u32>, target_size: Size<u32>,
cache: &Cache, cache: &Cache,
bounds: Rectangle<u32>, bounds: Rectangle<u32>,
scale_factor: f32,
) { ) {
let Cache::Uploaded { batch, layer, .. } = cache else { let Cache::Uploaded {
batch,
layer,
transformation,
..
} = cache
else {
return; return;
}; };
@ -164,8 +182,7 @@ impl Pipeline {
&self.solid, &self.solid,
&self.gradient, &self.gradient,
target_size, target_size,
std::iter::once((layer, batch, bounds)), std::iter::once((layer, batch, transformation, bounds)),
scale_factor,
); );
} }
@ -176,11 +193,16 @@ impl Pipeline {
target: &wgpu::TextureView, target: &wgpu::TextureView,
target_size: Size<u32>, target_size: Size<u32>,
group: impl Iterator<Item = (&'a Cache, Rectangle<u32>)>, group: impl Iterator<Item = (&'a Cache, Rectangle<u32>)>,
scale_factor: f32,
) { ) {
let group = group.filter_map(|(cache, bounds)| { let group = group.filter_map(|(cache, bounds)| {
if let Cache::Uploaded { batch, layer, .. } = cache { if let Cache::Uploaded {
Some((layer, batch, bounds)) batch,
layer,
transformation,
..
} = cache
{
Some((layer, batch, transformation, bounds))
} else { } else {
None None
} }
@ -195,7 +217,6 @@ impl Pipeline {
&self.gradient, &self.gradient,
target_size, target_size,
group, group,
scale_factor,
); );
} }
@ -207,8 +228,9 @@ impl Pipeline {
solid: &solid::Pipeline, solid: &solid::Pipeline,
gradient: &gradient::Pipeline, gradient: &gradient::Pipeline,
target_size: Size<u32>, target_size: Size<u32>,
group: impl Iterator<Item = (&'a Layer, &'a Batch, Rectangle<u32>)>, group: impl Iterator<
scale_factor: f32, Item = (&'a Layer, &'a Batch, &'a Transformation, Rectangle<u32>),
>,
) { ) {
{ {
let (attachment, resolve_target, load) = if let Some(blit) = let (attachment, resolve_target, load) = if let Some(blit) =
@ -244,13 +266,13 @@ impl Pipeline {
occlusion_query_set: None, occlusion_query_set: None,
}); });
for (layer, meshes, bounds) in group { for (layer, meshes, transformation, bounds) in group {
layer.render( layer.render(
solid, solid,
gradient, gradient,
meshes, meshes,
bounds, bounds,
scale_factor, *transformation,
&mut render_pass, &mut render_pass,
); );
} }
@ -272,6 +294,8 @@ pub enum Cache {
Uploaded { Uploaded {
batch: Batch, batch: Batch,
layer: Layer, layer: Layer,
transformation: Transformation,
projection: Transformation,
needs_reupload: bool, needs_reupload: bool,
}, },
} }
@ -390,6 +414,7 @@ impl Layer {
for mesh in meshes { for mesh in meshes {
let indices = mesh.indices(); let indices = mesh.indices();
let uniforms = let uniforms =
Uniforms::new(transformation * mesh.transformation()); Uniforms::new(transformation * mesh.transformation());
@ -448,7 +473,7 @@ impl Layer {
gradient: &'a gradient::Pipeline, gradient: &'a gradient::Pipeline,
meshes: &Batch, meshes: &Batch,
layer_bounds: Rectangle<u32>, layer_bounds: Rectangle<u32>,
scale_factor: f32, transformation: Transformation,
render_pass: &mut wgpu::RenderPass<'a>, render_pass: &mut wgpu::RenderPass<'a>,
) { ) {
let mut num_solids = 0; let mut num_solids = 0;
@ -457,15 +482,12 @@ impl Layer {
for (index, mesh) in meshes.iter().enumerate() { for (index, mesh) in meshes.iter().enumerate() {
let Some(clip_bounds) = Rectangle::<f32>::from(layer_bounds) let Some(clip_bounds) = Rectangle::<f32>::from(layer_bounds)
.intersection(&(mesh.clip_bounds() * scale_factor)) .intersection(&(mesh.clip_bounds() * transformation))
.map(Rectangle::snap)
else { else {
continue; continue;
}; };
if clip_bounds.width < 1 || clip_bounds.height < 1 { let clip_bounds = clip_bounds.snap();
continue;
}
render_pass.set_scissor_rect( render_pass.set_scissor_rect(
clip_bounds.x, clip_bounds.x,

View file

@ -17,7 +17,7 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::widget::tree::{self, Tree}; use crate::core::widget::tree::{self, Tree};
use crate::core::{ use crate::core::{
Clipboard, Element, Length, Rectangle, Shell, Size, Transformation, Widget, Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
}; };
use crate::graphics::geometry; use crate::graphics::geometry;
@ -222,8 +222,8 @@ where
let state = tree.state.downcast_ref::<P::State>(); let state = tree.state.downcast_ref::<P::State>();
renderer.with_transformation( renderer.with_translation(
Transformation::translate(bounds.x, bounds.y), Vector::new(bounds.x, bounds.y),
|renderer| { |renderer| {
let layers = let layers =
self.program.draw(state, renderer, theme, bounds, cursor); self.program.draw(state, renderer, theme, bounds, cursor);