Bug 1440664 - Update webrender to commit 22b831c02479eea31821f49a0fac7dd699083557. r=jrmuizel

MozReview-Commit-ID: 38UtaEA1NuB

--HG--
extra : rebase_source : c35153e2303cdef27020687718623de2120d29bb
This commit is contained in:
Kartikaya Gupta 2018-03-01 16:49:20 -05:00
parent 06cca893ea
commit 62f9190877
52 changed files with 4462 additions and 3962 deletions

View File

@ -18,7 +18,7 @@ replay = ["webrender_api/deserialize", "ron", "serde"]
app_units = "0.6"
bincode = "0.9"
byteorder = "1.0"
euclid = "0.16"
euclid = "0.17"
fxhash = "0.2.1"
gleam = "0.4.20"
lazy_static = "1"
@ -29,7 +29,7 @@ rayon = "1"
webrender_api = {path = "../webrender_api"}
bitflags = "1.0"
thread_profiler = "0.1.1"
plane-split = "0.7"
plane-split = "0.8"
png = { optional = true, version = "0.11" }
smallvec = "0.6"
ws = { optional = true, version = "0.7.3" }

View File

@ -13,6 +13,7 @@ flat varying float vAmount;
flat varying int vOp;
flat varying mat4 vColorMat;
flat varying vec4 vColorOffset;
flat varying vec4 vUvClipBounds;
#ifdef WR_VERTEX_SHADER
@ -30,6 +31,10 @@ void brush_vs(
src_task.content_origin;
vUv = vec3(uv / texture_size, src_task.common_data.texture_layer_index);
vec2 uv0 = src_task.common_data.task_rect.p0;
vec2 uv1 = uv0 + src_task.common_data.task_rect.size;
vUvClipBounds = vec4(uv0, uv1) / texture_size.xyxy;
vOp = user_data.y;
float lumR = 0.2126;
@ -142,6 +147,10 @@ vec4 brush_fs() {
color = vColorMat * Cs + vColorOffset;
}
// Fail-safe to ensure that we don't sample outside the rendered
// portion of a blend source.
color.a *= point_inside_rect(vUv.xy, vUvClipBounds.xy, vUvClipBounds.zw);
// Pre-multiply the alpha into the output value.
color.rgb *= color.a;

View File

@ -2,7 +2,7 @@
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 0
#define VECS_PER_SPECIFIC_BRUSH 1
#include shared,prim_shared,brush
@ -12,9 +12,14 @@ varying vec2 vLocalPos;
varying vec3 vUv;
flat varying vec4 vUvBounds;
flat varying vec4 vColor;
flat varying vec2 vSelect;
#ifdef WR_VERTEX_SHADER
#define IMAGE_SOURCE_COLOR 0
#define IMAGE_SOURCE_ALPHA 1
#define IMAGE_SOURCE_MASK_FROM_COLOR 2
void brush_vs(
VertexInfo vi,
int prim_address,
@ -35,6 +40,7 @@ void brush_vs(
vec2 uv1 = res.uv_rect.p1;
vUv.z = res.layer;
vColor = res.color;
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
vUv.xy = mix(uv0, uv1, f);
@ -47,6 +53,18 @@ void brush_vs(
max(uv0, uv1) - vec2(0.5)
) / texture_size.xyxy;
switch (user_data.y) {
case IMAGE_SOURCE_COLOR:
vSelect = vec2(0.0, 0.0);
break;
case IMAGE_SOURCE_ALPHA:
vSelect = vec2(0.0, 1.0);
break;
case IMAGE_SOURCE_MASK_FROM_COLOR:
vSelect = vec2(1.0, 1.0);
break;
}
#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;
#endif
@ -57,7 +75,9 @@ void brush_vs(
vec4 brush_fs() {
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
vec4 color = TEX_SAMPLE(sColor0, vec3(uv, vUv.z));
vec4 texel = TEX_SAMPLE(sColor0, vec3(uv, vUv.z));
vec4 mask = mix(texel.rrrr, texel.aaaa, vSelect.x);
vec4 color = mix(texel, vColor * mask, vSelect.y);
#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);

View File

@ -1,64 +0,0 @@
/* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 1
#include shared,prim_shared,ellipse,brush
flat varying float vClipMode;
flat varying vec4 vClipCenter_Radius;
flat varying vec4 vLocalRect;
varying vec2 vLocalPos;
#ifdef WR_VERTEX_SHADER
struct BrushMaskCornerPrimitive {
vec2 radius;
float clip_mode;
};
BrushMaskCornerPrimitive fetch_primitive(int address) {
vec4 data = fetch_from_resource_cache_1(address);
return BrushMaskCornerPrimitive(data.xy, data.z);
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
ivec3 user_data,
PictureTask pic_task
) {
// Load the specific primitive.
BrushMaskCornerPrimitive prim = fetch_primitive(prim_address);
// Write clip parameters
vClipMode = prim.clip_mode;
vClipCenter_Radius = vec4(local_rect.p0 + prim.radius, prim.radius);
vLocalRect = vec4(local_rect.p0, local_rect.p0 + local_rect.size);
vLocalPos = vi.local_pos;
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 brush_fs() {
float d = 1.0;
// NOTE: The AA range must be computed outside the if statement,
// since otherwise the results can be undefined if the
// input function is not continuous. I have observed this
// as flickering behaviour on Intel GPUs.
float aa_range = compute_aa_range(vLocalPos);
// Check if in valid clip region.
if (vLocalPos.x < vClipCenter_Radius.x && vLocalPos.y < vClipCenter_Radius.y) {
// Apply ellipse clip on corner.
d = distance_to_ellipse(vLocalPos - vClipCenter_Radius.xy,
vClipCenter_Radius.zw,
aa_range);
d = distance_aa(aa_range, d);
}
return vec4(mix(d, 1.0 - d, vClipMode));
}
#endif

View File

@ -15,14 +15,10 @@ flat varying int vImageKind;
flat varying vec4 vUvBounds;
flat varying vec4 vUvBounds_NoClamp;
flat varying vec4 vParams;
#if defined WR_FEATURE_ALPHA_TARGET || defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
flat varying vec4 vColor;
#endif
#define BRUSH_PICTURE_SIMPLE 0
#define BRUSH_PICTURE_NINEPATCH 1
#define BRUSH_PICTURE_MIRROR 2
#ifdef WR_VERTEX_SHADER
@ -44,24 +40,6 @@ void brush_vs(
) {
vImageKind = user_data.y;
// TODO(gw): There's quite a bit of code duplication here,
// depending on which variation of brush image
// this is being used for. This is because only
// box-shadow pictures are currently supported
// as texture cacheable items. Once we port the
// drop-shadows and text-shadows to be cacheable,
// most of this code can be merged together.
#if defined WR_FEATURE_COLOR_TARGET || defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
BlurTask blur_task = fetch_blur_task(user_data.x);
vUv.z = blur_task.common_data.texture_layer_index;
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
#if defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
vColor = blur_task.color;
#endif
vec2 uv0 = blur_task.common_data.task_rect.p0;
vec2 src_size = blur_task.common_data.task_rect.size * blur_task.scale_factor;
vec2 uv1 = uv0 + blur_task.common_data.task_rect.size;
#else
Picture pic = fetch_picture(prim_address);
ImageResource res = fetch_image_resource(user_data.x);
vec2 texture_size = vec2(textureSize(sColor1, 0).xy);
@ -70,7 +48,6 @@ void brush_vs(
vec2 uv1 = res.uv_rect.p1;
vec2 src_size = (uv1 - uv0) * res.user_data.x;
vUv.z = res.layer;
#endif
// TODO(gw): In the future we'll probably draw these as segments
// with the brush shader. When that occurs, we can
@ -92,12 +69,6 @@ void brush_vs(
vParams.zw = (local_rect.size / local_src_size - 0.5);
break;
}
case BRUSH_PICTURE_MIRROR: {
vec2 local_src_size = src_size / uDevicePixelRatio;
vUv.xy = (vi.local_pos - local_rect.p0) / local_src_size;
vParams.xy = 0.5 * local_rect.size / local_src_size;
break;
}
default:
vUv.xy = vec2(0.0);
vParams = vec4(0.0);
@ -128,30 +99,11 @@ vec4 brush_fs() {
uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
break;
}
case BRUSH_PICTURE_MIRROR: {
// Mirror and stretch the box shadow corner over the entire
// primitives.
uv = vParams.xy - abs(vUv.xy - vParams.xy);
// Ensure that we don't fetch texels outside the box
// shadow corner. This can happen, for example, when
// drawing the outer parts of an inset box shadow.
uv = clamp(uv, vec2(0.0), vec2(1.0));
uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
break;
}
default:
uv = vec2(0.0);
}
#if defined WR_FEATURE_COLOR_TARGET
vec4 color = texture(sColor0, vec3(uv, vUv.z));
#elif defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
vec4 color = vColor * texture(sColor0, vec3(uv, vUv.z)).a;
#else
vec4 color = vColor * texture(sColor1, vec3(uv, vUv.z)).r;
#endif
#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);

View File

@ -21,6 +21,26 @@ in int aBlurRenderTaskAddress;
in int aBlurSourceTaskAddress;
in int aBlurDirection;
struct BlurTask {
RenderTaskCommonData common_data;
float blur_radius;
float scale_factor;
vec4 color;
};
BlurTask fetch_blur_task(int address) {
RenderTaskData task_data = fetch_render_task_data(address);
BlurTask task = BlurTask(
task_data.common_data,
task_data.data1.x,
task_data.data1.y,
task_data.data2
);
return task;
}
void main(void) {
BlurTask blur_task = fetch_blur_task(aBlurRenderTaskAddress);
RenderTaskCommonData src_task = fetch_render_task_common_data(aBlurSourceTaskAddress);

View File

@ -116,6 +116,14 @@ vec4[3] fetch_from_resource_cache_3(int address) {
);
}
vec4[3] fetch_from_resource_cache_3_direct(ivec2 address) {
return vec4[3](
TEXEL_FETCH(sResourceCache, address, 0, ivec2(0, 0)),
TEXEL_FETCH(sResourceCache, address, 0, ivec2(1, 0)),
TEXEL_FETCH(sResourceCache, address, 0, ivec2(2, 0))
);
}
vec4[4] fetch_from_resource_cache_4_direct(ivec2 address) {
return vec4[4](
TEXEL_FETCH(sResourceCache, address, 0, ivec2(0, 0)),
@ -261,26 +269,6 @@ PictureTask fetch_picture_task(int address) {
return task;
}
struct BlurTask {
RenderTaskCommonData common_data;
float blur_radius;
float scale_factor;
vec4 color;
};
BlurTask fetch_blur_task(int address) {
RenderTaskData task_data = fetch_render_task_data(address);
BlurTask task = BlurTask(
task_data.common_data,
task_data.data1.x,
task_data.data1.y,
task_data.data2
);
return task;
}
struct ClipArea {
RenderTaskCommonData common_data;
vec2 screen_origin;
@ -688,19 +676,20 @@ struct ImageResource {
RectWithEndpoint uv_rect;
float layer;
vec3 user_data;
vec4 color;
};
ImageResource fetch_image_resource(int address) {
//Note: number of blocks has to match `renderer::BLOCKS_PER_UV_RECT`
vec4 data[2] = fetch_from_resource_cache_2(address);
vec4 data[3] = fetch_from_resource_cache_3(address);
RectWithEndpoint uv_rect = RectWithEndpoint(data[0].xy, data[0].zw);
return ImageResource(uv_rect, data[1].x, data[1].yzw);
return ImageResource(uv_rect, data[1].x, data[1].yzw, data[2]);
}
ImageResource fetch_image_resource_direct(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
vec4 data[3] = fetch_from_resource_cache_3_direct(address);
RectWithEndpoint uv_rect = RectWithEndpoint(data[0].xy, data[0].zw);
return ImageResource(uv_rect, data[1].x, data[1].yzw);
return ImageResource(uv_rect, data[1].x, data[1].yzw, data[2]);
}
struct TextRun {

View File

@ -46,3 +46,8 @@ bool rect_inside_rect(RectWithSize little, RectWithSize big) {
return all(lessThanEqual(vec4(big.p0, little.p0 + little.size),
vec4(little.p0, big.p0 + big.size)));
}
float point_inside_rect(vec2 p, vec2 p0, vec2 p1) {
vec2 s = step(p0, p) - step(p1, p);
return s.x * s.y;
}

View File

@ -12,7 +12,7 @@ use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress};
use gpu_types::{BrushFlags, BrushImageKind, BrushInstance, ClipChainRectIndex};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
@ -25,7 +25,7 @@ use renderer::{BlendMode, ImageBufferKind};
use renderer::BLOCKS_PER_UV_RECT;
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
use std::{usize, f32, i32};
use tiling::{RenderTargetContext, RenderTargetKind};
use tiling::{RenderTargetContext};
use util::{MatrixHelpers, TransformedRectKind};
// Special sentinel value recognized by the shader. It is considered to be
@ -46,25 +46,16 @@ pub enum TransformBatchKind {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BrushImageSourceKind {
Alpha,
Color,
ColorAlphaMask,
}
impl BrushImageSourceKind {
pub fn from_render_target_kind(render_target_kind: RenderTargetKind) -> BrushImageSourceKind {
match render_target_kind {
RenderTargetKind::Color => BrushImageSourceKind::Color,
RenderTargetKind::Alpha => BrushImageSourceKind::Alpha,
}
}
Color = 0,
//Alpha = 1, // Unused for now, but left here as shaders need to match.
ColorAlphaMask = 2,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BrushBatchKind {
Picture(BrushImageSourceKind),
Picture,
Solid,
Line,
Image(ImageBufferKind),
@ -310,12 +301,19 @@ impl BatchList {
}
}
fn add_bounding_rect(
&mut self,
task_relative_bounding_rect: &DeviceIntRect,
) {
self.combined_bounding_rect = self.combined_bounding_rect.union(task_relative_bounding_rect);
}
pub fn get_suitable_batch(
&mut self,
key: BatchKey,
task_relative_bounding_rect: &DeviceIntRect,
) -> &mut Vec<PrimitiveInstance> {
self.combined_bounding_rect = self.combined_bounding_rect.union(task_relative_bounding_rect);
self.add_bounding_rect(task_relative_bounding_rect);
match key.blend_mode {
BlendMode::None => {
@ -486,7 +484,7 @@ impl AlphaBatchBuilder {
// Add each run in this picture to the batch.
for run in &pic.runs {
let scroll_node = &ctx.clip_scroll_tree.nodes[&run.clip_and_scroll.scroll_node_id];
let scroll_node = &ctx.clip_scroll_tree.nodes[run.clip_and_scroll.scroll_node_id.0];
let scroll_id = scroll_node.node_data_index;
self.add_run_to_batch(
run,
@ -904,9 +902,7 @@ impl AlphaBatchBuilder {
}
PictureKind::BoxShadow { image_kind, .. } => {
let textures = BatchTextures::color(cache_item.texture_id);
let kind = BrushBatchKind::Picture(
BrushImageSourceKind::from_render_target_kind(picture.target_kind()),
);
let kind = BrushBatchKind::Picture;
self.add_brush_to_batch(
&picture.brush,
@ -936,12 +932,15 @@ impl AlphaBatchBuilder {
match picture.kind {
PictureKind::TextShadow { .. } => {
let kind = BatchKind::Brush(
BrushBatchKind::Picture(
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
@ -953,8 +952,8 @@ impl AlphaBatchBuilder {
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
cache_task_address.0 as i32,
BrushImageKind::Simple as i32,
uv_rect_address,
BrushImageSourceKind::Color as i32,
0,
],
};
@ -967,7 +966,7 @@ impl AlphaBatchBuilder {
composite_mode,
secondary_render_task_id,
is_in_3d_context,
reference_frame_id,
reference_frame_index,
real_local_rect,
ref extra_gpu_data_handle,
..
@ -979,7 +978,7 @@ impl AlphaBatchBuilder {
// Push into parent plane splitter.
let real_xf = &ctx.clip_scroll_tree
.nodes[&reference_frame_id]
.nodes[reference_frame_index.0]
.world_content_transform
.into();
let polygon = make_polygon(
@ -1028,10 +1027,14 @@ impl AlphaBatchBuilder {
}
FilterOp::DropShadow(offset, _, _) => {
let kind = BatchKind::Brush(
BrushBatchKind::Picture(BrushImageSourceKind::ColorAlphaMask),
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
@ -1043,8 +1046,8 @@ impl AlphaBatchBuilder {
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
cache_task_address.0 as i32,
BrushImageKind::Simple as i32,
uv_rect_address,
BrushImageSourceKind::ColorAlphaMask as i32,
0,
],
};
@ -1246,6 +1249,8 @@ impl AlphaBatchBuilder {
user_data,
};
self.batch_list.add_bounding_rect(task_relative_bounding_rect);
match brush.segment_desc {
Some(ref segment_desc) => {
let alpha_batch_key = BatchKey {
@ -1339,7 +1344,11 @@ impl BrushPrimitive {
Some((
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[cache_item.uv_rect_handle.as_int(gpu_cache), 0, 0],
[
cache_item.uv_rect_handle.as_int(gpu_cache),
BrushImageSourceKind::Color as i32,
0,
],
))
}
}

View File

@ -6,7 +6,7 @@ use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF, LayerPoin
use api::{LayerPrimitiveInfo, LayerRect, LayerSize, NormalBorder, RepeatMode, TexelRect};
use clip::ClipSource;
use ellipse::Ellipse;
use frame_builder::FrameBuilder;
use display_list_flattener::DisplayListFlattener;
use gpu_cache::GpuDataRequest;
use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor};
use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
@ -279,7 +279,7 @@ pub fn ensure_no_corner_overlap(
}
}
impl FrameBuilder {
impl<'a> DisplayListFlattener<'a> {
fn add_normal_border_primitive(
&mut self,
info: &LayerPrimitiveInfo,

View File

@ -7,13 +7,13 @@ use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, L
use api::PipelineId;
use app_units::Au;
use clip::ClipSource;
use frame_builder::FrameBuilder;
use display_list_flattener::DisplayListFlattener;
use gpu_types::BrushImageKind;
use prim_store::{BrushKind, BrushMaskKind, BrushPrimitive, PrimitiveContainer};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveContainer};
use prim_store::ScrollNodeAndClipChain;
use picture::PicturePrimitive;
use util::RectHelpers;
use render_task::MAX_BLUR_STD_DEVIATION;
use util::RectHelpers;
// The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels.
pub const BLUR_SAMPLE_SCALE: f32 = 3.0;
@ -22,11 +22,6 @@ pub const BLUR_SAMPLE_SCALE: f32 = 3.0;
// Taken from https://searchfox.org/mozilla-central/rev/c633ffa4c4611f202ca11270dcddb7b29edddff8/layout/painting/nsCSSRendering.cpp#4412
pub const MAX_BLUR_RADIUS : f32 = 300.;
// The amount of padding added to the border corner drawn in the box shadow
// mask. This ensures that we get a few pixels past the corner that can be
// blurred without being affected by the border radius.
pub const MASK_CORNER_PADDING: f32 = 4.0;
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -48,7 +43,7 @@ pub struct BoxShadowCacheKey {
pub clip_mode: BoxShadowClipMode,
}
impl FrameBuilder {
impl<'a> DisplayListFlattener<'a> {
pub fn add_box_shadow(
&mut self,
pipeline_id: PipelineId,
@ -171,68 +166,50 @@ impl FrameBuilder {
let mut width;
let mut height;
let brush_prim;
let corner_size = shadow_radius.is_uniform_size();
let mut image_kind;
let mut image_kind = BrushImageKind::NinePatch;
if !shadow_rect.is_well_formed_and_nonempty() {
return;
}
// If the outset box shadow has a uniform corner side, we can
// just blur the top left corner, and stretch / mirror that
// across the primitive.
if let Some(corner_size) = corner_size {
image_kind = BrushImageKind::Mirror;
width = MASK_CORNER_PADDING + corner_size.width.max(BLUR_SAMPLE_SCALE * blur_radius);
height = MASK_CORNER_PADDING + corner_size.height.max(BLUR_SAMPLE_SCALE * blur_radius);
// Create a minimal size primitive mask to blur. In this
// case, we ensure the size of each corner is the same,
// to simplify the shader logic that stretches the blurred
// result across the primitive.
let max_width = shadow_radius.top_left.width
.max(shadow_radius.bottom_left.width)
.max(shadow_radius.top_right.width)
.max(shadow_radius.bottom_right.width);
let max_height = shadow_radius.top_left.height
.max(shadow_radius.bottom_left.height)
.max(shadow_radius.top_right.height)
.max(shadow_radius.bottom_right.height);
brush_prim = BrushPrimitive::new(
BrushKind::Mask {
clip_mode: brush_clip_mode,
kind: BrushMaskKind::Corner(corner_size),
},
None,
);
} else {
// Create a minimal size primitive mask to blur. In this
// case, we ensure the size of each corner is the same,
// to simplify the shader logic that stretches the blurred
// result across the primitive.
image_kind = BrushImageKind::NinePatch;
let max_width = shadow_radius.top_left.width
.max(shadow_radius.bottom_left.width)
.max(shadow_radius.top_right.width)
.max(shadow_radius.bottom_right.width);
let max_height = shadow_radius.top_left.height
.max(shadow_radius.bottom_left.height)
.max(shadow_radius.top_right.height)
.max(shadow_radius.bottom_right.height);
width = 2.0 * max_width + BLUR_SAMPLE_SCALE * blur_radius;
height = 2.0 * max_height + BLUR_SAMPLE_SCALE * blur_radius;
width = 2.0 * max_width + BLUR_SAMPLE_SCALE * blur_radius;
height = 2.0 * max_height + BLUR_SAMPLE_SCALE * blur_radius;
// If the width or height ends up being bigger than the original
// primitive shadow rect, just blur the entire rect and draw that
// as a simple blit.
if width > prim_info.rect.size.width || height > prim_info.rect.size.height {
image_kind = BrushImageKind::Simple;
width = prim_info.rect.size.width + spread_amount * 2.0;
height = prim_info.rect.size.height + spread_amount * 2.0;
}
// If the width or height ends up being bigger than the original
// primitive shadow rect, just blur the entire rect and draw that
// as a simple blit.
if width > prim_info.rect.size.width || height > prim_info.rect.size.height {
image_kind = BrushImageKind::Simple;
width = prim_info.rect.size.width + spread_amount * 2.0;
height = prim_info.rect.size.height + spread_amount * 2.0;
}
let clip_rect = LayerRect::new(
LayerPoint::zero(),
LayerSize::new(width, height)
);
let clip_rect = LayerRect::new(
LayerPoint::zero(),
LayerSize::new(width, height)
);
brush_prim = BrushPrimitive::new(
BrushKind::Mask {
clip_mode: brush_clip_mode,
kind: BrushMaskKind::RoundedRect(clip_rect, shadow_radius),
},
None,
);
};
brush_prim = BrushPrimitive::new(
BrushKind::Mask {
clip_mode: brush_clip_mode,
rect: clip_rect,
radii: shadow_radius,
},
None,
);
// Construct a mask primitive to add to the picture.
let brush_rect = LayerRect::new(LayerPoint::zero(),
@ -307,7 +284,8 @@ impl FrameBuilder {
let brush_prim = BrushPrimitive::new(
BrushKind::Mask {
clip_mode: brush_clip_mode,
kind: BrushMaskKind::RoundedRect(clip_rect, shadow_radius),
rect: clip_rect,
radii: shadow_radius,
},
None,
);

View File

@ -14,7 +14,7 @@ use prim_store::{ClipData, ImageMaskData};
use resource_cache::{ImageRequest, ResourceCache};
use util::{LayerToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
use util::extract_inner_rect_safe;
use std::rc::Rc;
use std::sync::Arc;
pub type ClipStore = FreeList<ClipSources>;
pub type ClipSourcesHandle = FreeListHandle<ClipSources>;
@ -353,7 +353,7 @@ pub fn rounded_rectangle_contains_point(point: &LayoutPoint,
true
}
pub type ClipChainNodeRef = Option<Rc<ClipChainNode>>;
pub type ClipChainNodeRef = Option<Arc<ClipChainNode>>;
#[derive(Debug, Clone)]
pub struct ClipChainNode {
@ -382,29 +382,15 @@ impl ClipChain {
}
}
pub fn new_with_added_node(
&self,
work_item: ClipWorkItem,
local_clip_rect: LayerRect,
screen_outer_rect: DeviceIntRect,
screen_inner_rect: DeviceIntRect,
) -> ClipChain {
pub fn new_with_added_node(&self, new_node: &ClipChainNode) -> ClipChain {
// If the new node's inner rectangle completely surrounds our outer rectangle,
// we can discard the new node entirely since it isn't going to affect anything.
if screen_inner_rect.contains_rect(&self.combined_outer_screen_rect) {
if new_node.screen_inner_rect.contains_rect(&self.combined_outer_screen_rect) {
return self.clone();
}
let new_node = ClipChainNode {
work_item,
local_clip_rect,
screen_outer_rect,
screen_inner_rect,
prev: None,
};
let mut new_chain = self.clone();
new_chain.add_node(new_node);
new_chain.add_node(new_node.clone());
new_chain
}
@ -425,7 +411,7 @@ impl ClipChain {
self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero);
self.nodes = Some(Rc::new(new_node));
self.nodes = Some(Arc::new(new_node));
}
}
@ -434,7 +420,7 @@ pub struct ClipChainNodeIter {
}
impl Iterator for ClipChainNodeIter {
type Item = Rc<ClipChainNode>;
type Item = Arc<ClipChainNode>;
fn next(&mut self) -> ClipChainNodeRef {
let previous = self.current.clone();

View File

@ -2,16 +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::{ClipId, DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, LayerRect};
use api::{LayerSize, LayerVector2D, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding};
use api::{DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayerVector2D, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
use api::WorldPoint;
use clip::{ClipChain, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformUpdateState};
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
use clip_scroll_tree::TransformUpdateState;
use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
@ -58,7 +59,12 @@ pub enum NodeType {
/// Other nodes just do clipping, but no transformation.
Clip {
handle: ClipSourcesHandle,
clip_chain_index: ClipChainIndex
clip_chain_index: ClipChainIndex,
/// A copy of the ClipChainNode this node would produce. We need to keep a copy,
/// because the ClipChain may not contain our node if is optimized out, but API
/// defined ClipChains will still need to access it.
clip_chain_node: Option<ClipChainNode>,
},
/// Transforms it's content, but doesn't clip it. Can also be adjusted
@ -70,6 +76,11 @@ pub enum NodeType {
/// 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),
/// An empty node, used to pad the ClipScrollTree's array of nodes so that
/// we can immediately use each assigned ClipScrollNodeIndex. After display
/// list flattening this node type should never be used.
Empty,
}
impl NodeType {
@ -101,10 +112,10 @@ pub struct ClipScrollNode {
pub pipeline_id: PipelineId,
/// Parent layer. If this is None, we are the root node.
pub parent: Option<ClipId>,
pub parent: Option<ClipScrollNodeIndex>,
/// Child layers
pub children: Vec<ClipId>,
pub children: Vec<ClipScrollNodeIndex>,
/// The type of this node and any data associated with that node type.
pub node_type: NodeType,
@ -124,13 +135,13 @@ pub struct ClipScrollNode {
/// A linear ID / index of this clip-scroll node. Used as a reference to
/// pass to shaders, to allow them to fetch a given clip-scroll node.
pub node_data_index: ClipScrollNodeIndex,
pub node_data_index: GPUClipScrollNodeIndex,
}
impl ClipScrollNode {
pub fn new(
pipeline_id: PipelineId,
parent_id: Option<ClipId>,
parent_index: Option<ClipScrollNodeIndex>,
rect: &LayerRect,
node_type: NodeType
) -> Self {
@ -138,20 +149,24 @@ impl ClipScrollNode {
local_viewport_rect: *rect,
world_viewport_transform: LayerToWorldFastTransform::identity(),
world_content_transform: LayerToWorldFastTransform::identity(),
parent: parent_id,
parent: parent_index,
children: Vec::new(),
pipeline_id,
node_type: node_type,
invertible: true,
coordinate_system_id: CoordinateSystemId(0),
coordinate_system_relative_transform: LayerFastTransform::identity(),
node_data_index: ClipScrollNodeIndex(0),
node_data_index: GPUClipScrollNodeIndex(0),
}
}
pub fn empty() -> ClipScrollNode {
ClipScrollNode::new(PipelineId::dummy(), None, &LayerRect::zero(), NodeType::Empty)
}
pub fn new_scroll_frame(
pipeline_id: PipelineId,
parent_id: ClipId,
parent_index: ClipScrollNodeIndex,
external_id: Option<ExternalScrollId>,
frame_rect: &LayerRect,
content_size: &LayerSize,
@ -166,11 +181,11 @@ impl ClipScrollNode {
external_id,
));
Self::new(pipeline_id, Some(parent_id), frame_rect, node_type)
Self::new(pipeline_id, Some(parent_index), frame_rect, node_type)
}
pub fn new_reference_frame(
parent_id: Option<ClipId>,
parent_index: Option<ClipScrollNodeIndex>,
frame_rect: &LayerRect,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
@ -187,21 +202,21 @@ impl ClipScrollNode {
origin_in_parent_reference_frame,
invertible: true,
};
Self::new(pipeline_id, parent_id, frame_rect, NodeType::ReferenceFrame(info))
Self::new(pipeline_id, parent_index, frame_rect, NodeType::ReferenceFrame(info))
}
pub fn new_sticky_frame(
parent_id: ClipId,
parent_index: ClipScrollNodeIndex,
frame_rect: LayerRect,
sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId,
) -> Self {
let node_type = NodeType::StickyFrame(sticky_frame_info);
Self::new(pipeline_id, Some(parent_id), &frame_rect, node_type)
Self::new(pipeline_id, Some(parent_index), &frame_rect, node_type)
}
pub fn add_child(&mut self, child: ClipId) {
pub fn add_child(&mut self, child: ClipScrollNodeIndex) {
self.children.push(child);
}
@ -336,8 +351,9 @@ impl ClipScrollNode {
gpu_cache: &mut GpuCache,
clip_chains: &mut Vec<ClipChain>,
) {
let (clip_sources_handle, clip_chain_index) = match self.node_type {
NodeType::Clip { ref handle, clip_chain_index } => (handle, clip_chain_index),
let (clip_sources_handle, clip_chain_index, stored_clip_chain_node) = match self.node_type {
NodeType::Clip { ref handle, clip_chain_index, ref mut clip_chain_node } =>
(handle, clip_chain_index, clip_chain_node),
_ => {
self.invertible = true;
return;
@ -357,19 +373,23 @@ impl ClipScrollNode {
"Clipping node didn't have outer rect."
);
let work_item = ClipWorkItem {
scroll_node_data_index: self.node_data_index,
clip_sources: clip_sources_handle.weak(),
coordinate_system_id: state.current_coordinate_system_id,
};
let mut clip_chain = clip_chains[state.parent_clip_chain_index.0].new_with_added_node(
work_item,
self.coordinate_system_relative_transform.transform_rect(&local_outer_rect),
let new_node = ClipChainNode {
work_item: ClipWorkItem {
scroll_node_data_index: self.node_data_index,
clip_sources: clip_sources_handle.weak(),
coordinate_system_id: state.current_coordinate_system_id,
},
local_clip_rect:
self.coordinate_system_relative_transform.transform_rect(&local_outer_rect),
screen_outer_rect,
screen_inner_rect,
);
prev: None,
};
let mut clip_chain =
clip_chains[state.parent_clip_chain_index.0].new_with_added_node(&new_node);
*stored_clip_chain_node = Some(new_node);
clip_chain.parent_index = Some(state.parent_clip_chain_index);
clip_chains[clip_chain_index.0] = clip_chain;
state.parent_clip_chain_index = clip_chain_index;
@ -621,6 +641,7 @@ impl ClipScrollNode {
state.parent_accumulated_scroll_offset =
info.current_offset + state.parent_accumulated_scroll_offset;
}
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
}
}

View File

@ -2,13 +2,13 @@
* 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, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect};
use api::{LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLocation};
use api::{ScrollNodeState, WorldPoint};
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect, LayerVector2D};
use api::{PipelineId, ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollNodeState};
use api::WorldPoint;
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
use resource_cache::ResourceCache;
@ -26,6 +26,12 @@ pub type ScrollStates = FastHashMap<ExternalScrollId, ScrollFrameInfo>;
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CoordinateSystemId(pub u32);
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct ClipScrollNodeIndex(pub usize);
const ROOT_REFERENCE_FRAME_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(0);
const TOPMOST_SCROLL_NODE_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(1);
impl CoordinateSystemId {
pub fn root() -> Self {
CoordinateSystemId(0)
@ -44,14 +50,14 @@ impl CoordinateSystemId {
pub struct ClipChainDescriptor {
pub index: ClipChainIndex,
pub parent: Option<ClipChainIndex>,
pub clips: Vec<ClipId>,
pub clips: Vec<ClipScrollNodeIndex>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ClipChainIndex(pub usize);
pub struct ClipScrollTree {
pub nodes: FastHashMap<ClipId, ClipScrollNode>,
pub nodes: Vec<ClipScrollNode>,
/// 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
@ -66,21 +72,13 @@ pub struct ClipScrollTree {
/// 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>,
pub currently_scrolling_node_index: Option<ClipScrollNodeIndex>,
/// 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.
current_new_node_item: u64,
/// The root reference frame, which is the true root of the ClipScrollTree. Initially
/// this ID is not valid, which is indicated by ```node``` being empty.
pub root_reference_frame_id: ClipId,
/// The root scroll node which is the first child of the root reference frame.
/// Initially this ID is not valid, which is indicated by ```nodes``` being empty.
pub topmost_scrolling_node_id: ClipId,
/// A set of pipelines which should be discarded the next time this
/// tree is drained.
pub pipelines_to_discard: FastHashSet<PipelineId>,
@ -113,40 +111,39 @@ pub struct TransformUpdateState {
impl ClipScrollTree {
pub fn new() -> Self {
let dummy_pipeline = PipelineId::dummy();
ClipScrollTree {
nodes: FastHashMap::default(),
nodes: Vec::new(),
clip_chains_descriptors: Vec::new(),
clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())],
pending_scroll_offsets: FastHashMap::default(),
currently_scrolling_node_id: None,
root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline),
topmost_scrolling_node_id: ClipId::root_scroll_node(dummy_pipeline),
currently_scrolling_node_index: None,
current_new_node_item: 1,
pipelines_to_discard: FastHashSet::default(),
}
}
pub fn root_reference_frame_id(&self) -> ClipId {
/// The root reference frame, which is the true root of the ClipScrollTree. Initially
/// this ID is not valid, which is indicated by ```nodes``` being empty.
pub fn root_reference_frame_index(&self) -> ClipScrollNodeIndex {
// TODO(mrobinson): We should eventually make this impossible to misuse.
debug_assert!(!self.nodes.is_empty());
debug_assert!(self.nodes.contains_key(&self.root_reference_frame_id));
self.root_reference_frame_id
ROOT_REFERENCE_FRAME_INDEX
}
pub fn topmost_scrolling_node_id(&self) -> ClipId {
/// The root scroll node which is the first child of the root reference frame.
/// Initially this ID is not valid, which is indicated by ```nodes``` being empty.
pub fn topmost_scroll_node_index(&self) -> ClipScrollNodeIndex {
// TODO(mrobinson): We should eventually make this impossible to misuse.
debug_assert!(!self.nodes.is_empty());
debug_assert!(self.nodes.contains_key(&self.topmost_scrolling_node_id));
self.topmost_scrolling_node_id
debug_assert!(self.nodes.len() >= 1);
TOPMOST_SCROLL_NODE_INDEX
}
pub fn collect_nodes_bouncing_back(&self) -> FastHashSet<ClipId> {
pub fn collect_nodes_bouncing_back(&self) -> FastHashSet<ClipScrollNodeIndex> {
let mut nodes_bouncing_back = FastHashSet::default();
for (clip_id, node) in self.nodes.iter() {
for (index, node) in self.nodes.iter().enumerate() {
if let NodeType::ScrollFrame(ref scrolling) = node.node_type {
if scrolling.bouncing_back {
nodes_bouncing_back.insert(*clip_id);
nodes_bouncing_back.insert(ClipScrollNodeIndex(index));
}
}
}
@ -156,38 +153,36 @@ impl ClipScrollTree {
fn find_scrolling_node_at_point_in_node(
&self,
cursor: &WorldPoint,
clip_id: ClipId,
) -> Option<ClipId> {
self.nodes.get(&clip_id).and_then(|node| {
for child_layer_id in node.children.iter().rev() {
if let Some(layer_id) =
self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id)
{
return Some(layer_id);
}
index: ClipScrollNodeIndex,
) -> Option<ClipScrollNodeIndex> {
let node = &self.nodes[index.0];
for child_index in node.children.iter().rev() {
let found_index = self.find_scrolling_node_at_point_in_node(cursor, *child_index);
if found_index.is_some() {
return found_index;
}
}
match node.node_type {
NodeType::ScrollFrame(state) if state.sensitive_to_input_events() => {}
_ => return None,
}
match node.node_type {
NodeType::ScrollFrame(state) if state.sensitive_to_input_events() => {}
_ => return None,
}
if node.ray_intersects_node(cursor) {
Some(clip_id)
} else {
None
}
})
if node.ray_intersects_node(cursor) {
Some(index)
} else {
None
}
}
pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ClipId {
self.find_scrolling_node_at_point_in_node(cursor, self.root_reference_frame_id())
.unwrap_or(self.topmost_scrolling_node_id())
pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ClipScrollNodeIndex {
self.find_scrolling_node_at_point_in_node(cursor, self.root_reference_frame_index())
.unwrap_or(self.topmost_scroll_node_index())
}
pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
let mut result = vec![];
for node in self.nodes.values() {
for node in &self.nodes {
if let NodeType::ScrollFrame(info) = node.node_type {
if let Some(id) = info.external_id {
result.push(ScrollNodeState { id, scroll_offset: info.offset })
@ -201,8 +196,8 @@ impl ClipScrollTree {
self.current_new_node_item = 1;
let mut scroll_states = FastHashMap::default();
for (node_id, old_node) in &mut self.nodes.drain() {
if self.pipelines_to_discard.contains(&node_id.pipeline_id()) {
for old_node in &mut self.nodes.drain(..) {
if self.pipelines_to_discard.contains(&old_node.pipeline_id) {
continue;
}
@ -226,7 +221,7 @@ impl ClipScrollTree {
id: ExternalScrollId,
clamp: ScrollClamping
) -> bool {
for node in &mut self.nodes.values_mut() {
for node in &mut self.nodes {
if node.matches_external_id(id) {
return node.set_scroll_origin(&origin, clamp);
}
@ -246,37 +241,38 @@ impl ClipScrollTree {
return false;
}
let clip_id = match (
let node_index = match (
phase,
self.find_scrolling_node_at_point(&cursor),
self.currently_scrolling_node_id,
self.currently_scrolling_node_index,
) {
(ScrollEventPhase::Start, scroll_node_at_point_id, _) => {
self.currently_scrolling_node_id = Some(scroll_node_at_point_id);
scroll_node_at_point_id
(ScrollEventPhase::Start, scroll_node_at_point_index, _) => {
self.currently_scrolling_node_index = Some(scroll_node_at_point_index);
scroll_node_at_point_index
}
(_, scroll_node_at_point_id, Some(cached_clip_id)) => {
let clip_id = match self.nodes.get(&cached_clip_id) {
Some(_) => cached_clip_id,
(_, scroll_node_at_point_index, Some(cached_node_index)) => {
let node_index = match self.nodes.get(cached_node_index.0) {
Some(_) => cached_node_index,
None => {
self.currently_scrolling_node_id = Some(scroll_node_at_point_id);
scroll_node_at_point_id
self.currently_scrolling_node_index = Some(scroll_node_at_point_index);
scroll_node_at_point_index
}
};
clip_id
node_index
}
(_, _, None) => return false,
};
let topmost_scrolling_node_id = self.topmost_scrolling_node_id();
let non_root_overscroll = if clip_id != topmost_scrolling_node_id {
self.nodes.get(&clip_id).unwrap().is_overscrolling()
let topmost_scroll_node_index = self.topmost_scroll_node_index();
let non_root_overscroll = if node_index != topmost_scroll_node_index {
self.nodes[node_index.0].is_overscrolling()
} else {
false
};
let mut switch_node = false;
if let Some(node) = self.nodes.get_mut(&clip_id) {
{
let node = &mut self.nodes[node_index.0];
if let NodeType::ScrollFrame(ref mut scrolling) = node.node_type {
match phase {
ScrollEventPhase::Start => {
@ -298,16 +294,13 @@ impl ClipScrollTree {
}
}
let clip_id = if switch_node {
topmost_scrolling_node_id
let node_index = if switch_node {
topmost_scroll_node_index
} else {
clip_id
node_index
};
self.nodes
.get_mut(&clip_id)
.unwrap()
.scroll(scroll_location, phase)
self.nodes[node_index.0].scroll(scroll_location, phase)
}
pub fn update_tree(
@ -327,7 +320,7 @@ impl ClipScrollTree {
self.clip_chains[0] = ClipChain::empty(screen_rect);
let root_reference_frame_id = self.root_reference_frame_id();
let root_reference_frame_index = self.root_reference_frame_index();
let mut state = TransformUpdateState {
parent_reference_frame_transform: LayerVector2D::new(pan.x, pan.y).into(),
parent_accumulated_scroll_offset: LayerVector2D::zero(),
@ -340,7 +333,7 @@ impl ClipScrollTree {
};
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
self.update_node(
root_reference_frame_id,
root_reference_frame_index,
&mut state,
&mut next_coordinate_system_id,
device_pixel_scale,
@ -356,7 +349,7 @@ impl ClipScrollTree {
fn update_node(
&mut self,
layer_id: ClipId,
node_index: ClipScrollNodeIndex,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
device_pixel_scale: DevicePixelScale,
@ -370,13 +363,13 @@ impl ClipScrollTree {
// Restructure this to avoid the clones!
let mut state = state.clone();
let node_children = {
let node = match self.nodes.get_mut(&layer_id) {
let node = match self.nodes.get_mut(node_index.0) {
Some(node) => node,
None => return,
};
// We set this early so that we can use it to populate the ClipChain.
node.node_data_index = ClipScrollNodeIndex(gpu_node_data.len() as u32);
node.node_data_index = GPUClipScrollNodeIndex(gpu_node_data.len() as u32);
node.update(
&mut state,
@ -399,9 +392,9 @@ impl ClipScrollTree {
node.children.clone()
};
for child_node_id in node_children {
for child_node_index in node_children {
self.update_node(
child_node_id,
child_node_index,
&mut state,
next_coordinate_system_id,
device_pixel_scale,
@ -426,18 +419,14 @@ impl ClipScrollTree {
// Now we walk through each ClipScrollNode in the vector of clip nodes and
// extract their ClipChain nodes to construct the final list.
for clip_id in &descriptor.clips {
let node_clip_chain_index = match self.nodes[&clip_id].node_type {
NodeType::Clip { clip_chain_index, .. } => clip_chain_index,
_ => {
warn!("Tried to create a clip chain with non-clipping node.");
continue;
for clip_index in &descriptor.clips {
match self.nodes[clip_index.0].node_type {
NodeType::Clip { clip_chain_node: Some(ref node), .. } => {
chain.add_node(node.clone());
}
NodeType::Clip { .. } => warn!("Found uninitialized clipping ClipScrollNode."),
_ => warn!("Tried to create a clip chain with non-clipping node."),
};
if let Some(ref nodes) = self.clip_chains[node_clip_chain_index.0].nodes {
chain.add_node((**nodes).clone());
}
}
chain.parent_index = descriptor.parent;
@ -446,13 +435,13 @@ impl ClipScrollTree {
}
pub fn tick_scrolling_bounce_animations(&mut self) {
for (_, node) in &mut self.nodes {
for node in &mut self.nodes {
node.tick_scrolling_bounce_animation()
}
}
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
for node in self.nodes.values_mut() {
for node in &mut self.nodes {
let external_id = match node.node_type {
NodeType::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ) => id,
_ => continue,
@ -462,7 +451,6 @@ impl ClipScrollTree {
node.apply_old_scrolling_state(scrolling_state);
}
if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&external_id) {
node.set_scroll_origin(&offset, clamping);
}
@ -471,72 +459,97 @@ impl ClipScrollTree {
pub fn add_clip_node(
&mut self,
id: ClipId,
parent_id: ClipId,
index: ClipScrollNodeIndex,
parent_index: ClipScrollNodeIndex,
handle: ClipSourcesHandle,
clip_rect: LayerRect,
pipeline_id: PipelineId,
) -> ClipChainIndex {
let clip_chain_index = self.allocate_clip_chain();
let node_type = NodeType::Clip { handle, clip_chain_index };
let node = ClipScrollNode::new(id.pipeline_id(), Some(parent_id), &clip_rect, node_type);
self.add_node(node, id);
let node_type = NodeType::Clip { handle, clip_chain_index, clip_chain_node: None };
let node = ClipScrollNode::new(pipeline_id, Some(parent_index), &clip_rect, node_type);
self.add_node(node, index);
clip_chain_index
}
pub fn add_sticky_frame(
&mut self,
id: ClipId,
parent_id: ClipId,
index: ClipScrollNodeIndex,
parent_index: ClipScrollNodeIndex,
frame_rect: LayerRect,
sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId,
) {
let node = ClipScrollNode::new_sticky_frame(
parent_id,
parent_index,
frame_rect,
sticky_frame_info,
id.pipeline_id(),
pipeline_id,
);
self.add_node(node, id);
self.add_node(node, index);
}
pub fn add_clip_chain_descriptor(
&mut self,
parent: Option<ClipChainIndex>,
clips: Vec<ClipId>
clips: Vec<ClipScrollNodeIndex>
) -> ClipChainIndex {
let index = self.allocate_clip_chain();
self.clip_chains_descriptors.push(ClipChainDescriptor { index, parent, clips });
index
}
pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) {
pub fn add_node(&mut self, node: ClipScrollNode, index: ClipScrollNodeIndex) {
// When the parent node is None this means we are adding the root.
match node.parent {
Some(parent_id) => self.nodes.get_mut(&parent_id).unwrap().add_child(id),
None => self.root_reference_frame_id = id,
if let Some(parent_index) = node.parent {
self.nodes[parent_index.0].add_child(index);
}
debug_assert!(!self.nodes.contains_key(&id));
self.nodes.insert(id, node);
if index.0 == self.nodes.len() {
self.nodes.push(node);
return;
}
if let Some(empty_node) = self.nodes.get_mut(index.0) {
*empty_node = node;
return
}
let length_to_reserve = index.0 + 1 - self.nodes.len();
self.nodes.reserve_exact(length_to_reserve);
// We would like to use `Vec::resize` here, but the Clone trait is not supported
// for ClipScrollNodes. We can fix this either by splitting the clip nodes out into
// their own tree or when support is added for something like `Vec::resize_default`.
let length_to_extend = self.nodes.len() .. index.0;
self.nodes.extend(length_to_extend.map(|_| ClipScrollNode::empty()));
self.nodes.push(node);
}
pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
self.pipelines_to_discard.insert(pipeline_id);
match self.currently_scrolling_node_id {
Some(id) if id.pipeline_id() == pipeline_id => self.currently_scrolling_node_id = None,
_ => {}
if let Some(index) = self.currently_scrolling_node_index {
if self.nodes[index.0].pipeline_id == pipeline_id {
self.currently_scrolling_node_index = None;
}
}
}
fn print_node<T: PrintTreePrinter>(&self, id: &ClipId, pt: &mut T, clip_store: &ClipStore) {
let node = self.nodes.get(id).unwrap();
fn print_node<T: PrintTreePrinter>(
&self,
index: ClipScrollNodeIndex,
pt: &mut T,
clip_store: &ClipStore
) {
let node = &self.nodes[index.0];
match node.node_type {
NodeType::Clip { ref handle, .. } => {
pt.new_level("Clip".to_owned());
pt.add_item(format!("id: {:?}", id));
pt.add_item(format!("index: {:?}", index));
let clips = clip_store.get(&handle).clips();
pt.new_level(format!("Clip Sources [{}]", clips.len()));
for source in clips {
@ -546,40 +559,29 @@ impl ClipScrollTree {
}
NodeType::ReferenceFrame(ref info) => {
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
pt.add_item(format!("id: {:?}", id));
pt.add_item(format!("index: {:?}", index));
}
NodeType::ScrollFrame(scrolling_info) => {
pt.new_level(format!("ScrollFrame"));
pt.add_item(format!("id: {:?}", id));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
pt.add_item(format!("scroll.offset: {:?}", scrolling_info.offset));
}
NodeType::StickyFrame(ref sticky_frame_info) => {
pt.new_level(format!("StickyFrame"));
pt.add_item(format!("id: {:?}", id));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
}
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
}
pt.add_item(format!(
"local_viewport_rect: {:?}",
node.local_viewport_rect
));
pt.add_item(format!(
"world_viewport_transform: {:?}",
node.world_viewport_transform
));
pt.add_item(format!(
"world_content_transform: {:?}",
node.world_content_transform
));
pt.add_item(format!(
"coordinate_system_id: {:?}",
node.coordinate_system_id
));
pt.add_item(format!("local_viewport_rect: {:?}", node.local_viewport_rect));
pt.add_item(format!("world_viewport_transform: {:?}", node.world_viewport_transform));
pt.add_item(format!("world_content_transform: {:?}", node.world_content_transform));
pt.add_item(format!("coordinate_system_id: {:?}", node.coordinate_system_id));
for child_id in &node.children {
self.print_node(child_id, pt, clip_store);
for child_index in &node.children {
self.print_node(*child_index, pt, clip_store);
}
pt.end_level();
@ -595,7 +597,7 @@ impl ClipScrollTree {
pub fn print_with<T: PrintTreePrinter>(&self, clip_store: &ClipStore, pt: &mut T) {
if !self.nodes.is_empty() {
self.print_node(&self.root_reference_frame_id, pt, clip_store);
self.print_node(self.root_reference_frame_index(), pt, clip_store);
}
}
@ -609,5 +611,4 @@ impl ClipScrollTree {
pub fn get_clip_chain(&self, index: ClipChainIndex) -> &ClipChain {
&self.clip_chains[index.0]
}
}

View File

@ -1009,8 +1009,8 @@ impl Device {
pub fn init_texture(
&mut self,
texture: &mut Texture,
width: u32,
height: u32,
mut width: u32,
mut height: u32,
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
layer_count: i32,
@ -1018,6 +1018,12 @@ impl Device {
) {
debug_assert!(self.inside_frame);
if width > self.max_texture_size || height > self.max_texture_size {
error!("Attempting to allocate a texture of size {}x{} above the limit, trimming", width, height);
width = width.min(self.max_texture_size);
height = height.min(self.max_texture_size);
}
let is_resized = texture.width != width || texture.height != height;
texture.width = width;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -402,7 +402,7 @@ impl GlyphRasterizer {
if let Ok(Some(ref mut glyph_info)) = *entry.get_mut() {
if texture_cache.request(&mut glyph_info.texture_cache_handle, gpu_cache) {
// This case gets hit when we have already rasterized
// the glyph and stored it in CPU memory, the the glyph
// the glyph and stored it in CPU memory, but the glyph
// has been evicted from the texture cache. In which case
// we need to re-upload it to the GPU.
texture_cache.update(

View File

@ -2,8 +2,8 @@
* 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::{LayerToWorldTransform};
use gpu_cache::GpuCacheAddress;
use api::{DevicePoint, LayerToWorldTransform, PremultipliedColorF};
use gpu_cache::{GpuCacheAddress, GpuDataRequest};
use prim_store::EdgeAaSegmentMask;
use render_task::RenderTaskAddress;
@ -203,7 +203,6 @@ impl From<BrushInstance> for PrimitiveInstance {
pub enum BrushImageKind {
Simple = 0, // A normal rect
NinePatch = 1, // A nine-patch image (stretch inside segments)
Mirror = 2, // A top left corner only (mirror across x/y axes)
}
#[derive(Copy, Debug, Clone, PartialEq)]
@ -245,3 +244,33 @@ pub enum PictureType {
TextShadow = 2,
BoxShadow = 3,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct ImageSource {
pub p0: DevicePoint,
pub p1: DevicePoint,
pub texture_layer: f32,
pub user_data: [f32; 3],
pub color: PremultipliedColorF,
}
impl ImageSource {
pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push([
self.p0.x,
self.p0.y,
self.p1.x,
self.p1.y,
]);
request.push([
self.texture_layer,
self.user_data[0],
self.user_data[1],
self.user_data[2],
]);
request.push(self.color);
}
}

View File

@ -2,11 +2,11 @@
* 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::{BorderRadius, ClipId, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag};
use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LocalClip, PipelineId, WorldPoint};
use api::{BorderRadius, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag, LayerPoint};
use api::{LayerPrimitiveInfo, LayerRect, LocalClip, PipelineId, WorldPoint};
use clip::{ClipSource, ClipStore, Contains, rounded_rectangle_contains_point};
use clip_scroll_node::{ClipScrollNode, NodeType};
use clip_scroll_tree::{ClipChainIndex, ClipScrollTree};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
use internal_types::FastHashMap;
use prim_store::ScrollNodeAndClipChain;
use util::LayerToWorldFastTransform;
@ -15,6 +15,9 @@ use util::LayerToWorldFastTransform;
/// data from the ClipScrollTree that will persist as a new frame is under construction,
/// allowing hit tests consistent with the currently rendered frame.
pub struct HitTestClipScrollNode {
/// The pipeline id of this node.
pipeline_id: PipelineId,
/// A particular point must be inside all of these regions to be considered clipped in
/// for the purposes of a hit test.
regions: Vec<HitTestRegion>,
@ -37,7 +40,7 @@ pub struct HitTestClipScrollNode {
#[derive(Clone)]
struct HitTestClipChainDescriptor {
parent: Option<ClipChainIndex>,
clips: Vec<ClipId>,
clips: Vec<ClipScrollNodeIndex>,
}
impl HitTestClipChainDescriptor {
@ -88,8 +91,9 @@ impl HitTestRegion {
pub struct HitTester {
runs: Vec<HitTestingRun>,
nodes: FastHashMap<ClipId, HitTestClipScrollNode>,
nodes: Vec<HitTestClipScrollNode>,
clip_chains: Vec<HitTestClipChainDescriptor>,
pipeline_root_nodes: FastHashMap<PipelineId, ClipScrollNodeIndex>,
}
impl HitTester {
@ -100,8 +104,9 @@ impl HitTester {
) -> HitTester {
let mut hit_tester = HitTester {
runs: runs.clone(),
nodes: FastHashMap::default(),
nodes: Vec::new(),
clip_chains: Vec::new(),
pipeline_root_nodes: FastHashMap::default(),
};
hit_tester.read_clip_scroll_tree(clip_scroll_tree, clip_store);
hit_tester
@ -119,8 +124,15 @@ impl HitTester {
HitTestClipChainDescriptor::empty()
);
for (id, node) in &clip_scroll_tree.nodes {
self.nodes.insert(*id, HitTestClipScrollNode {
for (index, node) in clip_scroll_tree.nodes.iter().enumerate() {
let index = ClipScrollNodeIndex(index);
// If we haven't already seen a node for this pipeline, record this one as the root
// node.
self.pipeline_root_nodes.entry(node.pipeline_id).or_insert(index);
self.nodes.push(HitTestClipScrollNode {
pipeline_id: node.pipeline_id,
regions: get_regions_for_clip_scroll_node(node, clip_store),
world_content_transform: node.world_content_transform,
world_viewport_transform: node.world_viewport_transform,
@ -131,7 +143,7 @@ impl HitTester {
let clip_chain = self.clip_chains.get_mut(clip_chain_index.0).unwrap();
clip_chain.parent =
clip_scroll_tree.get_clip_chain(clip_chain_index).parent_index;
clip_chain.clips = vec![*id];
clip_chain.clips = vec![index];
}
}
@ -163,8 +175,8 @@ impl HitTester {
return false;
}
for clip_node in &descriptor.clips {
if !self.is_point_clipped_in_for_node(point, clip_node, test) {
for clip_node_index in &descriptor.clips {
if !self.is_point_clipped_in_for_node(point, *clip_node_index, test) {
test.set_in_clip_chain_cache(clip_chain_index, false);
return false;
}
@ -177,19 +189,19 @@ impl HitTester {
fn is_point_clipped_in_for_node(
&self,
point: WorldPoint,
node_id: &ClipId,
node_index: ClipScrollNodeIndex,
test: &mut HitTest
) -> bool {
if let Some(point) = test.node_cache.get(node_id) {
if let Some(point) = test.node_cache.get(&node_index) {
return point.is_some();
}
let node = self.nodes.get(node_id).unwrap();
let node = &self.nodes[node_index.0];
let transform = node.world_viewport_transform;
let transformed_point = match transform.inverse() {
Some(inverted) => inverted.transform_point2d(&point),
None => {
test.node_cache.insert(*node_id, None);
test.node_cache.insert(node_index, None);
return false;
}
};
@ -197,12 +209,12 @@ impl HitTester {
let point_in_layer = transformed_point - node.node_origin.to_vector();
for region in &node.regions {
if !region.contains(&transformed_point) {
test.node_cache.insert(*node_id, None);
test.node_cache.insert(node_index, None);
return false;
}
}
test.node_cache.insert(*node_id, Some(point_in_layer));
test.node_cache.insert(node_index, Some(point_in_layer));
true
}
@ -212,9 +224,9 @@ impl HitTester {
let mut result = HitTestResult::default();
for &HitTestingRun(ref items, ref clip_and_scroll) in self.runs.iter().rev() {
let scroll_node_id = clip_and_scroll.scroll_node_id;
let scroll_node = &self.nodes[&scroll_node_id];
let pipeline_id = scroll_node_id.pipeline_id();
match (test.pipeline_id, clip_and_scroll.scroll_node_id.pipeline_id()) {
let scroll_node = &self.nodes[scroll_node_id.0];
let pipeline_id = scroll_node.pipeline_id;
match (test.pipeline_id, pipeline_id) {
(Some(id), node_id) if node_id != id => continue,
_ => {},
}
@ -243,11 +255,11 @@ impl HitTester {
// hierarchy. If we don't have a valid point for this test, we are likely
// in a situation where the reference frame has an univertible transform, but the
// item's clip does not.
let root_reference_frame = ClipId::root_reference_frame(pipeline_id);
if !self.is_point_clipped_in_for_node(point, &root_reference_frame, &mut test) {
let root_node_index = self.pipeline_root_nodes[&pipeline_id];
if !self.is_point_clipped_in_for_node(point, root_node_index, &mut test) {
continue;
}
let point_in_viewport = match test.node_cache[&root_reference_frame] {
let point_in_viewport = match test.node_cache[&root_node_index] {
Some(point) => point,
None => continue,
};
@ -267,6 +279,10 @@ impl HitTester {
result.items.dedup();
result
}
pub fn get_pipeline_root(&self, pipeline_id: PipelineId) -> &HitTestClipScrollNode {
&self.nodes[self.pipeline_root_nodes[&pipeline_id].0]
}
}
fn get_regions_for_clip_scroll_node(
@ -294,7 +310,7 @@ pub struct HitTest {
pipeline_id: Option<PipelineId>,
point: WorldPoint,
flags: HitTestFlags,
node_cache: FastHashMap<ClipId, Option<LayerPoint>>,
node_cache: FastHashMap<ClipScrollNodeIndex, Option<LayerPoint>>,
clip_chain_cache: Vec<Option<bool>>,
}
@ -334,8 +350,8 @@ impl HitTest {
}
let point = &LayerPoint::new(self.point.x, self.point.y);
self.pipeline_id.and_then(|id| hit_tester.nodes.get(&ClipId::root_reference_frame(id)))
.map(|node| node.world_viewport_transform.transform_point2d(&point))
.unwrap_or_else(|| WorldPoint::new(self.point.x, self.point.y))
self.pipeline_id.map(|id|
hit_tester.get_pipeline_root(id).world_viewport_transform.transform_point2d(&point)
).unwrap_or_else(|| WorldPoint::new(self.point.x, self.point.y))
}
}

View File

@ -2,10 +2,9 @@
* 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, DeviceUintRect, DocumentId};
use api::{ExternalImageData, ExternalImageId};
use api::{DebugCommand, DeviceUintRect, DocumentId, ExternalImageData, ExternalImageId};
use api::ImageFormat;
use api::DebugCommand;
use clip_scroll_tree::ClipScrollNodeIndex;
use device::TextureFilter;
use renderer::PipelineInfo;
use gpu_cache::GpuCacheUpdateList;
@ -140,7 +139,7 @@ pub struct RenderedDocument {
/// - Pipelines that were removed from the scene.
pub pipeline_info: PipelineInfo,
/// The layers that are currently affected by the over-scrolling animation.
pub layers_bouncing_back: FastHashSet<ClipId>,
pub layers_bouncing_back: FastHashSet<ClipScrollNodeIndex>,
pub frame: tiling::Frame,
}
@ -148,7 +147,7 @@ pub struct RenderedDocument {
impl RenderedDocument {
pub fn new(
pipeline_info: PipelineInfo,
layers_bouncing_back: FastHashSet<ClipId>,
layers_bouncing_back: FastHashSet<ClipScrollNodeIndex>,
frame: tiling::Frame,
) -> Self {
RenderedDocument {

View File

@ -66,8 +66,8 @@ mod debug_render;
#[cfg(feature = "debugger")]
mod debug_server;
mod device;
mod display_list_flattener;
mod ellipse;
mod frame;
mod frame_builder;
mod freelist;
#[cfg(any(target_os = "macos", target_os = "windows"))]
@ -90,6 +90,7 @@ mod render_task;
mod renderer;
mod resource_cache;
mod scene;
mod scene_builder;
mod segment;
mod spring;
mod texture_allocator;

View File

@ -2,11 +2,12 @@
* 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::{BoxShadowClipMode, ClipId, ColorF, DeviceIntPoint, DeviceIntRect, FilterOp, LayerPoint};
use api::{BoxShadowClipMode, ColorF, DeviceIntPoint, DeviceIntRect, FilterOp, LayerPoint};
use api::{LayerRect, LayerToWorldScale, LayerVector2D, MixBlendMode, PipelineId};
use api::{PremultipliedColorF, Shadow};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey};
use frame_builder::{FrameContext, FrameState, PictureState};
use clip_scroll_tree::ClipScrollNodeIndex;
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
use gpu_cache::{GpuCacheHandle, GpuDataRequest};
use gpu_types::{BrushImageKind, PictureType};
use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
@ -86,7 +87,7 @@ pub enum PictureKind {
// The original reference frame ID for this picture.
// It is only different if this is part of a 3D
// rendering context.
reference_frame_id: ClipId,
reference_frame_index: ClipScrollNodeIndex,
real_local_rect: LayerRect,
// An optional cache handle for storing extra data
// in the GPU cache, depending on the type of
@ -208,7 +209,7 @@ impl PicturePrimitive {
composite_mode: Option<PictureCompositeMode>,
is_in_3d_context: bool,
pipeline_id: PipelineId,
reference_frame_id: ClipId,
reference_frame_index: ClipScrollNodeIndex,
frame_output_pipeline_id: Option<PipelineId>,
) -> Self {
PicturePrimitive {
@ -219,7 +220,7 @@ impl PicturePrimitive {
composite_mode,
is_in_3d_context,
frame_output_pipeline_id,
reference_frame_id,
reference_frame_index,
real_local_rect: LayerRect::zero(),
extra_gpu_data_handle: GpuCacheHandle::new(),
},
@ -287,31 +288,17 @@ impl PicturePrimitive {
content_rect.translate(&offset)
}
PictureKind::BoxShadow { blur_radius, clip_mode, image_kind, ref mut content_rect, .. } => {
PictureKind::BoxShadow { blur_radius, clip_mode, ref mut content_rect, .. } => {
// We need to inflate the content rect if outset.
*content_rect = match clip_mode {
BoxShadowClipMode::Outset => {
match image_kind {
BrushImageKind::Mirror => {
let half_offset = 0.5 * blur_radius * BLUR_SAMPLE_SCALE;
// If the radii are uniform, we can render just the top
// left corner and mirror it across the primitive. In
// this case, shift the content rect to leave room
// for the blur to take effect.
local_content_rect
.translate(&-LayerVector2D::new(half_offset, half_offset))
.inflate(half_offset, half_offset)
}
BrushImageKind::NinePatch | BrushImageKind::Simple => {
let full_offset = blur_radius * BLUR_SAMPLE_SCALE;
// For a non-uniform radii, we need to expand
// the content rect on all sides for the blur.
local_content_rect.inflate(
full_offset,
full_offset,
)
}
}
let full_offset = blur_radius * BLUR_SAMPLE_SCALE;
// For a non-uniform radii, we need to expand
// the content rect on all sides for the blur.
local_content_rect.inflate(
full_offset,
full_offset,
)
}
BoxShadowClipMode::Inset => {
local_content_rect
@ -330,8 +317,8 @@ impl PicturePrimitive {
prim_local_rect: &LayerRect,
pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
let content_scale = LayerToWorldScale::new(1.0) * frame_context.device_pixel_scale;
@ -642,12 +629,4 @@ impl PicturePrimitive {
}
}
}
pub fn target_kind(&self) -> RenderTargetKind {
match self.kind {
PictureKind::TextShadow { .. } => RenderTargetKind::Color,
PictureKind::BoxShadow { .. } => RenderTargetKind::Alpha,
PictureKind::Image { .. } => RenderTargetKind::Color,
}
}
}

View File

@ -2,17 +2,18 @@
* 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, ClipId, ClipMode, ColorF, ComplexClipRegion};
use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
use api::{LineStyle, PremultipliedColorF, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderEdgeKind};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
use clip_scroll_node::ClipScrollNode;
use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
use clip::{ClipSourcesHandle, ClipWorkItem};
use frame_builder::{FrameContext, FrameState, PictureContext, PictureState, PrimitiveRunContext};
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
use frame_builder::PrimitiveRunContext;
use glyph_rasterizer::{FontInstance, FontTransform};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
@ -24,7 +25,7 @@ use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache};
use segment::SegmentBuilder;
use std::{mem, usize};
use std::rc::Rc;
use std::sync::Arc;
use util::{MatrixHelpers, WorldToLayerFastTransform, calculate_screen_bounding_rect};
use util::{pack_as_float, recycle_vec};
@ -33,12 +34,15 @@ const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ScrollNodeAndClipChain {
pub scroll_node_id: ClipId,
pub scroll_node_id: ClipScrollNodeIndex,
pub clip_chain_index: ClipChainIndex,
}
impl ScrollNodeAndClipChain {
pub fn new(scroll_node_id: ClipId, clip_chain_index: ClipChainIndex) -> ScrollNodeAndClipChain {
pub fn new(
scroll_node_id: ClipScrollNodeIndex,
clip_chain_index: ClipChainIndex
) -> ScrollNodeAndClipChain {
ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
}
}
@ -184,18 +188,12 @@ pub struct PrimitiveMetadata {
pub tag: Option<ItemTag>,
}
#[derive(Debug)]
pub enum BrushMaskKind {
//Rect, // TODO(gw): Optimization opportunity for masks with 0 border radii.
Corner(LayerSize),
RoundedRect(LayerRect, BorderRadius),
}
#[derive(Debug)]
pub enum BrushKind {
Mask {
clip_mode: ClipMode,
kind: BrushMaskKind,
rect: LayerRect,
radii: BorderRadius,
},
Solid {
color: ColorF,
@ -330,9 +328,11 @@ impl BrushPrimitive {
// has to match VECS_PER_SPECIFIC_BRUSH
match self.kind {
BrushKind::Picture |
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } => {
}
BrushKind::Image { .. } => {
request.push([0.0; 4]);
}
BrushKind::Solid { color } => {
request.push(color.premultiplied());
}
@ -340,15 +340,7 @@ impl BrushPrimitive {
// Opaque black with operator dest out
request.push(PremultipliedColorF::BLACK);
}
BrushKind::Mask { clip_mode, kind: BrushMaskKind::Corner(radius) } => {
request.push([
radius.width,
radius.height,
clip_mode as u32 as f32,
0.0,
]);
}
BrushKind::Mask { clip_mode, kind: BrushMaskKind::RoundedRect(rect, radii) } => {
BrushKind::Mask { clip_mode, rect, radii } => {
request.push([
clip_mode as u32 as f32,
0.0,
@ -1088,8 +1080,8 @@ impl PrimitiveStore {
pic_state_for_children: PictureState,
pic_context: &PictureContext,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
let metadata = &mut self.cpu_metadata[prim_index.0];
match metadata.prim_kind {
@ -1367,8 +1359,8 @@ impl PrimitiveStore {
prim_run_context: &PrimitiveRunContext,
clips: &Vec<ClipWorkItem>,
has_clips_from_other_coordinate_systems: bool,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
match brush.segment_desc {
Some(ref segment_desc) => {
@ -1489,8 +1481,8 @@ impl PrimitiveStore {
combined_outer_rect: &DeviceIntRect,
has_clips_from_other_coordinate_systems: bool,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> bool {
let metadata = &self.cpu_metadata[prim_index.0];
let brush = match metadata.prim_kind {
@ -1557,8 +1549,8 @@ impl PrimitiveStore {
prim_run_context: &PrimitiveRunContext,
prim_screen_rect: &DeviceIntRect,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> bool {
self.cpu_metadata[prim_index.0].clip_task_id = None;
@ -1591,7 +1583,7 @@ impl PrimitiveStore {
combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer));
}
Some(Rc::new(ClipChainNode {
Some(Arc::new(ClipChainNode {
work_item: ClipWorkItem {
scroll_node_data_index: prim_run_context.scroll_node.node_data_index,
clip_sources: metadata.clip_sources.weak(),
@ -1688,8 +1680,8 @@ impl PrimitiveStore {
prim_run_context: &PrimitiveRunContext,
pic_context: &PictureContext,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> Option<LayerRect> {
let mut may_need_clip_mask = true;
let mut pic_state_for_children = PictureState::new();
@ -1721,10 +1713,10 @@ impl PrimitiveStore {
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))
let (draw_text_transformed, original_reference_frame_index) = match pic.kind {
PictureKind::Image { reference_frame_index, composite_mode, .. } => {
may_need_clip_mask = composite_mode.is_some();
(true, Some(reference_frame_index))
}
PictureKind::BoxShadow { .. } |
PictureKind::TextShadow { .. } => {
@ -1747,7 +1739,7 @@ impl PrimitiveStore {
pipeline_id: pic.pipeline_id,
perform_culling: pic.cull_children,
prim_runs: mem::replace(&mut pic.runs, Vec::new()),
original_reference_frame_id,
original_reference_frame_index,
display_list,
draw_text_transformed,
inv_world_transform,
@ -1847,8 +1839,8 @@ impl PrimitiveStore {
&mut self,
pic_context: &PictureContext,
pic_state: &mut PictureState,
frame_context: &FrameContext,
frame_state: &mut FrameState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> PrimitiveRunLocalRect {
let mut result = PrimitiveRunLocalRect {
local_rect_in_actual_parent_space: LayerRect::zero(),
@ -1861,7 +1853,7 @@ impl PrimitiveStore {
// lookups ever show up in a profile).
let scroll_node = &frame_context
.clip_scroll_tree
.nodes[&run.clip_and_scroll.scroll_node_id];
.nodes[run.clip_and_scroll.scroll_node_id.0];
let clip_chain = frame_context
.clip_scroll_tree
.get_clip_chain(run.clip_and_scroll.clip_chain_index);
@ -1884,11 +1876,11 @@ impl PrimitiveStore {
inv_parent.pre_mul(&scroll_node.world_content_transform)
});
let original_relative_transform = pic_context.original_reference_frame_id
.and_then(|original_reference_frame_id| {
let original_relative_transform = pic_context.original_reference_frame_index
.and_then(|original_reference_frame_index| {
let parent = frame_context
.clip_scroll_tree
.nodes[&original_reference_frame_id]
.nodes[original_reference_frame_index.0]
.world_content_transform;
parent.inverse()
.map(|inv_parent| {

View File

@ -2,7 +2,7 @@
* 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, DocumentMsg};
use api::{ApiMsg, FrameMsg};
use bincode::{serialize, Infinite};
use byteorder::{LittleEndian, WriteBytesExt};
use std::any::TypeId;
@ -67,13 +67,14 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
ApiMsg::AddDocument { .. } |
ApiMsg::DeleteDocument(..) => true,
ApiMsg::UpdateDocument(_, ref msgs) => {
for msg in msgs {
for msg in &msgs.frame_ops {
match *msg {
DocumentMsg::GetScrollNodeState(..) |
DocumentMsg::HitTest(..) => {}
FrameMsg::GetScrollNodeState(..) |
FrameMsg::HitTest(..) => {}
_ => { return true; }
}
}
false
}
_ => false,

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@ use box_shadow::BoxShadowCacheKey;
use clip::ClipWorkItem;
use clip_scroll_tree::CoordinateSystemId;
use device::TextureFilter;
use gpu_cache::GpuCache;
use gpu_types::PictureType;
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::{ImageSource, PictureType};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::ContentOrigin;
use prim_store::{PrimitiveIndex, ImageCacheKey};
@ -163,6 +163,7 @@ pub struct PictureTask {
pub content_origin: ContentOrigin,
pub color: PremultipliedColorF,
pub pic_type: PictureType,
pub uv_rect_handle: GpuCacheHandle,
}
#[derive(Debug)]
@ -173,6 +174,7 @@ pub struct BlurTask {
pub target_kind: RenderTargetKind,
pub color: PremultipliedColorF,
pub scale_factor: f32,
pub uv_rect_handle: GpuCacheHandle,
}
impl BlurTask {
@ -267,6 +269,7 @@ impl RenderTask {
content_origin,
color,
pic_type,
uv_rect_handle: GpuCacheHandle::new(),
}),
clear_mode,
saved_index: None,
@ -384,6 +387,7 @@ impl RenderTask {
target_kind,
color,
scale_factor,
uv_rect_handle: GpuCacheHandle::new(),
}),
clear_mode,
saved_index: None,
@ -399,6 +403,7 @@ impl RenderTask {
target_kind,
color,
scale_factor,
uv_rect_handle: GpuCacheHandle::new(),
}),
clear_mode,
saved_index: None,
@ -507,6 +512,24 @@ impl RenderTask {
}
}
pub fn get_texture_handle(&self) -> &GpuCacheHandle {
match self.kind {
RenderTaskKind::Picture(ref info) => {
&info.uv_rect_handle
}
RenderTaskKind::VerticalBlur(ref info) |
RenderTaskKind::HorizontalBlur(ref info) => {
&info.uv_rect_handle
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) |
RenderTaskKind::CacheMask(..) => {
panic!("texture handle not supported for this task kind");
}
}
}
pub fn get_dynamic_size(&self) -> DeviceIntSize {
match self.location {
RenderTaskLocation::Fixed(..) => DeviceIntSize::zero(),
@ -591,6 +614,40 @@ impl RenderTask {
}
}
pub fn prepare_for_render(
&mut self,
gpu_cache: &mut GpuCache,
) {
let (target_rect, target_index) = self.get_target_rect();
let (cache_handle, color) = match self.kind {
RenderTaskKind::HorizontalBlur(ref mut info) |
RenderTaskKind::VerticalBlur(ref mut info) => {
(&mut info.uv_rect_handle, info.color)
}
RenderTaskKind::Picture(ref mut info) => {
(&mut info.uv_rect_handle, info.color)
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) |
RenderTaskKind::CacheMask(..) => {
return;
}
};
if let Some(mut request) = gpu_cache.request(cache_handle) {
let image_source = ImageSource {
p0: target_rect.origin.to_f32(),
p1: target_rect.bottom_right().to_f32(),
color,
texture_layer: target_index.0 as f32,
user_data: [0.0; 3],
};
image_source.write_gpu_blocks(&mut request);
}
}
#[cfg(feature = "debugger")]
pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskTree) -> bool {
match self.kind {

View File

@ -19,8 +19,9 @@ use api::ApiMsg;
use api::DebugCommand;
#[cfg(not(feature = "debugger"))]
use api::channel::MsgSender;
use api::channel::PayloadReceiverHelperMethods;
use batch::{BatchKey, BatchKind, BatchTextures, BrushBatchKind};
use batch::{BrushImageSourceKind, TransformBatchKind};
use batch::{TransformBatchKind};
#[cfg(any(feature = "capture", feature = "replay"))]
use capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
use debug_colors;
@ -51,6 +52,7 @@ use query::{GpuProfiler, GpuTimer};
use rayon::{ThreadPool, ThreadPoolBuilder};
use record::ApiRecordingReceiver;
use render_backend::RenderBackend;
use scene_builder::SceneBuilder;
use render_task::{RenderTaskKind, RenderTaskTree};
use resource_cache::ResourceCache;
#[cfg(feature = "debugger")]
@ -219,7 +221,7 @@ impl BatchKind {
BatchKind::SplitComposite => "SplitComposite",
BatchKind::Brush(kind) => {
match kind {
BrushBatchKind::Picture(..) => "Brush (Picture)",
BrushBatchKind::Picture => "Brush (Picture)",
BrushBatchKind::Solid => "Brush (Solid)",
BrushBatchKind::Line => "Brush (Line)",
BrushBatchKind::Image(..) => "Brush (Image)",
@ -240,7 +242,7 @@ impl BatchKind {
BatchKind::SplitComposite => GPU_TAG_PRIM_SPLIT_COMPOSITE,
BatchKind::Brush(kind) => {
match kind {
BrushBatchKind::Picture(..) => GPU_TAG_BRUSH_PICTURE,
BrushBatchKind::Picture => GPU_TAG_BRUSH_PICTURE,
BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
BrushBatchKind::Line => GPU_TAG_BRUSH_LINE,
BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
@ -1600,11 +1602,8 @@ pub struct Renderer {
cs_blur_rgba8: LazilyCompiledShader,
// Brush shaders
brush_mask_corner: LazilyCompiledShader,
brush_mask_rounded_rect: LazilyCompiledShader,
brush_picture_rgba8: BrushShader,
brush_picture_rgba8_alpha_mask: BrushShader,
brush_picture_a8: BrushShader,
brush_picture: BrushShader,
brush_solid: BrushShader,
brush_line: BrushShader,
brush_image: Vec<Option<BrushShader>>,
@ -1660,6 +1659,7 @@ pub struct Renderer {
gpu_cache_texture: CacheTexture,
gpu_cache_frame_id: FrameId,
gpu_cache_overflow: bool,
pipeline_info: PipelineInfo,
@ -1801,14 +1801,6 @@ impl Renderer {
options.precache_shaders)
};
let brush_mask_corner = try!{
LazilyCompiledShader::new(ShaderKind::Brush,
"brush_mask_corner",
&[],
&mut device,
options.precache_shaders)
};
let brush_mask_rounded_rect = try!{
LazilyCompiledShader::new(ShaderKind::Brush,
"brush_mask_rounded_rect",
@ -1845,24 +1837,10 @@ impl Renderer {
options.precache_shaders)
};
let brush_picture_a8 = try!{
let brush_picture = try!{
BrushShader::new("brush_picture",
&mut device,
&["ALPHA_TARGET"],
options.precache_shaders)
};
let brush_picture_rgba8 = try!{
BrushShader::new("brush_picture",
&mut device,
&["COLOR_TARGET"],
options.precache_shaders)
};
let brush_picture_rgba8_alpha_mask = try!{
BrushShader::new("brush_picture",
&mut device,
&["COLOR_TARGET_ALPHA_MASK"],
&[],
options.precache_shaders)
};
@ -2198,7 +2176,7 @@ impl Renderer {
// First set the flags to default and later call set_debug_flags to ensure any
// potential transition when enabling a flag is run.
let debug_flags = DebugFlags::default();
let payload_tx_for_backend = payload_tx.clone();
let payload_rx_for_backend = payload_rx.to_mpsc_receiver();
let recorder = options.recorder;
let thread_listener = Arc::new(options.thread_listener);
let thread_listener_for_rayon_start = thread_listener.clone();
@ -2227,23 +2205,44 @@ impl Renderer {
let blob_image_renderer = options.blob_image_renderer.take();
let thread_listener_for_render_backend = thread_listener.clone();
let thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
let thread_listener_for_scene_builder = thread_listener.clone();
let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
let resource_cache = ResourceCache::new(
texture_cache,
workers,
blob_image_renderer,
)?;
let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(config, api_tx.clone());
try! {
thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
register_thread_with_profiler(scene_thread_name.clone());
if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
thread_listener.thread_started(&scene_thread_name);
}
let mut scene_builder = scene_builder;
scene_builder.run();
if let Some(ref thread_listener) = *thread_listener_for_scene_builder {
thread_listener.thread_stopped(&scene_thread_name);
}
})
};
try!{
thread::Builder::new().name(thread_name.clone()).spawn(move || {
register_thread_with_profiler(thread_name.clone());
thread::Builder::new().name(rb_thread_name.clone()).spawn(move || {
register_thread_with_profiler(rb_thread_name.clone());
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
thread_listener.thread_started(&thread_name);
thread_listener.thread_started(&rb_thread_name);
}
let mut backend = RenderBackend::new(
api_rx,
payload_rx,
payload_tx_for_backend,
payload_rx_for_backend,
result_tx,
scene_tx,
scene_rx,
device_pixel_ratio,
resource_cache,
backend_notifier,
@ -2253,7 +2252,7 @@ impl Renderer {
);
backend.run(backend_profile_counters);
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
thread_listener.thread_stopped(&thread_name);
thread_listener.thread_stopped(&rb_thread_name);
}
})
};
@ -2273,11 +2272,8 @@ impl Renderer {
cs_text_run,
cs_blur_a8,
cs_blur_rgba8,
brush_mask_corner,
brush_mask_rounded_rect,
brush_picture_rgba8,
brush_picture_rgba8_alpha_mask,
brush_picture_a8,
brush_picture,
brush_solid,
brush_line,
brush_image,
@ -2322,6 +2318,7 @@ impl Renderer {
gpu_profiles: VecDeque::new(),
gpu_cache_texture,
gpu_cache_frame_id: FrameId::new(0),
gpu_cache_overflow: false,
texture_cache_upload_pbo,
texture_resolver,
renderer_errors: Vec::new(),
@ -2435,7 +2432,7 @@ impl Renderer {
self.update_texture_cache();
self.device.end_frame();
// If we receive a `PublishDocument` message followed by this one
// within the same update we need ot cancel the frame because we
// within the same update we need to cancel the frame because we
// might have deleted the resources in use in the frame due to a
// memory pressure event.
if cancel_rendering {
@ -2532,11 +2529,6 @@ impl Renderer {
"Rectangles",
target.clip_batcher.rectangles.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Rectangle Brush (Corner)",
target.brush_mask_corners.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Rectangle Brush (Rounded Rect)",
@ -2975,6 +2967,11 @@ impl Renderer {
(count + list.blocks.len(), cmp::max(height, list.height))
});
if max_requested_height > self.max_texture_size && !self.gpu_cache_overflow {
self.gpu_cache_overflow = true;
self.renderer_errors.push(RendererError::MaxTextureSize);
}
//Note: if we decide to switch to scatter-style GPU cache update
// permanently, we can have this code nicer with `BufferUploader` kind
// of helper, similarly to how `TextureUploader` API is used.
@ -3205,13 +3202,8 @@ impl Renderer {
&mut self.renderer_errors,
);
}
BrushBatchKind::Picture(target_kind) => {
let shader = match target_kind {
BrushImageSourceKind::Alpha => &mut self.brush_picture_a8,
BrushImageSourceKind::Color => &mut self.brush_picture_rgba8,
BrushImageSourceKind::ColorAlphaMask => &mut self.brush_picture_rgba8_alpha_mask,
};
shader.bind(
BrushBatchKind::Picture => {
self.brush_picture.bind(
&mut self.device,
key.blend_mode,
projection,
@ -3985,20 +3977,6 @@ impl Renderer {
self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheA8);
if !target.brush_mask_corners.is_empty() {
self.device.set_blend(false);
let _timer = self.gpu_profile.start_timer(GPU_TAG_BRUSH_MASK);
self.brush_mask_corner
.bind(&mut self.device, projection, 0, &mut self.renderer_errors);
self.draw_instanced_batch(
&target.brush_mask_corners,
VertexArrayKind::Primitive,
&BatchTextures::no_texture(),
stats,
);
}
if !target.brush_mask_rounded_rects.is_empty() {
self.device.set_blend(false);
@ -4706,10 +4684,7 @@ impl Renderer {
self.cs_blur_a8.deinit(&mut self.device);
self.cs_blur_rgba8.deinit(&mut self.device);
self.brush_mask_rounded_rect.deinit(&mut self.device);
self.brush_mask_corner.deinit(&mut self.device);
self.brush_picture_rgba8.deinit(&mut self.device);
self.brush_picture_rgba8_alpha_mask.deinit(&mut self.device);
self.brush_picture_a8.deinit(&mut self.device);
self.brush_picture.deinit(&mut self.device);
self.brush_solid.deinit(&mut self.device);
self.brush_line.deinit(&mut self.device);
self.brush_blend.deinit(&mut self.device);

View File

@ -19,7 +19,6 @@ use capture::PlainExternalImage;
#[cfg(any(feature = "replay", feature = "png"))]
use capture::CaptureConfig;
use device::TextureFilter;
use frame::FrameId;
use glyph_cache::GlyphCache;
#[cfg(feature = "capture")]
use glyph_cache::{PlainGlyphCacheRef, PlainCachedGlyphInfo};
@ -30,6 +29,7 @@ use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use internal_types::{FastHashMap, FastHashSet, ResourceCacheError, SourceTexture, TextureUpdateList};
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
use rayon::ThreadPool;
use render_backend::FrameId;
use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId, RenderTaskTree};
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
use std::cmp;

View File

@ -6,12 +6,14 @@ use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutS
use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
use api::{ItemRange, MixBlendMode, StackingContext};
use internal_types::FastHashMap;
use std::sync::Arc;
/// Stores a map of the animated property bindings for the current display list. These
/// can be used to animate the transform and/or opacity of a display list without
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct SceneProperties {
transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
float_properties: FastHashMap<PropertyBindingId, f32>,
@ -86,9 +88,9 @@ impl SceneProperties {
/// A representation of the layout within the display port for a given document or iframe.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct ScenePipeline {
pub pipeline_id: PipelineId,
pub epoch: Epoch,
pub viewport_size: LayerSize,
pub content_size: LayoutSize,
pub background_color: Option<ColorF>,
@ -98,11 +100,11 @@ pub struct ScenePipeline {
/// A complete representation of the layout bundling visible pipelines together.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct Scene {
pub root_pipeline_id: Option<PipelineId>,
pub pipelines: FastHashMap<PipelineId, ScenePipeline>,
pub removed_pipelines: Vec<PipelineId>,
pub properties: SceneProperties,
pub pipelines: FastHashMap<PipelineId, Arc<ScenePipeline>>,
pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
}
impl Scene {
@ -110,8 +112,7 @@ impl Scene {
Scene {
root_pipeline_id: None,
pipelines: FastHashMap::default(),
removed_pipelines: Vec::new(),
properties: SceneProperties::new(),
pipeline_epochs: FastHashMap::default(),
}
}
@ -130,14 +131,14 @@ impl Scene {
) {
let new_pipeline = ScenePipeline {
pipeline_id,
epoch,
viewport_size,
content_size,
background_color,
display_list,
};
self.pipelines.insert(pipeline_id, new_pipeline);
self.pipelines.insert(pipeline_id, Arc::new(new_pipeline));
self.pipeline_epochs.insert(pipeline_id, epoch);
}
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
@ -145,13 +146,10 @@ impl Scene {
self.root_pipeline_id = None;
}
self.pipelines.remove(&pipeline_id);
self.removed_pipelines.push(pipeline_id);
}
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
if let Some(pipeline) = self.pipelines.get_mut(&pipeline_id) {
pipeline.epoch = epoch;
}
self.pipeline_epochs.insert(pipeline_id, epoch);
}
}

View File

@ -0,0 +1,127 @@
/* 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::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdates};
use api::channel::MsgSender;
use display_list_flattener::build_scene;
use frame_builder::{FrameBuilderConfig, FrameBuilder};
use clip_scroll_tree::ClipScrollTree;
use internal_types::FastHashSet;
use resource_cache::{FontInstanceMap, TiledImageMap};
use render_backend::DocumentView;
use scene::Scene;
use std::sync::mpsc::{channel, Receiver, Sender};
// Message from render backend to scene builder.
pub enum SceneBuilderRequest {
Transaction {
document_id: DocumentId,
scene: Option<SceneRequest>,
resource_updates: ResourceUpdates,
frame_ops: Vec<FrameMsg>,
render: bool,
},
Stop
}
// Message from scene builder to render backend.
pub enum SceneBuilderResult {
Transaction {
document_id: DocumentId,
built_scene: Option<BuiltScene>,
resource_updates: ResourceUpdates,
frame_ops: Vec<FrameMsg>,
render: bool,
},
}
/// Contains the the render backend data needed to build a scene.
pub struct SceneRequest {
pub scene: Scene,
pub view: DocumentView,
pub font_instances: FontInstanceMap,
pub tiled_image_map: TiledImageMap,
pub output_pipelines: FastHashSet<PipelineId>,
pub removed_pipelines: Vec<PipelineId>,
}
pub struct BuiltScene {
pub scene: Scene,
pub frame_builder: FrameBuilder,
pub clip_scroll_tree: ClipScrollTree,
pub removed_pipelines: Vec<PipelineId>,
}
pub struct SceneBuilder {
rx: Receiver<SceneBuilderRequest>,
tx: Sender<SceneBuilderResult>,
api_tx: MsgSender<ApiMsg>,
config: FrameBuilderConfig,
}
impl SceneBuilder {
pub fn new(
config: FrameBuilderConfig,
api_tx: MsgSender<ApiMsg>
) -> (Self, Sender<SceneBuilderRequest>, Receiver<SceneBuilderResult>) {
let (in_tx, in_rx) = channel();
let (out_tx, out_rx) = channel();
(
SceneBuilder {
rx: in_rx,
tx: out_tx,
api_tx,
config,
},
in_tx,
out_rx,
)
}
pub fn run(&mut self) {
loop {
match self.rx.recv() {
Ok(msg) => {
if !self.process_message(msg) {
return;
}
}
Err(_) => {
return;
}
}
}
}
fn process_message(&mut self, msg: SceneBuilderRequest) -> bool {
match msg {
SceneBuilderRequest::Transaction {
document_id,
scene,
resource_updates,
frame_ops,
render,
} => {
let built_scene = scene.map(|request|{
build_scene(&self.config, request)
});
// TODO: pre-rasterization.
self.tx.send(SceneBuilderResult::Transaction {
document_id,
built_scene,
resource_updates,
frame_ops,
render,
}).unwrap();
let _ = self.api_tx.send(ApiMsg::WakeUp);
}
SceneBuilderRequest::Stop => { return false; }
}
true
}
}

View File

@ -2,16 +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::{DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{ExternalImageType, ImageData, ImageFormat};
use api::{ColorF, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{ExternalImageType, ImageData, ImageFormat, PremultipliedColorF};
use api::ImageDescriptor;
use device::TextureFilter;
use frame::FrameId;
use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::ImageSource;
use internal_types::{CacheTextureId, FastHashMap, TextureUpdateList, TextureUpdateSource};
use internal_types::{RenderTargetInfo, SourceTexture, TextureUpdate, TextureUpdateOp};
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
use render_backend::FrameId;
use resource_cache::CacheItem;
use std::cmp;
use std::mem;
@ -102,6 +103,8 @@ struct CacheEntry {
filter: TextureFilter,
// The actual device texture ID this is part of.
texture_id: CacheTextureId,
// Color to modulate this cache item by.
color: PremultipliedColorF,
}
impl CacheEntry {
@ -123,6 +126,7 @@ impl CacheEntry {
format,
filter,
uv_rect_handle: GpuCacheHandle::new(),
color: ColorF::new(1.0, 1.0, 1.0, 1.0).premultiplied(),
}
}
@ -140,13 +144,14 @@ impl CacheEntry {
..
} => (origin, layer_index as f32),
};
request.push([
origin.x as f32,
origin.y as f32,
(origin.x + self.size.width) as f32,
(origin.y + self.size.height) as f32,
]);
request.push([layer_index, self.user_data[0], self.user_data[1], self.user_data[2]]);
let image_source = ImageSource {
p0: origin.to_f32(),
p1: (origin + self.size).to_f32(),
color: self.color,
texture_layer: layer_index,
user_data: self.user_data,
};
image_source.write_gpu_blocks(&mut request);
}
}
}
@ -264,7 +269,7 @@ impl TextureCache {
// Returns true if the image needs to be uploaded to the
// texture cache (either never uploaded, or has been
// evicted on a previous frame).
pub fn request(&mut self, handle: &mut TextureCacheHandle, gpu_cache: &mut GpuCache) -> bool {
pub fn request(&mut self, handle: &TextureCacheHandle, gpu_cache: &mut GpuCache) -> bool {
match handle.entry {
Some(ref handle) => {
match self.entries.get_opt_mut(handle) {
@ -1068,6 +1073,7 @@ impl TextureArray {
format: self.format,
filter: self.filter,
texture_id: self.texture_id.unwrap(),
color: ColorF::new(1.0, 1.0, 1.0, 1.0).premultiplied(),
}
})
}

View File

@ -2,22 +2,21 @@
* 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, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{DocumentLayer, FilterOp, ImageFormat};
use api::{LayerRect, MixBlendMode, PipelineId};
use api::{ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceUintPoint};
use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, FilterOp, ImageFormat, LayerRect};
use api::{MixBlendMode, PipelineId};
use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
use clip::{ClipStore};
use clip_scroll_tree::{ClipScrollTree};
use clip_scroll_tree::{ClipScrollTree, ClipScrollNodeIndex};
use device::{FrameId, Texture};
use gpu_cache::{GpuCache};
use gpu_types::{BlurDirection, BlurInstance, BrushFlags, BrushInstance, ClipChainRectIndex};
use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex};
use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex as GPUClipScrollNodeIndex};
use gpu_types::{PrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureKind};
use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask};
use prim_store::{BrushKind, DeferredResolve, EdgeAaSegmentMask};
use profiler::FrameProfileCounters;
use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
use render_task::{BlurTask, ClearMode, RenderTaskLocation, RenderTaskTree};
@ -29,7 +28,7 @@ const MIN_TARGET_SIZE: u32 = 2048;
#[derive(Debug)]
pub struct ScrollbarPrimitive {
pub clip_id: ClipId,
pub scroll_frame_index: ClipScrollNodeIndex,
pub prim_index: PrimitiveIndex,
pub frame_rect: LayerRect,
}
@ -481,7 +480,6 @@ impl RenderTarget for ColorRenderTarget {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct AlphaRenderTarget {
pub clip_batcher: ClipBatcher,
pub brush_mask_corners: Vec<PrimitiveInstance>,
pub brush_mask_rounded_rects: Vec<PrimitiveInstance>,
// List of blur operations to apply for this render target.
pub vertical_blurs: Vec<BlurInstance>,
@ -502,7 +500,6 @@ impl RenderTarget for AlphaRenderTarget {
) -> Self {
AlphaRenderTarget {
clip_batcher: ClipBatcher::new(),
brush_mask_corners: Vec::new(),
brush_mask_rounded_rects: Vec::new(),
vertical_blurs: Vec::new(),
horizontal_blurs: Vec::new(),
@ -584,7 +581,7 @@ impl RenderTarget for AlphaRenderTarget {
// transform primitives, these
// will need to be filled out!
clip_chain_rect_index: ClipChainRectIndex(0),
scroll_id: ClipScrollNodeIndex(0),
scroll_id: GPUClipScrollNodeIndex(0),
clip_task_address: RenderTaskAddress(0),
z: 0,
segment_index: 0,
@ -604,11 +601,8 @@ impl RenderTarget for AlphaRenderTarget {
BrushKind::Image { .. } => {
unreachable!("bug: unexpected brush here");
}
BrushKind::Mask { ref kind, .. } => {
match *kind {
BrushMaskKind::Corner(..) => &mut self.brush_mask_corners,
BrushMaskKind::RoundedRect(..) => &mut self.brush_mask_rounded_rects,
}
BrushKind::Mask { .. } => {
&mut self.brush_mask_rounded_rects
}
};
batch.push(PrimitiveInstance::from(instance));
@ -868,6 +862,10 @@ impl RenderPass {
};
}
// Give the render task an opportunity to add any
// information to the GPU cache, if appropriate.
task.prepare_for_render(gpu_cache);
(target_kind, texture_target)
};
@ -933,7 +931,7 @@ impl CompositeOps {
}
}
/// A rendering-oriented representation of frame::Frame built by the render backend
/// A rendering-oriented representation of the frame built by the render backend
/// and presented to the renderer.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]

View File

@ -97,9 +97,12 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
}
fn is_simple_translation(&self) -> bool {
if self.m11 != 1. || self.m22 != 1. || self.m33 != 1. {
if (self.m11 - 1.0).abs() > NEARLY_ZERO ||
(self.m22 - 1.0).abs() > NEARLY_ZERO ||
(self.m33 - 1.0).abs() > NEARLY_ZERO {
return false;
}
self.m12.abs() < NEARLY_ZERO && self.m13.abs() < NEARLY_ZERO &&
self.m14.abs() < NEARLY_ZERO && self.m21.abs() < NEARLY_ZERO &&
self.m23.abs() < NEARLY_ZERO && self.m24.abs() < NEARLY_ZERO &&

View File

@ -85,7 +85,7 @@ const SHADERS: &[Shader] = &[
},
Shader {
name: "brush_picture",
features: &["COLOR_TARGET", "ALPHA_TARGET"],
features: &[],
},
Shader {
name: "brush_blend",

View File

@ -16,7 +16,7 @@ app_units = "0.6"
bitflags = "1.0"
bincode = "0.9"
byteorder = "1.2.1"
euclid = "0.16"
euclid = { version = "0.17", features = ["serde"] }
ipc-channel = {version = "0.9", optional = true}
serde = { version = "=1.0.27", features = ["rc"] }
serde_derive = { version = "=1.0.27", features = ["deserialize_in_place"] }

View File

@ -131,24 +131,64 @@ impl ResourceUpdates {
/// - no redundant work is performed if two commands in the same transaction cause the scene or
/// the frame to be rebuilt.
pub struct Transaction {
ops: Vec<DocumentMsg>,
// Operations affecting the scene (applied before scene building).
scene_ops: Vec<SceneMsg>,
// Operations affecting the generation of frames (applied after scene building).
frame_ops: Vec<FrameMsg>,
// Additional display list data.
payloads: Vec<Payload>,
// Resource updates are applied after scene building.
resource_updates: ResourceUpdates,
// If true the transaction is piped through the scene building thread, if false
// it will be applied directly on the render backend.
use_scene_builder_thread: bool,
generate_frame: bool,
}
impl Transaction {
pub fn new() -> Self {
Transaction {
ops: Vec::new(),
scene_ops: Vec::new(),
frame_ops: Vec::new(),
resource_updates: ResourceUpdates::new(),
payloads: Vec::new(),
use_scene_builder_thread: false, // TODO: make this true by default.
generate_frame: false,
}
}
// TODO: better name?
pub fn skip_scene_builder(&mut self) {
self.use_scene_builder_thread = false;
}
// TODO: this is temporary, using the scene builder thread is the default for
// most transactions, and opt-in for specific cases like scrolling and async video.
pub fn use_scene_builder_thread(&mut self) {
self.use_scene_builder_thread = true;
}
pub fn is_empty(&self) -> bool {
self.ops.is_empty()
!self.generate_frame &&
self.scene_ops.is_empty() &&
self.frame_ops.is_empty() &&
self.resource_updates.updates.is_empty()
}
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
self.ops.push(DocumentMsg::UpdateEpoch(pipeline_id, epoch));
// We track epochs before and after scene building.
// This one will be applied to the pending scene right away:
self.scene_ops.push(SceneMsg::UpdateEpoch(pipeline_id, epoch));
// And this one will be applied to the currently built scene at the end
// of the transaction (potentially long after the scene_ops one).
self.frame_ops.push(FrameMsg::UpdateEpoch(pipeline_id, epoch));
// We could avoid the duplication here by storing the epoch updates in a
// separate array and let the render backend schedule the updates at the
// proper times, but it wouldn't make things simpler.
}
/// Sets the root pipeline.
@ -164,14 +204,14 @@ impl Transaction {
/// # }
/// ```
pub fn set_root_pipeline(&mut self, pipeline_id: PipelineId) {
self.ops.push(DocumentMsg::SetRootPipeline(pipeline_id));
self.scene_ops.push(SceneMsg::SetRootPipeline(pipeline_id));
}
/// Removes data associated with a pipeline from the internal data structures.
/// If the specified `pipeline_id` is for the root pipeline, the root pipeline
/// is reset back to `None`.
pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
self.ops.push(DocumentMsg::RemovePipeline(pipeline_id));
self.scene_ops.push(SceneMsg::RemovePipeline(pipeline_id));
}
/// Supplies a new frame to WebRender.
@ -205,8 +245,8 @@ impl Transaction {
preserve_frame_state: bool,
) {
let (display_list_data, list_descriptor) = display_list.into_data();
self.ops.push(
DocumentMsg::SetDisplayList {
self.scene_ops.push(
SceneMsg::SetDisplayList {
epoch,
pipeline_id,
background,
@ -220,7 +260,7 @@ impl Transaction {
}
pub fn update_resources(&mut self, resources: ResourceUpdates) {
self.ops.push(DocumentMsg::UpdateResources(resources));
self.resource_updates.merge(resources);
}
pub fn set_window_parameters(
@ -229,8 +269,8 @@ impl Transaction {
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
) {
self.ops.push(
DocumentMsg::SetWindowParameters {
self.scene_ops.push(
SceneMsg::SetWindowParameters {
window_size,
inner_rect,
device_pixel_ratio,
@ -248,7 +288,7 @@ impl Transaction {
cursor: WorldPoint,
phase: ScrollEventPhase,
) {
self.ops.push(DocumentMsg::Scroll(scroll_location, cursor, phase));
self.frame_ops.push(FrameMsg::Scroll(scroll_location, cursor, phase));
}
pub fn scroll_node_with_id(
@ -257,43 +297,95 @@ impl Transaction {
id: ExternalScrollId,
clamp: ScrollClamping,
) {
self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp));
self.frame_ops.push(FrameMsg::ScrollNodeWithId(origin, id, clamp));
}
pub fn set_page_zoom(&mut self, page_zoom: ZoomFactor) {
self.ops.push(DocumentMsg::SetPageZoom(page_zoom));
self.scene_ops.push(SceneMsg::SetPageZoom(page_zoom));
}
pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
self.ops.push(DocumentMsg::SetPinchZoom(pinch_zoom));
self.scene_ops.push(SceneMsg::SetPinchZoom(pinch_zoom));
}
pub fn set_pan(&mut self, pan: DeviceIntPoint) {
self.ops.push(DocumentMsg::SetPan(pan));
self.frame_ops.push(FrameMsg::SetPan(pan));
}
pub fn tick_scrolling_bounce_animations(&mut self) {
self.ops.push(DocumentMsg::TickScrollingBounce);
self.frame_ops.push(FrameMsg::TickScrollingBounce);
}
/// Generate a new frame.
pub fn generate_frame(&mut self) {
self.ops.push(DocumentMsg::GenerateFrame);
self.generate_frame = true;
}
/// Supply a list of animated property bindings that should be used to resolve
/// bindings in the current display list.
pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
self.ops.push(DocumentMsg::UpdateDynamicProperties(properties));
self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties));
}
/// Enable copying of the output of this pipeline id to
/// an external texture for callers to consume.
pub fn enable_frame_output(&mut self, pipeline_id: PipelineId, enable: bool) {
self.ops.push(DocumentMsg::EnableFrameOutput(pipeline_id, enable));
self.frame_ops.push(FrameMsg::EnableFrameOutput(pipeline_id, enable));
}
fn finalize(self) -> (TransactionMsg, Vec<Payload>) {
(
TransactionMsg {
scene_ops: self.scene_ops,
frame_ops: self.frame_ops,
resource_updates: self.resource_updates,
use_scene_builder_thread: self.use_scene_builder_thread,
generate_frame: self.generate_frame,
},
self.payloads,
)
}
}
/// Represents a transaction in the format sent through the channel.
#[derive(Clone, Deserialize, Serialize)]
pub struct TransactionMsg {
pub scene_ops: Vec<SceneMsg>,
pub frame_ops: Vec<FrameMsg>,
pub resource_updates: ResourceUpdates,
pub generate_frame: bool,
pub use_scene_builder_thread: bool,
}
impl TransactionMsg {
pub fn is_empty(&self) -> bool {
!self.generate_frame &&
self.scene_ops.is_empty() &&
self.frame_ops.is_empty() &&
self.resource_updates.updates.is_empty()
}
// TODO: We only need this for a few RenderApi methods which we should remove.
fn frame_message(msg: FrameMsg) -> Self {
TransactionMsg {
scene_ops: Vec::new(),
frame_ops: vec![msg],
resource_updates: ResourceUpdates::new(),
generate_frame: false,
use_scene_builder_thread: false,
}
}
fn scene_message(msg: SceneMsg) -> Self {
TransactionMsg {
scene_ops: vec![msg],
frame_ops: Vec::new(),
resource_updates: ResourceUpdates::new(),
generate_frame: false,
use_scene_builder_thread: false,
}
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddImage {
@ -358,9 +450,14 @@ pub struct AddFontInstance {
pub variations: Vec<FontVariation>,
}
// Frame messages affect building the scene.
#[derive(Clone, Deserialize, Serialize)]
pub enum DocumentMsg {
HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, MsgSender<HitTestResult>),
pub enum SceneMsg {
UpdateEpoch(PipelineId, Epoch),
SetPageZoom(ZoomFactor),
SetPinchZoom(ZoomFactor),
SetRootPipeline(PipelineId),
RemovePipeline(PipelineId),
SetDisplayList {
list_descriptor: BuiltDisplayListDescriptor,
epoch: Epoch,
@ -370,47 +467,53 @@ pub enum DocumentMsg {
content_size: LayoutSize,
preserve_frame_state: bool,
},
UpdateResources(ResourceUpdates),
UpdateEpoch(PipelineId, Epoch),
SetPageZoom(ZoomFactor),
SetPinchZoom(ZoomFactor),
SetPan(DeviceIntPoint),
SetRootPipeline(PipelineId),
RemovePipeline(PipelineId),
EnableFrameOutput(PipelineId, bool),
SetWindowParameters {
window_size: DeviceUintSize,
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
},
}
// Frame messages affect frame generation (applied after building the scene).
#[derive(Clone, Deserialize, Serialize)]
pub enum FrameMsg {
UpdateEpoch(PipelineId, Epoch),
HitTest(Option<PipelineId>, WorldPoint, HitTestFlags, MsgSender<HitTestResult>),
SetPan(DeviceIntPoint),
EnableFrameOutput(PipelineId, bool),
Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping),
TickScrollingBounce,
GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
GenerateFrame,
UpdateDynamicProperties(DynamicProperties),
}
impl fmt::Debug for DocumentMsg {
impl fmt::Debug for SceneMsg {
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",
DocumentMsg::SetRootPipeline(..) => "DocumentMsg::SetRootPipeline",
DocumentMsg::RemovePipeline(..) => "DocumentMsg::RemovePipeline",
DocumentMsg::SetWindowParameters { .. } => "DocumentMsg::SetWindowParameters",
DocumentMsg::Scroll(..) => "DocumentMsg::Scroll",
DocumentMsg::ScrollNodeWithId(..) => "DocumentMsg::ScrollNodeWithId",
DocumentMsg::TickScrollingBounce => "DocumentMsg::TickScrollingBounce",
DocumentMsg::GetScrollNodeState(..) => "DocumentMsg::GetScrollNodeState",
DocumentMsg::GenerateFrame => "DocumentMsg::GenerateFrame",
DocumentMsg::EnableFrameOutput(..) => "DocumentMsg::EnableFrameOutput",
DocumentMsg::UpdateResources(..) => "DocumentMsg::UpdateResources",
DocumentMsg::UpdateEpoch(..) => "DocumentMsg::UpdateEpoch",
DocumentMsg::UpdateDynamicProperties(..) => "DocumentMsg::UpdateDynamicProperties",
SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch",
SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList",
SceneMsg::SetPageZoom(..) => "SceneMsg::SetPageZoom",
SceneMsg::SetPinchZoom(..) => "SceneMsg::SetPinchZoom",
SceneMsg::RemovePipeline(..) => "SceneMsg::RemovePipeline",
SceneMsg::SetWindowParameters { .. } => "SceneMsg::SetWindowParameters",
SceneMsg::SetRootPipeline(..) => "SceneMsg::SetRootPipeline",
})
}
}
impl fmt::Debug for FrameMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
FrameMsg::UpdateEpoch(..) => "FrameMsg::UpdateEpoch",
FrameMsg::HitTest(..) => "FrameMsg::HitTest",
FrameMsg::SetPan(..) => "FrameMsg::SetPan",
FrameMsg::Scroll(..) => "FrameMsg::Scroll",
FrameMsg::ScrollNodeWithId(..) => "FrameMsg::ScrollNodeWithId",
FrameMsg::TickScrollingBounce => "FrameMsg::TickScrollingBounce",
FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState",
FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput",
FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
})
}
}
@ -496,7 +599,7 @@ pub enum ApiMsg {
/// Adds a new document with given initial size.
AddDocument(DocumentId, DeviceUintSize, DocumentLayer),
/// A message targeted at a particular document.
UpdateDocument(DocumentId, Vec<DocumentMsg>),
UpdateDocument(DocumentId, TransactionMsg),
/// Deletes an existing document.
DeleteDocument(DocumentId),
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
@ -509,6 +612,9 @@ pub enum ApiMsg {
MemoryPressure,
/// Change debugging options.
DebugCommand(DebugCommand),
/// Wakes the render backend's event loop up. Needed when an event is communicated
/// through another channel.
WakeUp,
ShutDown,
}
@ -527,6 +633,7 @@ impl fmt::Debug for ApiMsg {
ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
ApiMsg::DebugCommand(..) => "ApiMsg::DebugCommand",
ApiMsg::ShutDown => "ApiMsg::ShutDown",
ApiMsg::WakeUp => "ApiMsg::WakeUp",
})
}
}
@ -617,10 +724,22 @@ impl RenderApiSender {
channel::msg_channel().expect("Failed to create channel");
let msg = ApiMsg::CloneApi(sync_tx);
self.api_sender.send(msg).expect("Failed to send CloneApi message");
let namespace_id = match sync_rx.recv() {
Ok(id) => id,
Err(e) => {
// This is used to discover the underlying cause of https://github.com/servo/servo/issues/13480.
let webrender_is_alive = self.api_sender.send(ApiMsg::WakeUp);
if webrender_is_alive.is_err() {
panic!("Webrender was shut down before processing CloneApi: {}", e);
} else {
panic!("CloneApi message response was dropped while Webrender was still alive: {}", e);
}
}
};
RenderApi {
api_sender: self.api_sender.clone(),
payload_sender: self.payload_sender.clone(),
namespace_id: sync_rx.recv().expect("Failed to receive API response"),
namespace_id: namespace_id,
next_id: Cell::new(ResourceId(0)),
}
}
@ -756,25 +875,31 @@ impl RenderApi {
}
/// A helper method to send document messages.
fn send(&self, document_id: DocumentId, msg: DocumentMsg) {
fn send_scene_msg(&self, document_id: DocumentId, msg: SceneMsg) {
// This assertion fails on Servo use-cases, because it creates different
// `RenderApi` instances for layout and compositor.
//assert_eq!(document_id.0, self.namespace_id);
self.api_sender
.send(ApiMsg::UpdateDocument(document_id, vec![msg]))
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::scene_message(msg)))
.unwrap()
}
// TODO(nical) - decide what to do with the methods that are duplicated in Transaction.
// I think that we should remove them from RenderApi but we could also leave them here if
// it makes things easier for servo.
// They are all equivalent to creating a transaction with a single command.
/// A helper method to send document messages.
fn send_frame_msg(&self, document_id: DocumentId, msg: FrameMsg) {
// This assertion fails on Servo use-cases, because it creates different
// `RenderApi` instances for layout and compositor.
//assert_eq!(document_id.0, self.namespace_id);
self.api_sender
.send(ApiMsg::UpdateDocument(document_id, TransactionMsg::frame_message(msg)))
.unwrap()
}
pub fn send_transaction(&self, document_id: DocumentId, transaction: Transaction) {
for payload in transaction.payloads {
let (msg, payloads) = transaction.finalize();
for payload in payloads {
self.payload_sender.send_payload(payload).unwrap();
}
self.api_sender.send(ApiMsg::UpdateDocument(document_id, transaction.ops)).unwrap();
self.api_sender.send(ApiMsg::UpdateDocument(document_id, msg)).unwrap();
}
/// Does a hit test on display items in the specified document, at the given
@ -790,7 +915,11 @@ impl RenderApi {
flags: HitTestFlags)
-> HitTestResult {
let (tx, rx) = channel::msg_channel().unwrap();
self.send(document_id, DocumentMsg::HitTest(pipeline_id, point, flags, tx));
self.send_frame_msg(
document_id,
FrameMsg::HitTest(pipeline_id, point, flags, tx)
);
rx.recv().unwrap()
}
@ -801,19 +930,15 @@ impl RenderApi {
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
) {
self.send(
self.send_scene_msg(
document_id,
DocumentMsg::SetWindowParameters {
window_size,
inner_rect,
device_pixel_ratio,
},
SceneMsg::SetWindowParameters { window_size, inner_rect, device_pixel_ratio, },
);
}
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));
self.send_frame_msg(document_id, FrameMsg::GetScrollNodeState(tx));
rx.recv().unwrap()
}

View File

@ -6,6 +6,7 @@ use api::{Epoch, PipelineId};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{Cursor, Read};
use std::mem;
use std::sync::mpsc::Receiver;
#[derive(Clone)]
pub struct Payload {
@ -74,6 +75,10 @@ pub trait PayloadSenderHelperMethods {
pub trait PayloadReceiverHelperMethods {
fn recv_payload(&self) -> Result<Payload, Error>;
// For an MPSC receiver, this is the identity function,
// for an IPC receiver, it routes to a new mpsc receiver
fn to_mpsc_receiver(self) -> Receiver<Payload>;
}
#[cfg(not(feature = "ipc"))]

View File

@ -5,6 +5,8 @@
use ipc_channel::ipc::{self, IpcBytesReceiver, IpcBytesSender, IpcReceiver, IpcSender};
use serde::{Deserialize, Serialize};
use std::io::{Error, ErrorKind};
use std::sync::mpsc;
use std::thread;
use std::{error, io};
///
@ -30,6 +32,20 @@ impl PayloadReceiverHelperMethods for PayloadReceiver {
self.recv().map(|data| Payload::from_data(&data) )
.map_err(|e| io::Error::new(ErrorKind::Other, error::Error::description(&e)))
}
fn to_mpsc_receiver(self) -> Receiver<Payload> {
// It would be nice to use the IPC router for this,
// but that requires an IpcReceiver, not an IpcBytesReceiver.
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
while let Ok(payload) = self.recv_payload() {
if tx.send(payload).is_err() {
break;
}
}
});
rx
}
}
pub fn msg_channel<T: Serialize + for<'de> Deserialize<'de>>() -> Result<(MsgSender<T>, MsgReceiver<T>), Error> {

View File

@ -25,6 +25,10 @@ impl PayloadReceiverHelperMethods for PayloadReceiver {
fn recv_payload(&self) -> Result<Payload, Error> {
self.recv()
}
fn to_mpsc_receiver(self) -> Receiver<Payload> {
self.rx
}
}
pub struct MsgReceiver<T> {

View File

@ -769,12 +769,12 @@ pub struct ClipChainId(pub u64, pub PipelineId);
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ClipId {
Clip(u64, PipelineId),
Clip(usize, PipelineId),
ClipChain(ClipChainId),
}
const ROOT_REFERENCE_FRAME_CLIP_ID: u64 = 0;
const ROOT_SCROLL_NODE_CLIP_ID: u64 = 1;
const ROOT_REFERENCE_FRAME_CLIP_ID: usize = 0;
const ROOT_SCROLL_NODE_CLIP_ID: usize = 1;
impl ClipId {
pub fn root_scroll_node(pipeline_id: PipelineId) -> ClipId {

View File

@ -29,8 +29,8 @@ use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayIte
// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_PRIM_HEADER - VECS_PER_TEXT_RUN) * 2
pub const MAX_TEXT_RUN_LENGTH: usize = 2038;
// We start at 2 , because the root reference is always 0 and the root scroll node is always 1.
const FIRST_CLIP_ID: u64 = 2;
// We start at 2, because the root reference is always 0 and the root scroll node is always 1.
const FIRST_CLIP_ID: usize = 2;
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
@ -78,6 +78,8 @@ pub struct BuiltDisplayListDescriptor {
builder_finish_time: u64,
/// The third IPC time stamp: just before sending
send_start_time: u64,
/// The amount of clips ids assigned while building this display list.
total_clip_ids: usize,
}
pub struct BuiltDisplayListIter<'a> {
@ -143,6 +145,10 @@ impl BuiltDisplayList {
)
}
pub fn total_clip_ids(&self) -> usize {
self.descriptor.total_clip_ids
}
pub fn iter(&self) -> BuiltDisplayListIter {
BuiltDisplayListIter::new(self)
}
@ -499,10 +505,12 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
let mut data = Vec::new();
let mut temp = Vec::new();
let mut total_clip_ids = FIRST_CLIP_ID;
for complete in list {
let item = DisplayItem {
item: match complete.item {
Clip(specific_item, complex_clips) => {
total_clip_ids += 1;
DisplayListBuilder::push_iter_impl(&mut temp, complex_clips);
SpecificDisplayItem::Clip(specific_item)
},
@ -511,10 +519,14 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
SpecificDisplayItem::ClipChain(specific_item)
}
ScrollFrame(specific_item, complex_clips) => {
total_clip_ids += 2;
DisplayListBuilder::push_iter_impl(&mut temp, complex_clips);
SpecificDisplayItem::ScrollFrame(specific_item)
},
StickyFrame(specific_item) => SpecificDisplayItem::StickyFrame(specific_item),
StickyFrame(specific_item) => {
total_clip_ids += 1;
SpecificDisplayItem::StickyFrame(specific_item)
}
Rectangle(specific_item) => SpecificDisplayItem::Rectangle(specific_item),
ClearRectangle => SpecificDisplayItem::ClearRectangle,
Line(specific_item) => SpecificDisplayItem::Line(specific_item),
@ -529,8 +541,14 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
Gradient(specific_item) => SpecificDisplayItem::Gradient(specific_item),
RadialGradient(specific_item) =>
SpecificDisplayItem::RadialGradient(specific_item),
Iframe(specific_item) => SpecificDisplayItem::Iframe(specific_item),
Iframe(specific_item) => {
total_clip_ids += 1;
SpecificDisplayItem::Iframe(specific_item)
}
PushStackingContext(specific_item, filters) => {
if specific_item.stacking_context.reference_frame_id.is_some() {
total_clip_ids += 1;
}
DisplayListBuilder::push_iter_impl(&mut temp, filters);
SpecificDisplayItem::PushStackingContext(specific_item)
},
@ -556,6 +574,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
builder_start_time: 0,
builder_finish_time: 1,
send_start_time: 0,
total_clip_ids,
},
})
}
@ -780,7 +799,7 @@ impl<'a, 'b> Read for UnsafeReader<'a, 'b> {
pub struct SaveState {
dl_len: usize,
clip_stack_len: usize,
next_clip_id: u64,
next_clip_id: usize,
next_clip_chain_id: u64,
}
@ -789,7 +808,7 @@ pub struct DisplayListBuilder {
pub data: Vec<u8>,
pub pipeline_id: PipelineId,
clip_stack: Vec<ClipAndScrollInfo>,
next_clip_id: u64,
next_clip_id: usize,
next_clip_chain_id: u64,
builder_start_time: u64,
@ -1541,6 +1560,7 @@ impl DisplayListBuilder {
builder_start_time: self.builder_start_time,
builder_finish_time: end_time,
send_start_time: 0,
total_clip_ids: self.next_clip_id,
},
data: self.data,
},

View File

@ -7,7 +7,7 @@ license = "MPL-2.0"
[dependencies]
rayon = "1"
thread_profiler = "0.1.1"
euclid = "0.16"
euclid = { version = "0.17", features = ["serde"] }
app_units = "0.6"
gleam = "0.4.20"
log = "0.4"

View File

@ -1 +1 @@
8a19316a733a484bf9bafb8257e3008b1418bfe4
22b831c02479eea31821f49a0fac7dd699083557

View File

@ -10,7 +10,7 @@ base64 = "0.3"
bincode = "0.9"
byteorder = "1.0"
env_logger = { version = "0.5", optional = true }
euclid = "0.16"
euclid = "0.17"
gleam = "0.4"
glutin = "0.12"
app_units = "0.6"

View File

@ -11,7 +11,7 @@ use std::io::{Read, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::{mem, process};
use webrender::WEBRENDER_RECORDING_HEADER;
use webrender::api::{ApiMsg, DocumentMsg};
use webrender::api::{ApiMsg, SceneMsg};
use wrench::{Wrench, WrenchThing};
#[derive(Clone)]
@ -140,17 +140,17 @@ impl WrenchThing for BinaryFrameReader {
// (b) SetDisplayList
// (c) GenerateFrame that occurs *after* (a) and (b)
match msg {
ApiMsg::UpdateDocument(_, ref doc_msgs) => {
for doc_msg in doc_msgs {
ApiMsg::UpdateDocument(_, ref txn) => {
if txn.generate_frame {
found_frame_marker = true;
}
for doc_msg in &txn.scene_ops {
match *doc_msg {
DocumentMsg::GenerateFrame => {
found_frame_marker = true;
}
DocumentMsg::SetDisplayList { .. } => {
SceneMsg::SetDisplayList { .. } => {
found_frame_marker = false;
found_display_list = true;
}
DocumentMsg::SetRootPipeline(..) => {
SceneMsg::SetRootPipeline(..) => {
found_frame_marker = false;
found_pipeline = true;
}

View File

@ -278,13 +278,11 @@ impl webrender::ApiRecordingReceiver for JsonFrameWriter {
match *msg {
ApiMsg::UpdateResources(ref updates) => self.update_resources(updates),
ApiMsg::UpdateDocument(_, ref doc_msgs) => {
for doc_msg in doc_msgs {
ApiMsg::UpdateDocument(_, ref txn) => {
self.update_resources(&txn.resource_updates);
for doc_msg in &txn.scene_ops {
match *doc_msg {
DocumentMsg::UpdateResources(ref resources) => {
self.update_resources(resources);
}
DocumentMsg::SetDisplayList {
SceneMsg::SetDisplayList {
ref epoch,
ref pipeline_id,
ref background,

View File

@ -68,6 +68,7 @@ use std::ffi::CString;
use std::mem;
use std::os::raw::c_void;
use std::path::{Path, PathBuf};
use std::process;
use std::ptr;
use std::rc::Rc;
use std::sync::mpsc::{channel, Sender, Receiver};
@ -412,7 +413,6 @@ fn main() {
return;
} else if let Some(subargs) = args.subcommand_matches("reftest") {
let dim = window.get_inner_size();
let harness = ReftestHarness::new(&mut wrench, &mut window, rx.unwrap());
let base_manifest = Path::new("reftests/reftest.list");
let specific_reftest = subargs.value_of("REFTEST").map(|x| Path::new(x));
let mut reftest_options = ReftestOptions::default();
@ -420,8 +420,11 @@ fn main() {
reftest_options.allow_max_difference = allow_max_diff.parse().unwrap_or(1);
reftest_options.allow_num_differences = dim.width as usize * dim.height as usize;
}
harness.run(base_manifest, specific_reftest, &reftest_options);
return;
let num_failures = ReftestHarness::new(&mut wrench, &mut window, rx.unwrap())
.run(base_manifest, specific_reftest, &reftest_options);
wrench.renderer.deinit();
// exit with an error code to fail on CI
process::exit(num_failures as _);
} else if let Some(_) = args.subcommand_matches("rawtest") {
{
let harness = RawtestHarness::new(&mut wrench, &mut window, rx.unwrap());
@ -465,7 +468,9 @@ fn main() {
let mut body = |wrench: &mut Wrench, global_event: glutin::Event| {
if let Some(window_title) = wrench.take_title() {
window.set_title(&window_title);
if !cfg!(windows) { //TODO: calling `set_title` from inside the `run_forever` loop is illegal...
window.set_title(&window_title);
}
}
let mut do_frame = false;

View File

@ -299,7 +299,7 @@ impl<'a> ReftestHarness<'a> {
ReftestHarness { wrench, window, rx }
}
pub fn run(mut self, base_manifest: &Path, reftests: Option<&Path>, options: &ReftestOptions) {
pub fn run(mut self, base_manifest: &Path, reftests: Option<&Path>, options: &ReftestOptions) -> usize {
let manifest = ReftestManifest::new(base_manifest, options);
let reftests = manifest.find(reftests.unwrap_or(&PathBuf::new()));
@ -328,8 +328,7 @@ impl<'a> ReftestHarness<'a> {
}
}
// panic here so that we fail CI
assert!(failing.is_empty());
failing.len()
}
fn run_reftest(&mut self, t: &Reftest) -> bool {

View File

@ -156,13 +156,11 @@ impl webrender::ApiRecordingReceiver for RonFrameWriter {
fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
match *msg {
ApiMsg::UpdateResources(ref updates) => self.update_resources(updates),
ApiMsg::UpdateDocument(_, ref doc_msgs) => {
for doc_msg in doc_msgs {
ApiMsg::UpdateDocument(_, ref txn) => {
self.update_resources(&txn.resource_updates);
for doc_msg in &txn.scene_ops {
match *doc_msg {
DocumentMsg::UpdateResources(ref resources) => {
self.update_resources(resources);
}
DocumentMsg::SetDisplayList {
SceneMsg::SetDisplayList {
ref epoch,
ref pipeline_id,
ref background,

View File

@ -1124,13 +1124,11 @@ impl webrender::ApiRecordingReceiver for YamlFrameWriterReceiver {
ApiMsg::UpdateResources(ref updates) => {
self.frame_writer.update_resources(updates);
}
ApiMsg::UpdateDocument(_, ref doc_msgs) => {
for doc_msg in doc_msgs {
ApiMsg::UpdateDocument(_, ref txn) => {
self.frame_writer.update_resources(&txn.resource_updates);
for doc_msg in &txn.scene_ops {
match *doc_msg {
DocumentMsg::UpdateResources(ref resources) => {
self.frame_writer.update_resources(resources);
}
DocumentMsg::SetDisplayList {
SceneMsg::SetDisplayList {
ref epoch,
ref pipeline_id,
ref background,
@ -1147,13 +1145,18 @@ impl webrender::ApiRecordingReceiver for YamlFrameWriterReceiver {
list_descriptor,
);
}
DocumentMsg::SetRootPipeline(ref pipeline_id) => {
SceneMsg::SetRootPipeline(ref pipeline_id) => {
self.scene.set_root_pipeline_id(pipeline_id.clone());
}
DocumentMsg::RemovePipeline(ref pipeline_id) => {
SceneMsg::RemovePipeline(ref pipeline_id) => {
self.scene.remove_pipeline(pipeline_id);
}
DocumentMsg::UpdateDynamicProperties(ref properties) => {
_ => {}
}
}
for doc_msg in &txn.frame_ops {
match *doc_msg {
FrameMsg::UpdateDynamicProperties(ref properties) => {
self.scene.properties.set_properties(properties);
}
_ => {}