Bug 1423203 - Update webrender to commit 22f472f0adb02bd71c472e426e47182f2b218f6d. r=jrmuizel

MozReview-Commit-ID: JJK2le2vpeN

--HG--
extra : rebase_source : 677e4433eddb14fea5e0d9a978f28b57912d21f8
This commit is contained in:
Kartikaya Gupta 2017-12-08 13:43:37 -05:00
parent e22361a5ac
commit 14a9b3751e
21 changed files with 704 additions and 308 deletions

View File

@ -175,4 +175,4 @@ Troubleshooting tips:
-------------------------------------------------------------------------------
The version of WebRender currently in the tree is:
b7714b1d4348c00682b5643ea0e3f0b15adaeda5
22f472f0adb02bd71c472e426e47182f2b218f6d

View File

@ -49,6 +49,6 @@ freetype = { version = "0.3", default-features = false }
dwrote = "0.4.1"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.4"
core-foundation = "0.4.6"
core-graphics = "0.12.3"
core-text = { version = "8.0", default-features = false }

View File

@ -14,7 +14,7 @@ flat varying vec4 vUvBounds;
flat varying vec4 vUvBounds_NoClamp;
flat varying vec4 vParams;
#if defined WR_FEATURE_ALPHA_TARGET
#if defined WR_FEATURE_ALPHA_TARGET || defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
flat varying vec4 vColor;
#endif
@ -41,6 +41,9 @@ void brush_vs(
#if defined WR_FEATURE_COLOR_TARGET
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
#elif defined WR_FEATURE_COLOR_TARGET_ALPHA_MASK
vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
vColor = blur_task.color;
#else
vec2 texture_size = vec2(textureSize(sColor1, 0).xy);
vColor = blur_task.color;
@ -120,6 +123,8 @@ vec4 brush_fs() {
#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

View File

@ -34,6 +34,6 @@ void main(void) {
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
oFragColor = texture(sColor0, vec3(uv, vUv.z));
}
#endif

View File

@ -19,15 +19,12 @@ flat varying vec4 vUvBorder;
#define MODE_SUBPX_BG_PASS2 6
#define MODE_COLOR_BITMAP 7
VertexInfo write_text_vertex(vec2 local_pos,
VertexInfo write_text_vertex(vec2 clamped_local_pos,
RectWithSize local_clip_rect,
float z,
Layer layer,
PictureTask task,
RectWithSize snap_rect) {
// Clamp to the two local clip rects.
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect), layer.local_clip_rect);
// Transform the current vertex to world space.
vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0);
@ -75,9 +72,22 @@ void main(void) {
RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset),
res.uv_rect.zw - res.uv_rect.xy);
// Select the corner of the glyph rect that we are processing.
// Transform it from glyph space into local space.
vec2 local_pos = inverse(transform) * (glyph_rect.p0 + glyph_rect.size * aPosition.xy);
// Transform the glyph rect back to local space.
mat2 inv = inverse(transform);
RectWithSize local_rect = transform_rect(glyph_rect, inv);
// Select the corner of the glyph's local space rect that we are processing.
vec2 local_pos = local_rect.p0 + local_rect.size * aPosition.xy;
// Calculate a combined local clip rect.
RectWithSize local_clip_rect = intersect_rects(prim.local_clip_rect, prim.layer.local_clip_rect);
// If the glyph's local rect would fit inside the local clip rect, then select a corner from
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
local_pos = rect_inside_rect(local_rect, local_clip_rect) ?
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
clamp_rect(local_pos, local_clip_rect);
#else
// Scale from glyph space to local space.
float scale = res.scale / uDevicePixelRatio;
@ -88,6 +98,9 @@ void main(void) {
// Select the corner of the glyph rect that we are processing.
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
// Clamp to the two local clip rects.
local_pos = clamp_rect(clamp_rect(local_pos, prim.local_clip_rect), prim.layer.local_clip_rect);
#endif
VertexInfo vi = write_text_vertex(local_pos,
@ -131,16 +144,16 @@ void main(void) {
vec2 st1 = res.uv_rect.zw / texture_size;
vUv = vec3(mix(st0, st1, f), res.layer);
vUvBorder = (res.uv_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
vUvBorder = (res.uv_rect + vec4(0.499, 0.499, -0.499, -0.499)) / texture_size.xyxy;
}
#endif
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec3 tc = vec3(clamp(vUv.xy, vUvBorder.xy, vUvBorder.zw), vUv.z);
vec4 mask = texture(sColor0, tc);
vec4 mask = texture(sColor0, vUv);
float alpha = do_clip();
float alpha = float(all(lessThanEqual(vec4(vUvBorder.xy, vUv.xy), vec4(vUv.xy, vUvBorder.zw))));
alpha *= do_clip();
#ifdef WR_FEATURE_SUBPX_BG_PASS1
mask.rgb = vec3(mask.a) - mask.rgb;

View File

@ -27,3 +27,22 @@ RectWithSize to_rect_with_size(RectWithEndpoint rect) {
return result;
}
RectWithSize transform_rect(RectWithSize rect, mat2 transform) {
vec2 center = transform * (rect.p0 + rect.size * 0.5);
vec2 radius = mat2(abs(transform[0]), abs(transform[1])) * (rect.size * 0.5);
return RectWithSize(center - radius, radius * 2.0);
}
RectWithSize intersect_rects(RectWithSize a, RectWithSize b) {
RectWithSize result;
result.p0 = max(a.p0, b.p0);
result.size = min(a.p0 + a.size, b.p0 + b.size) - result.p0;
return result;
}
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)));
}

View File

