--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -30,20 +30,17 @@ listed below. Both options will give you
try pushes to verify the update. After that, continue with the steps below to
actually land the update into the tree.
Option A:
Use a script to do the update for you. This will usually work, if you satisfy
all the assumptions the script is making. The script can be found at
https://github.com/staktrace/moz-scripts/blob/master/try-latest-webrender.sh
and contains documentation on how to use it. Read the documentation carefully
- before trying to use it. The only extra change you need to make with this
- option is to manually update the revision in gfx/webrender_bindings/revision.txt
- so that it points to the new WR version you are landing. The script doesn't
- do that yet.
+ before trying to use it.
Option B:
Do the update manually. This is a little more cumbersome but may be required
if the script doesn't work or the repos are in a state that violates hidden
assumptions in the script (e.g. if the webrender_bindings/Cargo.toml file is
no longer in the format expected by the script). The steps to do this are,
roughly:
- Update your mozilla-central checkout to the latest code on mozilla-central.
--- a/gfx/webrender/examples/basic.rs
+++ b/gfx/webrender/examples/basic.rs
@@ -221,17 +221,17 @@ impl Example for App {
rect: (75, 75).by(100, 100),
repeat: false,
};
let complex = ComplexClipRegion::new(
(50, 50).to(150, 150),
BorderRadius::uniform(20.0),
ClipMode::Clip
);
- let id = builder.define_clip(None, bounds, vec![complex], Some(mask));
+ let id = builder.define_clip(bounds, vec![complex], Some(mask));
builder.push_clip_id(id);
let info = LayoutPrimitiveInfo::new((100, 100).to(200, 200));
builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
let info = LayoutPrimitiveInfo::new((250, 100).to(350, 200));
builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
let border_side = BorderSide {
--- a/gfx/webrender/examples/blob.rs
+++ b/gfx/webrender/examples/blob.rs
@@ -85,17 +85,17 @@ fn render_blob(
texels.push(color.r * checker + tc);
texels.push(color.a * checker + tc);
}
api::ImageFormat::R8 => {
texels.push(color.a * checker + tc);
}
_ => {
return Err(api::BlobImageError::Other(
- format!("Usupported image format {:?}", descriptor.format),
+ format!("Usupported image format"),
));
}
}
}
}
Ok(api::RasterizedBlobImage {
data: texels,
--- a/gfx/webrender/examples/scrolling.rs
+++ b/gfx/webrender/examples/scrolling.rs
@@ -104,17 +104,16 @@ impl Example for App {
let info = LayoutPrimitiveInfo::new((0, 200).to(50, 250));
builder.push_rect(&info, ColorF::new(0.0, 1.0, 1.0, 1.0));
// Add a sticky frame. It will "stick" twice while scrolling, once
// at a margin of 10px from the bottom, for 40 pixels of scrolling,
// and once at a margin of 10px from the top, for 60 pixels of
// scrolling.
let sticky_id = builder.define_sticky_frame(
- None,
(50, 350).by(50, 50),
SideOffsets2D::new(Some(10.0), None, Some(10.0), None),
StickyOffsetBounds::new(-40.0, 60.0),
StickyOffsetBounds::new(0.0, 0.0),
LayoutVector2D::new(0.0, 0.0)
);
builder.push_clip_id(sticky_id);
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -719,17 +719,18 @@ impl AlphaBatcher {
)
}
ImageSource::Cache { ref item, .. } => {
item.clone()
}
};
if cache_item.texture_id == SourceTexture::Invalid {
- warn!("Warnings: skip a PrimitiveKind::Image at {:?}.\n", item_bounding_rect);
+ warn!("Warnings: skip a PrimitiveKind::Image");
+ debug!("at {:?}.", item_bounding_rect);
return;
}
let batch_kind = TransformBatchKind::Image(Self::get_buffer_kind(cache_item.texture_id));
let key = BatchKey::new(
BatchKind::Transformable(transform_kind, batch_kind),
blend_mode,
BatchTextures {
@@ -1178,17 +1179,18 @@ impl AlphaBatcher {
image_yuv_cpu.image_rendering,
None,
ctx.resource_cache,
gpu_cache,
deferred_resolves,
);
if cache_item.texture_id == SourceTexture::Invalid {
- warn!("Warnings: skip a PrimitiveKind::YuvImage at {:?}.\n", item_bounding_rect);
+ warn!("Warnings: skip a PrimitiveKind::YuvImage");
+ debug!("at {:?}.", item_bounding_rect);
return;
}
textures.colors[channel] = cache_item.texture_id;
uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache);
}
// All yuv textures should be the same type.
@@ -1518,17 +1520,18 @@ impl ClipBatcher {
.entry(cache_item.texture_id)
.or_insert(Vec::new())
.push(ClipMaskInstance {
clip_data_address: gpu_address,
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
..instance
});
} else {
- warn!("Warnings: skip a image mask. Key:{:?} Rect::{:?}.\n", mask.image, mask.rect);
+ warn!("Warnings: skip a image mask");
+ debug!("Key:{:?} Rect::{:?}", mask.image, mask.rect);
continue;
}
}
ClipSource::Rectangle(..) => {
if work_item.coordinate_system_id != coordinate_system_id {
self.rectangles.push(ClipMaskInstance {
clip_data_address: gpu_address,
..instance
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -1,16 +1,16 @@
/* 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 api::{ClipId, DevicePixelScale, LayerPixel, LayerPoint, LayerRect, LayerSize};
-use api::{LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D};
-use api::{PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase, ScrollLocation};
-use api::{ScrollSensitivity, StickyOffsetBounds, WorldPoint};
+use api::{ClipId, DevicePixelScale, ExternalScrollId, IdType, LayerPixel, LayerPoint, LayerRect};
+use api::{LayerSize, LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform};
+use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase};
+use api::{ScrollLocation, ScrollSensitivity, StickyOffsetBounds, WorldPoint};
use clip::{ClipSourcesHandle, ClipStore};
use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState};
use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use render_task::{ClipChain, ClipWorkItem};
use resource_cache::ResourceCache;
@@ -55,17 +55,17 @@ pub enum NodeType {
/// A reference frame establishes a new coordinate space in the tree.
ReferenceFrame(ReferenceFrameInfo),
/// Other nodes just do clipping, but no transformation.
Clip(ClipSourcesHandle),
/// Transforms it's content, but doesn't clip it. Can also be adjusted
/// by scroll events or setting scroll offsets.
- ScrollFrame(ScrollingState),
+ ScrollFrame(ScrollFrameInfo),
/// A special kind of node that adjusts its position based on the position
/// of its parent node and a given set of sticky positioning offset bounds.
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
/// https://www.w3.org/TR/css-position-3/#sticky-pos
StickyFrame(StickyFrameInfo),
}
@@ -148,26 +148,28 @@ impl ClipScrollNode {
coordinate_system_relative_transform: TransformOrOffset::zero(),
node_data_index: ClipScrollNodeIndex(0),
}
}
pub fn new_scroll_frame(
pipeline_id: PipelineId,
parent_id: ClipId,
+ external_id: Option<ExternalScrollId>,
frame_rect: &LayerRect,
content_size: &LayerSize,
scroll_sensitivity: ScrollSensitivity,
) -> Self {
- let node_type = NodeType::ScrollFrame(ScrollingState::new(
+ let node_type = NodeType::ScrollFrame(ScrollFrameInfo::new(
scroll_sensitivity,
LayerSize::new(
(content_size.width - frame_rect.size.width).max(0.0),
(content_size.height - frame_rect.size.height).max(0.0)
- )
+ ),
+ external_id,
));
Self::new(pipeline_id, Some(parent_id), frame_rect, node_type)
}
pub fn new_clip_node(
pipeline_id: PipelineId,
parent_id: ClipId,
@@ -206,17 +208,17 @@ impl ClipScrollNode {
Self::new(pipeline_id, Some(parent_id), &frame_rect, node_type)
}
pub fn add_child(&mut self, child: ClipId) {
self.children.push(child);
}
- pub fn apply_old_scrolling_state(&mut self, old_scrolling_state: &ScrollingState) {
+ pub fn apply_old_scrolling_state(&mut self, old_scrolling_state: &ScrollFrameInfo) {
match self.node_type {
NodeType::ScrollFrame(ref mut scrolling) => {
let scroll_sensitivity = scrolling.scroll_sensitivity;
let scrollable_size = scrolling.scrollable_size;
*scrolling = *old_scrolling_state;
scrolling.scroll_sensitivity = scroll_sensitivity;
scrolling.scrollable_size = scrollable_size;
}
@@ -760,45 +762,65 @@ impl ClipScrollNode {
}
pub fn is_overscrolling(&self) -> bool {
match self.node_type {
NodeType::ScrollFrame(ref state) => state.overscroll_amount() != LayerVector2D::zero(),
_ => false,
}
}
+
+ pub fn matches_id(&self, node_id: ClipId, id_to_match: IdType) -> bool {
+ let external_id = match id_to_match {
+ IdType::ExternalScrollId(id) => id,
+ IdType::ClipId(clip_id) => return node_id == clip_id,
+ };
+
+ match self.node_type {
+ NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true,
+ _ => false,
+ }
+ }
}
#[derive(Copy, Clone, Debug)]
-pub struct ScrollingState {
+pub struct ScrollFrameInfo {
pub offset: LayerVector2D,
pub spring: Spring,
pub started_bouncing_back: bool,
pub bouncing_back: bool,
pub should_handoff_scroll: bool,
pub scroll_sensitivity: ScrollSensitivity,
/// Amount that this ScrollFrame can scroll in both directions.
pub scrollable_size: LayerSize,
+ /// An external id to identify this scroll frame to API clients. This
+ /// allows setting scroll positions via the API without relying on ClipsIds
+ /// which may change between frames.
+ pub external_id: Option<ExternalScrollId>,
+
}
/// Manages scrolling offset, overscroll state, etc.
-impl ScrollingState {
- pub fn new(scroll_sensitivity: ScrollSensitivity,
- scrollable_size: LayerSize
- ) -> ScrollingState {
- ScrollingState {
+impl ScrollFrameInfo {
+ pub fn new(
+ scroll_sensitivity: ScrollSensitivity,
+ scrollable_size: LayerSize,
+ external_id: Option<ExternalScrollId>,
+ ) -> ScrollFrameInfo {
+ ScrollFrameInfo {
offset: LayerVector2D::zero(),
spring: Spring::at(LayerPoint::zero(), STIFFNESS, DAMPING),
started_bouncing_back: false,
bouncing_back: false,
should_handoff_scroll: false,
scroll_sensitivity,
scrollable_size,
+ external_id,
}
}
pub fn sensitive_to_input_events(&self) -> bool {
match self.scroll_sensitivity {
ScrollSensitivity::ScriptAndInputEvents => true,
ScrollSensitivity::Script => false,
}
--- a/gfx/webrender/src/clip_scroll_tree.rs
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -1,27 +1,28 @@
/* 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 api::{ClipId, ClipChainId, DeviceIntRect, DevicePixelScale, LayerPoint, LayerRect};
-use api::{LayerToWorldTransform, LayerVector2D, LayoutTransform, PipelineId, PropertyBinding};
-use api::{ScrollClamping, ScrollEventPhase, ScrollLayerState, ScrollLocation, WorldPoint};
+use api::{ClipChainId, ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, IdType};
+use api::{LayerPoint, LayerRect, LayerToWorldTransform, LayerVector2D, LayoutTransform};
+use api::{PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase, ScrollLocation};
+use api::{ScrollNodeState, WorldPoint};
use clip::ClipStore;
-use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState, StickyFrameInfo};
+use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
use render_task::ClipChain;
use resource_cache::ResourceCache;
use scene::SceneProperties;
use util::TransformOrOffset;
-pub type ScrollStates = FastHashMap<ClipId, ScrollingState>;
+pub type ScrollStates = FastHashMap<ExternalScrollId, ScrollFrameInfo>;
/// An id that identifies coordinate systems in the ClipScrollTree. Each
/// coordinate system has an id and those ids will be shared when the coordinates
/// system are the same or are in the same axis-aligned space. This allows
/// for optimizing mask generation.
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -54,17 +55,17 @@ pub struct ClipScrollTree {
/// A Vec of all descriptors that describe ClipChains in the order in which they are
/// encountered during display list flattening. ClipChains are expected to never be
/// the children of ClipChains later in the list.
clip_chains_descriptors: Vec<ClipChainDescriptor>,
/// A HashMap of built ClipChains that are described by `clip_chains_descriptors`.
pub clip_chains: FastHashMap<ClipChainId, ClipChain>,
- pub pending_scroll_offsets: FastHashMap<ClipId, (LayerPoint, ScrollClamping)>,
+ pub pending_scroll_offsets: FastHashMap<IdType, (LayerPoint, ScrollClamping)>,
/// The ClipId of the currently scrolling node. Used to allow the same
/// node to scroll even if a touch operation leaves the boundaries of that node.
pub currently_scrolling_node_id: Option<ClipId>,
/// The current frame id, used for giving a unique id to all new dynamically
/// added frames and clips. The ClipScrollTree increments this by one every
/// time a new dynamic frame is created.
@@ -229,57 +230,56 @@ impl ClipScrollTree {
}
}
cache.insert(*node_id, Some(point_in_layer));
true
}
- pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
+ pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
let mut result = vec![];
- for (id, node) in self.nodes.iter() {
- if let NodeType::ScrollFrame(scrolling) = node.node_type {
- result.push(ScrollLayerState {
- id: *id,
- scroll_offset: scrolling.offset,
- })
+ for node in self.nodes.values() {
+ if let NodeType::ScrollFrame(info) = node.node_type {
+ if let Some(id) = info.external_id {
+ result.push(ScrollNodeState { id, scroll_offset: info.offset })
+ }
}
}
result
}
pub fn drain(&mut self) -> ScrollStates {
self.current_new_node_item = 1;
let mut scroll_states = FastHashMap::default();
- for (layer_id, old_node) in &mut self.nodes.drain() {
- if self.pipelines_to_discard.contains(&layer_id.pipeline_id()) {
+ for (node_id, old_node) in &mut self.nodes.drain() {
+ if self.pipelines_to_discard.contains(&node_id.pipeline_id()) {
continue;
}
- if let NodeType::ScrollFrame(scrolling) = old_node.node_type {
- scroll_states.insert(layer_id, scrolling);
+ match old_node.node_type {
+ NodeType::ScrollFrame(info) if info.external_id.is_some() => {
+ scroll_states.insert(info.external_id.unwrap(), info);
+ }
+ _ => {}
}
}
self.pipelines_to_discard.clear();
self.clip_chains.clear();
self.clip_chains_descriptors.clear();
scroll_states
}
- pub fn scroll_node(&mut self, origin: LayerPoint, id: ClipId, clamp: ScrollClamping) -> bool {
- if self.nodes.is_empty() {
- self.pending_scroll_offsets.insert(id, (origin, clamp));
- return false;
- }
-
- if let Some(node) = self.nodes.get_mut(&id) {
- return node.set_scroll_origin(&origin, clamp);
+ pub fn scroll_node(&mut self, origin: LayerPoint, id: IdType, clamp: ScrollClamping) -> bool {
+ for (clip_id, node) in &mut self.nodes {
+ if node.matches_id(*clip_id, id) {
+ return node.set_scroll_origin(&origin, clamp);
+ }
}
self.pending_scroll_offsets.insert(id, (origin, clamp));
false
}
pub fn scroll(
&mut self,
@@ -486,26 +486,40 @@ impl ClipScrollTree {
pub fn tick_scrolling_bounce_animations(&mut self) {
for (_, node) in &mut self.nodes {
node.tick_scrolling_bounce_animation()
}
}
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
- // TODO(gw): These are all independent - can be run through thread pool if it shows up
- // in the profile!
for (clip_id, node) in &mut self.nodes {
- if let Some(scrolling_state) = old_states.get(clip_id) {
- node.apply_old_scrolling_state(scrolling_state);
+ let external_id = match node.node_type {
+ NodeType::ScrollFrame(info) if info.external_id.is_some() => info.external_id,
+ _ => None,
+ };
+
+ if let Some(external_id) = external_id {
+ if let Some(scrolling_state) = old_states.get(&external_id) {
+ node.apply_old_scrolling_state(scrolling_state);
+ }
}
- if let Some((pending_offset, clamping)) = self.pending_scroll_offsets.remove(clip_id) {
- node.set_scroll_origin(&pending_offset, clamping);
+ let id = IdType::ClipId(*clip_id);
+ if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&id) {
+ node.set_scroll_origin(&offset, clamping);
}
+
+ if let Some(external_id) = external_id {
+ let id = IdType::ExternalScrollId(external_id);
+ if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&id) {
+ node.set_scroll_origin(&offset, clamping);
+ }
+ }
+
}
}
pub fn generate_new_clip_id(&mut self, pipeline_id: PipelineId) -> ClipId {
let new_id = ClipId::DynamicallyAddedNode(self.current_new_node_item, pipeline_id);
self.current_new_node_item += 1;
new_id
}
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -755,27 +755,27 @@ impl Device {
}
pub fn compile_shader(
gl: &gl::Gl,
name: &str,
shader_type: gl::GLenum,
source: &String,
) -> Result<gl::GLuint, ShaderError> {
- debug!("compile {:?}", name);
+ debug!("compile {}", name);
let id = gl.create_shader(shader_type);
gl.shader_source(id, &[source.as_bytes()]);
gl.compile_shader(id);
let log = gl.get_shader_info_log(id);
if gl.get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
- println!("Failed to compile shader: {:?}\n{}", name, log);
+ println!("Failed to compile shader: {}\n{}", name, log);
Err(ShaderError::Compilation(name.to_string(), log))
} else {
if !log.is_empty() {
- println!("Warnings detected on shader: {:?}\n{}", name, log);
+ println!("Warnings detected on shader: {}\n{}", name, log);
}
Ok(id)
}
}
pub fn begin_frame(&mut self) -> FrameId {
debug_assert!(!self.inside_frame);
self.inside_frame = true;
@@ -1312,17 +1312,17 @@ impl Device {
if let Some(ref cached_programs) = self.cached_programs {
if let Some(binary) = cached_programs.binaries.borrow().get(&sources)
{
self.gl.program_binary(pid, binary.format, &binary.binary);
if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) {
let error_log = self.gl.get_program_info_log(pid);
println!(
- "Failed to load a program object with a program binary: {:?} renderer {}\n{}",
+ "Failed to load a program object with a program binary: {} renderer {}\n{}",
base_filename,
self.renderer_name,
error_log
);
} else {
loaded = true;
}
}
@@ -1374,17 +1374,17 @@ impl Device {
self.gl.detach_shader(pid, vs_id);
self.gl.detach_shader(pid, fs_id);
self.gl.delete_shader(vs_id);
self.gl.delete_shader(fs_id);
if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) {
let error_log = self.gl.get_program_info_log(pid);
println!(
- "Failed to link shader program: {:?}\n{}",
+ "Failed to link shader program: {}\n{}",
base_filename,
error_log
);
self.gl.delete_program(pid);
return Err(ShaderError::Link(base_filename.to_string(), error_log));
}
}
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -1,21 +1,20 @@
/* 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 api::{BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion};
-use api::{DevicePixelScale, DeviceUintRect, DeviceUintSize};
-use api::{DisplayItemRef, DocumentLayer, Epoch, FilterOp};
-use api::{ImageDisplayItem, ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect};
-use api::{LayerSize, LayerVector2D, LayoutSize};
-use api::{LocalClip, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLayerState};
-use api::{ScrollLocation, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem, StackingContext};
-use api::{TileOffset, TransformStyle, WorldPoint};
+use api::{DevicePixelScale, DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch};
+use api::{ExternalScrollId, FilterOp, IdType, ImageDisplayItem, ItemRange, LayerPoint};
+use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, LocalClip};
+use api::{PipelineId, ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollNodeState};
+use api::{ScrollPolicy, ScrollSensitivity, SpecificDisplayItem, StackingContext, TileOffset};
+use api::{TransformStyle, WorldPoint};
use clip::ClipRegion;
use clip_scroll_node::StickyFrameInfo;
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use euclid::rect;
use frame_builder::{FrameBuilder, FrameBuilderConfig, ScrollbarInfo};
use gpu_cache::GpuCache;
use internal_types::{FastHashMap, FastHashSet, RenderedDocument};
use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters};
@@ -200,16 +199,17 @@ impl<'a> FlattenContext<'a> {
);
}
fn flatten_scroll_frame(
&mut self,
pipeline_id: PipelineId,
parent_id: &ClipId,
new_scroll_frame_id: &ClipId,
+ external_id: Option<ExternalScrollId>,
frame_rect: &LayerRect,
content_rect: &LayerRect,
clip_region: ClipRegion,
scroll_sensitivity: ScrollSensitivity,
) {
let clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
self.builder.add_clip_node(
clip_id,
@@ -217,16 +217,17 @@ impl<'a> FlattenContext<'a> {
pipeline_id,
clip_region,
self.clip_scroll_tree,
);
self.builder.add_scroll_frame(
*new_scroll_frame_id,
clip_id,
+ external_id,
pipeline_id,
&frame_rect,
&content_rect.size,
scroll_sensitivity,
self.clip_scroll_tree,
);
}
@@ -366,16 +367,17 @@ impl<'a> FlattenContext<'a> {
origin,
true,
self.clip_scroll_tree,
);
self.builder.add_scroll_frame(
ClipId::root_scroll_node(pipeline_id),
iframe_reference_frame_id,
+ Some(ExternalScrollId(0, pipeline_id)),
pipeline_id,
&iframe_rect,
&pipeline.content_size,
ScrollSensitivity::ScriptAndInputEvents,
self.clip_scroll_tree,
);
self.flatten_root(
@@ -453,17 +455,18 @@ impl<'a> FlattenContext<'a> {
instance,
&text_info.color,
item.glyphs(),
item.display_list().get(item.glyphs()).count(),
text_info.glyph_options,
);
}
None => {
- warn!("Unknown font instance key: {:?}", text_info.font_key);
+ warn!("Unknown font instance key");
+ debug!("key={:?}", text_info.font_key);
}
}
}
SpecificDisplayItem::Rectangle(ref info) => {
self.builder.add_solid_rectangle(
clip_and_scroll,
&prim_info,
info.color,
@@ -598,16 +601,17 @@ impl<'a> FlattenContext<'a> {
let frame_rect = item.local_clip()
.clip_rect()
.translate(&reference_frame_relative_offset);
let content_rect = item.rect().translate(&reference_frame_relative_offset);
self.flatten_scroll_frame(
pipeline_id,
&clip_and_scroll.scroll_node_id,
&info.id,
+ info.external_id,
&frame_rect,
&content_rect,
clip_region,
info.scroll_sensitivity,
);
}
SpecificDisplayItem::StickyFrame(ref info) => {
let frame_rect = item.rect().translate(&reference_frame_relative_offset);
@@ -976,22 +980,22 @@ impl FrameContext {
self.clip_scroll_tree.drain()
}
pub fn get_clip_scroll_tree(&self) -> &ClipScrollTree {
&self.clip_scroll_tree
}
- pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
+ pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
self.clip_scroll_tree.get_scroll_node_state()
}
/// Returns true if the node actually changed position or false otherwise.
- pub fn scroll_node(&mut self, origin: LayerPoint, id: ClipId, clamp: ScrollClamping) -> bool {
+ pub fn scroll_node(&mut self, origin: LayerPoint, id: IdType, clamp: ScrollClamping) -> bool {
self.clip_scroll_tree.scroll_node(origin, id, clamp)
}
/// Returns true if any nodes actually changed position or false otherwise.
pub fn scroll(
&mut self,
scroll_location: ScrollLocation,
cursor: WorldPoint,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -1,38 +1,38 @@
/* 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 api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo, ClipId};
-use api::{ColorF, ColorU, DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect};
-use api::{DeviceUintSize, DocumentLayer, ExtendMode, FontRenderMode, GlyphInstance, GlyphOptions};
-use api::{GradientStop, HitTestFlags, HitTestItem, HitTestResult, ImageKey, ImageRendering};
-use api::{Epoch, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize};
-use api::{LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation};
-use api::{LineStyle, LocalClip, PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode};
-use api::{ScrollSensitivity, Shadow, TexelRect, TileOffset, TransformStyle, WorldPoint};
-use api::{DeviceIntRect, DeviceIntSize, YuvColorSpace, YuvData};
+use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo};
+use api::{ClipId, ColorF, ColorU, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
+use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode};
+use api::{ExternalScrollId, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop};
+use api::{HitTestFlags, HitTestItem, HitTestResult, ImageKey, ImageRendering, ItemRange, ItemTag};
+use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize, LayerTransform, LayerVector2D};
+use api::{LayoutTransform, LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId};
+use api::{PremultipliedColorF, PropertyBinding, RepeatMode, ScrollSensitivity, Shadow, TexelRect};
+use api::{TileOffset, TransformStyle, WorldPoint, WorldToLayerTransform, YuvColorSpace, YuvData};
use app_units::Au;
use border::ImageBorderSegment;
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore, Contains};
use clip_scroll_node::{ClipScrollNode, NodeType};
use clip_scroll_tree::ClipScrollTree;
use euclid::{SideOffsets2D, vec2};
use frame::FrameId;
use glyph_rasterizer::FontInstance;
use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType};
use internal_types::{FastHashMap, FastHashSet, RenderPassIndex};
use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface};
use prim_store::{BrushKind, BrushPrimitive, ImageCacheKey, YuvImagePrimitiveCpu};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, ImageSource, PrimitiveKind};
-use prim_store::{PrimitiveContainer, PrimitiveIndex, SpecificPrimitiveIndex};
+use prim_store::{PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
-use prim_store::{BrushSegmentDescriptor, TextRunPrimitiveCpu};
+use prim_store::{BrushSegmentDescriptor, PrimitiveRun, TextRunPrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskTree};
use resource_cache::ResourceCache;
use scene::{ScenePipeline, SceneProperties};
use std::{mem, usize, f32};
use tiling::{CompositeOps, Frame, RenderPass, RenderTargetKind};
use tiling::{RenderPassKind, RenderTargetContext, ScrollbarPrimitive};
use util::{self, MaxRect, pack_as_float, RectHelpers, recycle_vec};
@@ -139,32 +139,51 @@ pub struct FrameState<'a> {
pub render_tasks: &'a mut RenderTaskTree,
pub profile_counters: &'a mut FrameProfileCounters,
pub clip_store: &'a mut ClipStore,
pub local_clip_rects: &'a mut Vec<LayerRect>,
pub resource_cache: &'a mut ResourceCache,
pub gpu_cache: &'a mut GpuCache,
}
+pub struct PictureContext<'a> {
+ pub pipeline_id: PipelineId,
+ pub perform_culling: bool,
+ pub prim_runs: Vec<PrimitiveRun>,
+ pub original_reference_frame_id: Option<ClipId>,
+ pub display_list: &'a BuiltDisplayList,
+ pub draw_text_transformed: bool,
+ pub inv_world_transform: Option<WorldToLayerTransform>,
+}
+
+pub struct PictureState {
+ pub tasks: Vec<RenderTaskId>,
+}
+
+impl PictureState {
+ pub fn new() -> PictureState {
+ PictureState {
+ tasks: Vec::new(),
+ }
+ }
+}
+
pub struct PrimitiveRunContext<'a> {
- pub display_list: &'a BuiltDisplayList,
pub clip_chain: Option<&'a ClipChain>,
pub scroll_node: &'a ClipScrollNode,
pub clip_chain_rect_index: ClipChainRectIndex,
}
impl<'a> PrimitiveRunContext<'a> {
pub fn new(
- display_list: &'a BuiltDisplayList,
clip_chain: Option<&'a ClipChain>,
scroll_node: &'a ClipScrollNode,
clip_chain_rect_index: ClipChainRectIndex,
) -> Self {
PrimitiveRunContext {
- display_list,
clip_chain,
scroll_node,
clip_chain_rect_index,
}
}
}
impl FrameBuilder {
@@ -646,16 +665,17 @@ impl FrameBuilder {
);
let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id);
clip_scroll_tree.topmost_scrolling_node_id = topmost_scrolling_node_id;
self.add_scroll_frame(
topmost_scrolling_node_id,
clip_scroll_tree.root_reference_frame_id,
+ Some(ExternalScrollId(0, pipeline_id)),
pipeline_id,
&viewport_rect,
content_size,
ScrollSensitivity::ScriptAndInputEvents,
clip_scroll_tree,
);
topmost_scrolling_node_id
@@ -678,25 +698,27 @@ impl FrameBuilder {
let node = ClipScrollNode::new_clip_node(pipeline_id, parent_id, handle, clip_rect);
clip_scroll_tree.add_node(node, new_node_id);
}
pub fn add_scroll_frame(
&mut self,
new_node_id: ClipId,
parent_id: ClipId,
+ external_id: Option<ExternalScrollId>,
pipeline_id: PipelineId,
frame_rect: &LayerRect,
content_size: &LayerSize,
scroll_sensitivity: ScrollSensitivity,
clip_scroll_tree: &mut ClipScrollTree,
) {
let node = ClipScrollNode::new_scroll_frame(
pipeline_id,
parent_id,
+ external_id,
frame_rect,
content_size,
scroll_sensitivity,
);
clip_scroll_tree.add_node(node, new_node_id);
}
@@ -1607,17 +1629,16 @@ impl FrameBuilder {
) -> Option<RenderTaskId> {
profile_scope!("cull");
if self.prim_store.cpu_pictures.is_empty() {
return None
}
// The root picture is always the first one added.
- let prim_run_cmds = mem::replace(&mut self.prim_store.cpu_pictures[0].runs, Vec::new());
let root_clip_scroll_node = &clip_scroll_tree.nodes[&clip_scroll_tree.root_reference_frame_id()];
let display_list = &pipelines
.get(&root_clip_scroll_node.pipeline_id)
.expect("No display list?")
.display_list;
let frame_context = FrameContext {
@@ -1633,48 +1654,47 @@ impl FrameBuilder {
render_tasks,
profile_counters,
clip_store: &mut self.clip_store,
local_clip_rects,
resource_cache,
gpu_cache,
};
- let root_prim_run_context = PrimitiveRunContext::new(
+ let pic_context = PictureContext {
+ pipeline_id: root_clip_scroll_node.pipeline_id,
+ perform_culling: true,
+ prim_runs: mem::replace(&mut self.prim_store.cpu_pictures[0].runs, Vec::new()),
+ original_reference_frame_id: None,
display_list,
- root_clip_scroll_node.clip_chain.as_ref(),
- root_clip_scroll_node,
- ClipChainRectIndex(0),
- );
+ draw_text_transformed: true,
+ inv_world_transform: None,
+ };
- let mut child_tasks = Vec::new();
+ let mut pic_state = PictureState::new();
+
self.prim_store.reset_prim_visibility();
self.prim_store.prepare_prim_runs(
- &prim_run_cmds,
- root_clip_scroll_node.pipeline_id,
- &root_prim_run_context,
- true,
- &mut child_tasks,
- None,
- SpecificPrimitiveIndex(0),
+ &pic_context,
+ &mut pic_state,
&frame_context,
&mut frame_state,
);
let pic = &mut self.prim_store.cpu_pictures[0];
- pic.runs = prim_run_cmds;
+ pic.runs = pic_context.prim_runs;
let root_render_task = RenderTask::new_picture(
None,
PrimitiveIndex(0),
RenderTargetKind::Color,
ContentOrigin::Screen(DeviceIntPoint::zero()),
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(root_render_task);
pic.surface = Some(PictureSurface::RenderTask(render_task_id));
Some(render_task_id)
}
--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -2,17 +2,17 @@
* 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 api::{ColorF, ClipAndScrollInfo, FilterOp, MixBlendMode};
use api::{DeviceIntPoint, DeviceIntRect, LayerToWorldScale, PipelineId};
use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerVector2D, Shadow};
use api::{ClipId, PremultipliedColorF};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey};
-use frame_builder::{FrameContext, FrameState};
+use frame_builder::{FrameContext, FrameState, PictureState};
use gpu_cache::GpuDataRequest;
use gpu_types::{BrushImageKind, PictureType};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use render_task::{ClearMode, RenderTask, RenderTaskCacheKey};
use render_task::{RenderTaskCacheKeyKind, RenderTaskId};
use resource_cache::CacheItem;
use scene::{FilterOpHelpers, SceneProperties};
use tiling::RenderTargetKind;
@@ -326,18 +326,18 @@ impl PicturePrimitive {
}
}
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_screen_rect: &DeviceIntRect,
prim_local_rect: &LayerRect,
- child_tasks: Vec<RenderTaskId>,
- parent_tasks: &mut Vec<RenderTaskId>,
+ pic_state_for_children: PictureState,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) {
let content_scale = LayerToWorldScale::new(1.0) * frame_context.device_pixel_scale;
match self.kind {
PictureKind::Image {
ref mut secondary_render_task_id,
@@ -349,46 +349,46 @@ impl PicturePrimitive {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
prim_index,
RenderTargetKind::Color,
content_origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state_for_children.tasks,
PictureType::Image,
);
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);
let (blur_render_task, _) = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
PremultipliedColorF::TRANSPARENT,
);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32();
let picture_task = RenderTask::new_picture(
Some(rect.size),
prim_index,
RenderTargetKind::Color,
ContentOrigin::Screen(rect.origin),
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state_for_children.tasks,
PictureType::Image,
);
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);
let (blur_render_task, _) = RenderTask::new_blur(
blur_std_deviation.round(),
@@ -397,84 +397,84 @@ impl PicturePrimitive {
RenderTargetKind::Color,
ClearMode::Transparent,
color.premultiplied(),
);
*secondary_render_task_id = Some(picture_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
prim_index,
RenderTargetKind::Color,
content_origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state_for_children.tasks,
PictureType::Image,
);
let readback_task_id = frame_state.render_tasks.add(RenderTask::new_readback(*prim_screen_rect));
*secondary_render_task_id = Some(readback_task_id);
- parent_tasks.push(readback_task_id);
+ pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(filter)) => {
// If this filter is not currently going to affect
// the picture, just collapse this picture into the
// current render task. This most commonly occurs
// when opacity == 1.0, but can also occur on other
// filters and be a significant performance win.
if filter.is_noop() {
- parent_tasks.extend(child_tasks);
+ pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
} else {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
prim_index,
RenderTargetKind::Color,
content_origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state_for_children.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
}
Some(PictureCompositeMode::Blit) => {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
prim_index,
RenderTargetKind::Color,
content_origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
- child_tasks,
+ pic_state_for_children.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
None => {
- parent_tasks.extend(child_tasks);
+ pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
}
}
}
PictureKind::TextShadow { blur_radius, color, content_rect, .. } => {
// This is a shadow element. Create a render task that will
// render the text run to a target, and then apply a gaussian
// blur to that text run in order to build the actual primitive
@@ -511,17 +511,17 @@ impl PicturePrimitive {
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
color.premultiplied(),
);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
- parent_tasks.push(render_task_id);
+ pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
PictureKind::BoxShadow { blur_radius, clip_mode, color, content_rect, cache_key, .. } => {
// TODO(gw): Rounding the content rect here to device pixels is not
// technically correct. Ideally we should ceil() here, and ensure that
// the extra part pixel in the case of fractional sizes is correctly
// handled. For now, just use rounding which passes the existing
// Gecko tests.
@@ -571,17 +571,17 @@ impl PicturePrimitive {
picture_task_id,
render_tasks,
RenderTargetKind::Alpha,
blur_clear_mode,
color.premultiplied(),
);
let root_task_id = render_tasks.add(blur_render_task);
- parent_tasks.push(root_task_id);
+ pic_state.tasks.push(root_task_id);
// TODO(gw): Remove the nastiness with having to pass
// the scale factor through the texture cache
// item user data. This will disappear once
// the brush_picture shader is updated to draw
// segments, since the scale factor will not
// be used at all then during drawing.
(root_task_id, [scale_factor, 0.0, 0.0], false)
--- a/gfx/webrender/src/platform/unix/font.rs
+++ b/gfx/webrender/src/platform/unix/font.rs
@@ -186,17 +186,18 @@ impl FontContext {
self.faces.insert(
*font_key,
Face {
face,
_bytes: Some(bytes),
},
);
} else {
- println!("WARN: webrender failed to load font {:?}", font_key);
+ println!("WARN: webrender failed to load font");
+ debug!("font={:?}", font_key);
}
}
}
pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) {
if !self.faces.contains_key(&font_key) {
let mut face: FT_Face = ptr::null_mut();
let pathname = CString::new(native_font_handle.pathname).unwrap();
@@ -212,17 +213,18 @@ impl FontContext {
self.faces.insert(
*font_key,
Face {
face,
_bytes: None,
},
);
} else {
- println!("WARN: webrender failed to load font {:?} from path {:?}", font_key, pathname);
+ println!("WARN: webrender failed to load font");
+ debug!("font={:?}, path={:?}", font_key, pathname);
}
}
}
pub fn delete_font(&mut self, font_key: &FontKey) {
if let Some(face) = self.faces.remove(font_key) {
let result = unsafe { FT_Done_Face(face.face) };
assert!(result.succeeded());
@@ -326,23 +328,25 @@ impl FontContext {
unsafe { FT_GlyphSlot_Embolden(slot) };
}
let format = unsafe { (*slot).format };
match format {
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE |
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => Some(slot),
_ => {
- error!("Unsupported {:?}", format);
+ error!("Unsupported format");
+ debug!("format={:?}", format);
None
}
}
} else {
- error!(
- "Unable to load glyph for {} of size {:?} from font {:?}, {:?}",
+ error!("Unable to load glyph");
+ debug!(
+ "{} of size {:?} from font {:?}, {:?}",
glyph.index,
font.size,
font.font_key,
result
);
None
}
}
@@ -559,18 +563,19 @@ impl FontContext {
let render_mode = match (font.render_mode, font.subpx_dir) {
(FontRenderMode::Mono, _) => FT_Render_Mode::FT_RENDER_MODE_MONO,
(FontRenderMode::Alpha, _) => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
(FontRenderMode::Subpixel, SubpixelDirection::Vertical) => FT_Render_Mode::FT_RENDER_MODE_LCD_V,
(FontRenderMode::Subpixel, _) => FT_Render_Mode::FT_RENDER_MODE_LCD,
};
let result = unsafe { FT_Render_Glyph(slot, render_mode) };
if !result.succeeded() {
- error!(
- "Unable to rasterize {:?} with {:?}, {:?}",
+ error!("Unable to rasterize");
+ debug!(
+ "{:?} with {:?}, {:?}",
key,
render_mode,
result
);
false
} else {
true
}
@@ -606,22 +611,23 @@ impl FontContext {
scale = font.size.to_f32_px() / y_size as f32;
}
FT_Glyph_Format::FT_GLYPH_FORMAT_OUTLINE => {
if !self.rasterize_glyph_outline(slot, font, key) {
return None;
}
}
_ => {
- error!("Unsupported {:?}", format);
+ error!("Unsupported format");
+ debug!("format={:?}", format);
return None;
}
};
- info!(
+ debug!(
"Rasterizing {:?} as {:?} with dimensions {:?}",
key,
font.render_mode,
dimensions
);
let bitmap = unsafe { &(*slot).bitmap };
let pixel_mode = unsafe { mem::transmute(bitmap.pixel_mode as u32) };
@@ -634,17 +640,17 @@ impl FontContext {
assert!(bitmap.rows % 3 == 0);
(bitmap.width as usize, (bitmap.rows / 3) as usize)
}
FT_Pixel_Mode::FT_PIXEL_MODE_MONO |
FT_Pixel_Mode::FT_PIXEL_MODE_GRAY |
FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
(bitmap.width as usize, bitmap.rows as usize)
}
- _ => panic!("Unsupported {:?}", pixel_mode),
+ _ => panic!("Unsupported mode"),
};
let mut final_buffer = vec![0u8; actual_width * actual_height * 4];
// Extract the final glyph from FT format into BGRA8 format, which is
// what WR expects.
let subpixel_bgr = font.flags.contains(FontInstanceFlags::SUBPIXEL_BGR);
let mut src_row = bitmap.buffer;
let mut dest: usize = 0;
@@ -712,17 +718,17 @@ impl FontContext {
src_row = unsafe { src_row.offset((2 * bitmap.pitch) as isize) };
}
FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
// The source is premultiplied BGRA data.
let dest_slice = &mut final_buffer[dest .. row_end];
let src_slice = unsafe { slice::from_raw_parts(src, dest_slice.len()) };
dest_slice.copy_from_slice(src_slice);
}
- _ => panic!("Unsupported {:?}", pixel_mode),
+ _ => panic!("Unsupported mode"),
}
src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
dest = row_end;
}
match format {
FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -1,24 +1,24 @@
/* 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 api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipId, ClipMode};
+use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipMode};
use api::{ColorF, ColorU, DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch};
use api::{ComplexClipRegion, ExtendMode, FontRenderMode};
use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
-use api::{LineStyle, PipelineId, PremultipliedColorF, TileOffset};
+use api::{LineStyle, PremultipliedColorF, TileOffset};
use api::{WorldToLayerTransform, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderEdgeKind};
use clip_scroll_tree::{CoordinateSystemId};
use clip_scroll_node::ClipScrollNode;
use clip::{ClipSource, ClipSourcesHandle};
-use frame_builder::{FrameContext, FrameState, PrimitiveRunContext};
+use frame_builder::{FrameContext, FrameState, PictureContext, PictureState, PrimitiveRunContext};
use glyph_rasterizer::{FontInstance, FontTransform};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use gpu_types::{ClipChainRectIndex};
use picture::{PictureKind, PicturePrimitive};
use render_task::{BlitSource, ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipWorkItem};
use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId};
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
@@ -1140,53 +1140,50 @@ impl PrimitiveStore {
pub fn prim_count(&self) -> usize {
self.cpu_metadata.len()
}
fn prepare_prim_for_render_inner(
&mut self,
prim_index: PrimitiveIndex,
prim_run_context: &PrimitiveRunContext,
- child_tasks: Vec<RenderTaskId>,
- parent_tasks: &mut Vec<RenderTaskId>,
- pic_index: SpecificPrimitiveIndex,
+ pic_state_for_children: PictureState,
+ pic_context: &PictureContext,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) {
let metadata = &mut self.cpu_metadata[prim_index.0];
match metadata.prim_kind {
PrimitiveKind::Border => {}
PrimitiveKind::Picture => {
self.cpu_pictures[metadata.cpu_prim_index.0]
.prepare_for_render(
prim_index,
metadata.screen_rect.as_ref().expect("bug: trying to draw an off-screen picture!?"),
&metadata.local_rect,
- child_tasks,
- parent_tasks,
+ pic_state_for_children,
+ pic_state,
frame_context,
frame_state,
);
}
PrimitiveKind::TextRun => {
- let pic = &self.cpu_pictures[pic_index.0];
let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
// The transform only makes sense for screen space rasterization
- let transform = match pic.kind {
- PictureKind::BoxShadow { .. } => None,
- PictureKind::TextShadow { .. } => None,
- PictureKind::Image { .. } => {
- Some(&prim_run_context.scroll_node.world_content_transform)
- },
+ let transform = if pic_context.draw_text_transformed {
+ Some(&prim_run_context.scroll_node.world_content_transform)
+ } else {
+ None
};
text.prepare_for_render(
frame_state.resource_cache,
frame_context.device_pixel_scale,
transform,
- prim_run_context.display_list,
+ pic_context.display_list,
frame_state.gpu_cache,
);
}
PrimitiveKind::Image => {
let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
let image_properties = frame_state
.resource_cache
.get_image_properties(image_cpu.key.image_key);
@@ -1267,17 +1264,17 @@ impl PrimitiveStore {
size,
BlitSource::RenderTask {
task_id: cache_to_target_task_id,
},
);
let target_to_cache_task_id = render_tasks.add(target_to_cache_task);
// Hook this into the render task tree at the right spot.
- parent_tasks.push(target_to_cache_task_id);
+ pic_state.tasks.push(target_to_cache_task_id);
// Pass the image opacity, so that the cached render task
// item inherits the same opacity properties.
(target_to_cache_task_id, [0.0; 3], image_properties.descriptor.is_opaque)
}
);
}
}
@@ -1318,25 +1315,34 @@ impl PrimitiveStore {
image.write_gpu_blocks(request);
}
PrimitiveKind::YuvImage => {
let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0];
yuv_image.write_gpu_blocks(request);
}
PrimitiveKind::AlignedGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
- metadata.opacity = gradient.build_gpu_blocks_for_aligned(prim_run_context.display_list, request);
+ metadata.opacity = gradient.build_gpu_blocks_for_aligned(
+ pic_context.display_list,
+ request,
+ );
}
PrimitiveKind::AngleGradient => {
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
- gradient.build_gpu_blocks_for_angle_radial(prim_run_context.display_list, request);
+ gradient.build_gpu_blocks_for_angle_radial(
+ pic_context.display_list,
+ request,
+ );
}
PrimitiveKind::RadialGradient => {
let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0];
- gradient.build_gpu_blocks_for_angle_radial(prim_run_context.display_list, request);
+ gradient.build_gpu_blocks_for_angle_radial(
+ pic_context.display_list,
+ request,
+ );
}
PrimitiveKind::TextRun => {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
text.write_gpu_blocks(&mut request);
}
PrimitiveKind::Picture => {
let pic = &self.cpu_pictures[metadata.cpu_prim_index.0];
pic.write_gpu_blocks(&mut request);
@@ -1493,20 +1499,20 @@ impl PrimitiveStore {
}
}
}
fn update_clip_task_for_brush(
&mut self,
prim_run_context: &PrimitiveRunContext,
prim_index: PrimitiveIndex,
- tasks: &mut Vec<RenderTaskId>,
clips: &Vec<ClipWorkItem>,
combined_outer_rect: &DeviceIntRect,
has_clips_from_other_coordinate_systems: bool,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) -> bool {
let metadata = &self.cpu_metadata[prim_index.0];
let brush = match metadata.prim_kind {
PrimitiveKind::Brush => {
&mut self.cpu_brushes[metadata.cpu_prim_index.0]
}
@@ -1550,31 +1556,31 @@ impl PrimitiveStore {
segment.clip_task_id = intersected_rect.map(|bounds| {
let clip_task = RenderTask::new_mask(
bounds,
clips.clone(),
prim_run_context.scroll_node.coordinate_system_id,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);
- tasks.push(clip_task_id);
+ pic_state.tasks.push(clip_task_id);
clip_task_id
})
}
true
}
fn update_clip_task(
&mut self,
prim_index: PrimitiveIndex,
prim_run_context: &PrimitiveRunContext,
prim_screen_rect: &DeviceIntRect,
- tasks: &mut Vec<RenderTaskId>,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) -> bool {
self.cpu_metadata[prim_index.0].clip_task_id = None;
let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
Some(rect) => rect,
None => {
@@ -1670,115 +1676,123 @@ impl PrimitiveStore {
if combined_inner_rect.contains_rect(&prim_screen_rect) {
return true;
}
// First try to render this primitive's mask using optimized brush rendering.
if self.update_clip_task_for_brush(
prim_run_context,
prim_index,
- tasks,
&clips,
&combined_outer_rect,
has_clips_from_other_coordinate_systems,
+ pic_state,
frame_context,
frame_state,
) {
return true;
}
let clip_task = RenderTask::new_mask(
combined_outer_rect,
clips,
prim_coordinate_system_id,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
- tasks.push(clip_task_id);
+ pic_state.tasks.push(clip_task_id);
true
}
pub fn prepare_prim_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_run_context: &PrimitiveRunContext,
- perform_culling: bool,
- parent_tasks: &mut Vec<RenderTaskId>,
- pic_index: SpecificPrimitiveIndex,
+ pic_context: &PictureContext,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) -> Option<LayerRect> {
- // Reset the visibility of this primitive.
+ let mut may_need_clip_mask = true;
+ let mut pic_state_for_children = PictureState::new();
+
// Do some basic checks first, that can early out
// without even knowing the local rect.
- let (cpu_prim_index, dependencies, cull_children, may_need_clip_mask) = {
- let metadata = &mut self.cpu_metadata[prim_index.0];
- metadata.screen_rect = None;
+ let (prim_kind, cpu_prim_index) = {
+ let metadata = &self.cpu_metadata[prim_index.0];
- if perform_culling &&
+ if pic_context.perform_culling &&
!metadata.is_backface_visible &&
prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
return None;
}
- let (dependencies, cull_children, may_need_clip_mask) = match metadata.prim_kind {
- PrimitiveKind::Picture => {
- let pic = &mut self.cpu_pictures[metadata.cpu_prim_index.0];
-
- if !pic.resolve_scene_properties(frame_context.scene_properties) {
- return None;
- }
-
- let (rfid, may_need_clip_mask) = match pic.kind {
- PictureKind::Image { reference_frame_id, .. } => {
- (Some(reference_frame_id), false)
- }
- _ => {
- (None, true)
- }
- };
- (Some((pic.pipeline_id, mem::replace(&mut pic.runs, Vec::new()), rfid)),
- pic.cull_children,
- may_need_clip_mask)
- }
- _ => {
- (None, true, true)
- }
- };
-
- (metadata.cpu_prim_index, dependencies, cull_children, may_need_clip_mask)
+ (metadata.prim_kind, metadata.cpu_prim_index)
};
// If we have dependencies, we need to prepare them first, in order
// to know the actual rect of this primitive.
// For example, scrolling may affect the location of an item in
// local space, which may force us to render this item on a larger
// picture target, if being composited.
- let mut child_tasks = Vec::new();
- if let Some((pipeline_id, dependencies, rfid)) = dependencies {
+ if let PrimitiveKind::Picture = prim_kind {
+ let pic_context_for_children = {
+ let pic = &mut self.cpu_pictures[cpu_prim_index.0];
+
+ if !pic.resolve_scene_properties(frame_context.scene_properties) {
+ return None;
+ }
+
+ let (draw_text_transformed, original_reference_frame_id) = match pic.kind {
+ PictureKind::Image { reference_frame_id, .. } => {
+ may_need_clip_mask = false;
+ (true, Some(reference_frame_id))
+ }
+ PictureKind::BoxShadow { .. } |
+ PictureKind::TextShadow { .. } => {
+ (false, None)
+ }
+ };
+
+ let display_list = &frame_context
+ .pipelines
+ .get(&pic.pipeline_id)
+ .expect("No display list?")
+ .display_list;
+
+ let inv_world_transform = prim_run_context
+ .scroll_node
+ .world_content_transform
+ .inverse();
+
+ PictureContext {
+ pipeline_id: pic.pipeline_id,
+ perform_culling: pic.cull_children,
+ prim_runs: mem::replace(&mut pic.runs, Vec::new()),
+ original_reference_frame_id,
+ display_list,
+ draw_text_transformed,
+ inv_world_transform,
+ }
+ };
+
let result = self.prepare_prim_runs(
- &dependencies,
- pipeline_id,
- prim_run_context,
- cull_children,
- &mut child_tasks,
- rfid,
- cpu_prim_index,
+ &pic_context_for_children,
+ &mut pic_state_for_children,
frame_context,
frame_state,
);
- let metadata = &mut self.cpu_metadata[prim_index.0];
-
// Restore the dependencies (borrow check dance)
let pic = &mut self.cpu_pictures[cpu_prim_index.0];
- pic.runs = dependencies;
+ pic.runs = pic_context_for_children.prim_runs;
+ let metadata = &mut self.cpu_metadata[prim_index.0];
metadata.local_rect = pic.update_local_rect(
metadata.local_rect,
result,
);
}
let (local_rect, unclipped_device_rect) = {
let metadata = &mut self.cpu_metadata[prim_index.0];
@@ -1786,58 +1800,58 @@ impl PrimitiveStore {
metadata.local_rect.size.height <= 0.0 {
//warn!("invalid primitive rect {:?}", metadata.local_rect);
return None;
}
let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect);
let local_rect = match local_rect {
Some(local_rect) => local_rect,
- None if perform_culling => return None,
+ None if pic_context.perform_culling => return None,
None => LayerRect::zero(),
};
let screen_bounding_rect = calculate_screen_bounding_rect(
&prim_run_context.scroll_node.world_content_transform,
&local_rect,
frame_context.device_pixel_scale,
);
let clip_bounds = match prim_run_context.clip_chain {
Some(ref node) => node.combined_outer_screen_rect,
None => frame_context.screen_rect,
};
metadata.screen_rect = screen_bounding_rect.intersection(&clip_bounds);
- if metadata.screen_rect.is_none() && perform_culling {
+ if metadata.screen_rect.is_none() && pic_context.perform_culling {
return None;
}
metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index;
(local_rect, screen_bounding_rect)
};
- if perform_culling && may_need_clip_mask && !self.update_clip_task(
+ if pic_context.perform_culling && may_need_clip_mask && !self.update_clip_task(
prim_index,
prim_run_context,
&unclipped_device_rect,
- parent_tasks,
+ pic_state,
frame_context,
frame_state,
) {
return None;
}
self.prepare_prim_for_render_inner(
prim_index,
prim_run_context,
- child_tasks,
- parent_tasks,
- pic_index,
+ pic_state_for_children,
+ pic_context,
+ pic_state,
frame_context,
frame_state,
);
Some(local_rect)
}
// TODO(gw): Make this simpler / more efficient by tidying
@@ -1845,113 +1859,99 @@ impl PrimitiveStore {
pub fn reset_prim_visibility(&mut self) {
for md in &mut self.cpu_metadata {
md.screen_rect = None;
}
}
pub fn prepare_prim_runs(
&mut self,
- runs: &[PrimitiveRun],
- pipeline_id: PipelineId,
- parent_prim_run_context: &PrimitiveRunContext,
- perform_culling: bool,
- parent_tasks: &mut Vec<RenderTaskId>,
- original_reference_frame_id: Option<ClipId>,
- pic_index: SpecificPrimitiveIndex,
+ pic_context: &PictureContext,
+ pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
) -> PrimitiveRunLocalRect {
let mut result = PrimitiveRunLocalRect {
local_rect_in_actual_parent_space: LayerRect::zero(),
local_rect_in_original_parent_space: LayerRect::zero(),
};
- for run in runs {
+ for run in &pic_context.prim_runs {
// TODO(gw): Perhaps we can restructure this to not need to create
// a new primitive context for every run (if the hash
// lookups ever show up in a profile).
let scroll_node = &frame_context
.clip_scroll_tree
.nodes[&run.clip_and_scroll.scroll_node_id];
let clip_chain = frame_context
.clip_scroll_tree
.get_clip_chain(&run.clip_and_scroll.clip_node_id());
- if perform_culling {
+ if pic_context.perform_culling {
if !scroll_node.invertible {
- debug!("{:?} {:?}: position not invertible", run.base_prim_index, pipeline_id);
+ debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id);
continue;
}
match clip_chain {
Some(ref chain) if chain.combined_outer_screen_rect.is_empty() => {
- debug!("{:?} {:?}: clipped out", run.base_prim_index, pipeline_id);
+ debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
continue;
}
_ => {},
}
}
- let parent_relative_transform = parent_prim_run_context
- .scroll_node
- .world_content_transform
- .inverse()
+ let parent_relative_transform = pic_context
+ .inv_world_transform
.map(|inv_parent| {
inv_parent.pre_mul(&scroll_node.world_content_transform)
});
- let original_relative_transform = original_reference_frame_id
+ let original_relative_transform = pic_context.original_reference_frame_id
.and_then(|original_reference_frame_id| {
let parent = frame_context
.clip_scroll_tree
.nodes[&original_reference_frame_id]
.world_content_transform;
parent.inverse()
.map(|inv_parent| {
inv_parent.pre_mul(&scroll_node.world_content_transform)
})
});
- let display_list = &frame_context.pipelines
- .get(&pipeline_id)
- .expect("No display list?")
- .display_list;
-
- let clip_chain_rect = match perform_culling {
+ let clip_chain_rect = match pic_context.perform_culling {
true => get_local_clip_rect_for_nodes(scroll_node, clip_chain),
false => None,
};
let clip_chain_rect_index = match clip_chain_rect {
Some(rect) if rect.is_empty() => continue,
Some(rect) => {
frame_state.local_clip_rects.push(rect);
ClipChainRectIndex(frame_state.local_clip_rects.len() - 1)
}
None => ClipChainRectIndex(0), // This is no clipping.
};
let child_prim_run_context = PrimitiveRunContext::new(
- display_list,
clip_chain,
scroll_node,
clip_chain_rect_index,
);
for i in 0 .. run.count {
let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
if let Some(prim_local_rect) = self.prepare_prim_for_render(
prim_index,
&child_prim_run_context,
- perform_culling,
- parent_tasks,
- pic_index,
+ pic_context,
+ pic_state,
frame_context,
frame_state,
) {
frame_state.profile_counters.visible_primitives.inc();
if let Some(ref matrix) = original_relative_transform {
let bounds = matrix.transform_rect(&prim_local_rect);
result.local_rect_in_original_parent_space =
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -1,16 +1,16 @@
/* 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 api::{ApiMsg, BuiltDisplayList, DebugCommand, DeviceIntPoint};
+use api::{ApiMsg, BuiltDisplayList, ClearCache, DebugCommand};
#[cfg(feature = "debugger")]
use api::{BuiltDisplayListIter, SpecificDisplayItem};
-use api::{DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
+use api::{DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{DocumentId, DocumentLayer, DocumentMsg, HitTestFlags, HitTestResult};
use api::{IdNamespace, PipelineId, RenderNotifier, WorldPoint};
use api::channel::{MsgReceiver, MsgSender, PayloadReceiver, PayloadReceiverHelperMethods};
use api::channel::{PayloadSender, PayloadSenderHelperMethods};
#[cfg(feature = "capture")]
use api::CaptureBits;
#[cfg(feature = "replay")]
use api::CapturedDocument;
@@ -558,28 +558,52 @@ impl RenderBackend {
.filter(|did| did.0 == namespace_id)
.cloned()
.collect::<Vec<_>>();
for document in document_ids {
self.documents.remove(&document);
}
}
ApiMsg::MemoryPressure => {
- self.resource_cache.on_memory_pressure();
+ // This is drastic. It will basically flush everything out of the cache,
+ // and the next frame will have to rebuild all of its resources.
+ // We may want to look into something less extreme, but on the other hand this
+ // should only be used in situations where are running low enough on memory
+ // that we risk crashing if we don't do something about it.
+ // The advantage of clearing the cache completely is that it gets rid of any
+ // remaining fragmentation that could have persisted if we kept around the most
+ // recently used resources.
+ self.resource_cache.clear(ClearCache::all());
let pending_update = self.resource_cache.pending_updates();
let msg = ResultMsg::UpdateResources {
updates: pending_update,
cancel_rendering: true,
};
self.result_tx.send(msg).unwrap();
self.notifier.wake_up();
}
ApiMsg::DebugCommand(option) => {
let msg = match option {
+ DebugCommand::EnableDualSourceBlending(enable) => {
+ // Set in the config used for any future documents
+ // that are created.
+ self.frame_config
+ .dual_source_blending_is_enabled = enable;
+
+ // Set for any existing documents.
+ for (_, doc) in &mut self.documents {
+ doc.frame_ctx
+ .frame_builder_config
+ .dual_source_blending_is_enabled = enable;
+ }
+
+ // We don't want to forward this message to the renderer.
+ continue;
+ }
DebugCommand::FetchDocuments => {
let json = self.get_docs_for_debugger();
ResultMsg::DebugOutput(DebugOutput::FetchDocuments(json))
}
DebugCommand::FetchClipScrollTree => {
let json = self.get_clip_scroll_tree_for_debugger();
ResultMsg::DebugOutput(DebugOutput::FetchClipScrollTree(json))
}
@@ -601,32 +625,20 @@ impl RenderBackend {
root_pipeline_id: doc.scene.root_pipeline_id,
window_size: doc.view.window_size,
};
tx.send(captured).unwrap();
}
// Note: we can't pass `LoadCapture` here since it needs to arrive
// before the `PublishDocument` messages sent by `load_capture`.
continue
- },
- DebugCommand::EnableDualSourceBlending(enable) => {
- // Set in the config used for any future documents
- // that are created.
- self.frame_config
- .dual_source_blending_is_enabled = enable;
-
- // Set for any existing documents.
- for (_, doc) in &mut self.documents {
- doc.frame_ctx
- .frame_builder_config
- .dual_source_blending_is_enabled = enable;
- }
-
- // We don't want to forward this message to the renderer.
- continue;
+ }
+ DebugCommand::ClearCaches(mask) => {
+ self.resource_cache.clear(mask);
+ continue
}
_ => ResultMsg::DebugCommand(option),
};
self.result_tx.send(msg).unwrap();
self.notifier.wake_up();
}
ApiMsg::ShutDown => {
self.notifier.shut_down();
@@ -686,17 +698,17 @@ impl RenderBackend {
let _timer = profile_counters.total_time.timer();
let rendered_document = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
&mut profile_counters.resources,
);
- info!("generated frame for document {:?} with {} passes",
+ debug!("generated frame for document {:?} with {} passes",
document_id, rendered_document.frame.passes.len());
let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
self.result_tx.send(msg).unwrap();
let pending_update = self.resource_cache.pending_updates();
(pending_update, rendered_document)
};
@@ -858,22 +870,22 @@ impl RenderBackend {
fn save_capture(
&mut self,
root: PathBuf,
bits: CaptureBits,
profile_counters: &mut BackendProfileCounters,
) -> DebugOutput {
use capture::CaptureConfig;
- info!("capture: saving {:?}", root);
+ debug!("capture: saving {:?}", root);
let (resources, deferred) = self.resource_cache.save_capture(&root);
let config = CaptureConfig::new(root, bits);
for (&id, doc) in &mut self.documents {
- info!("\tdocument {:?}", id);
+ debug!("\tdocument {:?}", id);
if config.bits.contains(CaptureBits::SCENE) {
let file_name = format!("scene-{}-{}", (id.0).0, id.1);
config.serialize(&doc.scene, file_name);
}
if config.bits.contains(CaptureBits::FRAME) {
let rendered_document = doc.render(
&mut self.resource_cache,
&mut self.gpu_cache,
@@ -927,17 +939,17 @@ impl RenderBackend {
fn load_capture(
&mut self,
root: &PathBuf,
profile_counters: &mut BackendProfileCounters,
) {
use capture::CaptureConfig;
use tiling::Frame;
- info!("capture: loading {:?}", root);
+ debug!("capture: loading {:?}", root);
let backend = CaptureConfig::deserialize::<PlainRenderBackend, _>(root, "backend")
.expect("Unable to open backend.ron");
let caches_maybe = CaptureConfig::deserialize::<PlainCacheOwn, _>(root, "resource_cache");
// Note: it would be great to have `RenderBackend` to be split
// rather explicitly on what's used before and after scene building
// so that, for example, we never miss anything in the code below:
@@ -953,17 +965,17 @@ impl RenderBackend {
};
self.documents.clear();
self.default_device_pixel_ratio = backend.default_device_pixel_ratio;
self.frame_config = backend.frame_config;
self.enable_render_on_scroll = backend.enable_render_on_scroll;
for (id, view) in backend.documents {
- info!("\tdocument {:?}", id);
+ debug!("\tdocument {:?}", id);
let scene_name = format!("scene-{}-{}", (id.0).0, id.1);
let scene = CaptureConfig::deserialize::<Scene, _>(root, &scene_name)
.expect(&format!("Unable to open {}.ron", scene_name));
let mut doc = Document {
scene,
view,
frame_ctx: FrameContext::new(self.frame_config.clone()),
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -726,39 +726,47 @@ impl RenderTask {
}
pt.end_level();
true
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum RenderTaskCacheKeyKind {
BoxShadow(BoxShadowCacheKey),
Image(ImageCacheKey),
}
#[derive(Debug, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCacheKey {
pub size: DeviceIntSize,
pub kind: RenderTaskCacheKeyKind,
}
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
struct RenderTaskCacheEntry {
handle: TextureCacheHandle,
}
// A cache of render tasks that are stored in the texture
// cache for usage across frames.
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCache {
entries: FastHashMap<RenderTaskCacheKey, RenderTaskCacheEntry>,
}
impl RenderTaskCache {
- pub fn new() -> RenderTaskCache {
+ pub fn new() -> Self {
RenderTaskCache {
entries: FastHashMap::default(),
}
}
pub fn clear(&mut self) {
self.entries.clear();
}
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -715,17 +715,17 @@ impl SourceTextureResolver {
let texture = self.cache_rgba8_texture
.as_ref()
.unwrap_or(&self.dummy_cache_texture);
device.bind_texture(sampler, texture);
}
SourceTexture::External(external_image) => {
let texture = self.external_images
.get(&(external_image.id, external_image.channel_index))
- .expect(&format!("BUG: External image should be resolved by now: {:?}", external_image));
+ .expect(&format!("BUG: External image should be resolved by now"));
device.bind_external_texture(sampler, texture);
}
SourceTexture::TextureCache(index) => {
let texture = &self.cache_texture_map[index.0];
device.bind_texture(sampler, texture);
}
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
let pool_index = self.pass_rgba8_textures
@@ -1187,17 +1187,17 @@ impl LazilyCompiledShader {
if precache {
let t0 = precise_time_ns();
let program = try!{ shader.get(device) };
let t1 = precise_time_ns();
device.bind_program(program);
device.draw_triangles_u16(0, 3);
let t2 = precise_time_ns();
- println!("[C: {:.1} ms D: {:.1} ms] Precache {} {:?}",
+ debug!("[C: {:.1} ms D: {:.1} ms] Precache {} {:?}",
(t1 - t0) as f64 / 1000000.0,
(t2 - t1) as f64 / 1000000.0,
name,
features
);
}
Ok(shader)
@@ -2679,16 +2679,19 @@ impl Renderer {
self.set_debug_flag(DebugFlags::ALPHA_PRIM_DBG, enable);
}
DebugCommand::EnableGpuTimeQueries(enable) => {
self.set_debug_flag(DebugFlags::GPU_TIME_QUERIES, enable);
}
DebugCommand::EnableGpuSampleQueries(enable) => {
self.set_debug_flag(DebugFlags::GPU_SAMPLE_QUERIES, enable);
}
+ DebugCommand::EnableDualSourceBlending(_) => {
+ panic!("Should be handled by render backend");
+ }
DebugCommand::FetchDocuments |
DebugCommand::FetchClipScrollTree => {}
DebugCommand::FetchRenderTasks => {
let json = self.get_render_tasks_for_debugger();
self.debug_server.send(json);
}
DebugCommand::FetchPasses => {
let json = self.get_passes_for_debugger();
@@ -2697,18 +2700,29 @@ impl Renderer {
DebugCommand::FetchScreenshot => {
let json = self.get_screenshot_for_debugger();
self.debug_server.send(json);
}
DebugCommand::SaveCapture(..) |
DebugCommand::LoadCapture(..) => {
panic!("Capture commands are not welcome here! Did you build with 'capture' feature?")
}
- DebugCommand::EnableDualSourceBlending(_) => {
- panic!("Should be handled by render backend");
+ DebugCommand::ClearCaches(_) => {}
+ DebugCommand::InvalidateGpuCache => {
+ match self.gpu_cache_texture.bus {
+ CacheBus::PixelBuffer { ref mut rows, .. } => {
+ info!("Invalidating GPU caches");
+ for row in rows {
+ row.is_dirty = true;
+ }
+ }
+ CacheBus::Scatter { .. } => {
+ warn!("Unable to invalidate scattered GPU cache");
+ }
+ }
}
}
}
/// Set a callback for handling external images.
pub fn set_external_image_handler(&mut self, handler: Box<ExternalImageHandler>) {
self.external_image_handler = Some(handler);
}
@@ -4127,31 +4141,32 @@ impl Renderer {
let props = &deferred_resolve.image_properties;
let ext_image = props
.external_image
.expect("BUG: Deferred resolves must be external images!");
let image = handler.lock(ext_image.id, ext_image.channel_index);
let texture_target = match ext_image.image_type {
ExternalImageType::TextureHandle(target) => target,
ExternalImageType::Buffer => {
- panic!("{:?} is not a suitable image type in update_deferred_resolves()", ext_image.image_type);
+ panic!("not a suitable image type in update_deferred_resolves()");
}
};
// In order to produce the handle, the external image handler may call into
// the GL context and change some states.
self.device.reset_state();
let texture = match image.source {
ExternalImageSource::NativeTexture(texture_id) => {
ExternalTexture::new(texture_id, texture_target)
}
ExternalImageSource::Invalid => {
- warn!(
- "Invalid ext-image for ext_id:{:?}, channel:{}.",
+ warn!("Invalid ext-image");
+ debug!(
+ "For ext_id:{:?}, channel:{}.",
ext_image.id,
ext_image.channel_index
);
// Just use 0 as the gl handle for this failed case.
ExternalTexture::new(0, texture_target)
}
ExternalImageSource::RawData(_) => {
panic!("Raw external data is not expected for deferred resolves!");
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -1,15 +1,15 @@
/* 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 api::{AddFont, BlobImageData, BlobImageResources, ResourceUpdate, ResourceUpdates};
use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
-use api::{ColorF, DevicePoint, DeviceUintRect, DeviceUintSize};
+use api::{ClearCache, ColorF, DevicePoint, DeviceUintRect, DeviceUintSize};
use api::{Epoch, FontInstanceKey, FontKey, FontTemplate};
use api::{ExternalImageData, ExternalImageType};
use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
use api::{GlyphDimensions, GlyphKey, IdNamespace};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
use api::{TileOffset, TileSize};
use app_units::Au;
#[cfg(feature = "capture")]
@@ -108,27 +108,22 @@ struct ImageResource {
#[derive(Clone, Debug)]
pub struct ImageTiling {
pub image_size: DeviceUintSize,
pub tile_size: TileSize,
}
pub type TiledImageMap = FastHashMap<ImageKey, ImageTiling>;
+#[derive(Default)]
struct ImageTemplates {
images: FastHashMap<ImageKey, ImageResource>,
}
impl ImageTemplates {
- fn new() -> Self {
- ImageTemplates {
- images: FastHashMap::default(),
- }
- }
-
fn insert(&mut self, key: ImageKey, resource: ImageResource) {
self.images.insert(key, resource);
}
fn remove(&mut self, key: ImageKey) -> Option<ImageResource> {
self.images.remove(&key)
}
@@ -227,16 +222,17 @@ impl Into<BlobImageRequest> for ImageReq
tile: self.tile,
}
}
}
type ImageCache = ResourceClassCache<ImageRequest, CachedImageInfo>;
pub type FontInstanceMap = Arc<RwLock<FastHashMap<FontInstanceKey, FontInstance>>>;
+#[derive(Default)]
struct Resources {
font_templates: FastHashMap<FontKey, FontTemplate>,
font_instances: FontInstanceMap,
image_templates: ImageTemplates,
}
impl BlobImageResources for Resources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate {
@@ -281,21 +277,17 @@ impl ResourceCache {
blob_image_renderer: Option<Box<BlobImageRenderer>>,
) -> Result<Self, ResourceCacheError> {
let glyph_rasterizer = GlyphRasterizer::new(workers)?;
Ok(ResourceCache {
cached_glyphs: GlyphCache::new(),
cached_images: ResourceClassCache::new(),
cached_render_tasks: RenderTaskCache::new(),
- resources: Resources {
- font_templates: FastHashMap::default(),
- font_instances: Arc::new(RwLock::new(FastHashMap::default())),
- image_templates: ImageTemplates::new(),
- },
+ resources: Resources::default(),
cached_glyph_dimensions: FastHashMap::default(),
texture_cache,
state: State::Idle,
current_frame_id: FrameId(0),
pending_image_requests: FastHashSet::default(),
glyph_rasterizer,
blob_image_renderer,
})
@@ -494,20 +486,17 @@ impl ResourceCache {
image_key: ImageKey,
descriptor: ImageDescriptor,
mut data: ImageData,
dirty_rect: Option<DeviceUintRect>,
) {
let max_texture_size = self.max_texture_size();
let image = match self.resources.image_templates.get_mut(image_key) {
Some(res) => res,
- None => panic!(
- "Attempt to update non-existent image (key {:?}).",
- image_key
- ),
+ None => panic!("Attempt to update non-existent image"),
};
let mut tiling = image.tiling;
if tiling.is_none() && Self::should_tile(max_texture_size, &descriptor, &data) {
tiling = Some(DEFAULT_TILE_SIZE);
}
if let ImageData::Blob(ref mut blob) = data {
@@ -536,17 +525,18 @@ impl ResourceCache {
self.cached_images
.clear_keys(|request| request.key == image_key);
match value {
Some(image) => if image.data.is_blob() {
self.blob_image_renderer.as_mut().unwrap().delete(image_key);
},
None => {
- println!("Delete the non-exist key:{:?}", image_key);
+ warn!("Delete the non-exist key");
+ debug!("key={:?}", image_key);
}
}
}
pub fn request_image(
&mut self,
key: ImageKey,
rendering: ImageRendering,
@@ -558,20 +548,18 @@ impl ResourceCache {
key,
rendering,
tile,
};
let template = match self.resources.image_templates.get(key) {
Some(template) => template,
None => {
- warn!(
- "ERROR: Trying to render deleted / non-existent key {:?}",
- key
- );
+ warn!("ERROR: Trying to render deleted / non-existent key");
+ debug!("key={:?}", key);
return
}
};
// Images that don't use the texture cache can early out.
if !template.data.uses_texture_cache() {
return;
}
@@ -937,28 +925,29 @@ impl ResourceCache {
}
}
pub fn end_frame(&mut self) {
debug_assert_eq!(self.state, State::QueryResources);
self.state = State::Idle;
}
- pub fn on_memory_pressure(&mut self) {
- // This is drastic. It will basically flush everything out of the cache,
- // and the next frame will have to rebuild all of its resources.
- // We may want to look into something less extreme, but on the other hand this
- // should only be used in situations where are running low enough on memory
- // that we risk crashing if we don't do something about it.
- // The advantage of clearing the cache completely is that it gets rid of any
- // remaining fragmentation that could have persisted if we kept around the most
- // recently used resources.
- self.cached_images.clear();
- self.cached_glyphs.clear();
- self.cached_render_tasks.clear();
+ pub fn clear(&mut self, what: ClearCache) {
+ if what.contains(ClearCache::IMAGES) {
+ self.cached_images.clear();
+ }
+ if what.contains(ClearCache::GLYPHS) {
+ self.cached_glyphs.clear();
+ }
+ if what.contains(ClearCache::GLYPH_DIMENSIONS) {
+ self.cached_glyph_dimensions.clear();
+ }
+ if what.contains(ClearCache::RENDER_TASKS) {
+ self.cached_render_tasks.clear();
+ }
}
pub fn clear_namespace(&mut self, namespace: IdNamespace) {
self.resources
.image_templates
.images
.retain(|key, _| key.0 != namespace);
@@ -1030,26 +1019,28 @@ pub struct PlainResources {
#[cfg(feature = "capture")]
#[derive(Serialize)]
pub struct PlainCacheRef<'a> {
current_frame_id: FrameId,
glyphs: PlainGlyphCacheRef<'a>,
glyph_dimensions: &'a GlyphDimensionsCache,
images: &'a ImageCache,
+ render_tasks: &'a RenderTaskCache,
textures: &'a TextureCache,
}
#[cfg(feature = "replay")]
#[derive(Deserialize)]
pub struct PlainCacheOwn {
current_frame_id: FrameId,
glyphs: PlainGlyphCacheOwn,
glyph_dimensions: GlyphDimensionsCache,
images: ImageCache,
+ render_tasks: RenderTaskCache,
textures: TextureCache,
}
#[cfg(feature = "replay")]
const NATIVE_FONT: &'static [u8] = include_bytes!("../res/Proggy.ttf");
impl ResourceCache {
#[cfg(feature = "capture")]
@@ -1281,16 +1272,17 @@ impl ResourceCache {
})
})
.collect();
(font_instance, ResourceClassCache { resources })
})
.collect(),
glyph_dimensions: &self.cached_glyph_dimensions,
images: &self.cached_images,
+ render_tasks: &self.cached_render_tasks,
textures: &self.texture_cache,
}
}
#[cfg(feature = "replay")]
pub fn load_capture(
&mut self,
resources: PlainResources,
@@ -1345,32 +1337,32 @@ impl ResourceCache {
})
.collect();
(font_instance, ResourceClassCache { resources })
})
.collect();
self.current_frame_id = cached.current_frame_id;
self.cached_glyphs = GlyphCache { glyph_key_caches };
self.cached_glyph_dimensions = cached.glyph_dimensions;
+ self.cached_images = cached.images;
+ self.cached_render_tasks = cached.render_tasks;
self.texture_cache = cached.textures;
}
None => {
self.current_frame_id = FrameId(0);
self.cached_glyphs.clear();
self.cached_glyph_dimensions.clear();
self.cached_images.clear();
+ self.cached_render_tasks.clear();
let max_texture_size = self.texture_cache.max_texture_size();
self.texture_cache = TextureCache::new(max_texture_size);
}
}
- self.state = State::Idle;
self.glyph_rasterizer.reset();
- self.pending_image_requests.clear();
-
let res = &mut self.resources;
res.font_templates.clear();
*res.font_instances.write().unwrap() = resources.font_instances;
res.image_templates.images.clear();
info!("\tfont templates...");
let native_font_replacement = Arc::new(NATIVE_FONT.to_vec());
for (key, plain_template) in resources.font_templates {
--- a/gfx/webrender/src/scene.rs
+++ b/gfx/webrender/src/scene.rs
@@ -48,17 +48,18 @@ impl SceneProperties {
) -> LayoutTransform {
match *property {
PropertyBinding::Value(value) => value,
PropertyBinding::Binding(ref key) => {
self.transform_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
- warn!("Property binding {:?} has an invalid value.", key);
+ warn!("Property binding has an invalid value.");
+ debug!("key={:?}", key);
LayoutTransform::identity()
})
}
}
}
/// Get the current value for a float property.
pub fn resolve_float(
@@ -68,17 +69,18 @@ impl SceneProperties {
) -> f32 {
match *property {
PropertyBinding::Value(value) => value,
PropertyBinding::Binding(ref key) => {
self.float_properties
.get(&key.id)
.cloned()
.unwrap_or_else(|| {
- warn!("Property binding {:?} has an invalid value.", key);
+ warn!("Property binding has an invalid value.");
+ debug!("key={:?}", key);
default_value
})
}
}
}
}
/// A representation of the layout within the display port for a given document or iframe.
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -194,17 +194,17 @@ impl<T: RenderTarget> RenderTargetList<T
.last_mut()
.and_then(|target| target.allocate(alloc_size));
let origin = match existing_origin {
Some(origin) => origin,
None => {
let mut new_target = T::new(Some(self.max_size), self.screen_size);
let origin = new_target.allocate(alloc_size).expect(&format!(
- "Each render task must allocate <= size of one target! ({:?})",
+ "Each render task must allocate <= size of one target! ({})",
alloc_size
));
self.targets.push(new_target);
origin
}
};
(origin, RenderTargetIndex(self.targets.len() - 1))
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -1,14 +1,14 @@
/* 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 {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceUintRect};
-use {DeviceUintSize, FontInstanceKey, FontInstanceOptions};
+use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphKey, ImageData};
use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
use {NativeFontHandle, WorldPoint};
use app_units::Au;
use channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethods};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
@@ -249,17 +249,17 @@ impl Transaction {
phase: ScrollEventPhase,
) {
self.ops.push(DocumentMsg::Scroll(scroll_location, cursor, phase));
}
pub fn scroll_node_with_id(
&mut self,
origin: LayoutPoint,
- id: ClipId,
+ id: IdType,
clamp: ScrollClamping,
) {
self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp));
}
pub fn set_page_zoom(&mut self, page_zoom: ZoomFactor) {
self.ops.push(DocumentMsg::SetPageZoom(page_zoom));
}
@@ -379,23 +379,29 @@ pub enum DocumentMsg {
RemovePipeline(PipelineId),
EnableFrameOutput(PipelineId, bool),
SetWindowParameters {
window_size: DeviceUintSize,
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
},
Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
- ScrollNodeWithId(LayoutPoint, ClipId, ScrollClamping),
+ ScrollNodeWithId(LayoutPoint, IdType, ScrollClamping),
TickScrollingBounce,
- GetScrollNodeState(MsgSender<Vec<ScrollLayerState>>),
+ GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
GenerateFrame,
UpdateDynamicProperties(DynamicProperties),
}
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+pub enum IdType {
+ ExternalScrollId(ExternalScrollId),
+ ClipId(ClipId),
+}
+
impl fmt::Debug for DocumentMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
DocumentMsg::SetDisplayList { .. } => "DocumentMsg::SetDisplayList",
DocumentMsg::HitTest(..) => "DocumentMsg::HitTest",
DocumentMsg::SetPageZoom(..) => "DocumentMsg::SetPageZoom",
DocumentMsg::SetPinchZoom(..) => "DocumentMsg::SetPinchZoom",
DocumentMsg::SetPan(..) => "DocumentMsg::SetPan",
@@ -420,16 +426,27 @@ bitflags!{
// Note: capturing `FRAME` without `SCENE` is not currently supported.
#[derive(Deserialize, Serialize)]
pub struct CaptureBits: u8 {
const SCENE = 0x1;
const FRAME = 0x2;
}
}
+bitflags!{
+ /// Mask for clearing caches in debug commands.
+ #[derive(Deserialize, Serialize)]
+ pub struct ClearCache: u8 {
+ const IMAGES = 0x1;
+ const GLYPHS = 0x2;
+ const GLYPH_DIMENSIONS = 0x4;
+ const RENDER_TASKS = 0x8;
+ }
+}
+
/// Information about a loaded capture of each document
/// that is returned by `RenderBackend`.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CapturedDocument {
pub document_id: DocumentId,
pub root_pipeline_id: Option<PipelineId>,
pub window_size: DeviceUintSize,
}
@@ -443,32 +460,36 @@ pub enum DebugCommand {
/// Display intermediate render targets on screen.
EnableRenderTargetDebug(bool),
/// Display alpha primitive rects.
EnableAlphaRectsDebug(bool),
/// Display GPU timing results.
EnableGpuTimeQueries(bool),
/// Display GPU overdraw results
EnableGpuSampleQueries(bool),
+ /// Configure if dual-source blending is used, if available.
+ EnableDualSourceBlending(bool),
/// Fetch current documents and display lists.
FetchDocuments,
/// Fetch current passes and batches.
FetchPasses,
/// Fetch clip-scroll tree.
FetchClipScrollTree,
/// Fetch render tasks.
FetchRenderTasks,
/// Fetch screenshot.
FetchScreenshot,
/// Save a capture of all the documents state.
SaveCapture(PathBuf, CaptureBits),
/// Load a capture of all the documents state.
LoadCapture(PathBuf, MsgSender<CapturedDocument>),
- /// Configure if dual-source blending is used, if available.
- EnableDualSourceBlending(bool),
+ /// Clear cached resources, forcing them to be re-uploaded from templates.
+ ClearCaches(ClearCache),
+ /// Invalidate GPU cache, forcing the update from the CPU mirror.
+ InvalidateGpuCache,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum ApiMsg {
/// Add/remove/update images and fonts.
UpdateResources(ResourceUpdates),
/// Gets the glyph dimensions
GetGlyphDimensions(
@@ -793,17 +814,17 @@ impl RenderApi {
DocumentMsg::SetWindowParameters {
window_size,
inner_rect,
device_pixel_ratio,
},
);
}
- pub fn get_scroll_node_state(&self, document_id: DocumentId) -> Vec<ScrollLayerState> {
+ pub fn get_scroll_node_state(&self, document_id: DocumentId) -> Vec<ScrollNodeState> {
let (tx, rx) = channel::msg_channel().unwrap();
self.send(document_id, DocumentMsg::GetScrollNodeState(tx));
rx.recv().unwrap()
}
/// Save a capture of the current frame state for debugging.
pub fn save_capture(&self, path: PathBuf, bits: CaptureBits) {
let msg = ApiMsg::DebugCommand(DebugCommand::SaveCapture(path, bits));
@@ -843,18 +864,18 @@ pub enum ScrollEventPhase {
/// The user performed a scroll. The Boolean flag indicates whether the user's fingers are
/// down, if a touchpad is in use. (If false, the event is a touchpad fling.)
Move(bool),
/// The user ended scrolling.
End,
}
#[derive(Clone, Deserialize, Serialize)]
-pub struct ScrollLayerState {
- pub id: ClipId,
+pub struct ScrollNodeState {
+ pub id: ExternalScrollId,
pub scroll_offset: LayoutVector2D,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum ScrollLocation {
/// Scroll by a certain amount.
Delta(LayoutVector2D),
/// Scroll to very top of element.
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -209,16 +209,17 @@ pub struct StickyFrameDisplayItem {
pub enum ScrollSensitivity {
ScriptAndInputEvents,
Script,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ScrollFrameDisplayItem {
pub id: ClipId,
+ pub external_id: Option<ExternalScrollId>,
pub image_mask: Option<ImageMask>,
pub scroll_sensitivity: ScrollSensitivity,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct RectangleDisplayItem {
pub color: ColorF,
}
@@ -746,54 +747,55 @@ impl ComplexClipRegion {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ClipChainId(pub u64, pub PipelineId);
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ClipId {
Clip(u64, PipelineId),
ClipChain(ClipChainId),
- ClipExternalId(u64, PipelineId),
DynamicallyAddedNode(u64, PipelineId),
}
impl ClipId {
pub fn root_scroll_node(pipeline_id: PipelineId) -> ClipId {
ClipId::Clip(0, pipeline_id)
}
pub fn root_reference_frame(pipeline_id: PipelineId) -> ClipId {
ClipId::DynamicallyAddedNode(0, pipeline_id)
}
- pub fn new(id: u64, pipeline_id: PipelineId) -> ClipId {
- // We do this because it is very easy to create accidentally create something that
- // seems like a root scroll node, but isn't one.
- if id == 0 {
- return ClipId::root_scroll_node(pipeline_id);
- }
-
- ClipId::ClipExternalId(id, pipeline_id)
- }
-
pub fn pipeline_id(&self) -> PipelineId {
match *self {
ClipId::Clip(_, pipeline_id) |
ClipId::ClipChain(ClipChainId(_, pipeline_id)) |
- ClipId::ClipExternalId(_, pipeline_id) |
ClipId::DynamicallyAddedNode(_, pipeline_id) => pipeline_id,
}
}
- pub fn external_id(&self) -> Option<u64> {
- match *self {
- ClipId::ClipExternalId(id, _) => Some(id),
- _ => None,
- }
- }
-
pub fn is_root_scroll_node(&self) -> bool {
match *self {
ClipId::Clip(0, _) => true,
_ => false,
}
}
}
+
+/// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which
+/// may change from frame to frame. This should be unique within a pipeline. WebRender makes no
+/// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of
+/// every pipeline, which always has an external id.
+///
+/// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll
+/// offsets between different sets of ClipScrollNodes which are ScrollFrames.
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+pub struct ExternalScrollId(pub u64, pub PipelineId);
+
+impl ExternalScrollId {
+ pub fn pipeline_id(&self) -> PipelineId {
+ self.1
+ }
+
+ pub fn is_root(&self) -> bool {
+ self.0 == 0
+ }
+}
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -1,18 +1,18 @@
/* 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 {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode};
use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId};
-use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, FilterOp, FontInstanceKey, GlyphInstance};
-use {GlyphOptions, Gradient, GradientDisplayItem, GradientStop, IframeDisplayItem};
-use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo, LayoutPoint};
-use {LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
+use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp};
+use {FontInstanceKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem, GradientStop};
+use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo};
+use {LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyOffsetBounds};
use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem};
use bincode;
use euclid::SideOffsets2D;
use serde::{Deserialize, Serialize};
@@ -187,17 +187,18 @@ impl<'a> BuiltDisplayListIter<'a> {
pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
BuiltDisplayListIter {
list,
data: &data,
cur_item: DisplayItem {
// Dummy data, will be overwritten by `next`
item: SpecificDisplayItem::PopStackingContext,
- clip_and_scroll: ClipAndScrollInfo::simple(ClipId::new(0, PipelineId::dummy())),
+ clip_and_scroll:
+ ClipAndScrollInfo::simple(ClipId::root_scroll_node(PipelineId::dummy())),
info: LayoutPrimitiveInfo::new(LayoutRect::zero()),
},
cur_stops: ItemRange::default(),
cur_glyphs: ItemRange::default(),
cur_filters: ItemRange::default(),
cur_clip_chain_items: ItemRange::default(),
cur_complex_clip: (ItemRange::default(), 0),
peeking: Peek::NotPeeking,
@@ -1332,69 +1333,68 @@ impl DisplayListBuilder {
pub fn push_stops(&mut self, stops: &[GradientStop]) {
if stops.is_empty() {
return;
}
self.push_new_empty_item(SpecificDisplayItem::SetGradientStops);
self.push_iter(stops);
}
- fn generate_clip_id(&mut self, id: Option<ClipId>) -> ClipId {
- id.unwrap_or_else(|| {
- self.next_clip_id += 1;
- ClipId::Clip(self.next_clip_id - 1, self.pipeline_id)
- })
+ fn generate_clip_id(&mut self) -> ClipId {
+ self.next_clip_id += 1;
+ ClipId::Clip(self.next_clip_id - 1, self.pipeline_id)
}
fn generate_clip_chain_id(&mut self) -> ClipChainId {
self.next_clip_chain_id += 1;
ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id)
}
pub fn define_scroll_frame<I>(
&mut self,
- id: Option<ClipId>,
+ external_id: Option<ExternalScrollId>,
content_rect: LayoutRect,
clip_rect: LayoutRect,
complex_clips: I,
image_mask: Option<ImageMask>,
scroll_sensitivity: ScrollSensitivity,
) -> ClipId
where
I: IntoIterator<Item = ComplexClipRegion>,
I::IntoIter: ExactSizeIterator + Clone,
{
let parent = self.clip_stack.last().unwrap().scroll_node_id;
self.define_scroll_frame_with_parent(
- id,
parent,
+ external_id,
content_rect,
clip_rect,
complex_clips,
image_mask,
scroll_sensitivity)
}
pub fn define_scroll_frame_with_parent<I>(
&mut self,
- id: Option<ClipId>,
parent: ClipId,
+ external_id: Option<ExternalScrollId>,
content_rect: LayoutRect,
clip_rect: LayoutRect,
complex_clips: I,
image_mask: Option<ImageMask>,
scroll_sensitivity: ScrollSensitivity,
) -> ClipId
where
I: IntoIterator<Item = ComplexClipRegion>,
I::IntoIter: ExactSizeIterator + Clone,
{
- let id = self.generate_clip_id(id);
+ let id = self.generate_clip_id();
let item = SpecificDisplayItem::ScrollFrame(ScrollFrameDisplayItem {
id,
+ external_id,
image_mask,
scroll_sensitivity,
});
let info = LayoutPrimitiveInfo::with_clip_rect(content_rect, clip_rect);
let scrollinfo = ClipAndScrollInfo::simple(parent);
self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
self.push_iter(complex_clips);
@@ -1413,71 +1413,68 @@ impl DisplayListBuilder {
let id = self.generate_clip_chain_id();
self.push_new_empty_item(SpecificDisplayItem::ClipChain(ClipChainItem { id, parent}));
self.push_iter(clips);
id
}
pub fn define_clip<I>(
&mut self,
- id: Option<ClipId>,
clip_rect: LayoutRect,
complex_clips: I,
image_mask: Option<ImageMask>,
) -> ClipId
where
I: IntoIterator<Item = ComplexClipRegion>,
I::IntoIter: ExactSizeIterator + Clone,
{
let parent = self.clip_stack.last().unwrap().scroll_node_id;
self.define_clip_with_parent(
- id,
parent,
clip_rect,
complex_clips,
- image_mask)
+ image_mask
+ )
}
pub fn define_clip_with_parent<I>(
&mut self,
- id: Option<ClipId>,
parent: ClipId,
clip_rect: LayoutRect,
complex_clips: I,
image_mask: Option<ImageMask>,
) -> ClipId
where
I: IntoIterator<Item = ComplexClipRegion>,
I::IntoIter: ExactSizeIterator + Clone,
{
- let id = self.generate_clip_id(id);
+ let id = self.generate_clip_id();
let item = SpecificDisplayItem::Clip(ClipDisplayItem {
id,
image_mask: image_mask,
});
let info = LayoutPrimitiveInfo::new(clip_rect);
let scrollinfo = ClipAndScrollInfo::simple(parent);
self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
self.push_iter(complex_clips);
id
}
pub fn define_sticky_frame(
&mut self,
- id: Option<ClipId>,
frame_rect: LayoutRect,
margins: SideOffsets2D<Option<f32>>,
vertical_offset_bounds: StickyOffsetBounds,
horizontal_offset_bounds: StickyOffsetBounds,
previously_applied_offset: LayoutVector2D,
) -> ClipId {
- let id = self.generate_clip_id(id);
+ let id = self.generate_clip_id();
let item = SpecificDisplayItem::StickyFrame(StickyFrameDisplayItem {
id,
margins,
vertical_offset_bounds,
horizontal_offset_bounds,
previously_applied_offset,
});
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-b6e69a8efbcd8dc3e0c0a8a9925e6a9355635de3
+e772c3cb8ea0a35e6477e9dc8dd2144e2de87b56
--- a/gfx/wrench/src/rawtest.rs
+++ b/gfx/wrench/src/rawtest.rs
@@ -426,26 +426,32 @@ impl<'a> RawtestHarness<'a> {
DeviceUintPoint::new(0, window_size.height - test_size.height),
test_size,
);
let layout_size = LayoutSize::new(400., 400.);
let mut do_test = |should_try_and_fail| {
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
- let clip = builder.define_clip(None, rect(110., 120., 200., 200.),
- None::<ComplexClipRegion>, None);
+ let clip = builder.define_clip(
+ rect(110., 120., 200., 200.),
+ None::<ComplexClipRegion>,
+ None
+ );
builder.push_clip_id(clip);
builder.push_rect(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
ColorF::new(0.0, 0.0, 1.0, 1.0));
if should_try_and_fail {
builder.save();
- let clip = builder.define_clip(None, rect(80., 80., 90., 90.),
- None::<ComplexClipRegion>, None);
+ let clip = builder.define_clip(
+ rect(80., 80., 90., 90.),
+ None::<ComplexClipRegion>,
+ None
+ );
builder.push_clip_id(clip);
builder.push_rect(&PrimitiveInfo::new(rect(110., 110., 50., 50.)),
ColorF::new(0.0, 1.0, 0.0, 1.0));
builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
Shadow {
offset: LayoutVector2D::new(1.0, 1.0),
blur_radius: 1.0,
color: ColorF::new(0.0, 0.0, 0.0, 1.0),
@@ -453,18 +459,21 @@ impl<'a> RawtestHarness<'a> {
builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)),
0.0, LineOrientation::Horizontal,
&ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid);
builder.restore();
}
{
builder.save();
- let clip = builder.define_clip(None, rect(80., 80., 100., 100.),
- None::<ComplexClipRegion>, None);
+ let clip = builder.define_clip(
+ rect(80., 80., 100., 100.),
+ None::<ComplexClipRegion>,
+ None
+ );
builder.push_clip_id(clip);
builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)),
ColorF::new(0.0, 0.0, 1.0, 1.0));
builder.pop_clip_id();
builder.clear_save();
}
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -519,17 +519,17 @@ impl Wrench {
// operations into separate transactions for mysterious -but probably related
// to the other comment below- reasons.
self.api.send_transaction(self.document_id, txn);
let mut txn = Transaction::new();
for (id, offset) in scroll_offsets {
txn.scroll_node_with_id(
*offset,
- *id,
+ IdType::ClipId(*id),
ScrollClamping::NoClamping,
);
}
// TODO(nical) - Wrench does not notify frames when there was scrolling
// in the transaction (See RenderNotifier implementations). If we don't
// generate a frame after scrolling, wrench just stops and some tests
// will time out.
// I suppose this was to avoid taking the snapshot after scrolling if
--- a/gfx/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wrench/src/yaml_frame_reader.rs
@@ -1268,21 +1268,23 @@ impl YamlFrameReader {
) {
let clip_rect = yaml["bounds"]
.as_rect()
.expect("scroll frame must have a bounds");
let content_size = yaml["content-size"].as_size().unwrap_or(clip_rect.size);
let content_rect = LayerRect::new(clip_rect.origin, content_size);
let numeric_id = yaml["id"].as_i64().map(|id| id as u64);
+
let complex_clips = self.to_complex_clip_regions(&yaml["complex"]);
let image_mask = self.to_image_mask(&yaml["image-mask"], wrench);
+ let external_id = numeric_id.map(|id| ExternalScrollId(id as u64, dl.pipeline_id));
let real_id = dl.define_scroll_frame(
- None,
+ external_id,
content_rect,
clip_rect,
complex_clips,
image_mask,
ScrollSensitivity::Script,
);
if let Some(numeric_id) = numeric_id {
self.clip_id_map.insert(numeric_id, real_id);
@@ -1304,17 +1306,16 @@ impl YamlFrameReader {
dl: &mut DisplayListBuilder,
wrench: &mut Wrench,
yaml: &Yaml,
) {
let bounds = yaml["bounds"].as_rect().expect("sticky frame must have a bounds");
let numeric_id = yaml["id"].as_i64().map(|id| id as u64);
let real_id = dl.define_sticky_frame(
- None,
bounds,
SideOffsets2D::new(
yaml["margin-top"].as_f32(),
yaml["margin-right"].as_f32(),
yaml["margin-bottom"].as_f32(),
yaml["margin-left"].as_f32(),
),
self.to_sticky_offset_bounds(&yaml["vertical-offset-bounds"]),
@@ -1384,17 +1385,17 @@ impl YamlFrameReader {
}
pub fn handle_clip(&mut self, dl: &mut DisplayListBuilder, wrench: &mut Wrench, yaml: &Yaml) {
let clip_rect = yaml["bounds"].as_rect().expect("clip must have a bounds");
let numeric_id = yaml["id"].as_i64();
let complex_clips = self.to_complex_clip_regions(&yaml["complex"]);
let image_mask = self.to_image_mask(&yaml["image-mask"], wrench);
- let real_id = dl.define_clip(None, clip_rect, complex_clips, image_mask);
+ let real_id = dl.define_clip(clip_rect, complex_clips, image_mask);
if let Some(numeric_id) = numeric_id {
self.clip_id_map.insert(numeric_id as u64, real_id);
}
if !yaml["items"].is_badvalue() {
dl.push_clip_id(real_id);
self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]);
dl.pop_clip_id();