Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script paint worklets speculative evaluation #17810

Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Speculatively evaluate paint functions during style.

  • Loading branch information
asajeffrey committed Jul 31, 2017
commit 936dd3ef634cf6e6bfce1925a25f3fe985faa635

Some generated files are not rendered by default. Learn more.

@@ -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;
@@ -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));

@@ -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.
@@ -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>;
}
@@ -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,
@@ -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"]}
@@ -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;
@@ -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};
@@ -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;
@@ -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;
@@ -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 {
@@ -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,
@@ -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),
@@ -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(),
@@ -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,
}
}

@@ -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);
@@ -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)
}
}
@@ -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;
@@ -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;
@@ -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);
@@ -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
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.