use std::sync::Arc;
use valo_dl::DisplayList;
use valo_geometry::{Matrix, Rect};
use crate::pipelines::PipelineBlend;
use crate::raster::{FillTarget, QuadSource, RasterVerdict};
use super::draw_state::DrawState;
use super::drawing::Drawing;
use super::emit::{Cover, Entity, Role};
use super::replay::ReplayState;
use super::Planner;
impl Planner<'_> {
pub(super) fn embed_cached_list(
&mut self,
list: &Arc<DisplayList>,
base_slot: u32,
state: &ReplayState,
) {
let at = self.draw_state(state, base_slot);
if !embeds_as_quad(&at.transform) {
return self.replay_embedded(list, base_slot, state);
}
let device = self.tools.device;
let verdict = self.caches.rasters.resolve(
device,
self.tools.format,
list,
at.transform.max_scale(),
device.limits().max_texture_dimension_2d,
);
match verdict {
RasterVerdict::Quad(source) => self.drawing().draw_raster_quad(&source, &at),
RasterVerdict::Fill(target) => {
let source = target.quad_source();
self.render_raster_fill(list, target);
self.drawing().draw_raster_quad(&source, &at);
}
RasterVerdict::Inline => self.replay_embedded(list, base_slot, state),
}
}
fn render_raster_fill(&mut self, list: &Arc<DisplayList>, fill: FillTarget) {
self.plan.stats.raster_fills += 1;
let base = Matrix::scale(fill.content_scale, fill.content_scale).then(
&Matrix::translation(-fill.content_bounds.x, -fill.content_bounds.y),
);
self.open_raster_target(&fill, list);
self.replay_list(list, &mut ReplayState::raster_fill(base));
self.close_target();
}
}
impl Drawing<'_, '_> {
fn draw_raster_quad(&mut self, source: &QuadSource, at: &DrawState) {
self.stats.raster_quads += 1;
let embed = &at.transform;
let mapped = embed.map_rect(&source.content_bounds);
let ratio = embed.max_scale() / source.content_scale.max(1e-6);
let exact = (ratio - 1.0).abs() < 1e-3;
let extent = if exact {
[source.size[0] as f32, source.size[1] as f32]
} else {
[source.size[0] as f32 * ratio, source.size[1] as f32 * ratio]
};
let dest = if exact {
Rect::new(mapped.x.round(), mapped.y.round(), extent[0], extent[1])
} else {
mapped
};
let sampled = Rect::new(dest.x, dest.y, extent[0], extent[1]);
let entity = Entity {
stencil: None,
cover: Cover::Quad {
transform: Matrix::IDENTITY,
rect: dest,
},
role: Role::Fill,
shading: self.emit.raster_shading(&source.view, &sampled, at.alpha),
blend: PipelineBlend::SrcOver,
z: at.z,
};
self.emit.push(self.context, entity);
}
}
fn embeds_as_quad(embed: &Matrix) -> bool {
let [_, shear_b, shear_c, ..] = embed.to_affine();
shear_b == 0.0 && shear_c == 0.0 && embed.is_affine()
}