@ -329,6 +329,7 @@ impl ClipScrollNode {
pub fn update(
&mut self,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
device_pixel_ratio: f32,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
@ -352,7 +353,7 @@ impl ClipScrollNode {
}
}
self.update_transform(state, scene_properties);
self.update_transform(state, next_coordinate_system_id, scene_properties);
self.update_clip_work_item(
state,
device_pixel_ratio,
@ -441,10 +442,15 @@ impl ClipScrollNode {
pub fn update_transform(
&mut self,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
scene_properties: &SceneProperties,
) {
if self.node_type.is_reference_frame() {
self.update_transform_for_reference_frame(state, scene_properties);
self.update_transform_for_reference_frame(
state,
next_coordinate_system_id,
scene_properties
);
return;
}
@ -484,6 +490,7 @@ impl ClipScrollNode {
pub fn update_transform_for_reference_frame(
&mut self,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
scene_properties: &SceneProperties,
) {
let info = match self.node_type {
@ -502,10 +509,10 @@ impl ClipScrollNode {
if !info.resolved_transform.preserves_2d_axis_alignment() ||
info.resolved_transform.has_perspective_component() {
state.current_coordinate_system_id = state.next_coordinate_system_id;
state.next_coordinate_system_id = state.next_coordinate_system_id.next();
self.coordinate_system_id = state.current_coordinate_system_id;
state.current_coordinate_system_id = *next_coordinate_system_id;
next_coordinate_system_id.advance();
}
self.coordinate_system_id = state.current_coordinate_system_id;
// The transformation for this viewport in world coordinates is the transformation for
// our parent reference frame, plus any accumulated scrolling offsets from nodes

View File

@ -34,6 +34,10 @@ impl CoordinateSystemId {
let CoordinateSystemId(id) = *self;
CoordinateSystemId(id + 1)
}
pub fn advance(&mut self) {
self.0 += 1;
}
}
pub struct ClipScrollTree {
@ -78,7 +82,6 @@ pub struct TransformUpdateState {
/// display list item, since optimizations can usually only be done among
/// coordinate systems which are relatively axis aligned.
pub current_coordinate_system_id: CoordinateSystemId,
pub next_coordinate_system_id: CoordinateSystemId,
}
impl ClipScrollTree {
@ -362,12 +365,13 @@ impl ClipScrollTree {
parent_clip_chain: None,
combined_outer_clip_bounds: *screen_rect,
combined_inner_clip_bounds: DeviceIntRect::max_rect(),
current_coordinate_system_id: CoordinateSystemId(0),
next_coordinate_system_id: CoordinateSystemId(0).next(),
current_coordinate_system_id: CoordinateSystemId::root(),
};
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
self.update_node(
root_reference_frame_id,
&mut state,
&mut next_coordinate_system_id,
device_pixel_ratio,
clip_store,
resource_cache,
@ -381,6 +385,7 @@ impl ClipScrollTree {
&mut self,
layer_id: ClipId,
state: &mut TransformUpdateState,
next_coordinate_system_id: &mut CoordinateSystemId,
device_pixel_ratio: f32,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
@ -402,6 +407,7 @@ impl ClipScrollTree {
node.update(
&mut state,
next_coordinate_system_id,
device_pixel_ratio,
clip_store,
resource_cache,
@ -411,10 +417,11 @@ impl ClipScrollTree {
node.push_gpu_node_data(&state, gpu_node_data);
if !node.children.is_empty() {
node.prepare_state_for_children(&mut state, gpu_node_data);
if node.children.is_empty() {
return;
}
node.prepare_state_for_children(&mut state, gpu_node_data);
node.children.clone()
};
@ -422,6 +429,7 @@ impl ClipScrollTree {
self.update_node(
child_layer_id,
&mut state,
next_coordinate_system_id,
device_pixel_ratio,
clip_store,
resource_cache,

View File

@ -22,7 +22,7 @@ use frame::FrameId;
use glyph_rasterizer::FontInstance;
use gpu_cache::GpuCache;
use gpu_types::ClipScrollNodeData;
use internal_types::{FastHashMap, FastHashSet};
use internal_types::{FastHashMap, FastHashSet, RenderPassIndex};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, RasterizationSpace};
use prim_store::{BrushAntiAliasMode, BrushKind, BrushPrimitive, TexelRect, YuvImagePrimitiveCpu};
use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
@ -35,7 +35,7 @@ use resource_cache::ResourceCache;
use scene::{ScenePipeline, SceneProperties};
use std::{mem, usize, f32};
use tiling::{CompositeOps, Frame};
use tiling::{RenderPass, RenderPassKind, RenderTargetKind};
use tiling::{RenderPass, RenderTargetKind};
use tiling::{RenderTargetContext, ScrollbarPrimitive};
use util::{self, MaxRect, pack_as_float, RectHelpers, recycle_vec};
@ -1761,7 +1761,7 @@ impl FrameBuilder {
let mut deferred_resolves = vec![];
for pass in &mut passes {
for (pass_index, pass) in passes.iter_mut().enumerate() {
let ctx = RenderTargetContext {
device_pixel_ratio,
prim_store: &self.prim_store,
@ -1776,23 +1776,8 @@ impl FrameBuilder {
&mut render_tasks,
&mut deferred_resolves,
&self.clip_store,
RenderPassIndex(pass_index),
);
profile_counters.passes.inc();
match pass.kind {
RenderPassKind::MainFramebuffer(_) => {
profile_counters.color_targets.add(1);
}
RenderPassKind::OffScreen { ref color, ref alpha } => {
profile_counters
.color_targets
.add(color.targets.len());
profile_counters
.alpha_targets
.add(alpha.targets.len());
}
}
}
let gpu_cache_updates = gpu_cache.end_frame(gpu_cache_profile);

View File

@ -32,6 +32,9 @@ pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct CacheTextureId(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct RenderPassIndex(pub usize);
// Represents the source for a texture.
// These are passed from throughout the
// pipeline until they reach the rendering
@ -45,6 +48,10 @@ pub enum SourceTexture {
External(ExternalImageData),
CacheA8,
CacheRGBA8,
// XXX Remove this once RenderTaskCacheA8 is used.
#[allow(dead_code)]
RenderTaskCacheA8(RenderPassIndex),
RenderTaskCacheRGBA8(RenderPassIndex),
}
pub const ORTHO_NEAR_PLANE: f32 = -1000000.0;

View File

@ -67,7 +67,10 @@ pub enum PictureKind {
// If a mix-blend-mode, contains the render task for
// the readback of the framebuffer that we use to sample
// from in the mix-blend-mode shader.
readback_render_task_id: Option<RenderTaskId>,
// For drop-shadow filter, this will store the original
// picture task which would be rendered on screen after
// blur pass.
secondary_render_task_id: Option<RenderTaskId>,
/// How this picture should be composited.
/// If None, don't composite - just draw directly on parent surface.
composite_mode: Option<PictureCompositeMode>,
@ -186,7 +189,7 @@ impl PicturePrimitive {
runs: Vec::new(),
render_task_id: None,
kind: PictureKind::Image {
readback_render_task_id: None,
secondary_render_task_id: None,
composite_mode,
is_in_3d_context,
frame_output_pipeline_id,
@ -236,6 +239,11 @@ impl PicturePrimitive {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
.translate(&offset)
}
_ => {
local_content_rect
}
@ -304,7 +312,7 @@ impl PicturePrimitive {
) {
match self.kind {
PictureKind::Image {
ref mut readback_render_task_id,
ref mut secondary_render_task_id,
composite_mode,
..
} => {
@ -341,6 +349,37 @@ impl PicturePrimitive {
let blur_render_task_id = render_tasks.add(blur_render_task);
self.render_task_id = Some(blur_render_task_id);
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.origin.x as f32 - offset.x,
prim_screen_rect.origin.y as f32 - offset.y,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
self.rasterization_kind,
child_tasks,
None,
);
let blur_std_deviation = blur_radius * prim_context.device_pixel_ratio;
let picture_task_id = render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
RenderTargetKind::Color,
&[],
ClearMode::Transparent,
color.premultiplied(),
None,
);
*secondary_render_task_id = Some(picture_task_id);
self.render_task_id = Some(render_tasks.add(blur_render_task));
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
Some(prim_screen_rect.size),
@ -357,7 +396,7 @@ impl PicturePrimitive {
let readback_task_id = render_tasks.add(RenderTask::new_readback(*prim_screen_rect));
*readback_render_task_id = Some(readback_task_id);
*secondary_render_task_id = Some(readback_task_id);
parent_tasks.push(readback_task_id);
self.render_task_id = Some(render_tasks.add(picture_task));

View File

@ -247,7 +247,7 @@ fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVa
val = val.max(min_val).min(max_val);
if val != def_val {
vals.push((name, CFNumber::from_f64(val)));
vals.push((name, CFNumber::from(val)));
}
}
if vals.is_empty() {

View File

@ -19,8 +19,8 @@ use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuData
use gpu_types::ClipScrollNodeData;
use picture::{PictureKind, PicturePrimitive, RasterizationSpace};
use profiler::FrameProfileCounters;
use render_task::{ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask, RenderTaskId};
use render_task::RenderTaskTree;
use render_task::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask};
use render_task::{RenderTaskId, RenderTaskTree};
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use resource_cache::{ImageProperties, ResourceCache};
use scene::{ScenePipeline, SceneProperties};
@ -209,6 +209,15 @@ pub enum BrushKind {
Clear,
}
impl BrushKind {
fn is_solid(&self) -> bool {
match *self {
BrushKind::Solid { .. } => true,
_ => false,
}
}
}
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum BrushAntiAliasMode {
@ -1367,6 +1376,154 @@ impl PrimitiveStore {
}
}
fn write_brush_nine_patch_segment_description(
&mut self,
prim_index: PrimitiveIndex,
prim_context: &PrimitiveContext,
clip_store: &mut ClipStore,
node_data: &[ClipScrollNodeData],
clips: &Vec<ClipWorkItem>,
) {
debug_assert!(self.cpu_metadata[prim_index.0].prim_kind == PrimitiveKind::Brush);
if clips.len() != 1 {
return;
}
let clip_item = clips.first().unwrap();
if clip_item.coordinate_system_id != prim_context.scroll_node.coordinate_system_id {
return;
}
let metadata = &self.cpu_metadata[prim_index.0];
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
if brush.segment_desc.is_some() {
return;
}
if !brush.kind.is_solid() {
return;
}
if metadata.local_rect.size.area() <= MIN_BRUSH_SPLIT_AREA {
return;
}
let local_clips = clip_store.get_opt(&clip_item.clip_sources).expect("bug");
let mut selected_clip = None;
for &(ref clip, _) in &local_clips.clips {
match *clip {
ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) => {
if selected_clip.is_some() {
selected_clip = None;
break;
}
selected_clip = Some((rect, radii, clip_item.scroll_node_data_index));
}
ClipSource::Rectangle(..) => {}
ClipSource::RoundedRectangle(_, _, ClipMode::ClipOut) |
ClipSource::BorderCorner(..) |
ClipSource::Image(..) => {
selected_clip = None;
break;
}
}
}
if let Some((rect, radii, clip_scroll_node_data_index)) = selected_clip {
// If the scroll node transforms are different between the clip
// node and the primitive, we need to get the clip rect in the
// local space of the primitive, in order to generate correct
// local segments.
let local_clip_rect = if clip_scroll_node_data_index == prim_context.scroll_node.node_data_index {
rect
} else {
let clip_transform_data = &node_data[clip_scroll_node_data_index.0 as usize];
let prim_transform = &prim_context.scroll_node.world_content_transform;
let relative_transform = prim_transform
.inverse()
.unwrap_or(WorldToLayerTransform::identity())
.pre_mul(&clip_transform_data.transform);
relative_transform.transform_rect(&rect)
};
brush.segment_desc = create_nine_patch(
&metadata.local_rect,
&local_clip_rect,
&radii
);
}
}
fn update_nine_patch_clip_task_for_brush(
&mut self,
prim_context: &PrimitiveContext,
prim_index: PrimitiveIndex,
render_tasks: &mut RenderTaskTree,
clip_store: &mut ClipStore,
tasks: &mut Vec<RenderTaskId>,
node_data: &[ClipScrollNodeData],
clips: &Vec<ClipWorkItem>,
combined_outer_rect: &DeviceIntRect,
) -> bool {
if self.cpu_metadata[prim_index.0].prim_kind != PrimitiveKind::Brush {
return false;
}
self.write_brush_nine_patch_segment_description(
prim_index,
prim_context,
clip_store,
node_data,
clips
);
let metadata = &self.cpu_metadata[prim_index.0];
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
let segment_desc = match brush.segment_desc {
Some(ref mut description) => description,
None => return false,
};
let enabled_segments = segment_desc.enabled_segments;
let can_optimize_clip_mask = segment_desc.can_optimize_clip_mask;
for (i, segment) in segment_desc.segments.iter_mut().enumerate() {
// We only build clips for the corners. The ordering of the
// BrushSegmentKind enum is such that corners come first, then
// edges, then inner.
let segment_enabled = ((1 << i) & enabled_segments) != 0;
let create_clip_task =
segment_enabled &&
(!can_optimize_clip_mask || i <= BrushSegmentKind::BottomLeft as usize);
segment.clip_task_id = if create_clip_task {
let segment_screen_rect = calculate_screen_bounding_rect(
&prim_context.scroll_node.world_content_transform,
&segment.local_rect,
prim_context.device_pixel_ratio
);
combined_outer_rect.intersection(&segment_screen_rect).map(|bounds| {
let clip_task = RenderTask::new_mask(
None,
bounds,
clips.clone(),
prim_context.scroll_node.coordinate_system_id,
);
let clip_task_id = render_tasks.add(clip_task);
tasks.push(clip_task_id);
clip_task_id
})
} else {
None
};
}
true
}
fn update_clip_task(
&mut self,
prim_index: PrimitiveIndex,
@ -1380,13 +1537,12 @@ impl PrimitiveStore {
tasks: &mut Vec<RenderTaskId>,
node_data: &[ClipScrollNodeData],
) -> bool {
let metadata = &mut self.cpu_metadata[prim_index.0];
metadata.clip_task_id = None;
self.cpu_metadata[prim_index.0].clip_task_id = None;
let prim_screen_rect = match prim_screen_rect.intersection(screen_rect) {
Some(rect) => rect,
None => {
metadata.screen_rect = None;
self.cpu_metadata[prim_index.0].screen_rect = None;
return false;
}
};
@ -1400,6 +1556,7 @@ impl PrimitiveStore {
let prim_coordinate_system_id = prim_context.scroll_node.coordinate_system_id;
let transform = &prim_context.scroll_node.world_content_transform;
let extra_clip = {
let metadata = &self.cpu_metadata[prim_index.0];
let prim_clips = clip_store.get_mut(&metadata.clip_sources);
if prim_clips.has_clips() {
prim_clips.update(gpu_cache, resource_cache);
@ -1431,34 +1588,18 @@ impl PrimitiveStore {
let combined_outer_rect = match combined_outer_rect {
Some(rect) if !rect.is_empty() => rect,
_ => {
metadata.screen_rect = None;
self.cpu_metadata[prim_index.0].screen_rect = None;
return false;
}
};
// Filter out all the clip instances that don't contribute to the result.
let mut combined_inner_rect = *screen_rect;
let clips: Vec<_> = ClipChainNodeIter { current: extra_clip }
.chain(ClipChainNodeIter { current: clip_chain })
.take_while(|node| {
!node.combined_inner_screen_rect.contains_rect(&combined_outer_rect)
})
.filter_map(|node| {
combined_inner_rect = if !node.screen_inner_rect.is_empty() {
// If this clip's inner area contains the area of the primitive clipped
// by previous clips, then it's not going to affect rendering in any way.
if node.screen_inner_rect.contains_rect(&combined_outer_rect) {
return None;
}
combined_inner_rect.intersection(&node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero)
} else {
DeviceIntRect::zero()
};
Some(node.work_item.clone())
})
.collect();
let clips = convert_clip_chain_to_clip_vector(
clip_chain,
extra_clip,
&combined_outer_rect,
&mut combined_inner_rect
);
if clips.is_empty() {
// If this item is in the root coordinate system, then
@ -1483,116 +1624,30 @@ impl PrimitiveStore {
return true;
}
let mut needs_prim_clip_task = true;
if metadata.prim_kind == PrimitiveKind::Brush {
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
if brush.segment_desc.is_none() && metadata.local_rect.size.area() > MIN_BRUSH_SPLIT_AREA {
if let BrushKind::Solid { .. } = brush.kind {
if clips.len() == 1 {
let clip_item = clips.first().unwrap();
if clip_item.coordinate_system_id == prim_coordinate_system_id {
let local_clips = clip_store.get_opt(&clip_item.clip_sources).expect("bug");
let mut selected_clip = None;
for &(ref clip, _) in &local_clips.clips {
match *clip {
ClipSource::RoundedRectangle(rect, radii, ClipMode::Clip) => {
if selected_clip.is_some() {
selected_clip = None;
break;
}
selected_clip = Some((rect, radii, clip_item.scroll_node_data_index));
}
ClipSource::Rectangle(..) => {}
ClipSource::RoundedRectangle(_, _, ClipMode::ClipOut) |
ClipSource::BorderCorner(..) |
ClipSource::Image(..) => {
selected_clip = None;
break;
}
}
}
if let Some((rect, radii, clip_scroll_node_data_index)) = selected_clip {
// If the scroll node transforms are different between the clip
// node and the primitive, we need to get the clip rect in the
// local space of the primitive, in order to generate correct
// local segments.
let local_clip_rect = if clip_scroll_node_data_index == prim_context.scroll_node.node_data_index {
rect
} else {
let clip_transform_data = &node_data[clip_scroll_node_data_index.0 as usize];
let prim_transform = &prim_context.scroll_node.world_content_transform;
let relative_transform = prim_transform
.inverse()
.unwrap_or(WorldToLayerTransform::identity())
.pre_mul(&clip_transform_data.transform);
relative_transform.transform_rect(&rect)
};
brush.segment_desc = create_nine_patch(
&metadata.local_rect,
&local_clip_rect,
&radii
);
}
}
}
}
}
if let Some(ref mut segment_desc) = brush.segment_desc {
let enabled_segments = segment_desc.enabled_segments;
let can_optimize_clip_mask = segment_desc.can_optimize_clip_mask;
for (i, segment) in segment_desc.segments.iter_mut().enumerate() {
// We only build clips for the corners. The ordering of the
// BrushSegmentKind enum is such that corners come first, then
// edges, then inner.
let segment_enabled = ((1 << i) & enabled_segments) != 0;
let create_clip_task = segment_enabled &&
(!can_optimize_clip_mask || i <= BrushSegmentKind::BottomLeft as usize);
segment.clip_task_id = if create_clip_task {
let segment_screen_rect = calculate_screen_bounding_rect(
&prim_context.scroll_node.world_content_transform,
&segment.local_rect,
prim_context.device_pixel_ratio
);
combined_outer_rect.intersection(&segment_screen_rect).map(|bounds| {
let clip_task = RenderTask::new_mask(
None,
bounds,
clips.clone(),
prim_coordinate_system_id,
);
let clip_task_id = render_tasks.add(clip_task);
tasks.push(clip_task_id);
clip_task_id
})
} else {
None
};
}
needs_prim_clip_task = false;
}
// First try to render this primitive's mask using optimized nine-patch brush rendering.
if self.update_nine_patch_clip_task_for_brush(
prim_context,
prim_index,
render_tasks,
clip_store,
tasks,
node_data,
&clips,
&combined_outer_rect,
) {
return true;
}
if needs_prim_clip_task {
let clip_task = RenderTask::new_mask(
None,
combined_outer_rect,
clips,
prim_coordinate_system_id,
);
let clip_task = RenderTask::new_mask(
None,
combined_outer_rect,
clips,
prim_coordinate_system_id,
);
let clip_task_id = render_tasks.add(clip_task);
metadata.clip_task_id = Some(clip_task_id);
tasks.push(clip_task_id);
}
let clip_task_id = render_tasks.add(clip_task);
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
tasks.push(clip_task_id);
true
}
@ -1913,3 +1968,33 @@ fn create_nine_patch(
Box::new(desc)
})
}
fn convert_clip_chain_to_clip_vector(
clip_chain: ClipChain,
extra_clip: ClipChain,
combined_outer_rect: &DeviceIntRect,
combined_inner_rect: &mut DeviceIntRect,
) -> Vec<ClipWorkItem> {
// Filter out all the clip instances that don't contribute to the result.
ClipChainNodeIter { current: extra_clip }
.chain(ClipChainNodeIter { current: clip_chain })
.take_while(|node| {
!node.combined_inner_screen_rect.contains_rect(&combined_outer_rect)
})
.filter_map(|node| {
*combined_inner_rect = if !node.screen_inner_rect.is_empty() {
// If this clip's inner area contains the area of the primitive clipped
// by previous clips, then it's not going to affect rendering in any way.
if node.screen_inner_rect.contains_rect(&combined_outer_rect) {
return None;
}
combined_inner_rect.intersection(&node.screen_inner_rect)
.unwrap_or_else(DeviceIntRect::zero)
} else {
DeviceIntRect::zero()
};
Some(node.work_item.clone())
})
.collect()
}

View File

@ -37,15 +37,6 @@ trait ProfileCounter {
fn value(&self) -> String;
}
impl<'a, T: ProfileCounter> ProfileCounter for &'a T {
fn description(&self) -> &'static str {
(*self).description()
}
fn value(&self) -> String {
(*self).value()
}
}
#[derive(Clone)]
pub struct IntProfileCounter {
description: &'static str,
@ -309,9 +300,6 @@ impl ProfileCounter for AverageTimeProfileCounter {
pub struct FrameProfileCounters {
pub total_primitives: IntProfileCounter,
pub visible_primitives: IntProfileCounter,
pub passes: IntProfileCounter,
pub color_targets: IntProfileCounter,
pub alpha_targets: IntProfileCounter,
}
impl FrameProfileCounters {
@ -319,9 +307,6 @@ impl FrameProfileCounters {
FrameProfileCounters {
total_primitives: IntProfileCounter::new("Total Primitives"),
visible_primitives: IntProfileCounter::new("Visible Primitives"),
passes: IntProfileCounter::new("Passes"),
color_targets: IntProfileCounter::new("Color Targets"),
alpha_targets: IntProfileCounter::new("Alpha Targets"),
}
}
}
@ -449,6 +434,8 @@ pub struct RendererProfileCounters {
pub draw_calls: IntProfileCounter,
pub vertices: IntProfileCounter,
pub vao_count_and_size: ResourceProfileCounter,
pub color_targets: IntProfileCounter,
pub alpha_targets: IntProfileCounter,
}
pub struct RendererProfileTimers {
@ -465,12 +452,16 @@ impl RendererProfileCounters {
draw_calls: IntProfileCounter::new("Draw Calls"),
vertices: IntProfileCounter::new("Vertices"),
vao_count_and_size: ResourceProfileCounter::new("VAO"),
color_targets: IntProfileCounter::new("Color Targets"),
alpha_targets: IntProfileCounter::new("Alpha Targets"),
}
}
pub fn reset(&mut self) {
self.draw_calls.reset();
self.vertices.reset();
self.color_targets.reset();
self.alpha_targets.reset();
}
}
@ -493,13 +484,18 @@ struct GraphStats {
struct ProfileGraph {
max_samples: usize,
values: VecDeque<f32>,
short_description: &'static str,
}
impl ProfileGraph {
fn new(max_samples: usize) -> Self {
fn new(
max_samples: usize,
short_description: &'static str,
) -> Self {
ProfileGraph {
max_samples,
values: VecDeque::new(),
short_description,
}
}
@ -620,6 +616,16 @@ impl ProfileGraph {
}
}
impl ProfileCounter for ProfileGraph {
fn description(&self) -> &'static str {
self.short_description
}
fn value(&self) -> String {
format!("{:.2}ms", self.stats().mean_value)
}
}
struct GpuFrame {
total_time: u64,
samples: Vec<GpuTimer<GpuProfileTag>>,
@ -737,11 +743,15 @@ impl GpuFrameCollection {
}
}
pub struct Profiler {
struct DrawState {
x_left: f32,
y_left: f32,
x_right: f32,
y_right: f32,
}
pub struct Profiler {
draw_state: DrawState,
backend_time: ProfileGraph,
compositor_time: ProfileGraph,
gpu_time: ProfileGraph,
@ -752,30 +762,32 @@ pub struct Profiler {
impl Profiler {
pub fn new() -> Self {
Profiler {
x_left: 0.0,
y_left: 0.0,
x_right: 0.0,
y_right: 0.0,
backend_time: ProfileGraph::new(600),
compositor_time: ProfileGraph::new(600),
gpu_time: ProfileGraph::new(600),
draw_state: DrawState {
x_left: 0.0,
y_left: 0.0,
x_right: 0.0,
y_right: 0.0,
},
backend_time: ProfileGraph::new(600, "Backend:"),
compositor_time: ProfileGraph::new(600, "Compositor:"),
gpu_time: ProfileGraph::new(600, "GPU:"),
gpu_frames: GpuFrameCollection::new(),
ipc_time: ProfileGraph::new(600),
ipc_time: ProfileGraph::new(600, "IPC:"),
}
}
fn draw_counters<T: ProfileCounter>(
&mut self,
counters: &[T],
fn draw_counters<T: ProfileCounter + ?Sized>(
counters: &[&T],
debug_renderer: &mut DebugRenderer,
left: bool,
draw_state: &mut DrawState,
) {
let mut label_rect = Rect::zero();
let mut value_rect = Rect::zero();
let (mut current_x, mut current_y) = if left {
(self.x_left, self.y_left)
(draw_state.x_left, draw_state.y_left)
} else {
(self.x_right, self.y_right)
(draw_state.x_right, draw_state.y_right)
};
let mut color_index = 0;
let line_height = debug_renderer.line_height();
@ -800,7 +812,7 @@ impl Profiler {
color_index = 0;
current_x = label_rect.origin.x + label_rect.size.width + 60.0;
current_y = if left { self.y_left } else { self.y_right };
current_y = if left { draw_state.y_left } else { draw_state.y_right };
for counter in counters {
let rect = debug_renderer.add_text(
@ -826,9 +838,9 @@ impl Profiler {
);
let new_y = total_rect.origin.y + total_rect.size.height + 30.0;
if left {
self.y_left = new_y;
draw_state.y_left = new_y;
} else {
self.y_right = new_y;
draw_state.y_right = new_y;
}
}
@ -840,15 +852,15 @@ impl Profiler {
debug_renderer: &mut DebugRenderer,
) -> Rect<f32> {
let mut rect = debug_renderer.add_text(
self.x_left,
self.y_left,
self.draw_state.x_left,
self.draw_state.y_left,
label,
label_color,
);
let x_base = rect.origin.x + rect.size.width + 10.0;
let height = debug_renderer.line_height();
let width = (self.x_right - 30.0 - x_base).max(0.0);
let width = (self.draw_state.x_right - 30.0 - x_base).max(0.0);
let total_value = counters.last().unwrap().1.value;
let scale = width / total_value as f32;
let mut x_current = x_base;
@ -866,7 +878,7 @@ impl Profiler {
x_current = x_stop;
}
self.y_left += height;
self.draw_state.y_left += height;
rect.size.width += width + 10.0;
rect
@ -922,10 +934,31 @@ impl Profiler {
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
);
self.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
}
pub fn draw_profile(
fn draw_compact_profile(
&mut self,
renderer_profile: &RendererProfileCounters,
debug_renderer: &mut DebugRenderer,
) {
Profiler::draw_counters(
&[
&renderer_profile.frame_time as &ProfileCounter,
&renderer_profile.color_targets,
&renderer_profile.alpha_targets,
&renderer_profile.draw_calls,
&self.backend_time,
&self.compositor_time,
&self.gpu_time,
],
debug_renderer,
true,
&mut self.draw_state,
);
}
fn draw_full_profile(
&mut self,
frame_profiles: &[FrameProfileCounters],
backend_profile: &BackendProfileCounters,
@ -935,36 +968,34 @@ impl Profiler {
screen_fraction: f32,
debug_renderer: &mut DebugRenderer,
) {
self.x_left = 20.0;
self.y_left = 40.0;
self.x_right = 450.0;
self.y_right = 40.0;
let mut gpu_time = 0;
let gpu_timers = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
for sample in &gpu_timers {
gpu_time += sample.time_ns;
}
renderer_timers.gpu_time.set(gpu_time);
self.draw_counters(&[&renderer_profile.frame_time], debug_renderer, true);
self.draw_counters(&[&renderer_profile.frame_counter], debug_renderer, true);
Profiler::draw_counters(
&[
&renderer_profile.frame_time as &ProfileCounter,
&renderer_profile.frame_counter,
&renderer_profile.color_targets,
&renderer_profile.alpha_targets,
],
debug_renderer,
true,
&mut self.draw_state
);
self.draw_gpu_cache_bars(
&backend_profile.resources.gpu_cache,
debug_renderer,
);
self.draw_counters(
Profiler::draw_counters(
&[
&backend_profile.resources.font_templates,
&backend_profile.resources.image_templates,
],
debug_renderer,
true,
&mut self.draw_state
);
self.draw_counters(
Profiler::draw_counters(
&[
&backend_profile.resources.texture_cache.pages_a8_linear,
&backend_profile.resources.texture_cache.pages_rgb8_linear,
@ -975,9 +1006,10 @@ impl Profiler {
],
debug_renderer,
true,
&mut self.draw_state
);
self.draw_counters(
Profiler::draw_counters(
&[
&backend_profile.ipc.build_time,
&backend_profile.ipc.send_time,
@ -986,29 +1018,29 @@ impl Profiler {
],
debug_renderer,
true,
&mut self.draw_state
);
for frame_profile in frame_profiles {
self.draw_counters(
Profiler::draw_counters(
&[
&frame_profile.total_primitives,
&frame_profile.visible_primitives,
&frame_profile.passes,
&frame_profile.color_targets,
&frame_profile.alpha_targets,
],
debug_renderer,
true,
&mut self.draw_state
);
}
self.draw_counters(
Profiler::draw_counters(
&[&renderer_profile.draw_calls, &renderer_profile.vertices],
debug_renderer,
true,
&mut self.draw_state
);
self.draw_counters(
Profiler::draw_counters(
&[
&backend_profile.total_time,
&renderer_timers.cpu_time,
@ -1016,6 +1048,7 @@ impl Profiler {
],
debug_renderer,
false,
&mut self.draw_state
);
if !gpu_samplers.is_empty() {
@ -1034,9 +1067,63 @@ impl Profiler {
}),
}
}
self.draw_counters(&samplers, debug_renderer, false);
let samplers: Vec<&ProfileCounter> = samplers.iter().map(|sampler| {
sampler as &ProfileCounter
}).collect();
Profiler::draw_counters(
&samplers,
debug_renderer,
false,
&mut self.draw_state,
);
}
let rect =
self.backend_time
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "CPU (backend)", debug_renderer);
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.compositor_time.draw_graph(
self.draw_state.x_right,
self.draw_state.y_right,
"CPU (compositor)",
debug_renderer,
);
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
let rect =
self.ipc_time
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "DisplayList IPC", debug_renderer);
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.gpu_time
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "GPU", debug_renderer);
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.gpu_frames
.draw(self.draw_state.x_left, f32::max(self.draw_state.y_left, self.draw_state.y_right), debug_renderer);
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
}
pub fn draw_profile(
&mut self,
frame_profiles: &[FrameProfileCounters],
backend_profile: &BackendProfileCounters,
renderer_profile: &RendererProfileCounters,
renderer_timers: &mut RendererProfileTimers,
gpu_samplers: &[GpuSampler<GpuProfileTag>],
screen_fraction: f32,
debug_renderer: &mut DebugRenderer,
compact: bool,
) {
self.draw_state.x_left = 20.0;
self.draw_state.y_left = 40.0;
self.draw_state.x_right = 450.0;
self.draw_state.y_right = 40.0;
let mut gpu_time = 0;
let gpu_timers = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
for sample in &gpu_timers {
gpu_time += sample.time_ns;
}
renderer_timers.gpu_time.set(gpu_time);
self.backend_time
.push(backend_profile.total_time.nanoseconds);
self.compositor_time
@ -1046,27 +1133,21 @@ impl Profiler {
self.gpu_time.push(gpu_time);
self.gpu_frames.push(gpu_time, gpu_timers);
let rect =
self.backend_time
.draw_graph(self.x_right, self.y_right, "CPU (backend)", debug_renderer);
self.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.compositor_time.draw_graph(
self.x_right,
self.y_right,
"CPU (compositor)",
debug_renderer,
);
self.y_right += rect.size.height + PROFILE_PADDING;
let rect =
self.ipc_time
.draw_graph(self.x_right, self.y_right, "DisplayList IPC", debug_renderer);
self.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.gpu_time
.draw_graph(self.x_right, self.y_right, "GPU", debug_renderer);
self.y_right += rect.size.height + PROFILE_PADDING;
let rect = self.gpu_frames
.draw(self.x_left, f32::max(self.y_left, self.y_right), debug_renderer);
self.y_right += rect.size.height + PROFILE_PADDING;
if compact {
self.draw_compact_profile(
renderer_profile,
debug_renderer,
);
} else {
self.draw_full_profile(
frame_profiles,
backend_profile,
renderer_profile,
renderer_timers,
gpu_samplers,
screen_fraction,
debug_renderer,
);
}
}
}

View File

@ -9,6 +9,7 @@ use clip::{ClipSourcesWeakHandle};
use clip_scroll_tree::CoordinateSystemId;
use euclid::TypedSize2D;
use gpu_types::{ClipScrollNodeIndex};
use internal_types::RenderPassIndex;
use picture::RasterizationSpace;
use prim_store::{PrimitiveIndex};
#[cfg(feature = "debugger")]
@ -241,6 +242,7 @@ pub struct RenderTask {
pub children: Vec<RenderTaskId>,
pub kind: RenderTaskKind,
pub clear_mode: ClearMode,
pub pass_index: Option<RenderPassIndex>,
}
impl RenderTask {
@ -276,6 +278,7 @@ impl RenderTask {
rasterization_kind,
}),
clear_mode,
pass_index: None,
}
}
@ -286,6 +289,7 @@ impl RenderTask {
location: RenderTaskLocation::Dynamic(None, screen_rect.size),
kind: RenderTaskKind::Readback(screen_rect),
clear_mode: ClearMode::Transparent,
pass_index: None,
}
}
@ -305,6 +309,7 @@ impl RenderTask {
coordinate_system_id: prim_coordinate_system_id,
}),
clear_mode: ClearMode::One,
pass_index: None,
}
}
@ -375,6 +380,7 @@ impl RenderTask {
scale_factor,
}),
clear_mode,
pass_index: None,
};
let blur_task_v_id = render_tasks.add(blur_task_v);
@ -394,6 +400,7 @@ impl RenderTask {
scale_factor,
}),
clear_mode,
pass_index: None,
};
blur_task_h
@ -417,6 +424,7 @@ impl RenderTask {
RenderTargetKind::Color => ClearMode::Transparent,
RenderTargetKind::Alpha => ClearMode::One,
},
pass_index: None,
}
}

View File

@ -40,7 +40,7 @@ use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
use gpu_types::PrimitiveInstance;
use internal_types::{BatchTextures, SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE};
use internal_types::{CacheTextureId, FastHashMap, RenderedDocument, ResultMsg, TextureUpdateOp};
use internal_types::{DebugOutput, RenderTargetInfo, TextureUpdateList, TextureUpdateSource};
use internal_types::{DebugOutput, RenderPassIndex, RenderTargetInfo, TextureUpdateList, TextureUpdateSource};
use profiler::{BackendProfileCounters, Profiler};
use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
use query::{GpuProfiler, GpuTimer};
@ -65,8 +65,8 @@ use std::thread;
use texture_cache::TextureCache;
use thread_profiler::{register_thread_with_profiler, write_profile};
use tiling::{AlphaRenderTarget, ColorRenderTarget};
use tiling::{RenderPass, RenderPassKind, RenderTargetKind, RenderTargetList};
use tiling::{BatchKey, BatchKind, BrushBatchKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
use tiling::{RenderPass, RenderPassKind, RenderTargetList};
use tiling::{BatchKey, BatchKind, BrushBatchKind, BrushImageSourceKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
use time::precise_time_ns;
use util::TransformedRectKind;
@ -256,6 +256,7 @@ bitflags! {
const GPU_SAMPLE_QUERIES= 1 << 5;
const DISABLE_BATCHING = 1 << 6;
const EPOCHS = 1 << 7;
const COMPACT_PROFILER = 1 << 8;
}
}
@ -551,6 +552,8 @@ impl CpuProfile {
}
}
struct RenderTargetPoolId(usize);
struct SourceTextureResolver {
/// A vector for fast resolves of texture cache IDs to
/// native texture IDs. This maps to a free-list managed
@ -573,6 +576,11 @@ struct SourceTextureResolver {
/// The current cache textures.
cache_rgba8_texture: Option<Texture>,
cache_a8_texture: Option<Texture>,
pass_rgba8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
pass_a8_textures: FastHashMap<RenderPassIndex, RenderTargetPoolId>,
render_target_pool: Vec<Texture>,
}
impl SourceTextureResolver {
@ -595,6 +603,9 @@ impl SourceTextureResolver {
dummy_cache_texture,
cache_a8_texture: None,
cache_rgba8_texture: None,
pass_rgba8_textures: FastHashMap::default(),
pass_a8_textures: FastHashMap::default(),
render_target_pool: Vec::new(),
}
}
@ -604,27 +615,44 @@ impl SourceTextureResolver {
for texture in self.cache_texture_map {
device.delete_texture(texture);
}
for texture in self.render_target_pool {
device.delete_texture(texture);
}
}
fn begin_frame(&self) {
fn begin_frame(&mut self) {
assert!(self.cache_rgba8_texture.is_none());
assert!(self.cache_a8_texture.is_none());
self.pass_rgba8_textures.clear();
self.pass_a8_textures.clear();
}
fn end_frame(&mut self, pool: &mut Vec<Texture>) {
fn end_frame(&mut self, pass_index: RenderPassIndex) {
// return the cached targets to the pool
self.end_pass(None, None, pool)
self.end_pass(None, None, pass_index)
}
fn end_pass(
&mut self,
a8_texture: Option<Texture>,
rgba8_texture: Option<Texture>,
pool: &mut Vec<Texture>,
pass_index: RenderPassIndex,
) {
// If we have cache textures from previous pass, return them to the pool.
pool.extend(self.cache_rgba8_texture.take());
pool.extend(self.cache_a8_texture.take());
// Also assign the pool index of those cache textures to last pass's index because this is
// the result of last pass.
if let Some(texture) = self.cache_rgba8_texture.take() {
self.pass_rgba8_textures.insert(
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
self.render_target_pool.push(texture);
}
if let Some(texture) = self.cache_a8_texture.take() {
self.pass_a8_textures.insert(
RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len()));
self.render_target_pool.push(texture);
}
// We have another pass to process, make these textures available
// as inputs to the next pass.
@ -658,6 +686,18 @@ impl SourceTextureResolver {
let texture = &self.cache_texture_map[index.0];
device.bind_texture(sampler, texture);
}
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
let pool_index = self.pass_rgba8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
}
SourceTexture::RenderTaskCacheA8(pass_index) => {
let pool_index = self.pass_a8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
device.bind_texture(sampler, &self.render_target_pool[pool_index.0])
}
}
}
@ -681,6 +721,18 @@ impl SourceTextureResolver {
panic!("BUG: External textures cannot be resolved, they can only be bound.");
}
SourceTexture::TextureCache(index) => Some(&self.cache_texture_map[index.0]),
SourceTexture::RenderTaskCacheRGBA8(pass_index) => {
let pool_index = self.pass_rgba8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
Some(&self.render_target_pool[pool_index.0])
},
SourceTexture::RenderTaskCacheA8(pass_index) => {
let pool_index = self.pass_a8_textures
.get(&pass_index)
.expect("BUG: pass_index doesn't map to pool_index");
Some(&self.render_target_pool[pool_index.0])
},
}
}
}
@ -1349,6 +1401,7 @@ pub struct Renderer {
brush_mask_corner: LazilyCompiledShader,
brush_mask_rounded_rect: LazilyCompiledShader,
brush_image_rgba8: BrushShader,
brush_image_rgba8_alpha_mask: BrushShader,
brush_image_a8: BrushShader,
brush_solid: BrushShader,
@ -1394,8 +1447,6 @@ pub struct Renderer {
profiler: Profiler,
last_time: u64,
render_target_pool: Vec<Texture>,
gpu_profile: GpuProfiler<GpuProfileTag>,
prim_vao: VAO,
blur_vao: VAO,
@ -1574,6 +1625,13 @@ impl Renderer {
options.precache_shaders)
};
let brush_image_rgba8_alpha_mask = try!{
BrushShader::new("brush_image",
&mut device,
&["COLOR_TARGET_ALPHA_MASK"],
options.precache_shaders)
};
let cs_blur_a8 = try!{
LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur),
"cs_blur",
@ -1998,6 +2056,7 @@ impl Renderer {
brush_mask_corner,
brush_mask_rounded_rect,
brush_image_rgba8,
brush_image_rgba8_alpha_mask,
brush_image_a8,
brush_solid,
cs_clip_rectangle,
@ -2027,7 +2086,6 @@ impl Renderer {
clear_color: options.clear_color,
enable_clear_scissor: options.enable_clear_scissor,
last_time: 0,
render_target_pool: Vec::new(),
gpu_profile,
prim_vao,
blur_vao,
@ -2549,6 +2607,7 @@ impl Renderer {
&profile_samplers,
screen_fraction,
&mut self.debug,
self.debug_flags.contains(DebugFlags::COMPACT_PROFILER),
);
}
@ -2778,8 +2837,9 @@ impl Renderer {
}
BrushBatchKind::Image(target_kind) => {
let shader = match target_kind {
RenderTargetKind::Alpha => &mut self.brush_image_a8,
RenderTargetKind::Color => &mut self.brush_image_rgba8,
BrushImageSourceKind::Alpha => &mut self.brush_image_a8,
BrushImageSourceKind::Color => &mut self.brush_image_rgba8,
BrushImageSourceKind::ColorAlphaMask => &mut self.brush_image_rgba8_alpha_mask,
};
shader.bind(
&mut self.device,
@ -2987,6 +3047,7 @@ impl Renderer {
frame_id: FrameId,
stats: &mut RendererStats,
) {
self.profile_counters.color_targets.inc();
let _gm = self.gpu_profile.start_marker("color target");
// sanity check for the depth buffer
@ -3408,6 +3469,7 @@ impl Renderer {
render_tasks: &RenderTaskTree,
stats: &mut RendererStats,
) {
self.profile_counters.alpha_targets.inc();
let _gm = self.gpu_profile.start_marker("alpha target");
let alpha_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_ALPHA);
@ -3684,7 +3746,7 @@ impl Renderer {
num_layers: list.targets.len() as _,
format: list.format,
};
let index = self.render_target_pool
let index = self.texture_resolver.render_target_pool
.iter()
.position(|texture| {
selector == TargetSelector {
@ -3694,14 +3756,14 @@ impl Renderer {
}
});
match index {
Some(pos) => self.render_target_pool.swap_remove(pos),
Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos),
None => return,
}
} else {
if list.texture.is_some() {
return
}
match self.render_target_pool.pop() {
match self.texture_resolver.render_target_pool.pop() {
Some(texture) => texture,
None => self.device.create_texture(TextureTarget::Array),
}
@ -3885,7 +3947,7 @@ impl Renderer {
self.texture_resolver.end_pass(
cur_alpha,
cur_color,
&mut self.render_target_pool,
RenderPassIndex(pass_index),
);
// After completing the first pass, make the A8 target available as an
@ -3900,7 +3962,7 @@ impl Renderer {
}
}
self.texture_resolver.end_frame(&mut self.render_target_pool);
self.texture_resolver.end_frame(RenderPassIndex(frame.passes.len()));
self.draw_render_target_debug(framebuffer_size);
self.draw_texture_cache_debug(framebuffer_size);
self.draw_epoch_debug();
@ -3967,7 +4029,7 @@ impl Renderer {
let mut spacing = 16;
let mut size = 512;
let fb_width = framebuffer_size.width as i32;
let num_layers: i32 = self.render_target_pool
let num_layers: i32 = self.texture_resolver.render_target_pool
.iter()
.map(|texture| texture.get_render_target_layer_count() as i32)
.sum();
@ -3979,7 +4041,7 @@ impl Renderer {
}
let mut target_index = 0;
for texture in &self.render_target_pool {
for texture in &self.texture_resolver.render_target_pool {
let dimensions = texture.get_dimensions();
let src_rect = DeviceIntRect::new(DeviceIntPoint::zero(), dimensions.to_i32());
@ -4121,9 +4183,6 @@ impl Renderer {
}
self.node_data_texture.deinit(&mut self.device);
self.render_task_texture.deinit(&mut self.device);
for texture in self.render_target_pool {
self.device.delete_texture(texture);
}
self.device.delete_pbo(self.texture_cache_upload_pbo);
self.texture_resolver.deinit(&mut self.device);
self.device.delete_vao(self.prim_vao);
@ -4137,6 +4196,7 @@ impl Renderer {
self.brush_mask_rounded_rect.deinit(&mut self.device);
self.brush_mask_corner.deinit(&mut self.device);
self.brush_image_rgba8.deinit(&mut self.device);
self.brush_image_rgba8_alpha_mask.deinit(&mut self.device);
self.brush_image_a8.deinit(&mut self.device);
self.brush_solid.deinit(&mut self.device);
self.cs_clip_rectangle.deinit(&mut self.device);

View File

@ -162,7 +162,8 @@ impl FilterOpHelpers for FilterOp {
FilterOp::HueRotate(..) |
FilterOp::Invert(..) |
FilterOp::Saturate(..) |
FilterOp::Sepia(..) => true,
FilterOp::Sepia(..) |
FilterOp::DropShadow(..) => true,
FilterOp::Opacity(_, amount) => {
amount > OPACITY_EPSILON
}
@ -180,6 +181,9 @@ impl FilterOpHelpers for FilterOp {
FilterOp::Opacity(_, amount) => amount >= 1.0,
FilterOp::Saturate(amount) => amount == 1.0,
FilterOp::Sepia(amount) => amount == 0.0,
FilterOp::DropShadow(offset, blur, _) => {
offset.x == 0.0 && offset.y == 0.0 && blur == 0.0
}
}
}
}

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadiusKind, ClipId, ColorF, DeviceIntPoint, ImageKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{DeviceIntRect, DeviceIntSize, device_length, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{DocumentLayer, ExternalImageType, FilterOp, FontRenderMode};
use api::{ImageFormat, ImageRendering};
use api::{LayerRect, MixBlendMode, PipelineId};
@ -20,7 +20,7 @@ use gpu_types::{BlurDirection, BlurInstance, BrushInstance, BrushImageKind, Clip
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use internal_types::{FastHashMap, SourceTexture};
use internal_types::{BatchTextures};
use internal_types::{BatchTextures, RenderPassIndex};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, RasterizationSpace};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
@ -148,9 +148,6 @@ pub struct ScrollbarPrimitive {
#[derive(Debug, Copy, Clone)]
pub struct RenderTargetIndex(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct RenderPassIndex(isize);
#[derive(Debug)]
struct DynamicTaskInfo {
task_id: RenderTaskId,
@ -627,7 +624,8 @@ fn add_to_batch(
match picture.kind {
PictureKind::TextShadow { .. } => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(picture.target_kind()),
BrushBatchKind::Image(
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
);
let key = BatchKey::new(kind, blend_mode, textures);
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
@ -647,7 +645,8 @@ fn add_to_batch(
}
PictureKind::BoxShadow { radii_kind, .. } => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(picture.target_kind()),
BrushBatchKind::Image(
BrushImageSourceKind::from_render_target_kind(picture.target_kind())),
);
let key = BatchKey::new(kind, blend_mode, textures);
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
@ -676,7 +675,7 @@ fn add_to_batch(
}
PictureKind::Image {
composite_mode,
readback_render_task_id,
secondary_render_task_id,
is_in_3d_context,
reference_frame_id,
real_local_rect,
@ -717,7 +716,7 @@ fn add_to_batch(
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
BatchTextures::render_target_cache(),
);
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
let instance = CompositePrimitiveInstance::new(
@ -733,6 +732,61 @@ fn add_to_batch(
batch.push(PrimitiveInstance::from(instance));
}
FilterOp::DropShadow(offset, _, _) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(BrushImageSourceKind::ColorAlphaMask),
);
let key = BatchKey::new(kind, blend_mode, textures);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_id,
scroll_id,
clip_task_address,
z,
segment_kind: 0,
user_data0: cache_task_address.0 as i32,
user_data1: BrushImageKind::Simple as i32,
};
{
let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
batch.push(PrimitiveInstance::from(instance));
}
let secondary_id = secondary_render_task_id.expect("no secondary!?");
let render_task = &render_tasks[secondary_id];
let secondary_task_address = render_tasks.get_task_address(secondary_id);
let render_pass_index = render_task.pass_index.expect("no render_pass_index!?");
let secondary_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCacheRGBA8(render_pass_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
};
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
secondary_textures,
);
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
let device_offset_x = device_length(offset.x, ctx.device_pixel_ratio);
let device_offset_y = device_length(offset.y, ctx.device_pixel_ratio);
let instance = CompositePrimitiveInstance::new(
task_address,
secondary_task_address,
RenderTaskAddress(0),
item_bounding_rect.origin.x - device_offset_x.0,
item_bounding_rect.origin.y - device_offset_y.0,
z,
item_bounding_rect.size.width,
item_bounding_rect.size.height,
);
batch.push(PrimitiveInstance::from(instance));
}
_ => {
let key = BatchKey::new(
BatchKind::Blend,
@ -751,6 +805,7 @@ fn add_to_batch(
FilterOp::Sepia(amount) => (6, amount),
FilterOp::Brightness(amount) => (7, amount),
FilterOp::Opacity(_, amount) => (8, amount),
FilterOp::DropShadow(..) => unreachable!(),
};
let amount = (amount * 65535.0).round() as i32;
@ -772,7 +827,7 @@ fn add_to_batch(
}
}
PictureCompositeMode::MixBlend(mode) => {
let backdrop_id = readback_render_task_id.expect("no backdrop!?");
let backdrop_id = secondary_render_task_id.expect("no backdrop!?");
let key = BatchKey::new(
BatchKind::Composite {
@ -805,7 +860,7 @@ fn add_to_batch(
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
BatchTextures::render_target_cache(),
);
let batch = batch_list.get_suitable_batch(key, &item_bounding_rect);
let instance = CompositePrimitiveInstance::new(
@ -1796,6 +1851,7 @@ impl RenderPass {
render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>,
clip_store: &ClipStore,
pass_index: RenderPassIndex,
) {
profile_scope!("RenderPass::build");
@ -1803,6 +1859,7 @@ impl RenderPass {
RenderPassKind::MainFramebuffer(ref mut target) => {
for &task_id in &self.tasks {
assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color);
render_tasks[task_id].pass_index = Some(pass_index);
target.add_task(task_id, ctx, gpu_cache, render_tasks, clip_store);
}
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
@ -1812,6 +1869,7 @@ impl RenderPass {
for &task_id in &self.tasks {
let target_kind = {
let task = &mut render_tasks[task_id];
task.pass_index = Some(pass_index);
let target_kind = task.target_kind();
// Find a target to assign this task to, or create a new
@ -1880,9 +1938,25 @@ pub enum TransformBatchKind {
Line,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
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,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum BrushBatchKind {
Image(RenderTargetKind),
Image(BrushImageSourceKind),
Solid,
}

View File

@ -20,7 +20,7 @@ serde = { version = "1.0", features = ["rc", "derive"] }
time = "0.1"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.4"
core-foundation = "0.4.6"
core-graphics = "0.12.3"
[target.'cfg(target_os = "windows")'.dependencies]

View File

@ -458,6 +458,7 @@ pub enum FilterOp {
Opacity(PropertyBinding<f32>, f32),
Saturate(f32),
Sepia(f32),
DropShadow(LayoutVector2D, f32, ColorF),
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]

View File

@ -21,7 +21,7 @@ default-features = false
dwrote = "0.4.1"
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.4"
core-foundation = "0.4.6"
core-graphics = "0.12.3"
foreign-types = "0.3.0"