Skip to content

Commit

Permalink
Speculatively evaluate paint functions during style.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Jul 31, 2017
1 parent b35791f commit 936dd3e
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 52 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 9 additions & 8 deletions components/layout/context.rs
Expand Up @@ -4,7 +4,6 @@

//! Data needed by the layout thread.

use fnv::FnvHashMap;
use fnv::FnvHasher;
use gfx::display_list::{WebRenderImageInfo, OpaqueNode};
use gfx::font_cache_thread::FontCacheThread;
Expand All @@ -25,8 +24,8 @@ use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::sync::{Arc, Mutex};
use std::thread;
use style::context::RegisteredSpeculativePainter;
use style::context::SharedStyleContext;
use style::properties::PropertyId;

thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));

Expand Down Expand Up @@ -73,7 +72,7 @@ pub struct LayoutContext<'a> {
BuildHasherDefault<FnvHasher>>>>,

/// Paint worklets
pub registered_painters: Arc<RwLock<FnvHashMap<Atom, RegisteredPainter>>>,
pub registered_painters: &'a RegisteredPainters,

/// A list of in-progress image loads to be shared with the script thread.
/// A None value means that this layout was not initiated by the script thread.
Expand Down Expand Up @@ -179,9 +178,11 @@ impl<'a> LayoutContext<'a> {
}
}

