Resolve paint and transform columns once per lane loop

This commit is contained in:
Dennis Kobert
2026-08-26 23:03:17 +00:00
parent 694d3d34b3
commit 084f14e973
3 changed files with 41 additions and 25 deletions

View File

@@ -1,5 +1,5 @@
use crate::Color;
use crate::lane::LaneSource;
use crate::lane::{LaneColumn, LaneSource};
use glam::{DAffine2, DVec2};
#[derive(Clone, Copy, Default, Debug, PartialEq)]
@@ -61,9 +61,10 @@ where
{
let mut combined_bounds = None;
let transforms = source.column::<crate::attribute::Transform>();
for lane in 0..source.lane_count() {
let Some(element) = source.element(lane) else { continue };
let lane_transform: DAffine2 = source.attr::<crate::attribute::Transform>(lane);
let lane_transform: DAffine2 = transforms.get(lane);
match element.bounding_box(transform * lane_transform, include_stroke) {
RenderBoundingBox::None => continue,
RenderBoundingBox::Infinite => return RenderBoundingBox::Infinite,
@@ -90,9 +91,10 @@ where
let mut combined_bounds = None;
let mut any_infinite = false;
let transforms = source.column::<crate::attribute::Transform>();
for lane in 0..source.lane_count() {
let Some(element) = source.element(lane) else { continue };
let lane_transform: DAffine2 = source.attr::<crate::attribute::Transform>(lane);
let lane_transform: DAffine2 = transforms.get(lane);
match element.thumbnail_bounding_box(transform * lane_transform, include_stroke) {
RenderBoundingBox::None => continue,
RenderBoundingBox::Infinite => any_infinite = true,

View File

@@ -248,16 +248,32 @@ pub struct LanePaint<'a> {
impl<'a> LanePaint<'a> {
pub const NONE: Self = Self { fill: None, stroke: None };
/// The lane's present, non-blank paint.
pub fn read<S: LaneSource>(source: &'a S, index: usize) -> Self {
pub fn is_present(&self) -> bool {
self.fill.is_some() || self.stroke.is_some()
}
}
/// A source's fill and stroke columns, resolved once for per-lane reads.
pub struct PaintColumns<'a, S: LaneSource + 'a> {
fill: S::Column<'a, Fill>,
stroke: S::Column<'a, Stroke>,
}
impl<'a, S: LaneSource> PaintColumns<'a, S> {
pub fn new(source: &'a S) -> Self {
Self {
fill: paint_graphics::<Fill, _>(source, index),
stroke: paint_graphics::<Stroke, _>(source, index),
fill: source.column::<Fill>(),
stroke: source.column::<Stroke>(),
}
}
pub fn is_present(&self) -> bool {
self.fill.is_some() || self.stroke.is_some()
/// The lane's present, non-blank paint.
pub fn read(&self, lane: usize) -> LanePaint<'a> {
let present = |value: Option<Option<&'a List<Graphic>>>| value.flatten().filter(|list| is_paint_present(list));
LanePaint {
fill: present(self.fill.try_get(lane)),
stroke: present(self.stroke.try_get(lane)),
}
}
}

View File

@@ -22,7 +22,7 @@ use dyn_any::DynAny;
use glam::{DAffine2, DMat2, DVec2};
use graphene_hash::CacheHashWrapper;
use graphene_resource::Resource;
use graphic_types::graphic::{LanePaint, PaintOverlay, group_to_legacy_list, has_paint, is_paint_present, paint_graphics, set_paint_attribute, vector_can_reduce_to_clip_path};
use graphic_types::graphic::{LanePaint, PaintColumns, PaintOverlay, group_to_legacy_list, has_paint, is_paint_present, paint_graphics, set_paint_attribute, vector_can_reduce_to_clip_path};
use graphic_types::markers::{EditorMergedLayers, Fill, Stroke};
use graphic_types::raster_types::{BitmapMut, CPU, GPU, Image, Raster, Texture};
use graphic_types::vector_types::gradient::{GradientStops, GradientType};
@@ -626,20 +626,13 @@ struct PaintReach<'a> {
impl<'a> PaintReach<'a> {
const NONE: Self = Self { paint: LanePaint::NONE, hops: 0 };
fn read<S: LaneSource>(source: &'a S, index: usize) -> Self {
Self {
paint: LanePaint::read(source, index),
hops: 2,
}
}
/// The lane's effective reach: an inherited paint stays authoritative
/// (lane paint below a push's origin is inert in the legacy model), an
/// absent one reads the lane's own paint.
fn for_lane<S: LaneSource>(self, source: &'a S, index: usize) -> Self {
fn for_lane<S: LaneSource>(self, columns: &PaintColumns<'a, S>, index: usize) -> Self {
match self.paint.is_present() {
true => self,
false => Self::read(source, index),
false => Self { paint: columns.read(index), hops: 2 },
}
}
@@ -1109,6 +1102,7 @@ fn render_graphic_svg<S: LaneSource<Element = Graphic>>(source: &S, render: &mut
}
fn render_graphic_svg_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S, inherited: PaintReach<'a>, render: &mut SvgRender, render_params: &RenderParams) {
let paint_columns = PaintColumns::new(source);
let mut mask_state = None;
for index in 0..source.lane_count() {
@@ -1117,7 +1111,7 @@ fn render_graphic_svg_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S,
let opacity_attr: f64 = source.attr::<Opacity>(index);
let opacity_fill_attr: f64 = source.attr::<OpacityFill>(index);
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
render.parent_tag(
"g",
@@ -1170,6 +1164,7 @@ fn render_graphic_vello<S: LaneSource<Element = Graphic>>(source: &S, scene: &mu
}
fn render_graphic_vello_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S, inherited: PaintReach<'a>, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
let paint_columns = PaintColumns::new(source);
let mut mask_element_and_transform = None;
for index in 0..source.lane_count() {
@@ -1179,7 +1174,7 @@ fn render_graphic_vello_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S
let opacity_attr: f64 = source.attr::<Opacity>(index);
let opacity_fill_attr: f64 = source.attr::<OpacityFill>(index);
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
let mut layer = false;
@@ -1253,12 +1248,13 @@ fn collect_graphic_metadata<S: LaneSource<Element = Graphic>>(source: &S, metada
}
fn collect_graphic_metadata_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S, inherited: PaintReach<'a>, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
let paint_columns = PaintColumns::new(source);
for index in 0..source.lane_count() {
let item_transform: DAffine2 = source.attr::<Transform>(index);
let layer_path: &[NodeId] = source.attr::<EditorLayerPath>(index);
let layer = layer_path.last().copied();
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
let mut footprint = footprint;
footprint.transform *= item_transform;
@@ -1278,7 +1274,7 @@ fn collect_graphic_metadata_with<'a, S: LaneSource<Element = Graphic>>(source: &
for index in 0..source.lane_count() {
let item_transform: DAffine2 = source.attr::<Transform>(index);
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
let mut new_click_targets = Vec::new();
add_element_upstream_click_targets(element, reach, &mut new_click_targets);
@@ -1307,10 +1303,11 @@ fn add_graphic_upstream_click_targets<S: LaneSource<Element = Graphic>>(source:
}
fn add_graphic_upstream_click_targets_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S, inherited: PaintReach<'a>, click_targets: &mut Vec<ClickTarget>) {
let paint_columns = PaintColumns::new(source);
for index in 0..source.lane_count() {
let item_transform: DAffine2 = source.attr::<Transform>(index);
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
let mut new_click_targets = Vec::new();
add_element_upstream_click_targets(element, reach, &mut new_click_targets);
@@ -1328,10 +1325,11 @@ fn add_graphic_upstream_outline_targets<S: LaneSource<Element = Graphic>>(source
}
fn add_graphic_upstream_outline_targets_with<'a, S: LaneSource<Element = Graphic>>(source: &'a S, inherited: PaintReach<'a>, outlines: &mut Vec<ClickTarget>) {
let paint_columns = PaintColumns::new(source);
for index in 0..source.lane_count() {
let item_transform: DAffine2 = source.attr::<Transform>(index);
let element = source.element(index).unwrap();
let reach = inherited.for_lane(source, index);
let reach = inherited.for_lane(&paint_columns, index);
let mut new_outlines = Vec::new();
add_element_upstream_outline_targets(element, reach, &mut new_outlines);