Bug 1491130. Update webrender to commit da76f6aad61c1ba769566861ec41b42d511fa456

This commit is contained in:
Jeff Muizelaar 2018-09-14 13:39:33 -04:00
parent 6c22936032
commit 7dd93d2e5d
18 changed files with 259 additions and 128 deletions

View File

@ -48,7 +48,7 @@ vec2 transform_point_snapped(
RectWithSize local_rect,
mat4 transform
) {
vec2 snap_offset = compute_snap_offset(local_pos, transform, local_rect, vec2(0.5));
vec2 snap_offset = compute_snap_offset(local_pos, transform, local_rect);
vec4 world_pos = transform * vec4(local_pos, 0.0, 1.0);
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;

View File

@ -74,8 +74,7 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
clip_transform.m,
local_clip_rect,
RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy),
snap_positions,
vec2(0.5)
snap_positions
);
device_pos -= snap_offsets;

View File

@ -114,8 +114,7 @@ VertexInfo write_vertex(RectWithSize instance_rect,
vec2 snap_offset = compute_snap_offset(
clamped_local_pos,
transform.m,
snap_rect,
vec2(0.5)
snap_rect
);
// Transform the current vertex to world space.

View File

@ -61,64 +61,86 @@ TextRun fetch_text_run(int address) {
return TextRun(data[0], data[1], data[2].xy);
}
VertexInfo write_text_vertex(vec2 clamped_local_pos,
RectWithSize local_clip_rect,
VertexInfo write_text_vertex(RectWithSize local_clip_rect,
float z,
Transform transform,
PictureTask task,
vec2 text_offset,
RectWithSize snap_rect,
vec2 glyph_offset,
RectWithSize glyph_rect,
vec2 snap_bias) {
// Transform the current vertex to world space.
vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
// Convert the world positions to device pixel space.
float device_scale = uDevicePixelRatio / world_pos.w;
vec2 device_pos = world_pos.xy * device_scale;
// The offset to snap the glyph rect to a device pixel
vec2 snap_offset = vec2(0.0);
mat2 local_transform;
#if defined(WR_FEATURE_GLYPH_TRANSFORM)
#ifdef WR_FEATURE_GLYPH_TRANSFORM
bool remove_subpx_offset = true;
#else
bool remove_subpx_offset = transform.is_axis_aligned;
#endif
// Compute the snapping offset only if the scroll node transform is axis-aligned.
if (remove_subpx_offset) {
// Transform from local space to device space.
float device_scale = uDevicePixelRatio / transform.m[3].w;
mat2 device_transform = mat2(transform.m) * device_scale;
// Ensure the transformed text offset does not contain a subpixel translation
// such that glyph snapping is stable for equivalent glyph subpixel positions.
vec2 world_text_offset = mat2(transform.m) * text_offset;
vec2 device_text_pos = (transform.m[3].xy + world_text_offset) * device_scale;
snap_offset += floor(device_text_pos + 0.5) - device_text_pos;
vec2 device_text_pos = device_transform * text_offset + transform.m[3].xy * device_scale;
snap_offset = floor(device_text_pos + 0.5) - device_text_pos;
#ifdef WR_FEATURE_GLYPH_TRANSFORM
// For transformed subpixels, we just need to align the glyph origin to a device pixel.
// The transformed text offset has already been snapped, so remove it from the glyph
// origin when snapping the glyph.
vec2 rough_offset = snap_rect.p0 - world_text_offset * device_scale;
snap_offset += floor(rough_offset + snap_bias) - rough_offset;
#else
// The transformed text offset has already been snapped, so remove it from the transform
// when snapping the glyph.
mat4 snap_transform = transform.m;
snap_transform[3].xy = -world_text_offset;
snap_offset += compute_snap_offset(
clamped_local_pos,
snap_transform,
snap_rect,
snap_bias
);
// Snap the glyph offset to a device pixel, using an appropriate bias depending
// on whether subpixel positioning is required.
vec2 device_glyph_offset = device_transform * glyph_offset;
snap_offset += floor(device_glyph_offset + snap_bias) - device_glyph_offset;
// Transform from device space back to local space.
local_transform = inverse(device_transform);
#ifndef WR_FEATURE_GLYPH_TRANSFORM
// If not using transformed subpixels, the glyph rect is actually in local space.
// So convert the snap offset back to local space.
snap_offset = local_transform * snap_offset;
#endif
}
// Actually translate the glyph rect to a device pixel using the snap offset.
glyph_rect.p0 += snap_offset;
#ifdef WR_FEATURE_GLYPH_TRANSFORM
// The glyph rect is in device space, so transform it back to local space.
RectWithSize local_rect = transform_rect(glyph_rect, local_transform);
// 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;
// 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.
if (rect_inside_rect(local_rect, local_clip_rect)) {
local_pos = local_transform * (glyph_rect.p0 + glyph_rect.size * aPosition.xy);
}
#else
// Select the corner of the glyph rect that we are processing.
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
#endif
// Clamp to the local clip rect.
local_pos = clamp_rect(local_pos, local_clip_rect);
// Map the clamped local space corner into device space.
vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0);
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
// Apply offsets for the render task to get correct screen location.
vec2 final_pos = device_pos + snap_offset -
vec2 final_pos = device_pos -
task.content_origin +
task.common_data.task_rect.p0;
gl_Position = uTransform * vec4(final_pos, z, 1.0);
VertexInfo vi = VertexInfo(
clamped_local_pos,
local_pos,
snap_offset,
world_pos
);
@ -156,19 +178,6 @@ void main(void) {
RectWithSize glyph_rect = RectWithSize(res.offset + glyph_transform * (text.offset + glyph.offset),
res.uv_rect.zw - res.uv_rect.xy);
// Transform the glyph rect back to local space.
mat2 inv = inverse(glyph_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;
// 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, ph.local_clip_rect) ?
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
clamp_rect(local_pos, ph.local_clip_rect);
#else
// Scale from glyph space to local space.
float scale = res.scale / uDevicePixelRatio;
@ -176,12 +185,6 @@ void main(void) {
// Compute the glyph rect in local space.
RectWithSize glyph_rect = RectWithSize(scale * res.offset + text.offset + glyph.offset,
scale * (res.uv_rect.zw - res.uv_rect.xy));
// 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 local clip rect.
local_pos = clamp_rect(local_pos, ph.local_clip_rect);
#endif
vec2 snap_bias;
@ -209,14 +212,15 @@ void main(void) {
break;
}
VertexInfo vi = write_text_vertex(local_pos,
ph.local_clip_rect,
VertexInfo vi = write_text_vertex(ph.local_clip_rect,
ph.z,
transform,
task,
text.offset,
glyph.offset,
glyph_rect,
snap_bias);
glyph_rect.p0 += vi.snap_offset;
#ifdef WR_FEATURE_GLYPH_TRANSFORM
vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;

View File

@ -27,11 +27,10 @@ vec2 compute_snap_offset_impl(
mat4 transform,
RectWithSize snap_rect,
RectWithSize reference_rect,
vec4 snap_positions,
vec2 snap_bias) {
vec4 snap_positions) {
/// World offsets applied to the corners of the snap rectangle.
vec4 snap_offsets = floor(snap_positions + snap_bias.xyxy) - snap_positions;
vec4 snap_offsets = floor(snap_positions + 0.5) - snap_positions;
/// Compute the position of this vertex inside the snap rectangle.
vec2 normalized_snap_pos = (reference_pos - reference_rect.p0) / reference_rect.size;
@ -44,8 +43,7 @@ vec2 compute_snap_offset_impl(
// given local position on the transform and a snap rectangle.
vec2 compute_snap_offset(vec2 local_pos,
mat4 transform,
RectWithSize snap_rect,
vec2 snap_bias) {
RectWithSize snap_rect) {
vec4 snap_positions = compute_snap_positions(
transform,
snap_rect
@ -56,8 +54,7 @@ vec2 compute_snap_offset(vec2 local_pos,
transform,
snap_rect,
snap_rect,
snap_positions,
snap_bias
snap_positions
);
return snap_offsets;

View File

@ -6,6 +6,7 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS
use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D, LocalClip};
use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle, PicturePixel, WorldPixel};
use api::{PictureRect, LayoutPixel, WorldPoint, WorldSize, WorldRect, LayoutToWorldTransform};
use api::{VoidPtrToSizeFn};
use border::{ensure_no_corner_overlap};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
@ -17,7 +18,8 @@ use prim_store::{ClipData, ImageMaskData, SpaceMapper};
use render_task::to_cache_size;
use resource_cache::{ImageRequest, ResourceCache};
use std::{cmp, u32};
use util::{extract_inner_rect_safe, pack_as_float, project_rect, recycle_vec, ScaleOffset};
use std::os::raw::c_void;
use util::{extract_inner_rect_safe, pack_as_float, project_rect, ScaleOffset};
/*
@ -347,16 +349,6 @@ impl ClipStore {
}
}
pub fn recycle(self) -> Self {
ClipStore {
clip_nodes: recycle_vec(self.clip_nodes),
clip_chain_nodes: recycle_vec(self.clip_chain_nodes),
clip_node_indices: recycle_vec(self.clip_node_indices),
clip_node_info: recycle_vec(self.clip_node_info),
clip_node_collectors: recycle_vec(self.clip_node_collectors),
}
}
pub fn add_clip_items(
&mut self,
clip_items: Vec<ClipItem>,
@ -629,6 +621,18 @@ impl ClipStore {
needs_mask,
})
}
/// Reports the heap usage of this clip store.
pub fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize {
let mut size = 0;
unsafe {
size += op(self.clip_nodes.as_ptr() as *const c_void);
size += op(self.clip_chain_nodes.as_ptr() as *const c_void);
size += op(self.clip_node_indices.as_ptr() as *const c_void);
size += op(self.clip_node_info.as_ptr() as *const c_void);
}
size
}
}
#[derive(Debug)]

View File

@ -23,7 +23,7 @@ use gpu_types::BrushFlags;
use hit_test::{HitTestingItem, HitTestingRun};
use image::simplify_repeated_primitive;
use internal_types::{FastHashMap, FastHashSet};
use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
use picture::{PictureCompositeMode, PictureIdGenerator, PicturePrimitive};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor};
use prim_store::{EdgeAaSegmentMask, ImageSource};
use prim_store::{BorderSource, BrushSegment, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
@ -34,7 +34,7 @@ use scene::{Scene, ScenePipeline, StackingContextHelpers};
use spatial_node::{SpatialNodeType, StickyFrameInfo};
use std::{f32, iter, mem};
use tiling::{CompositeOps, ScrollbarPrimitive};
use util::{MaxRect, RectHelpers, recycle_vec};
use util::{MaxRect, RectHelpers};
static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
r: 0.3,
@ -93,6 +93,9 @@ pub struct DisplayListFlattener<'a> {
/// The ClipScrollTree that we are currently building during flattening.
clip_scroll_tree: &'a mut ClipScrollTree,
/// A counter for generating unique picture ids.
picture_id_generator: &'a mut PictureIdGenerator,
/// The map of all font instances.
font_instances: FontInstanceMap,
@ -128,13 +131,10 @@ pub struct DisplayListFlattener<'a> {
/// The configuration to use for the FrameBuilder. We consult this in
/// order to determine the default font.
pub config: FrameBuilderConfig,
pub next_picture_id: u64,
}
impl<'a> DisplayListFlattener<'a> {
pub fn create_frame_builder(
old_builder: FrameBuilder,
scene: &Scene,
clip_scroll_tree: &mut ClipScrollTree,
font_instances: FontInstanceMap,
@ -143,6 +143,7 @@ impl<'a> DisplayListFlattener<'a> {
frame_builder_config: &FrameBuilderConfig,
new_scene: &mut Scene,
scene_id: u64,
picture_id_generator: &mut PictureIdGenerator,
) -> FrameBuilder {
// We checked that the root pipeline is available on the render backend.
let root_pipeline_id = scene.root_pipeline_id.unwrap();
@ -159,14 +160,14 @@ impl<'a> DisplayListFlattener<'a> {
config: *frame_builder_config,
output_pipelines,
id_to_index_mapper: ClipIdToIndexMapper::default(),
hit_testing_runs: recycle_vec(old_builder.hit_testing_runs),
scrollbar_prims: recycle_vec(old_builder.scrollbar_prims),
hit_testing_runs: Vec::new(),
scrollbar_prims: Vec::new(),
shadow_stack: Vec::new(),
sc_stack: Vec::new(),
next_picture_id: old_builder.next_picture_id,
pipeline_clip_chain_stack: vec![ClipChainId::NONE],
prim_store: old_builder.prim_store.recycle(),
clip_store: old_builder.clip_store.recycle(),
prim_store: PrimitiveStore::new(),
clip_store: ClipStore::new(),
picture_id_generator,
};
flattener.push_root(
@ -887,12 +888,6 @@ impl<'a> DisplayListFlattener<'a> {
}
}
fn get_next_picture_id(&mut self) -> PictureId {
let id = PictureId(self.next_picture_id);
self.next_picture_id += 1;
id
}
pub fn push_stacking_context(
&mut self,
pipeline_id: PipelineId,
@ -972,7 +967,7 @@ impl<'a> DisplayListFlattener<'a> {
// Add picture for this actual stacking context contents to render into.
let leaf_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
self.picture_id_generator.next(),
composite_mode,
participating_in_3d_context,
pipeline_id,
@ -1001,7 +996,7 @@ impl<'a> DisplayListFlattener<'a> {
// For each filter, create a new image with that composite mode.
for filter in &composite_ops.filters {
let mut filter_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
self.picture_id_generator.next(),
Some(PictureCompositeMode::Filter(*filter)),
false,
pipeline_id,
@ -1026,7 +1021,7 @@ impl<'a> DisplayListFlattener<'a> {
// Same for mix-blend-mode.
if let Some(mix_blend_mode) = composite_ops.mix_blend_mode {
let mut blend_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
self.picture_id_generator.next(),
Some(PictureCompositeMode::MixBlend(mix_blend_mode)),
false,
pipeline_id,
@ -1053,7 +1048,7 @@ impl<'a> DisplayListFlattener<'a> {
// that will be the container for all the planes and any
// un-transformed content.
let mut container_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
self.picture_id_generator.next(),
None,
false,
pipeline_id,
@ -1328,7 +1323,7 @@ impl<'a> DisplayListFlattener<'a> {
// detect this and mark the picture to be drawn directly into the
// parent picture, which avoids an intermediate surface and blur.
let shadow_pic = PicturePrimitive::new_image(
self.get_next_picture_id(),
self.picture_id_generator.next(),
Some(PictureCompositeMode::Filter(FilterOp::Blur(std_deviation))),
false,
pipeline_id,

View File

@ -58,7 +58,6 @@ pub struct FrameBuilder {
background_color: Option<ColorF>,
window_size: DeviceUintSize,
scene_id: u64,
pub next_picture_id: u64,
pub prim_store: PrimitiveStore,
pub clip_store: ClipStore,
pub hit_testing_runs: Vec<HitTestingRun>,
@ -128,6 +127,7 @@ impl<'a> PrimitiveContext<'a> {
}
impl FrameBuilder {
#[cfg(feature = "replay")]
pub fn empty() -> Self {
FrameBuilder {
hit_testing_runs: Vec::new(),
@ -138,7 +138,6 @@ impl FrameBuilder {
window_size: DeviceUintSize::zero(),
background_color: None,
scene_id: 0,
next_picture_id: 0,
config: FrameBuilderConfig {
enable_scrollbars: false,
default_font_render_mode: FontRenderMode::Mono,
@ -166,7 +165,6 @@ impl FrameBuilder {
window_size,
scene_id,
config: flattener.config,
next_picture_id: flattener.next_picture_id,
}
}

View File

@ -25,12 +25,14 @@
//! for this frame.
use api::{PremultipliedColorF, TexelRect};
use api::{VoidPtrToSizeFn};
use device::FrameId;
use euclid::TypedRect;
use profiler::GpuCacheProfileCounters;
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use std::{mem, u16, u32};
use std::ops::Add;
use std::os::raw::c_void;
pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
@ -340,6 +342,18 @@ impl Texture {
}
}
// Reports the CPU heap usage of this Texture struct.
fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize {
let mut size = 0;
unsafe {
size += op(self.blocks.as_ptr() as *const c_void);
size += op(self.rows.as_ptr() as *const c_void);
size += op(self.pending_blocks.as_ptr() as *const c_void);
size += op(self.updates.as_ptr() as *const c_void);
}
size
}
// Push new data into the cache. The ```pending_block_index``` field represents
// where the data was pushed into the texture ```pending_blocks``` array.
// Return the allocated address for this data.
@ -645,4 +659,9 @@ impl GpuCache {
debug_assert_eq!(block.last_access_time, self.frame_id);
block.address
}
/// Reports the CPU heap usage of this GpuCache struct.
pub fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize {
self.texture.malloc_size_of(op)
}
}

View File

@ -3,12 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{BorderRadius, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag, LayoutPoint};
use api::{LayoutPrimitiveInfo, LayoutRect, PipelineId, WorldPoint};
use api::{LayoutPrimitiveInfo, LayoutRect, PipelineId, VoidPtrToSizeFn, WorldPoint};
use clip::{ClipNodeIndex, ClipChainNode, ClipNode, ClipItem, ClipStore};
use clip::{ClipChainId, rounded_rectangle_contains_point};
use clip_scroll_tree::{SpatialNodeIndex, ClipScrollTree};
use internal_types::FastHashMap;
use prim_store::ScrollNodeAndClipChain;
use std::os::raw::c_void;
use util::LayoutToWorldFastTransform;
/// A copy of important clip scroll node data to use during hit testing. This a copy of
@ -336,6 +337,21 @@ impl HitTester {
pub fn get_pipeline_root(&self, pipeline_id: PipelineId) -> &HitTestSpatialNode {
&self.spatial_nodes[self.pipeline_root_nodes[&pipeline_id].0]
}
// Reports the CPU heap usage of this HitTester struct.
pub fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize {
let mut size = 0;
unsafe {
size += op(self.runs.as_ptr() as *const c_void);
size += op(self.spatial_nodes.as_ptr() as *const c_void);
size += op(self.clip_nodes.as_ptr() as *const c_void);
size += op(self.clip_chains.as_ptr() as *const c_void);
// We can't measure pipeline_root_nodes because we don't have the
// real machinery from the malloc_size_of crate. We could estimate
// it but it should generally be very small so we don't bother.
}
size
}
}
#[derive(Clone, Copy, PartialEq)]

View File

@ -78,6 +78,29 @@ pub enum PictureSurface {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PictureId(pub u64);
// TODO(gw): Having to generate globally unique picture
// ids for caching is not ideal. We should be
// able to completely remove this once we cache
// pictures based on their content, rather than
// the current cache key structure.
pub struct PictureIdGenerator {
next: u64,
}
impl PictureIdGenerator {
pub fn new() -> Self {
PictureIdGenerator {
next: 0,
}
}
pub fn next(&mut self) -> PictureId {
let id = PictureId(self.next);
self.next += 1;
id
}
}
// Cache key that determines whether a pre-existing
// picture in the texture cache matches the content
// of the current picture.

View File

@ -30,7 +30,7 @@ use resource_cache::{ImageProperties, ImageRequest, ResourceCache};
use scene::SceneProperties;
use segment::SegmentBuilder;
use std::{cmp, fmt, mem, usize};
use util::{ScaleOffset, MatrixHelpers, pack_as_float, recycle_vec, project_rect, raster_rect_to_device_pixels};
use util::{ScaleOffset, MatrixHelpers, pack_as_float, project_rect, raster_rect_to_device_pixels};
const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0;
@ -1386,13 +1386,6 @@ impl PrimitiveStore {
}
}
pub fn recycle(self) -> Self {
PrimitiveStore {
primitives: recycle_vec(self.primitives),
chase_id: self.chase_id,
}
}
pub fn get_pic(&self, index: PrimitiveIndex) -> &PicturePrimitive {
self.primitives[index.0].as_pic()
}

View File

@ -8,6 +8,7 @@ use api::{BuiltDisplayListIter, SpecificDisplayItem};
use api::{DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestFlags, HitTestResult};
use api::{IdNamespace, LayoutPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
use api::{MemoryReport, VoidPtrToSizeFn};
use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, ImageKey};
use api::{NotificationRequest, Checkpoint};
use api::channel::{MsgReceiver, Payload};
@ -40,6 +41,7 @@ use serde_json;
use std::path::PathBuf;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::mem::replace;
use std::os::raw::c_void;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::u32;
#[cfg(feature = "replay")]
@ -384,6 +386,7 @@ pub struct RenderBackend {
notifier: Box<RenderNotifier>,
recorder: Option<Box<ApiRecordingReceiver>>,
sampler: Option<Box<AsyncPropertySampler + Send>>,
size_of_op: Option<VoidPtrToSizeFn>,
last_scene_id: u64,
}
@ -402,6 +405,7 @@ impl RenderBackend {
frame_config: FrameBuilderConfig,
recorder: Option<Box<ApiRecordingReceiver>>,
sampler: Option<Box<AsyncPropertySampler + Send>>,
size_of_op: Option<VoidPtrToSizeFn>,
) -> RenderBackend {
// The namespace_id should start from 1.
NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed);
@ -422,6 +426,7 @@ impl RenderBackend {
notifier,
recorder,
sampler,
size_of_op,
last_scene_id: 0,
}
}
@ -734,6 +739,9 @@ impl RenderBackend {
self.result_tx.send(msg).unwrap();
self.notifier.wake_up();
}
ApiMsg::ReportMemory(tx) => {
tx.send(self.report_memory()).unwrap();
}
ApiMsg::DebugCommand(option) => {
let msg = match option {
DebugCommand::EnableDualSourceBlending(enable) => {
@ -1139,6 +1147,27 @@ impl RenderBackend {
serde_json::to_string(&debug_root).unwrap()
}
fn size_of<T>(&self, ptr: *const T) -> usize {
let op = self.size_of_op.as_ref().unwrap();
unsafe { op(ptr as *const c_void) }
}
fn report_memory(&self) -> MemoryReport {
let mut report = MemoryReport::default();
let op = self.size_of_op.as_ref().unwrap();
report.gpu_cache_metadata = self.gpu_cache.malloc_size_of(*op);
for (_id, doc) in &self.documents {
if let Some(ref fb) = doc.frame_builder {
report.primitive_stores += self.size_of(fb.prim_store.primitives.as_ptr());
report.clip_stores += fb.clip_store.malloc_size_of(*op);
}
report.hit_testers +=
doc.hit_tester.as_ref().map_or(0, |ht| ht.malloc_size_of(*op));
}
report
}
}
fn get_blob_image_updates(updates: &[ResourceUpdate]) -> Vec<ImageKey> {

View File

@ -13,6 +13,7 @@ use api::{BlobImageHandler, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, Epoch, ExternalImageId};
use api::{ExternalImageType, FontRenderMode, FrameMsg, ImageFormat, PipelineId};
use api::{ImageRendering};
use api::{MemoryReport, VoidPtrToSizeFn};
use api::{RenderApiSender, RenderNotifier, TexelRect, TextureTarget};
use api::{channel};
use api::DebugCommand;
@ -55,6 +56,7 @@ use std::collections::VecDeque;
use std::collections::hash_map::Entry;
use std::f32;
use std::mem;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
@ -1380,6 +1382,9 @@ pub struct Renderer {
/// copy the WR output to.
output_image_handler: Option<Box<OutputImageHandler>>,
/// Optional function pointer for memory reporting.
size_of_op: Option<VoidPtrToSizeFn>,
// Currently allocated FBOs for output frames.
output_targets: FastHashMap<u32, FrameOutput>,
@ -1670,6 +1675,7 @@ impl Renderer {
Arc::new(worker.unwrap())
});
let sampler = options.sampler;
let size_of_op = options.size_of_op;
let blob_image_handler = options.blob_image_handler.take();
let thread_listener_for_render_backend = thread_listener.clone();
@ -1751,6 +1757,7 @@ impl Renderer {
config,
recorder,
sampler,
size_of_op,
);
backend.run(backend_profile_counters);
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
@ -1804,6 +1811,7 @@ impl Renderer {
dither_matrix_texture,
external_image_handler: None,
output_image_handler: None,
size_of_op: options.size_of_op,
output_targets: FastHashMap::default(),
cpu_profiles: VecDeque::new(),
gpu_profiles: VecDeque::new(),
@ -4033,6 +4041,26 @@ impl Renderer {
self.device.end_frame();
}
fn size_of<T>(&self, ptr: *const T) -> usize {
let op = self.size_of_op.as_ref().unwrap();
unsafe { op(ptr as *const c_void) }
}
/// Collects a memory report.
pub fn report_memory(&self) -> MemoryReport {
let mut report = MemoryReport::default();
if let CacheBus::PixelBuffer{ref cpu_blocks, ..} = self.gpu_cache_texture.bus {
report.gpu_cache_cpu_mirror += self.size_of(cpu_blocks.as_ptr());
}
for (_id, doc) in &self.active_documents {
report.render_tasks += self.size_of(doc.frame.render_tasks.tasks.as_ptr());
report.render_tasks += self.size_of(doc.frame.render_tasks.task_data.as_ptr());
}
report
}
// Sets the blend mode. Blend is unconditionally set if the "show overdraw" debugging mode is
// enabled.
fn set_blend(&self, mut blend: bool, framebuffer_kind: FramebufferKind) {
@ -4192,6 +4220,7 @@ pub struct RendererOptions {
pub blob_image_handler: Option<Box<BlobImageHandler>>,
pub recorder: Option<Box<ApiRecordingReceiver>>,
pub thread_listener: Option<Box<ThreadListener + Send + Sync>>,
pub size_of_op: Option<VoidPtrToSizeFn>,
pub cached_programs: Option<Rc<ProgramCache>>,
pub debug_flags: DebugFlags,
pub renderer_id: Option<u64>,
@ -4227,6 +4256,7 @@ impl Default for RendererOptions {
blob_image_handler: None,
recorder: None,
thread_listener: None,
size_of_op: None,
renderer_id: None,
cached_programs: None,
disable_dual_source_blending: false,

View File

@ -10,6 +10,7 @@ use frame_builder::{FrameBuilderConfig, FrameBuilder};
use clip_scroll_tree::ClipScrollTree;
use display_list_flattener::DisplayListFlattener;
use internal_types::{FastHashMap, FastHashSet};
use picture::PictureIdGenerator;
use resource_cache::FontInstanceMap;
use render_backend::DocumentView;
use renderer::{PipelineInfo, SceneBuilderHooks};
@ -139,6 +140,7 @@ pub struct SceneBuilder {
api_tx: MsgSender<ApiMsg>,
config: FrameBuilderConfig,
hooks: Option<Box<SceneBuilderHooks + Send>>,
picture_id_generator: PictureIdGenerator,
}
impl SceneBuilder {
@ -157,6 +159,7 @@ impl SceneBuilder {
api_tx,
config,
hooks,
picture_id_generator: PictureIdGenerator::new(),
},
in_tx,
out_rx,
@ -224,7 +227,6 @@ impl SceneBuilder {
let mut new_scene = Scene::new();
let frame_builder = DisplayListFlattener::create_frame_builder(
FrameBuilder::empty(),
&item.scene,
&mut clip_scroll_tree,
item.font_instances,
@ -233,6 +235,7 @@ impl SceneBuilder {
&self.config,
&mut new_scene,
item.scene_id,
&mut self.picture_id_generator,
);
built_scene = Some(BuiltScene {
@ -300,7 +303,6 @@ impl SceneBuilder {
let mut new_scene = Scene::new();
let frame_builder = DisplayListFlattener::create_frame_builder(
FrameBuilder::empty(),
&scene,
&mut clip_scroll_tree,
request.font_instances,
@ -309,6 +311,7 @@ impl SceneBuilder {
&self.config,
&mut new_scene,
request.scene_id,
&mut self.picture_id_generator,
);
built_scene = Some(BuiltScene {

View File

@ -376,22 +376,6 @@ pub fn extract_inner_rect_safe<U>(
extract_inner_rect_impl(rect, radii, 1.0)
}
/// Consumes the old vector and returns a new one that may reuse the old vector's allocated
/// memory.
pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
if old_vec.capacity() > 2 * old_vec.len() {
// Avoid reusing the buffer if it is a lot larger than it needs to be. This prevents
// a frame with exceptionally large allocations to cause subsequent frames to retain
// more memory than they need.
return Vec::with_capacity(old_vec.len());
}
old_vec.clear();
old_vec
}
#[cfg(test)]
pub mod test {
use super::*;

View File

@ -9,6 +9,7 @@ use channel::{self, MsgSender, Payload, PayloadSender, PayloadSenderHelperMethod
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::sync::Arc;
use std::u32;
@ -667,6 +668,8 @@ pub enum ApiMsg {
ClearNamespace(IdNamespace),
/// Flush from the caches anything that isn't necessary, to free some memory.
MemoryPressure,
/// Collects a memory report.
ReportMemory(MsgSender<MemoryReport>),
/// Change debugging options.
DebugCommand(DebugCommand),
/// Wakes the render backend's event loop up. Needed when an event is communicated
@ -690,6 +693,7 @@ impl fmt::Debug for ApiMsg {
ApiMsg::ExternalEvent(..) => "ApiMsg::ExternalEvent",
ApiMsg::ClearNamespace(..) => "ApiMsg::ClearNamespace",
ApiMsg::MemoryPressure => "ApiMsg::MemoryPressure",
ApiMsg::ReportMemory(..) => "ApiMsg::ReportMemory",
ApiMsg::DebugCommand(..) => "ApiMsg::DebugCommand",
ApiMsg::ShutDown => "ApiMsg::ShutDown",
ApiMsg::WakeUp => "ApiMsg::WakeUp",
@ -735,6 +739,34 @@ impl PipelineId {
}
}
/// Collection of heap sizes, in bytes.
#[repr(C)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct MemoryReport {
pub primitive_stores: usize,
pub clip_stores: usize,
pub gpu_cache_metadata: usize,
pub gpu_cache_cpu_mirror: usize,
pub render_tasks: usize,
pub hit_testers: usize,
}
impl ::std::ops::AddAssign for MemoryReport {
fn add_assign(&mut self, other: MemoryReport) {
self.primitive_stores += other.primitive_stores;
self.clip_stores += other.clip_stores;
self.gpu_cache_metadata += other.gpu_cache_metadata;
self.gpu_cache_cpu_mirror += other.gpu_cache_cpu_mirror;
self.render_tasks += other.render_tasks;
self.hit_testers += other.hit_testers;
}
}
/// A C function that takes a pointer to a heap allocation and returns its size.
///
/// This is borrowed from the malloc_size_of crate, upon which we want to avoid
/// a dependency from WebRender.
pub type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize;
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
@ -897,6 +929,12 @@ impl RenderApi {
self.api_sender.send(ApiMsg::MemoryPressure).unwrap();
}
pub fn report_memory(&self) -> MemoryReport {
let (tx, rx) = channel::msg_channel().unwrap();
self.api_sender.send(ApiMsg::ReportMemory(tx)).unwrap();
rx.recv().unwrap()
}
pub fn shut_down(&self) {
self.api_sender.send(ApiMsg::ShutDown).unwrap();
}

View File

@ -1 +1 @@
0f142521b86f201a0f0957cc852aa14923ebfc73
da76f6aad61c1ba769566861ec41b42d511fa456