/// A registered paint worklet.
pub struct RegisteredPainter {
pub name: Atom,
pub properties: FnvHashMap<Atom, PropertyId>,
pub painter: Arc<Painter>,
/// A registered painter
pub trait RegisteredPainter: RegisteredSpeculativePainter + Painter {}

/// A set of registered painters
pub trait RegisteredPainters: Sync {
/// Look up a painter
fn get(&self, name: &Atom) -> Option<&RegisteredPainter>;
}
20 changes: 7 additions & 13 deletions components/layout/display_list_builder.rs
Expand Up @@ -1181,24 +1181,18 @@ impl FragmentDisplayListBuilding for Fragment {
.map(|argument| argument.to_css_string())
.collect();

// Get the painter, and the computed values for its properties.
// TODO: less copying.
let (properties, painter) = match state.layout_context.registered_painters.read().get(&name) {
Some(registered_painter) => (
registered_painter.properties
.iter()
let mut draw_result = match state.layout_context.registered_painters.get(&name) {
Some(painter) => {
debug!("Drawing a paint image {}({},{}).", name, size_in_px.width, size_in_px.height);
let properties = painter.properties().iter()
.filter_map(|(name, id)| id.as_shorthand().err().map(|id| (name, id)))
.map(|(name, id)| (name.clone(), style.computed_value_to_string(id)))
.collect(),
registered_painter.painter.clone()
),
.collect();
painter.draw_a_paint_image(size_in_px, device_pixel_ratio, properties, arguments)
},
None => return debug!("Worklet {} called before registration.", name),
};

// TODO: add a one-place cache to avoid drawing the paint image every time.
// https://github.com/servo/servo/issues/17369
debug!("Drawing a paint image {}({},{}).", name, size_in_px.width, size_in_px.height);
let mut draw_result = painter.draw_a_paint_image(size_in_px, device_pixel_ratio, properties, arguments);
let webrender_image = WebRenderImageInfo {
width: draw_result.width,
height: draw_result.height,
Expand Down
1 change: 1 addition & 0 deletions components/layout_thread/Cargo.toml
Expand Up @@ -41,4 +41,5 @@ servo_config = {path = "../config"}
servo_geometry = {path = "../geometry"}
servo_url = {path = "../url"}
style = {path = "../style"}
style_traits = {path = "../style_traits"}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
76 changes: 67 additions & 9 deletions components/layout_thread/lib.rs
Expand Up @@ -46,14 +46,15 @@ extern crate servo_config;
extern crate servo_geometry;
extern crate servo_url;
extern crate style;
extern crate style_traits;
extern crate webrender_api;

mod dom_wrapper;

use app_units::Au;
use dom_wrapper::{ServoLayoutElement, ServoLayoutDocument, ServoLayoutNode};
use dom_wrapper::drop_style_and_layout_data;
use euclid::{Point2D, Rect, Size2D, ScaleFactor};
use euclid::{Point2D, Rect, Size2D, ScaleFactor, TypedSize2D};
use fnv::FnvHashMap;
use gfx::display_list::{OpaqueNode, WebRenderImageInfo};
use gfx::font;
Expand All @@ -67,6 +68,7 @@ use layout::animation;
use layout::construct::ConstructionResult;
use layout::context::LayoutContext;
use layout::context::RegisteredPainter;
use layout::context::RegisteredPainters;
use layout::context::heap_size_of_persistent_local_context;
use layout::display_list_builder::ToGfxColor;
use layout::flow::{self, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
Expand Down Expand Up @@ -99,6 +101,8 @@ use script_layout_interface::rpc::TextIndexResponse;
use script_layout_interface::wrapper_traits::LayoutNode;
use script_traits::{ConstellationControlMsg, LayoutControlMsg, LayoutMsg as ConstellationMsg};
use script_traits::{ScrollState, UntrustedNodeAddress};
use script_traits::DrawAPaintImageResult;
use script_traits::Painter;
use selectors::Element;
use servo_arc::Arc as ServoArc;
use servo_atoms::Atom;
Expand All @@ -122,6 +126,8 @@ use std::thread;
use style::animation::Animation;
use style::context::{QuirksMode, ReflowGoal, SharedStyleContext};
use style::context::{StyleSystemOptions, ThreadLocalStyleContextCreationInfo};
use style::context::RegisteredSpeculativePainter;
use style::context::RegisteredSpeculativePainters;
use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
use style::error_reporting::{NullReporter, RustLogReporter};
use style::invalidation::element::restyle_hints::RestyleHint;
Expand All @@ -137,6 +143,9 @@ use style::thread_state;
use style::timer::Timer;
use style::traversal::{DomTraversal, TraversalDriver};
use style::traversal_flags::TraversalFlags;
use style_traits::CSSPixel;
use style_traits::DevicePixel;
use style_traits::SpeculativePainter;

/// Information needed by the layout thread.
pub struct LayoutThread {
Expand Down Expand Up @@ -235,9 +244,9 @@ pub struct LayoutThread {

webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder),
WebRenderImageInfo>>>,
/// The executor for paint worklets.
/// Will be None if the script thread hasn't added any paint worklet modules.
registered_painters: Arc<RwLock<FnvHashMap<Atom, RegisteredPainter>>>,

/// The executors for paint worklets.
registered_painters: RegisteredPaintersImpl,

/// Webrender interface.
webrender_api: webrender_api::RenderApi,
Expand Down Expand Up @@ -520,7 +529,7 @@ impl LayoutThread {
constellation_chan: constellation_chan.clone(),
time_profiler_chan: time_profiler_chan,
mem_profiler_chan: mem_profiler_chan,
registered_painters: Arc::new(RwLock::new(FnvHashMap::default())),
registered_painters: RegisteredPaintersImpl(FnvHashMap::default()),
image_cache: image_cache.clone(),
font_cache_thread: font_cache_thread,
first_reflow: Cell::new(true),
Expand Down Expand Up @@ -605,6 +614,7 @@ impl LayoutThread {
visited_styles_enabled: false,
running_animations: self.running_animations.clone(),
expired_animations: self.expired_animations.clone(),
registered_speculative_painters: &self.registered_painters,
local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
timer: self.timer.clone(),
quirks_mode: self.quirks_mode.unwrap(),
Expand All @@ -616,7 +626,7 @@ impl LayoutThread {
webrender_image_cache: self.webrender_image_cache.clone(),
pending_images: if script_initiated_layout { Some(Mutex::new(vec![])) } else { None },
newly_transitioning_nodes: if script_initiated_layout { Some(Mutex::new(vec![])) } else { None },
registered_painters: self.registered_painters.clone(),
registered_painters: &self.registered_painters,
}
}

Expand Down Expand Up @@ -738,13 +748,12 @@ impl LayoutThread {
.filter_map(|name| PropertyId::parse(&*name).ok().map(|id| (name.clone(), id)))
.filter(|&(_, ref id)| id.as_shorthand().is_err())
.collect();
let registered_painter = RegisteredPainter {
let registered_painter = RegisteredPainterImpl {
name: name.clone(),
properties: properties,
painter: painter,
};
self.registered_painters.write()
.insert(name, registered_painter);
self.registered_painters.0.insert(name, registered_painter);
},
Msg::PrepareToExit(response_chan) => {
self.prepare_to_exit(response_chan);
Expand Down Expand Up @@ -1790,3 +1799,52 @@ lazy_static! {
}
};
}

struct RegisteredPainterImpl {
painter: Box<Painter>,
name: Atom,
properties: FnvHashMap<Atom, PropertyId>,
}

impl SpeculativePainter for RegisteredPainterImpl {
fn speculatively_draw_a_paint_image(&self, properties: Vec<(Atom, String)>, arguments: Vec<String>) {
self.painter.speculatively_draw_a_paint_image(properties, arguments);
}
}

impl RegisteredSpeculativePainter for RegisteredPainterImpl {
fn properties(&self) -> &FnvHashMap<Atom, PropertyId> {
&self.properties
}
fn name(&self) -> Atom {
self.name.clone()
}
}

impl Painter for RegisteredPainterImpl {
fn draw_a_paint_image(&self,
size: TypedSize2D<f32, CSSPixel>,
device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>,
properties: Vec<(Atom, String)>,
arguments: Vec<String>)
-> DrawAPaintImageResult
{
self.painter.draw_a_paint_image(size, device_pixel_ratio, properties, arguments)
}
}

impl RegisteredPainter for RegisteredPainterImpl {}

struct RegisteredPaintersImpl(FnvHashMap<Atom, RegisteredPainterImpl>);

impl RegisteredSpeculativePainters for RegisteredPaintersImpl {
fn get(&self, name: &Atom) -> Option<&RegisteredSpeculativePainter> {
self.0.get(&name).map(|painter| painter as &RegisteredSpeculativePainter)
}
}

impl RegisteredPainters for RegisteredPaintersImpl {
fn get(&self, name: &Atom) -> Option<&RegisteredPainter> {
self.0.get(&name).map(|painter| painter as &RegisteredPainter)
}
}
13 changes: 11 additions & 2 deletions components/script/dom/bindings/trace.rs
Expand Up @@ -43,7 +43,7 @@ use dom::bindings::str::{DOMString, USVString};
use dom::bindings::utils::WindowProxyHandler;
use dom::document::PendingRestyle;
use encoding::types::EncodingRef;
use euclid::{Transform2D, Transform3D, Point2D, Vector2D, Rect, Size2D, ScaleFactor};
use euclid::{Transform2D, Transform3D, Point2D, Vector2D, Rect, TypedSize2D, ScaleFactor};
use euclid::Length as EuclidLength;
use html5ever::{Prefix, LocalName, Namespace, QualName};
use html5ever::buffer_queue::BufferQueue;
Expand Down Expand Up @@ -75,6 +75,7 @@ use script_layout_interface::reporter::CSSErrorReporter;
use script_layout_interface::rpc::LayoutRPC;
use script_traits::{DocumentActivity, TimerEventId, TimerSource, TouchpadPressurePhase};
use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
use script_traits::DrawAPaintImageResult;
use selectors::matching::ElementSelectorFlags;
use serde::{Deserialize, Serialize};
use servo_arc::Arc as ServoArc;
Expand Down Expand Up @@ -389,6 +390,7 @@ unsafe_no_jsmanaged_fields!(RelativePos);
unsafe_no_jsmanaged_fields!(OpaqueStyleAndLayoutData);
unsafe_no_jsmanaged_fields!(PathBuf);
unsafe_no_jsmanaged_fields!(CSSErrorReporter);
unsafe_no_jsmanaged_fields!(DrawAPaintImageResult);
unsafe_no_jsmanaged_fields!(WebGLBufferId);
unsafe_no_jsmanaged_fields!(WebGLFramebufferId);
unsafe_no_jsmanaged_fields!(WebGLProgramId);
Expand Down Expand Up @@ -519,7 +521,14 @@ unsafe impl JSTraceable for Rect<f32> {
}
}

unsafe impl JSTraceable for Size2D<i32> {
unsafe impl<U> JSTraceable for TypedSize2D<i32, U> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing
}
}

unsafe impl<U> JSTraceable for TypedSize2D<f32, U> {
#[inline]
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing
Expand Down

0 comments on commit 936dd3e

Please sign in to comment.