gfx: Add display list optimization to eliminate clipped items before

submitting them to Skia.

40x improvement in painting time on Wikipedia.
This commit is contained in:
Patrick Walton 2014-06-05 10:50:04 -07:00
parent b2e7e67087
commit 081e054b4a
5 changed files with 116 additions and 11 deletions

View file

@ -33,6 +33,8 @@ use std::slice::Items;
use style::computed_values::border_style;
use sync::Arc;
pub mod optimizer;
/// An opaque handle to a node. The only safe operation that can be performed on this node is to
/// compare it to another opaque handle or to another node.
///
@ -51,7 +53,7 @@ impl OpaqueNode {
}
/// "Steps" as defined by CSS 2.1 § E.2.
#[deriving(Eq)]
#[deriving(Clone, Eq)]
pub enum StackingLevel {
/// The border and backgrounds for the root of this stacking context: steps 1 and 2.
BackgroundAndBordersStackingLevel,
@ -207,6 +209,7 @@ pub enum BackgroundAndBorderLevel {
}
/// A list of rendering operations to be performed.
#[deriving(Clone)]
pub struct DisplayList {
pub list: DList<DisplayItem>,
}
@ -331,6 +334,7 @@ impl DisplayList {
}
/// One drawing command in the list.
#[deriving(Clone)]
pub enum DisplayItem {
SolidColorDisplayItemClass(Box<SolidColorDisplayItem>),
TextDisplayItemClass(Box<TextDisplayItem>),
@ -348,6 +352,7 @@ pub enum DisplayItem {
}
/// Information common to all display items.
#[deriving(Clone)]
pub struct BaseDisplayItem {
/// The boundaries of the display item.
///
@ -372,12 +377,14 @@ impl BaseDisplayItem {
}
/// Renders a solid color.
#[deriving(Clone)]
pub struct SolidColorDisplayItem {
pub base: BaseDisplayItem,
pub color: Color,
}
/// Text decoration information.
#[deriving(Clone)]
pub struct TextDecorations {
/// The color to use for underlining, if any.
pub underline: Option<Color>,
@ -388,6 +395,7 @@ pub struct TextDecorations {
}
/// Renders text.
#[deriving(Clone)]
pub struct TextDisplayItem {
/// Fields common to all display items.
pub base: BaseDisplayItem,
@ -406,6 +414,7 @@ pub struct TextDisplayItem {
}
/// Renders an image.
#[deriving(Clone)]
pub struct ImageDisplayItem {
pub base: BaseDisplayItem,
pub image: Arc<Box<Image>>,
@ -417,6 +426,7 @@ pub struct ImageDisplayItem {
}
/// Renders a border.
#[deriving(Clone)]
pub struct BorderDisplayItem {
pub base: BaseDisplayItem,
@ -431,6 +441,7 @@ pub struct BorderDisplayItem {
}
/// Renders a line segment.
#[deriving(Clone)]
pub struct LineDisplayItem {
pub base: BaseDisplayItem,
@ -442,6 +453,7 @@ pub struct LineDisplayItem {
}
/// Clips a list of child display items to this display item's boundaries.
#[deriving(Clone)]
pub struct ClipDisplayItem {
/// The base information.
pub base: BaseDisplayItem,

View file

@ -0,0 +1,74 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use display_list::{BorderDisplayItemClass, ClipDisplayItem, ClipDisplayItemClass, DisplayItem};
use display_list::{DisplayList, ImageDisplayItemClass, LineDisplayItemClass};
use display_list::{PseudoDisplayItemClass, SolidColorDisplayItemClass, TextDisplayItemClass};
use collections::deque::Deque;
use collections::dlist::DList;
use geom::rect::Rect;
use servo_util::geometry::Au;
use sync::Arc;
pub struct DisplayListOptimizer {
display_list: Arc<DisplayList>,
/// The visible rect in page coordinates.
visible_rect: Rect<Au>,
}
impl DisplayListOptimizer {
/// `visible_rect` specifies the visible rect in page coordinates.
pub fn new(display_list: Arc<DisplayList>, visible_rect: Rect<Au>) -> DisplayListOptimizer {
DisplayListOptimizer {
display_list: display_list,
visible_rect: visible_rect,
}
}
pub fn optimize(self) -> DisplayList {
self.process_display_list(&*self.display_list)
}
fn process_display_list(&self, display_list: &DisplayList) -> DisplayList {
let mut result = DList::new();
for item in display_list.iter() {
match self.process_display_item(item) {
None => {}
Some(display_item) => result.push_back(display_item),
}
}
DisplayList {
list: result,
}
}
fn process_display_item(&self, display_item: &DisplayItem) -> Option<DisplayItem> {
// Eliminate display items outside the visible region.
if !self.visible_rect.intersects(&display_item.base().bounds) {
return None
}
// Recur.
match *display_item {
ClipDisplayItemClass(ref clip) => {
let new_children = self.process_display_list(&clip.children);
if new_children.is_empty() {
return None
}
Some(ClipDisplayItemClass(box ClipDisplayItem {
base: clip.base.clone(),
children: new_children,
}))
}
BorderDisplayItemClass(_) | ImageDisplayItemClass(_) | LineDisplayItemClass(_) |
PseudoDisplayItemClass(_) | SolidColorDisplayItemClass(_) |
TextDisplayItemClass(_) => {
Some((*display_item).clone())
}
}
}
}

View file

@ -56,6 +56,7 @@ mod render_context;
// Rendering
pub mod color;
#[path="display_list/mod.rs"]
pub mod display_list;
pub mod render_task;

View file

@ -5,6 +5,7 @@
//! The task that handles all rendering/painting.
use buffer_map::BufferMap;
use display_list::optimizer::DisplayListOptimizer;
use display_list::DisplayList;
use font_context::{FontContext, FontContextInfo};
use render_context::RenderContext;
@ -17,19 +18,18 @@ use geom::size::Size2D;
use layers::platform::surface::{NativePaintingGraphicsContext, NativeSurface};
use layers::platform::surface::{NativeSurfaceMethods};
use layers;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer};
use servo_msg::compositor_msg::{LayerBufferSet, LayerId, LayerMetadata, RenderListener};
use servo_msg::compositor_msg::{RenderingRenderState, ScrollPolicy};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
use servo_msg::constellation_msg::{Failure, FailureMsg};
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet, LayerId};
use servo_msg::compositor_msg::{LayerMetadata, RenderListener, RenderingRenderState, ScrollPolicy};
use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId};
use servo_msg::constellation_msg::{RendererReadyMsg};
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
use servo_util::geometry;
use servo_util::opts::Opts;
use servo_util::smallvec::{SmallVec, SmallVec1};
use servo_util::task::send_on_failure;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use servo_util::task::send_on_failure;
use std::comm::{channel, Receiver, Sender};
use std::comm::{Receiver, Sender, channel};
use std::task::TaskBuilder;
use sync::Arc;
@ -154,7 +154,7 @@ fn initialize_layers<C:RenderListener>(
compositor.initialize_layers_for_pipeline(pipeline_id, metadata, epoch);
}
impl<C: RenderListener + Send> RenderTask<C> {
impl<C:RenderListener + Send> RenderTask<C> {
pub fn create(id: PipelineId,
port: Receiver<Msg>,
compositor: C,
@ -294,6 +294,12 @@ impl<C: RenderListener + Send> RenderTask<C> {
// Divide up the layer into tiles.
for tile in tiles.iter() {
// Optimize the display list for this tile.
let page_rect_au = geometry::f32_rect_to_au_rect(tile.page_rect);
let optimizer = DisplayListOptimizer::new(render_layer.display_list.clone(),
page_rect_au);
let display_list = optimizer.optimize();
let width = tile.screen_rect.size.width;
let height = tile.screen_rect.size.height;
@ -340,7 +346,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
// Draw the display list.
profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || {
render_layer.display_list.draw_into_context(&mut ctx);
display_list.draw_into_context(&mut ctx);
ctx.draw_target.flush();
});
}

View file

@ -4,6 +4,7 @@
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use std::default::Default;
use std::num::{NumCast, One, Zero};
@ -159,6 +160,11 @@ impl Au {
else { return Au(s - res) };
}
#[inline]
pub fn from_frac32_px(px: f32) -> Au {
Au((px * 60f32) as i32)
}
#[inline]
pub fn from_pt(pt: f64) -> Au {
from_px(pt_to_px(pt) as int)
@ -231,3 +237,9 @@ pub fn rect_contains_point<T:Ord + Add<T,T>>(rect: Rect<T>, point: Point2D<T>) -
point.y >= rect.origin.y && point.y < rect.origin.y + rect.size.height
}
/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
Rect(Point2D(Au::from_frac32_px(rect.origin.x), Au::from_frac32_px(rect.origin.y)),
Size2D(Au::from_frac32_px(rect.size.width), Au::from_frac32_px(rect.size.height)))
}