mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Bug 1491130. Update webrender to commit da76f6aad61c1ba769566861ec41b42d511fa456
This commit is contained in:
parent
6c22936032
commit
7dd93d2e5d
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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::*;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
0f142521b86f201a0f0957cc852aa14923ebfc73
|
||||
da76f6aad61c1ba769566861ec41b42d511fa456
|
||||
|
Loading…
Reference in New Issue
Block a user