diff --git a/Cargo.lock b/Cargo.lock index 22c42cb877..f445fdf90d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,6 +757,16 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "malloc_size_of_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.6" @@ -1320,6 +1330,17 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tempfile" version = "3.0.2" @@ -1553,6 +1574,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "mozangle 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "pathfinder_font_renderer 0.5.0 (git+https://github.com/pcwalton/pathfinder?branch=webrender)", @@ -1572,6 +1594,7 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.58.0", "webrender_build 0.0.1", + "wr_malloc_size_of 0.0.1", "ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1602,10 +1625,12 @@ dependencies = [ "dwrote 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (git+https://github.com/servo/serde?branch=deserialize_from_enums9)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "wr_malloc_size_of 0.0.1", ] [[package]] @@ -1674,6 +1699,14 @@ dependencies = [ "x11-dl 2.17.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wr_malloc_size_of" +version = "0.0.1" +dependencies = [ + "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "wrench" version = "0.3.0" @@ -1861,6 +1894,7 @@ dependencies = [ "checksum lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9dc8e0746b7cca11960b602f7fe037bb067746a01eab4aa502fed1494544843" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" @@ -1925,6 +1959,7 @@ dependencies = [ "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.15.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3391038ebc3e4ab24eb028cb0ef2f2dc4ba0cbf72ee895ed6a6fad730640b5bc" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml index caf620bb7f..5d83ba28f1 100644 --- a/webrender/Cargo.toml +++ b/webrender/Cargo.toml @@ -34,6 +34,7 @@ gleam = "0.6.8" image = { optional = true, version = "0.20" } lazy_static = "1" log = "0.4" +malloc_size_of_derive = "0.1" num-traits = "0.2" plane-split = "0.13.3" png = { optional = true, version = "0.12" } @@ -47,6 +48,7 @@ thread_profiler = "0.1.1" time = "0.1" webrender_api = { version = "0.58.0", path = "../webrender_api" } webrender_build = { version = "0.0.1", path = "../webrender_build" } +wr_malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of" } ws = { optional = true, version = "0.7.3" } [dependencies.pathfinder_font_renderer] diff --git a/webrender/src/border.rs b/webrender/src/border.rs index c07d1a27ad..397d696937 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -34,7 +34,7 @@ pub const MAX_DASH_COUNT: u32 = 2048; // all the border structs with hashable // variants... -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BorderRadiusAu { @@ -66,7 +66,7 @@ impl From for BorderRadius { } } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BorderSideAu { @@ -94,7 +94,7 @@ impl From for BorderSide { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Hash, Eq, PartialEq)] +#[derive(Debug, Clone, Hash, Eq, MallocSizeOf, PartialEq)] pub struct NormalBorderAu { pub left: BorderSideAu, pub right: BorderSideAu, @@ -148,7 +148,7 @@ impl From for ApiNormalBorder { /// Cache key that uniquely identifies a border /// segment in the render task cache. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BorderSegmentCacheKey { diff --git a/webrender/src/box_shadow.rs b/webrender/src/box_shadow.rs index f14a526423..db04712aa0 100644 --- a/webrender/src/box_shadow.rs +++ b/webrender/src/box_shadow.rs @@ -12,7 +12,7 @@ use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind}; use render_task::RenderTaskCacheEntryHandle; use util::RectHelpers; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BoxShadowClipSource { @@ -51,7 +51,7 @@ pub const BLUR_SAMPLE_SCALE: f32 = 3.0; // A cache key that uniquely identifies a minimally sized // and blurred box-shadow rect that can be stored in the // texture cache and applied to clip-masks. -#[derive(Debug, Clone, Eq, Hash, PartialEq)] +#[derive(Debug, Clone, Eq, Hash, MallocSizeOf, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BoxShadowCacheKey { diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index bfba1ad729..183871f9bf 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -6,7 +6,7 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D}; use api::{BoxShadowClipMode, LayoutToWorldScale, PicturePixel, WorldPixel}; use api::{PictureRect, LayoutPixel, WorldPoint, WorldSize, WorldRect, LayoutToWorldTransform}; -use api::{VoidPtrToSizeFn, ImageKey}; +use api::{ImageKey}; use app_units::Au; use border::{ensure_no_corner_overlap, BorderRadiusAu}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey}; @@ -22,7 +22,6 @@ use prim_store::{PointKey, PrimitiveInstance, SizeKey, RectangleKey}; use render_task::to_cache_size; use resource_cache::{ImageRequest, ResourceCache}; use std::{cmp, u32}; -use std::os::raw::c_void; use util::{extract_inner_rect_safe, project_rect, ScaleOffset}; /* @@ -107,7 +106,7 @@ use util::{extract_inner_rect_safe, project_rect, ScaleOffset}; // Type definitions for interning clip nodes. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)] pub struct ClipDataMarker; pub type ClipDataStore = intern::DataStore; @@ -134,6 +133,7 @@ enum ClipResult { #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct ClipNode { pub item: ClipItem, pub gpu_cache_handle: GpuCacheHandle, @@ -186,6 +186,7 @@ impl From for ClipNode { bitflags! { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] + #[derive(MallocSizeOf)] pub struct ClipNodeFlags: u8 { const SAME_SPATIAL_NODE = 0x1; const SAME_COORD_SYSTEM = 0x2; @@ -195,7 +196,7 @@ bitflags! { // Identifier for a clip chain. Clip chains are stored // in a contiguous array in the clip store. They are // identified by a simple index into that array. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Hash)] pub struct ClipChainId(pub u32); // The root of each clip chain is the NONE id. The @@ -209,7 +210,7 @@ impl ClipChainId { // A clip chain node is an id for a range of clip sources, // and a link to a parent clip chain node, or ClipChainId::NONE. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, MallocSizeOf)] pub struct ClipChainNode { pub handle: ClipDataHandle, pub local_pos: LayoutPoint, @@ -223,7 +224,7 @@ pub struct ClipChainNode { // an index to the node data itself, as well as // some flags describing how this clip node instance // is positioned. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ClipNodeInstance { @@ -250,7 +251,7 @@ pub struct ClipNodeRange { // todo(gw): optimize: // separate arrays for matrices // cache and only build as needed. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] enum ClipSpaceConversion { Local, ScaleOffset(ScaleOffset), @@ -259,6 +260,7 @@ enum ClipSpaceConversion { // Temporary information that is cached and reused // during building of a clip chain instance. +#[derive(MallocSizeOf)] struct ClipNodeInfo { conversion: ClipSpaceConversion, handle: ClipDataHandle, @@ -434,7 +436,8 @@ impl ClipNode { } } -// The main clipping public interface that other modules access. +/// The main clipping public interface that other modules access. +#[derive(MallocSizeOf)] pub struct ClipStore { pub clip_chain_nodes: Vec, clip_node_instances: Vec, @@ -708,17 +711,6 @@ impl ClipStore { pub fn clear_old_instances(&mut self) { self.clip_node_instances.clear(); } - - /// 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_chain_nodes.as_ptr() as *const c_void); - size += op(self.clip_node_instances.as_ptr() as *const c_void); - size += op(self.clip_node_info.as_ptr() as *const c_void); - } - size - } } pub struct ComplexTranslateIter { @@ -790,7 +782,7 @@ impl ClipRegion> { // the uploaded GPU cache handle to be retained between display lists. // TODO(gw): Maybe we should consider constructing these directly // in the DL builder? -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum ClipItemKey { @@ -853,7 +845,7 @@ impl ClipItemKey { impl intern::InternDebug for ClipItemKey {} -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum ClipItem { @@ -1287,7 +1279,7 @@ pub fn project_inner_rect( // Collects a list of unique clips to be applied to a rasterization // root at the end of primitive preparation. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub struct ClipNodeCollector { spatial_node_index: SpatialNodeIndex, clips: FastHashSet, diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index ea0c212ebc..8040d421a6 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -41,7 +41,7 @@ impl CoordinateSystem { } } -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct SpatialNodeIndex(pub u32); diff --git a/webrender/src/freelist.rs b/webrender/src/freelist.rs index faec9b7109..bcff127fec 100644 --- a/webrender/src/freelist.rs +++ b/webrender/src/freelist.rs @@ -23,7 +23,7 @@ use std::{fmt, u32}; use std::marker::PhantomData; -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Epoch(u32); @@ -96,6 +96,7 @@ impl PartialEq for WeakFreeListHandle { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct WeakFreeListHandle { index: u32, epoch: Epoch, diff --git a/webrender/src/glyph_rasterizer/mod.rs b/webrender/src/glyph_rasterizer/mod.rs index 78b0265908..2c7dc7081c 100644 --- a/webrender/src/glyph_rasterizer/mod.rs +++ b/webrender/src/glyph_rasterizer/mod.rs @@ -28,7 +28,7 @@ pub use self::pathfinder::{ThreadSafePathfinderFontContext, NativeFontHandleWrap #[cfg(not(feature = "pathfinder"))] mod no_pathfinder; -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FontTransform { @@ -164,7 +164,7 @@ impl<'a> From<&'a LayoutToWorldTransform> for FontTransform { // Ensure glyph sizes are reasonably limited to avoid that scenario. pub const FONT_SIZE_LIMIT: f64 = 512.0; -#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)] +#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FontInstance { diff --git a/webrender/src/gpu_cache.rs b/webrender/src/gpu_cache.rs index 49e9f7dfc6..1ce2544186 100644 --- a/webrender/src/gpu_cache.rs +++ b/webrender/src/gpu_cache.rs @@ -25,7 +25,6 @@ //! for this frame. use api::{DebugFlags, DocumentId, PremultipliedColorF, IdNamespace, TexelRect}; -use api::{VoidPtrToSizeFn}; use euclid::TypedRect; use internal_types::{FastHashMap}; use profiler::GpuCacheProfileCounters; @@ -34,7 +33,6 @@ use renderer::MAX_VERTEX_TEXTURE_WIDTH; use std::{mem, u16, u32}; use std::num::NonZeroU32; use std::ops::Add; -use std::os::raw::c_void; use std::time::{Duration, Instant}; @@ -55,7 +53,7 @@ const RECLAIM_THRESHOLD: f32 = 0.2; /// blow away the cache and rebuild it. const RECLAIM_DELAY_S: u64 = 5; -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, MallocSizeOf, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Epoch(u32); @@ -66,7 +64,7 @@ impl Epoch { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct CacheLocation { @@ -75,7 +73,7 @@ struct CacheLocation { } /// A single texel in RGBAF32 texture - 16 bytes. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuBlockData { @@ -131,7 +129,7 @@ pub trait ToGpuBlocks { } // A handle to a GPU resource. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuCacheHandle { @@ -147,7 +145,7 @@ impl GpuCacheHandle { // A unique address in the GPU cache. These are uploaded // as part of the primitive instances, to allow the vertex // shader to fetch the specific data. -#[derive(Copy, Debug, Clone, Eq, PartialEq)] +#[derive(Copy, Debug, Clone, MallocSizeOf, Eq, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct GpuCacheAddress { @@ -183,7 +181,7 @@ impl Add for GpuCacheAddress { } // An entry in a free-list of blocks in the GPU cache. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Block { @@ -235,7 +233,7 @@ impl Block { /// /// Because we use Option in a lot of places, we use a NonZeroU32 /// here and avoid ever using the index zero. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct BlockIndex(NonZeroU32); @@ -254,6 +252,7 @@ impl BlockIndex { // A row in the cache texture. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] struct Row { // The fixed size of blocks that this row supports. // Each row becomes a slab allocator for a fixed block size. @@ -276,6 +275,7 @@ impl Row { // where GL commands can be applied. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub enum GpuCacheUpdate { Copy { block_index: usize, @@ -286,6 +286,7 @@ pub enum GpuCacheUpdate { /// Command to inform the debug display in the renderer when chunks are allocated /// or freed. +#[derive(MallocSizeOf)] pub enum GpuCacheDebugCmd { /// Describes an allocated chunk. Alloc(GpuCacheDebugChunk), @@ -293,7 +294,7 @@ pub enum GpuCacheDebugCmd { Free(GpuCacheAddress), } -#[derive(Clone)] +#[derive(Clone, MallocSizeOf)] pub struct GpuCacheDebugChunk { pub address: GpuCacheAddress, pub size: usize, @@ -302,6 +303,7 @@ pub struct GpuCacheDebugChunk { #[must_use] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct GpuCacheUpdateList { /// The frame current update list was generated from. pub frame_id: FrameId, @@ -325,6 +327,7 @@ pub struct GpuCacheUpdateList { // just serves to work around the borrow checker. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] struct FreeBlockLists { free_list_1: Option, free_list_2: Option, @@ -392,6 +395,7 @@ impl FreeBlockLists { // CPU-side representation of the GPU resource cache texture. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] struct Texture { // Current texture height height: i32, @@ -456,18 +460,6 @@ 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. @@ -672,6 +664,7 @@ impl<'a> Drop for GpuDataRequest<'a> { /// The main LRU cache interface. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct GpuCache { /// Current FrameId. now: FrameStamp, @@ -865,11 +858,6 @@ impl GpuCache { debug_assert_eq!(block.last_access_time, self.now.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) - } } #[test] diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 5f37271fe7..6c7d7214c5 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -59,7 +59,7 @@ pub enum RasterizationSpace { Screen = 1, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[repr(C)] @@ -96,7 +96,7 @@ pub struct ScalingInstance { pub src_task_address: RenderTaskAddress, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -317,6 +317,7 @@ bitflags! { /// code should process this instance. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] + #[derive(MallocSizeOf)] pub struct BrushFlags: u8 { /// Apply perspective interpolation to UVs const PERSPECTIVE_INTERPOLATION = 0x1; diff --git a/webrender/src/hit_test.rs b/webrender/src/hit_test.rs index 56f917b0b2..d44f4128f1 100644 --- a/webrender/src/hit_test.rs +++ b/webrender/src/hit_test.rs @@ -3,19 +3,19 @@ * 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, VoidPtrToSizeFn, WorldPoint}; +use api::{LayoutPrimitiveInfo, LayoutRect, PipelineId, WorldPoint}; use clip::{ClipDataStore, ClipNode, ClipItem, ClipStore}; use clip::{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 std::u32; use util::LayoutToWorldFastTransform; /// A copy of important clip scroll node data to use during hit testing. This a copy of /// data from the ClipScrollTree that will persist as a new frame is under construction, /// allowing hit tests consistent with the currently rendered frame. +#[derive(MallocSizeOf)] pub struct HitTestSpatialNode { /// The pipeline id of this node. pipeline_id: PipelineId, @@ -27,6 +27,7 @@ pub struct HitTestSpatialNode { world_viewport_transform: LayoutToWorldFastTransform, } +#[derive(MallocSizeOf)] pub struct HitTestClipNode { /// A particular point must be inside all of these regions to be considered clipped in /// for the purposes of a hit test. @@ -64,20 +65,21 @@ impl HitTestClipNode { // copy the complete interned clip data store for // hit testing. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Eq, Hash)] pub struct HitTestClipChainId(u32); impl HitTestClipChainId { pub const NONE: Self = HitTestClipChainId(u32::MAX); } +#[derive(MallocSizeOf)] pub struct HitTestClipChainNode { pub region: HitTestClipNode, pub spatial_node_index: SpatialNodeIndex, pub parent_clip_chain_id: HitTestClipChainId, } -#[derive(Clone)] +#[derive(Clone, MallocSizeOf)] pub struct HitTestingItem { rect: LayoutRect, clip_rect: LayoutRect, @@ -96,9 +98,10 @@ impl HitTestingItem { } } -#[derive(Clone)] +#[derive(Clone, MallocSizeOf)] pub struct HitTestingRun(pub Vec, pub ScrollNodeAndClipChain); +#[derive(MallocSizeOf)] enum HitTestRegion { Invalid, Rectangle(LayoutRect, ClipMode), @@ -121,6 +124,7 @@ impl HitTestRegion { } } +#[derive(MallocSizeOf)] pub struct HitTester { runs: Vec, spatial_nodes: Vec, @@ -371,28 +375,15 @@ impl HitTester { pub fn get_pipeline_root(&self, pipeline_id: PipelineId) -> &HitTestSpatialNode { &self.spatial_nodes[self.pipeline_root_nodes[&pipeline_id].0 as usize] } - - // 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_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)] +#[derive(Clone, Copy, MallocSizeOf, PartialEq)] enum ClippedIn { ClippedIn, NotClippedIn, } +#[derive(MallocSizeOf)] pub struct HitTest { pipeline_id: Option, point: WorldPoint, diff --git a/webrender/src/intern.rs b/webrender/src/intern.rs index f37742948f..0d51ffb69a 100644 --- a/webrender/src/intern.rs +++ b/webrender/src/intern.rs @@ -3,14 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{LayoutPrimitiveInfo, LayoutRect}; -use api::VoidPtrToSizeFn; use internal_types::FastHashMap; +use malloc_size_of::MallocSizeOf; use profiler::ResourceProfileCounter; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use std::{mem, ops, u64}; -use std::os::raw::c_void; use std::sync::atomic::{AtomicUsize, Ordering}; use util::VecHelper; @@ -51,7 +50,7 @@ use util::VecHelper; /// correctness validation (handle). #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)] struct Epoch(u64); impl Epoch { @@ -76,7 +75,7 @@ lazy_static! { /// A globally, unique identifier #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, Hash, MallocSizeOf, PartialEq)] pub struct ItemUid { uid: usize, } @@ -90,7 +89,7 @@ impl ItemUid { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] pub struct Handle { index: u32, epoch: Epoch, @@ -106,6 +105,7 @@ impl Handle where M: Copy { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub enum UpdateKind { Insert, Remove, @@ -114,6 +114,7 @@ pub enum UpdateKind { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct Update { index: usize, kind: UpdateKind, @@ -123,7 +124,8 @@ pub struct Update { /// correct access patterns. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -struct Item { +#[derive(MallocSizeOf)] +struct Item { epoch: Epoch, data: T, } @@ -136,13 +138,18 @@ pub trait InternDebug { /// contains a free-list of items for fast access. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct DataStore { +#[derive(MallocSizeOf)] +pub struct DataStore { items: Vec>, _source: PhantomData, _marker: PhantomData, } -impl ::std::default::Default for DataStore where S: Debug, T: From, M: Debug +impl ::std::default::Default for DataStore +where + S: Debug + MallocSizeOf, + T: From + MallocSizeOf, + M: Debug { fn default() -> Self { DataStore { @@ -153,7 +160,11 @@ impl ::std::default::Default for DataStore where S: Debug, T: } } -impl DataStore where S: Debug, T: From, M: Debug +impl DataStore +where + S: Debug + MallocSizeOf, + T: From + MallocSizeOf, + M: Debug { /// Apply any updates from the scene builder thread to /// this data store. @@ -185,16 +196,14 @@ impl DataStore where S: Debug, T: From, M: Debug debug_assert!(data_iter.next().is_none()); } - - /// Reports CPU heap usage. - pub fn malloc_size_of(&self, op: VoidPtrToSizeFn) -> usize { - unsafe { op(self.items.as_ptr() as *const c_void) } - } } /// Retrieve an item from the store via handle impl ops::Index> for DataStore -where M: Copy +where + S: MallocSizeOf, + T: MallocSizeOf, + M: Copy { type Output = T; fn index(&self, handle: Handle) -> &T { @@ -208,6 +217,8 @@ where M: Copy /// Retrieve an item from the store via handle impl ops::IndexMut> for DataStore where + S: MallocSizeOf, + T: MallocSizeOf, M: Copy { fn index_mut(&mut self, handle: Handle) -> &mut T { @@ -224,10 +235,12 @@ where /// an update list of additions / removals. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct Interner where - S: Eq + Hash + Clone + Debug, - M: Copy + S: Eq + Hash + Clone + Debug + MallocSizeOf, + D: MallocSizeOf, + M: Copy + MallocSizeOf, { /// Uniquely map an interning key to a handle map: FastHashMap>, @@ -246,8 +259,9 @@ where impl ::std::default::Default for Interner where - S: Eq + Hash + Clone + Debug, - M: Copy + Debug + S: Eq + Hash + Clone + Debug + MallocSizeOf, + D: MallocSizeOf, + M: Copy + Debug + MallocSizeOf, { fn default() -> Self { Interner { @@ -263,8 +277,9 @@ where impl Interner where - S: Eq + Hash + Clone + Debug + InternDebug, - M: Copy + Debug + S: Eq + Hash + Clone + Debug + InternDebug + MallocSizeOf, + D: MallocSizeOf, + M: Copy + Debug + MallocSizeOf { /// Intern a data structure, and return a handle to /// that data. The handle can then be stored in the @@ -382,24 +397,14 @@ where updates } - - /// Reports CPU heap usage. - pub fn malloc_size_of(&self, op: VoidPtrToSizeFn, eop: VoidPtrToSizeFn) -> usize { - let mut bytes = 0; - unsafe { - bytes += op(self.local_data.as_ptr() as *const c_void); - bytes += self.map.values().next() - .map_or(0, |v| eop(v as *const _ as *const c_void)); - } - bytes - } } /// Retrieve the local data for an item from the interner via handle impl ops::Index> for Interner where - S: Eq + Clone + Hash + Debug, - M: Copy + Debug + S: Eq + Clone + Hash + Debug + MallocSizeOf, + D: MallocSizeOf, + M: Copy + Debug + MallocSizeOf { type Output = D; fn index(&self, handle: Handle) -> &D { @@ -413,10 +418,10 @@ where /// /// see DisplayListFlattener::add_interned_primitive

pub trait Internable { - type Marker: Copy + Debug; - type Source: Eq + Hash + Clone + Debug; - type StoreData: From; - type InternData; + type Marker: Copy + Debug + MallocSizeOf; + type Source: Eq + Hash + Clone + Debug + MallocSizeOf; + type StoreData: From + MallocSizeOf; + type InternData: MallocSizeOf; /// Build a new key from self with `info`. fn build_key( diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs index c3f8e16dc0..65f7dfe743 100644 --- a/webrender/src/lib.rs +++ b/webrender/src/lib.rs @@ -58,12 +58,17 @@ extern crate cfg_if; extern crate lazy_static; #[macro_use] extern crate log; +#[macro_use] +extern crate malloc_size_of_derive; #[cfg(any(feature = "serde"))] #[macro_use] extern crate serde; #[macro_use] extern crate thread_profiler; +extern crate wr_malloc_size_of; +use wr_malloc_size_of as malloc_size_of; + mod batch; mod border; mod box_shadow; @@ -193,6 +198,7 @@ extern crate png; #[cfg(test)] extern crate rand; +#[macro_use] pub extern crate webrender_api; extern crate webrender_build; diff --git a/webrender/src/prim_store/borders.rs b/webrender/src/prim_store/borders.rs index 81b39c7dc5..e18b6f925e 100644 --- a/webrender/src/prim_store/borders.rs +++ b/webrender/src/prim_store/borders.rs @@ -24,7 +24,7 @@ use storage; #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct NormalBorderPrim { pub border: NormalBorderAu, pub widths: LayoutSideOffsetsAu, @@ -67,6 +67,7 @@ impl AsInstanceKind for NormalBorderKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct NormalBorderData { pub brush_segments: Vec, pub border_segments: Vec, @@ -161,7 +162,7 @@ impl From for NormalBorderTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct NormalBorderDataMarker; pub type NormalBorderDataStore = intern::DataStore; @@ -209,8 +210,9 @@ impl IsVisible for NormalBorderPrim { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct ImageBorder { + #[ignore_malloc_size_of = "Arc"] pub request: ImageRequest, pub nine_patch: NinePatchDescriptor, } @@ -251,7 +253,9 @@ impl AsInstanceKind for ImageBorderKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct ImageBorderData { + #[ignore_malloc_size_of = "Arc"] pub request: ImageRequest, pub brush_segments: Vec, } @@ -339,7 +343,7 @@ impl From for ImageBorderTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct ImageBorderDataMarker; pub type ImageBorderDataStore = intern::DataStore; diff --git a/webrender/src/prim_store/gradient.rs b/webrender/src/prim_store/gradient.rs index dd514146c5..d102ca01df 100644 --- a/webrender/src/prim_store/gradient.rs +++ b/webrender/src/prim_store/gradient.rs @@ -20,7 +20,7 @@ use util::pack_as_float; /// A hashable gradient stop that can be used in primitive keys. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq)] pub struct GradientStopKey { pub offset: f32, pub color: ColorU, @@ -38,7 +38,7 @@ impl hash::Hash for GradientStopKey { /// Identifying key for a line decoration. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)] pub struct LinearGradientKey { pub common: PrimKeyCommonData, pub extend_mode: ExtendMode, @@ -95,6 +95,7 @@ impl AsInstanceKind for LinearGradientKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct LinearGradientTemplate { pub common: PrimTemplateCommonData, pub extend_mode: ExtendMode, @@ -228,7 +229,7 @@ impl LinearGradientTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct LinearGradientDataMarker; pub type LinearGradientDataStore = DataStore; @@ -279,7 +280,7 @@ impl IsVisible for LinearGradient { /// Hashable radial gradient parameters, for use during prim interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq)] pub struct RadialGradientParams { pub start_radius: f32, pub end_radius: f32, @@ -299,7 +300,7 @@ impl hash::Hash for RadialGradientParams { /// Identifying key for a line decoration. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, MallocSizeOf)] pub struct RadialGradientKey { pub common: PrimKeyCommonData, pub extend_mode: ExtendMode, @@ -354,6 +355,7 @@ impl AsInstanceKind for RadialGradientKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct RadialGradientTemplate { pub common: PrimTemplateCommonData, pub extend_mode: ExtendMode, @@ -458,7 +460,7 @@ impl RadialGradientTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct RadialGradientDataMarker; pub type RadialGradientDataStore = DataStore; diff --git a/webrender/src/prim_store/image.rs b/webrender/src/prim_store/image.rs index afdfc18c3b..7c4812493b 100644 --- a/webrender/src/prim_store/image.rs +++ b/webrender/src/prim_store/image.rs @@ -67,7 +67,7 @@ pub struct ImageInstance { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf, Hash)] pub struct Image { pub key: ApiImageKey, pub stretch_size: SizeKey, @@ -127,7 +127,7 @@ impl AsInstanceKind for ImageKey { // Where to find the texture data for an image primitive. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub enum ImageSource { // A normal image - just reference the texture cache. Default, @@ -141,6 +141,7 @@ pub enum ImageSource { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct ImageData { pub key: ApiImageKey, pub stretch_size: LayoutSize, @@ -336,7 +337,7 @@ impl From for ImageTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct ImageDataMarker; pub type ImageDataStore = DataStore; @@ -389,7 +390,7 @@ impl IsVisible for Image { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct YuvImage { pub color_depth: ColorDepth, pub yuv_key: [ApiImageKey; 3], @@ -438,6 +439,7 @@ impl AsInstanceKind for YuvImageKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct YuvImageData { pub color_depth: ColorDepth, pub yuv_key: [ApiImageKey; 3], @@ -513,7 +515,7 @@ impl From for YuvImageTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct YuvImageDataMarker; pub type YuvImageDataStore = DataStore; diff --git a/webrender/src/prim_store/line_dec.rs b/webrender/src/prim_store/line_dec.rs index 8ddcdf085a..d56a6022db 100644 --- a/webrender/src/prim_store/line_dec.rs +++ b/webrender/src/prim_store/line_dec.rs @@ -17,7 +17,7 @@ use prim_store::{ }; use prim_store::PrimitiveInstanceKind; -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct LineDecorationCacheKey { @@ -28,7 +28,7 @@ pub struct LineDecorationCacheKey { } /// Identifying key for a line decoration. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct LineDecoration { @@ -77,6 +77,7 @@ impl AsInstanceKind for LineDecorationKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct LineDecorationData { pub cache_key: Option, pub color: ColorF, @@ -136,7 +137,7 @@ impl From for LineDecorationTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct LineDecorationDataMarker; pub type LineDecorationDataStore = intern::DataStore; diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index f59d39ab1b..0142983ccf 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -28,6 +28,7 @@ use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpu use gpu_types::BrushFlags; use image::{Repetition}; use intern; +use malloc_size_of::MallocSizeOf; use picture::{PictureCompositeMode, PicturePrimitive, PictureUpdateState, TileCacheUpdateState}; use picture::{ClusterIndex, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTiles, RasterConfig}; use prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle}; @@ -79,7 +80,7 @@ pub fn register_prim_chase_id(_: PrimitiveDebugId) { const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0; pub const VECS_PER_SEGMENT: usize = 2; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)] pub struct ScrollNodeAndClipChain { pub spatial_node_index: SpatialNodeIndex, pub clip_chain_id: ClipChainId, @@ -99,7 +100,7 @@ impl ScrollNodeAndClipChain { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, MallocSizeOf)] pub struct PrimitiveOpacity { pub is_opaque: bool, } @@ -347,6 +348,7 @@ impl GpuCacheAddress { /// thread. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct PrimitiveSceneData { pub prim_size: LayoutSize, pub prim_relative_clip_rect: LayoutRect, @@ -357,7 +359,7 @@ pub struct PrimitiveSceneData { /// uniquely identifies a primitive template by key. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub enum PrimitiveKeyKind { /// Clear an existing rect, used for special effects on some platforms. Clear, @@ -368,7 +370,7 @@ pub enum PrimitiveKeyKind { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq)] pub struct RectangleKey { x: f32, y: f32, @@ -410,7 +412,7 @@ impl From for RectangleKey { /// A hashable SideOffset2D that can be used in primitive keys. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq)] pub struct SideOffsetsKey { pub top: f32, pub right: f32, @@ -465,7 +467,7 @@ impl From> for SideOffsetsKey { /// A hashable size for using as a key during primitive interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Copy, Debug, Clone, PartialEq)] +#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)] pub struct SizeKey { w: f32, h: f32, @@ -498,7 +500,7 @@ impl From> for SizeKey { /// A hashable vec for using as a key during primitive interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Copy, Debug, Clone, PartialEq)] +#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)] pub struct VectorKey { pub x: f32, pub y: f32, @@ -531,7 +533,7 @@ impl From for VectorKey { /// A hashable point for using as a key during primitive interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq)] pub struct PointKey { pub x: f32, pub y: f32, @@ -563,7 +565,7 @@ impl From for PointKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct PrimKeyCommonData { pub is_backface_visible: bool, pub prim_size: SizeKey, @@ -585,15 +587,15 @@ impl PrimKeyCommonData { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct PrimKey { +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] +pub struct PrimKey { pub common: PrimKeyCommonData, pub kind: T, } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct PrimitiveKey { pub common: PrimKeyCommonData, pub kind: PrimitiveKeyKind, @@ -648,6 +650,7 @@ impl AsInstanceKind for PrimitiveKey { /// both across frames and display lists, by comparing the matching PrimitiveKey. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub enum PrimitiveTemplateKind { Rectangle { color: ColorF, @@ -675,6 +678,7 @@ impl PrimitiveKeyKind { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct PrimTemplateCommonData { pub is_backface_visible: bool, pub prim_size: LayoutSize, @@ -701,6 +705,7 @@ impl PrimTemplateCommonData { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct PrimTemplate { pub common: PrimTemplateCommonData, pub kind: T, @@ -708,6 +713,7 @@ pub struct PrimTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct PrimitiveTemplate { pub common: PrimTemplateCommonData, pub kind: PrimitiveTemplateKind, @@ -780,7 +786,7 @@ impl PrimitiveTemplate { // Type definitions for interning primitives. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct PrimitiveDataMarker; impl intern::Internable for PrimitiveKeyKind { @@ -846,7 +852,7 @@ impl OpacityBinding { } } -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct VisibleMaskImageTile { @@ -865,7 +871,7 @@ pub struct VisibleGradientTile { /// along with the current render task cache entry. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub struct BorderSegmentInfo { pub local_task_size: LayoutSize, pub cache_key: BorderSegmentCacheKey, @@ -880,6 +886,7 @@ bitflags! { /// `write_transform_vertex()` function. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] + #[derive(MallocSizeOf)] pub struct EdgeAaSegmentMask: u8 { const LEFT = 0x1; const TOP = 0x2; @@ -901,7 +908,7 @@ pub enum ClipMaskKind { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, MallocSizeOf)] pub struct BrushSegment { pub local_rect: LayoutRect, pub may_need_clip_mask: bool, @@ -1191,7 +1198,7 @@ impl ClipData { /// A hashable descriptor for nine-patches, used by image and /// gradient borders. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct NinePatchDescriptor { diff --git a/webrender/src/prim_store/picture.rs b/webrender/src/prim_store/picture.rs index 2ea28ccc3b..06a341ec0e 100644 --- a/webrender/src/prim_store/picture.rs +++ b/webrender/src/prim_store/picture.rs @@ -19,7 +19,7 @@ use prim_store::{ /// will be composited into its parent. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq, Hash, Eq)] +#[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)] pub enum PictureCompositeKey { // No visual compositing effect Identity, @@ -127,7 +127,7 @@ impl From> for PictureCompositeKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct Picture { pub composite_mode_key: PictureCompositeKey, } @@ -171,6 +171,7 @@ impl AsInstanceKind for PictureKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct PictureData; pub type PictureTemplate = PrimTemplate; @@ -188,7 +189,7 @@ impl From for PictureTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct PictureDataMarker; pub type PictureDataStore = DataStore; diff --git a/webrender/src/prim_store/text_run.rs b/webrender/src/prim_store/text_run.rs index dc79060bfd..7deeaf16b4 100644 --- a/webrender/src/prim_store/text_run.rs +++ b/webrender/src/prim_store/text_run.rs @@ -23,7 +23,7 @@ use storage; /// A run of glyphs, with associated font information. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] pub struct TextRunKey { pub common: PrimKeyCommonData, pub font: FontInstance, @@ -73,6 +73,7 @@ impl AsInstanceKind for TextRunKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(MallocSizeOf)] pub struct TextRunTemplate { pub common: PrimTemplateCommonData, pub font: FontInstance, @@ -161,7 +162,7 @@ impl TextRunTemplate { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, Eq, MallocSizeOf, PartialEq)] pub struct TextRunDataMarker; pub type TextRunDataStore = intern::DataStore; diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index e881532cd3..07a55efc72 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -14,7 +14,7 @@ use api::{BuiltDisplayListIter, SpecificDisplayItem}; use api::{DevicePixelScale, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestFlags, HitTestResult}; use api::{IdNamespace, LayoutPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping}; -use api::{MemoryReport, VoidPtrToSizeFn}; +use api::{MemoryReport}; use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, BlobImageKey}; use api::{NotificationRequest, Checkpoint}; use api::channel::{MsgReceiver, MsgSender, Payload}; @@ -30,6 +30,7 @@ use frame_builder::{FrameBuilder, FrameBuilderConfig}; use gpu_cache::GpuCache; use hit_test::{HitTest, HitTester}; use internal_types::{DebugOutput, FastHashMap, FastHashSet, RenderedDocument, ResultMsg}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use picture::RetainedTiles; use prim_store::{PrimitiveDataStore, PrimitiveScratchBuffer, PrimitiveInstance}; use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; @@ -88,7 +89,7 @@ impl DocumentView { } } -#[derive(Copy, Clone, Hash, PartialEq, PartialOrd, Debug, Eq, Ord)] +#[derive(Copy, Clone, Hash, MallocSizeOf, PartialEq, PartialOrd, Debug, Eq, Ord)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FrameId(usize); @@ -142,7 +143,7 @@ impl ::std::ops::Sub for FrameId { /// decisions. As such, we use the `FrameId` for equality and comparison, since /// we should never have two `FrameStamps` with the same id but different /// timestamps. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, MallocSizeOf)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FrameStamp { @@ -213,30 +214,32 @@ impl FrameStamp { }; } -// A collection of resources that are shared by clips, primitives -// between display lists. -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Default)] -pub struct FrameResources { - /// The store of currently active / available clip nodes. This is kept - /// in sync with the clip interner in the scene builder for each document. - pub clip_data_store: ClipDataStore, - - /// Currently active / available primitives. Kept in sync with the - /// primitive interner in the scene builder, per document. - pub prim_data_store: PrimitiveDataStore, - pub image_data_store: ImageDataStore, - pub image_border_data_store: ImageBorderDataStore, - pub line_decoration_data_store: LineDecorationDataStore, - pub linear_grad_data_store: LinearGradientDataStore, - pub normal_border_data_store: NormalBorderDataStore, - pub picture_data_store: PictureDataStore, - pub radial_grad_data_store: RadialGradientDataStore, - pub text_run_data_store: TextRunDataStore, - pub yuv_image_data_store: YuvImageDataStore, +macro_rules! declare_frame_resources { + ( $( { $x: ident, $y: ty, $datastore_ident: ident, $datastore_type: ty } )+ ) => { + /// A collection of resources that are shared by clips, primitives + /// between display lists. + #[cfg_attr(feature = "capture", derive(Serialize))] + #[cfg_attr(feature = "replay", derive(Deserialize))] + #[derive(Default)] + pub struct FrameResources { + $( + pub $datastore_ident: $datastore_type, + )+ + } + + impl FrameResources { + /// Reports CPU heap usage. + fn report_memory(&self, ops: &mut MallocSizeOfOps, r: &mut MemoryReport) { + $( + r.interning.$datastore_ident += self.$datastore_ident.size_of(ops); + )+ + } + } + } } +enumerate_interners!(declare_frame_resources); + impl FrameResources { pub fn as_common_data( &self, @@ -286,15 +289,6 @@ impl FrameResources { } } } - - /// Reports CPU heap usage. - fn report_memory(&self, op: VoidPtrToSizeFn, r: &mut MemoryReport) { - r.data_stores += self.clip_data_store.malloc_size_of(op); - r.data_stores += self.prim_data_store.malloc_size_of(op); - r.data_stores += self.linear_grad_data_store.malloc_size_of(op); - r.data_stores += self.radial_grad_data_store.malloc_size_of(op); - r.data_stores += self.text_run_data_store.malloc_size_of(op); - } } struct Document { @@ -679,7 +673,7 @@ pub struct RenderBackend { notifier: Box, recorder: Option>, sampler: Option>, - size_of_op: Option, + size_of_ops: Option, debug_flags: DebugFlags, namespace_alloc_by_client: bool, } @@ -698,7 +692,7 @@ impl RenderBackend { frame_config: FrameBuilderConfig, recorder: Option>, sampler: Option>, - size_of_op: Option, + size_of_ops: Option, debug_flags: DebugFlags, namespace_alloc_by_client: bool, ) -> RenderBackend { @@ -718,7 +712,7 @@ impl RenderBackend { notifier, recorder, sampler, - size_of_op, + size_of_ops, debug_flags, namespace_alloc_by_client, } @@ -1552,18 +1546,18 @@ impl RenderBackend { serde_json::to_string(&debug_root).unwrap() } - fn report_memory(&self, tx: MsgSender) { + fn report_memory(&mut self, tx: MsgSender) { let mut report = MemoryReport::default(); - let op = self.size_of_op.unwrap(); - report.gpu_cache_metadata = self.gpu_cache.malloc_size_of(op); + let ops = self.size_of_ops.as_mut().unwrap(); + let op = ops.size_of_op; + report.gpu_cache_metadata = self.gpu_cache.size_of(ops); for (_id, doc) in &self.documents { if let Some(ref fb) = doc.frame_builder { - report.clip_stores += fb.clip_store.malloc_size_of(op); + report.clip_stores += fb.clip_store.size_of(ops); } - report.hit_testers += - doc.hit_tester.as_ref().map_or(0, |ht| ht.malloc_size_of(op)); + report.hit_testers += doc.hit_tester.size_of(ops); - doc.resources.report_memory(op, &mut report) + doc.resources.report_memory(ops, &mut report) } report += self.resource_cache.report_memory(op); diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 5ef5544447..f590111326 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -1113,7 +1113,7 @@ pub struct RenderTaskCacheEntry { pub handle: TextureCacheHandle, } -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub enum RenderTaskCacheMarker {} // A cache of render tasks that are stored in the texture diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 8e275175e8..2df4124291 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -59,6 +59,7 @@ use internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceC use internal_types::{CacheTextureId, DebugOutput, FastHashMap, LayerIndex, RenderedDocument, ResultMsg}; use internal_types::{TextureCacheAllocationKind, TextureCacheUpdate, TextureUpdateList, TextureUpdateSource}; use internal_types::{RenderTargetInfo, SavedTargetIndex}; +use malloc_size_of::MallocSizeOfOps; use prim_store::DeferredResolve; use profiler::{BackendProfileCounters, FrameProfileCounters, TimeProfileCounter, GpuProfileTag, RendererProfileCounters, RendererProfileTimers}; @@ -1556,17 +1557,9 @@ pub struct Renderer { /// copy the WR output to. output_image_handler: Option>, - /// Optional function pointer for measuring memory used by a given + /// Optional function pointers for measuring memory used by a given /// heap-allocated pointer. - size_of_op: Option, - - /// Optional function pointer for measuring memory used by a given - /// heap-allocated region of memory. Unlike the above, pointers passed - /// to this function do not need to point to the start of the allocation, - /// and can be anywhere in the allocated region. This is useful for measuring - /// structures like hashmaps that don't expose pointers to the start of the - /// allocation, but do expose pointers to elements within the allocation. - _enclosing_size_of_op: Option, + size_of_ops: Option, // Currently allocated FBOs for output frames. output_targets: FastHashMap, @@ -1832,6 +1825,10 @@ impl Renderer { let device_pixel_ratio = options.device_pixel_ratio; let debug_flags = options.debug_flags; let payload_rx_for_backend = payload_rx.to_mpsc_receiver(); + let size_of_op = options.size_of_op; + let enclosing_size_of_op = options.enclosing_size_of_op; + let make_size_of_ops = + move || size_of_op.map(|o| MallocSizeOfOps::new(o, enclosing_size_of_op)); let recorder = options.recorder; let thread_listener = Arc::new(options.thread_listener); let thread_listener_for_rayon_start = thread_listener.clone(); @@ -1857,8 +1854,6 @@ impl Renderer { Arc::new(worker.unwrap()) }); let sampler = options.sampler; - let size_of_op = options.size_of_op; - let enclosing_size_of_op = options.enclosing_size_of_op; let namespace_alloc_by_client = options.namespace_alloc_by_client; let blob_image_handler = options.blob_image_handler.take(); @@ -1875,8 +1870,7 @@ impl Renderer { config, api_tx.clone(), scene_builder_hooks, - size_of_op, - enclosing_size_of_op, + make_size_of_ops(), ); thread::Builder::new().name(scene_thread_name.clone()).spawn(move || { register_thread_with_profiler(scene_thread_name.clone()); @@ -1949,7 +1943,7 @@ impl Renderer { config, recorder, sampler, - size_of_op, + make_size_of_ops(), debug_flags, namespace_alloc_by_client, ); @@ -2011,8 +2005,7 @@ impl Renderer { dither_matrix_texture, external_image_handler: None, output_image_handler: None, - size_of_op: options.size_of_op, - _enclosing_size_of_op: options.enclosing_size_of_op, + size_of_ops: make_size_of_ops(), output_targets: FastHashMap::default(), cpu_profiles: VecDeque::new(), gpu_profiles: VecDeque::new(), @@ -4572,7 +4565,7 @@ impl Renderer { } fn size_of(&self, ptr: *const T) -> usize { - let op = self.size_of_op.as_ref().unwrap(); + let op = self.size_of_ops.as_ref().unwrap().size_of_op; unsafe { op(ptr as *const c_void) } } diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index 3cb0db61f9..04860c1def 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -1821,6 +1821,13 @@ impl ResourceCache { } /// Reports the CPU heap usage of this ResourceCache. + /// + /// NB: It would be much better to use the derive(MallocSizeOf) machinery + /// here, but the Arcs complicate things. The two ways to handle that would + /// be to either (a) Implement MallocSizeOf manually for the things that own + /// them and manually avoid double-counting, or (b) Use the "seen this pointer + /// yet" machinery from the proper malloc_size_of crate. We can do this if/when + /// more accurate memory reporting on these resources becomes a priority. pub fn report_memory(&self, op: VoidPtrToSizeFn) -> MemoryReport { let mut report = MemoryReport::default(); diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 1e8c4d82f6..41ca3c75bb 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -5,7 +5,7 @@ use api::{AsyncBlobImageRasterizer, BlobImageRequest, BlobImageParams, BlobImageResult}; use api::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdate, ExternalEvent, Epoch}; use api::{BuiltDisplayList, ColorF, LayoutSize, NotificationRequest, Checkpoint, IdNamespace}; -use api::{MemoryReport, VoidPtrToSizeFn}; +use api::{MemoryReport}; use api::channel::MsgSender; #[cfg(feature = "capture")] use capture::CaptureConfig; @@ -15,6 +15,7 @@ use clip_scroll_tree::ClipScrollTree; use display_list_flattener::DisplayListFlattener; use intern::{Internable, Interner}; use internal_types::{FastHashMap, FastHashSet}; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use prim_store::{PrimitiveDataInterner, PrimitiveDataUpdateList, PrimitiveKeyKind}; use prim_store::PrimitiveStoreStats; use prim_store::borders::{ @@ -193,45 +194,40 @@ pub enum SceneSwapResult { Aborted, } -// This struct contains all items that can be shared between -// display lists. We want to intern and share the same clips, -// primitives and other things between display lists so that: -// - GPU cache handles remain valid, reducing GPU cache updates. -// - Comparison of primitives and pictures between two -// display lists is (a) fast (b) done during scene building. -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Default)] -pub struct DocumentResources { - pub clip_interner: ClipDataInterner, - pub prim_interner: PrimitiveDataInterner, - pub image_interner: ImageDataInterner, - pub image_border_interner: ImageBorderDataInterner, - pub line_decoration_interner: LineDecorationDataInterner, - pub linear_grad_interner: LinearGradientDataInterner, - pub normal_border_interner: NormalBorderDataInterner, - pub picture_interner: PictureDataInterner, - pub radial_grad_interner: RadialGradientDataInterner, - pub text_run_interner: TextRunDataInterner, - pub yuv_image_interner: YuvImageDataInterner, -} +macro_rules! declare_document_resources { + ( $( { $interner_ident: ident, $interner_type: ty, $x: ident, $y: ty } )+ ) => { + /// This struct contains all items that can be shared between + /// display lists. We want to intern and share the same clips, + /// primitives and other things between display lists so that: + /// - GPU cache handles remain valid, reducing GPU cache updates. + /// - Comparison of primitives and pictures between two + /// display lists is (a) fast (b) done during scene building. + #[cfg_attr(feature = "capture", derive(Serialize))] + #[cfg_attr(feature = "replay", derive(Deserialize))] + #[derive(Default)] + pub struct DocumentResources { + $( + pub $interner_ident: $interner_type, + )+ + } -impl DocumentResources { - /// Reports CPU heap memory used by the interners. - fn report_memory( - &self, - op: VoidPtrToSizeFn, - eop: VoidPtrToSizeFn, - r: &mut MemoryReport, - ) { - r.interners += self.clip_interner.malloc_size_of(op, eop); - r.interners += self.prim_interner.malloc_size_of(op, eop); - r.interners += self.linear_grad_interner.malloc_size_of(op, eop); - r.interners += self.radial_grad_interner.malloc_size_of(op, eop); - r.interners += self.text_run_interner.malloc_size_of(op, eop); + impl DocumentResources { + /// Reports CPU heap memory used by the interners. + fn report_memory( + &self, + ops: &mut MallocSizeOfOps, + r: &mut MemoryReport, + ) { + $( + r.interning.$interner_ident += self.$interner_ident.size_of(ops); + )+ + } + } } } +enumerate_interners!(declare_document_resources); + // Access to `DocumentResources` interners by `Internable` pub trait InternerMut { @@ -293,8 +289,7 @@ pub struct SceneBuilder { config: FrameBuilderConfig, hooks: Option>, simulate_slow_ms: u32, - size_of_op: Option, - enclosing_size_of_op: Option, + size_of_ops: Option, } impl SceneBuilder { @@ -302,8 +297,7 @@ impl SceneBuilder { config: FrameBuilderConfig, api_tx: MsgSender, hooks: Option>, - size_of_op: Option, - enclosing_size_of_op: Option, + size_of_ops: Option, ) -> (Self, Sender, Receiver) { let (in_tx, in_rx) = channel(); let (out_tx, out_rx) = channel(); @@ -315,8 +309,7 @@ impl SceneBuilder { api_tx, config, hooks, - size_of_op, - enclosing_size_of_op, + size_of_ops, simulate_slow_ms: 0, }, in_tx, @@ -763,12 +756,11 @@ impl SceneBuilder { } /// Reports CPU heap memory used by the SceneBuilder. - fn report_memory(&self) -> MemoryReport { - let op = self.size_of_op.unwrap(); - let eop = self.enclosing_size_of_op.unwrap(); + fn report_memory(&mut self) -> MemoryReport { + let ops = self.size_of_ops.as_mut().unwrap(); let mut report = MemoryReport::default(); for doc in self.documents.values() { - doc.resources.report_memory(op, eop, &mut report); + doc.resources.report_memory(ops, &mut report); } report diff --git a/webrender/src/util.rs b/webrender/src/util.rs index ba94c2a28f..9c6dd4e24f 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -92,7 +92,7 @@ impl VecHelper for Vec { // TODO(gw): We should try and incorporate F <-> T units here, // but it's a bit tricky to do that now with the // way the current clip-scroll tree works. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, MallocSizeOf)] pub struct ScaleOffset { pub scale: Vector2D, pub offset: Vector2D, @@ -556,7 +556,7 @@ impl MaxRect for TypedRect { /// An enum that tries to avoid expensive transformation matrix calculations /// when possible when dealing with non-perspective axis-aligned transformations. -#[derive(Debug)] +#[derive(Debug, MallocSizeOf)] pub enum FastTransform { /// A simple offset, which can be used without doing any matrix math. Offset(TypedVector2D), diff --git a/webrender_api/Cargo.toml b/webrender_api/Cargo.toml index db4063d984..be2d4109f4 100644 --- a/webrender_api/Cargo.toml +++ b/webrender_api/Cargo.toml @@ -19,10 +19,12 @@ bitflags = "1.0" byteorder = "1.2.1" ipc-channel = {version = "0.11.0", optional = true} euclid = { version = "0.19.4", features = ["serde"] } +malloc_size_of_derive = "0.1" serde = { version = "=1.0.80", features = ["rc"] } serde_derive = { version = "=1.0.80", features = ["deserialize_in_place"] } serde_bytes = "0.10" time = "0.1" +wr_malloc_size_of = { version = "0.0.1", path = "../wr_malloc_size_of" } [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.6" diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs index 5838c24bc3..80ce10842d 100644 --- a/webrender_api/src/api.rs +++ b/webrender_api/src/api.rs @@ -561,7 +561,7 @@ pub struct HitTestResult { } bitflags! { - #[derive(Deserialize, Serialize)] + #[derive(Deserialize, MallocSizeOf, Serialize)] pub struct HitTestFlags: u8 { const FIND_ALL = 0b00000001; const POINT_RELATIVE_TO_PIPELINE_VIEWPORT = 0b00000010; @@ -787,11 +787,11 @@ impl Epoch { } #[repr(C)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] pub struct IdNamespace(pub u32); #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct DocumentId(pub IdNamespace, pub u32); impl DocumentId { @@ -807,7 +807,7 @@ pub type PipelineSourceId = u32; /// From the point of view of WR, `PipelineId` is completely opaque and generic as long as /// it's clonable, serializable, comparable, and hashable. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct PipelineId(pub PipelineSourceId, pub u32); impl PipelineId { @@ -816,14 +816,64 @@ impl PipelineId { } } +/// Meta-macro to enumerate the various interner identifiers and types. +/// +/// IMPORTANT: Keep this synchronized with the list in mozilla-central located at +/// gfx/webrender_bindings/webrender_ffi.h +/// +/// Note that this could be a lot less verbose if concat_idents! were stable. :-( +#[macro_export] +macro_rules! enumerate_interners { + ($macro_name: ident) => { + $macro_name! { + { clip_interner, ClipDataInterner, clip_data_store, ClipDataStore } + { prim_interner, PrimitiveDataInterner, prim_data_store, PrimitiveDataStore } + { normal_border_interner, NormalBorderDataInterner, normal_border_data_store, NormalBorderDataStore } + { image_border_interner, ImageBorderDataInterner, image_border_data_store, ImageBorderDataStore } + { image_interner, ImageDataInterner, image_data_store, ImageDataStore } + { yuv_image_interner, YuvImageDataInterner, yuv_image_data_store, YuvImageDataStore } + { line_decoration_interner, LineDecorationDataInterner, + line_decoration_data_store, LineDecorationDataStore } + { linear_grad_interner, LinearGradientDataInterner, linear_grad_data_store, LinearGradientDataStore } + { radial_grad_interner, RadialGradientDataInterner, radial_grad_data_store, RadialGradientDataStore } + { picture_interner, PictureDataInterner, picture_data_store, PictureDataStore } + { text_run_interner, TextRunDataInterner, text_run_data_store, TextRunDataStore } + } + } +} + +macro_rules! declare_interning_memory_report { + ( $( { $interner_ident: ident, $x: ty, $datastore_ident: ident, $y: ty } )+ ) => { + #[repr(C)] + #[derive(Clone, Debug, Default, Deserialize, Serialize)] + pub struct InterningMemoryReport { + $( + pub $interner_ident: usize, + pub $datastore_ident: usize, + )+ + } + + impl ::std::ops::AddAssign for InterningMemoryReport { + fn add_assign(&mut self, other: InterningMemoryReport) { + $( + self.$interner_ident += other.$interner_ident; + self.$datastore_ident += other.$datastore_ident; + )+ + } + } + } +} + +enumerate_interners!(declare_interning_memory_report); + /// Collection of heap sizes, in bytes. +/// cbindgen:derive-eq=false #[repr(C)] #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct MemoryReport { // // CPU Memory. // - pub primitive_stores: usize, pub clip_stores: usize, pub gpu_cache_metadata: usize, pub gpu_cache_cpu_mirror: usize, @@ -833,8 +883,7 @@ pub struct MemoryReport { pub images: usize, pub rasterized_blobs: usize, pub shader_cache: usize, - pub data_stores: usize, - pub interners: usize, + pub interning: InterningMemoryReport, // // GPU memory. @@ -849,7 +898,6 @@ pub struct MemoryReport { 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; @@ -859,8 +907,8 @@ impl ::std::ops::AddAssign for MemoryReport { self.images += other.images; self.rasterized_blobs += other.rasterized_blobs; self.shader_cache += other.shader_cache; - self.data_stores += other.data_stores; - self.interners += other.interners; + self.interning += other.interning; + self.gpu_cache_textures += other.gpu_cache_textures; self.vertex_data_textures += other.vertex_data_textures; self.render_target_textures += other.render_target_textures; @@ -963,7 +1011,7 @@ impl RenderApiSender { } bitflags! { - #[derive(Default, Deserialize, Serialize)] + #[derive(Default, Deserialize, MallocSizeOf, Serialize)] pub struct DebugFlags: u32 { /// Display the frame profiler on screen. const PROFILER_DBG = 1 << 0; @@ -1289,7 +1337,7 @@ impl ZoomFactor { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] pub struct PropertyBindingId { namespace: IdNamespace, uid: u32, diff --git a/webrender_api/src/color.rs b/webrender_api/src/color.rs index bdda69e819..bc8cd07105 100644 --- a/webrender_api/src/color.rs +++ b/webrender_api/src/color.rs @@ -39,7 +39,7 @@ impl PremultipliedColorF { /// All components must be between 0.0 and 1.0. /// An alpha value of 1.0 is opaque while 0.0 is fully transparent. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct ColorF { pub r: f32, pub g: f32, @@ -112,7 +112,7 @@ impl Hash for PremultipliedColorF { /// /// If the alpha value `a` is 255 the color is opaque. #[repr(C)] -#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Hash, Eq, Debug, Deserialize, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct ColorU { pub r: u8, pub g: u8, diff --git a/webrender_api/src/display_item.rs b/webrender_api/src/display_item.rs index 4df5f0a13f..0559f4323f 100644 --- a/webrender_api/src/display_item.rs +++ b/webrender_api/src/display_item.rs @@ -247,14 +247,14 @@ pub struct LineDisplayItem { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] pub enum LineOrientation { Vertical, Horizontal, } #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash)] pub enum LineStyle { Solid, Dotted, @@ -269,7 +269,7 @@ pub struct TextDisplayItem { pub glyph_options: Option, } // IMPLICIT: glyphs: Vec -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct NormalBorder { pub left: BorderSide, pub right: BorderSide, @@ -328,7 +328,7 @@ impl NormalBorder { } #[repr(u32)] -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] +#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)] pub enum RepeatMode { Stretch, Repeat, @@ -401,7 +401,7 @@ pub enum BorderRadiusKind { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct BorderRadius { pub top_left: LayoutSize, pub top_right: LayoutSize, @@ -410,14 +410,14 @@ pub struct BorderRadius { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct BorderSide { pub color: ColorF, pub style: BorderStyle, } #[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Hash, Eq)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq)] pub enum BorderStyle { None = 0, Solid = 1, @@ -438,7 +438,7 @@ impl BorderStyle { } #[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum BoxShadowClipMode { Outset = 0, Inset = 1, @@ -464,7 +464,7 @@ pub struct Shadow { } #[repr(u8)] -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] pub enum ExtendMode { Clamp, Repeat, @@ -485,7 +485,7 @@ pub struct GradientDisplayItem { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct GradientStop { pub offset: f32, pub color: ColorF, @@ -659,14 +659,14 @@ pub struct ImageDisplayItem { } #[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum ImageRendering { Auto = 0, CrispEdges = 1, Pixelated = 2, } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum AlphaType { Alpha = 0, PremultipliedAlpha = 1, @@ -681,7 +681,7 @@ pub struct YuvImageDisplayItem { } #[repr(u32)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum YuvColorSpace { Rec601 = 0, Rec709 = 1, @@ -704,7 +704,7 @@ impl YuvData { } } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum YuvFormat { NV12 = 0, PlanarYCbCr = 1, @@ -741,7 +741,7 @@ impl ImageMask { } #[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] +#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)] pub enum ClipMode { Clip, // Pixels inside the region are visible. ClipOut, // Pixels outside the region are visible. diff --git a/webrender_api/src/font.rs b/webrender_api/src/font.rs index b8c1cd914e..8ab85721ae 100644 --- a/webrender_api/src/font.rs +++ b/webrender_api/src/font.rs @@ -71,7 +71,7 @@ pub struct GlyphDimensions { } #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, Ord, PartialOrd)] pub struct FontKey(pub IdNamespace, pub u32); impl FontKey { @@ -94,7 +94,7 @@ pub enum FontTemplate { } #[repr(u32)] -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] +#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] pub enum FontRenderMode { Mono = 0, Alpha, @@ -112,7 +112,7 @@ impl FontRenderMode { } #[repr(C)] -#[derive(Clone, Copy, Debug, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialOrd, Deserialize, Serialize)] pub struct FontVariation { pub tag: u32, pub value: f32, @@ -159,7 +159,7 @@ impl Default for GlyphOptions { bitflags! { #[repr(C)] - #[derive(Deserialize, Serialize)] + #[derive(Deserialize, MallocSizeOf, Serialize)] pub struct FontInstanceFlags: u32 { // Common flags const SYNTHETIC_BOLD = 1 << 1; @@ -204,7 +204,7 @@ impl Default for FontInstanceFlags { #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct SyntheticItalics { // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point. pub angle: i16, @@ -273,7 +273,7 @@ impl Default for FontInstanceOptions { #[cfg(target_os = "windows")] #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct FontInstancePlatformOptions { pub gamma: u16, // percent pub contrast: u16, // percent @@ -291,7 +291,7 @@ impl Default for FontInstancePlatformOptions { #[cfg(target_os = "macos")] #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct FontInstancePlatformOptions { pub unused: u32, } @@ -307,7 +307,7 @@ impl Default for FontInstancePlatformOptions { #[cfg(not(any(target_os = "macos", target_os = "windows")))] #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub enum FontLCDFilter { None, Default, @@ -317,7 +317,7 @@ pub enum FontLCDFilter { #[cfg(not(any(target_os = "macos", target_os = "windows")))] #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub enum FontHinting { None, Mono, @@ -328,7 +328,7 @@ pub enum FontHinting { #[cfg(not(any(target_os = "macos", target_os = "windows")))] #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)] pub struct FontInstancePlatformOptions { pub lcd_filter: FontLCDFilter, pub hinting: FontHinting, @@ -370,7 +370,7 @@ pub struct FontInstanceData { pub type GlyphIndex = u32; #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)] pub struct GlyphInstance { pub index: GlyphIndex, pub point: LayoutPoint, diff --git a/webrender_api/src/image.rs b/webrender_api/src/image.rs index d3f4ac8ee7..6ce0401a1e 100644 --- a/webrender_api/src/image.rs +++ b/webrender_api/src/image.rs @@ -17,7 +17,7 @@ use std::ops::{Add, Sub}; /// This is used as a handle to reference images, and is used as the /// hash map key for the actual image storage in the `ResourceCache`. #[repr(C)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub struct ImageKey(pub IdNamespace, pub u32); impl ImageKey { @@ -137,7 +137,7 @@ impl ImageFormat { /// Specifies the color depth of an image. Currently only used for YUV images. #[repr(u8)] -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum ColorDepth { /// 8 bits image (most common) Color8, diff --git a/webrender_api/src/lib.rs b/webrender_api/src/lib.rs index 6da3ff31c1..63be1f807a 100644 --- a/webrender_api/src/lib.rs +++ b/webrender_api/src/lib.rs @@ -30,11 +30,15 @@ extern crate dwrote; pub extern crate euclid; #[cfg(feature = "ipc")] extern crate ipc_channel; +#[macro_use] +extern crate malloc_size_of_derive; extern crate serde; #[macro_use] extern crate serde_derive; extern crate time; +extern crate wr_malloc_size_of; +use wr_malloc_size_of as malloc_size_of; mod api; pub mod channel; diff --git a/webrender_api/src/units.rs b/webrender_api/src/units.rs index 8939a06075..3fcf4655de 100644 --- a/webrender_api/src/units.rs +++ b/webrender_api/src/units.rs @@ -65,7 +65,7 @@ pub type RasterVector2D = TypedVector2D; pub type RasterVector3D = TypedVector3D; /// Geometry in a stacking context's local coordinate space (logical pixels). -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize)] pub struct LayoutPixel; pub type LayoutRect = TypedRect; @@ -81,7 +81,7 @@ pub type LayoutIntPoint = TypedPoint2D; pub type LayoutIntSize = TypedSize2D; /// Geometry in the document's coordinate space (logical pixels). -#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd)] pub struct WorldPixel; pub type WorldRect = TypedRect; diff --git a/wr_malloc_size_of/Cargo.toml b/wr_malloc_size_of/Cargo.toml new file mode 100644 index 0000000000..48d1814997 --- /dev/null +++ b/wr_malloc_size_of/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wr_malloc_size_of" +version = "0.0.1" +license = "MIT/Apache-2.0" +publish = false + +[lib] +path = "lib.rs" + +[dependencies] +app_units = "0.7" +euclid = "0.19" diff --git a/wr_malloc_size_of/LICENSE-APACHE b/wr_malloc_size_of/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/wr_malloc_size_of/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/wr_malloc_size_of/LICENSE-MIT b/wr_malloc_size_of/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/wr_malloc_size_of/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/wr_malloc_size_of/lib.rs b/wr_malloc_size_of/lib.rs new file mode 100644 index 0000000000..1e05a8435b --- /dev/null +++ b/wr_malloc_size_of/lib.rs @@ -0,0 +1,435 @@ +// Copyright 2016-2017 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A reduced fork of Firefox's malloc_size_of crate, for bundling with WebRender. + +extern crate app_units; +extern crate euclid; + +use std::hash::{BuildHasher, Hash}; +use std::mem::size_of; +use std::ops::Range; +use std::os::raw::c_void; + +/// A C function that takes a pointer to a heap allocation and returns its size. +type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -> usize; + +/// Operations used when measuring heap usage of data structures. +pub struct MallocSizeOfOps { + /// A function that returns the size of a heap allocation. + pub size_of_op: VoidPtrToSizeFn, + + /// Like `size_of_op`, but can take an interior pointer. Optional because + /// not all allocators support this operation. If it's not provided, some + /// memory measurements will actually be computed estimates rather than + /// real and accurate measurements. + pub enclosing_size_of_op: Option, +} + +impl MallocSizeOfOps { + pub fn new( + size_of: VoidPtrToSizeFn, + malloc_enclosing_size_of: Option, + ) -> Self { + MallocSizeOfOps { + size_of_op: size_of, + enclosing_size_of_op: malloc_enclosing_size_of, + } + } + + /// Check if an allocation is empty. This relies on knowledge of how Rust + /// handles empty allocations, which may change in the future. + fn is_empty(ptr: *const T) -> bool { + // The correct condition is this: + // `ptr as usize <= ::std::mem::align_of::()` + // But we can't call align_of() on a ?Sized T. So we approximate it + // with the following. 256 is large enough that it should always be + // larger than the required alignment, but small enough that it is + // always in the first page of memory and therefore not a legitimate + // address. + return ptr as *const usize as usize <= 256; + } + + /// Call `size_of_op` on `ptr`, first checking that the allocation isn't + /// empty, because some types (such as `Vec`) utilize empty allocations. + pub unsafe fn malloc_size_of(&self, ptr: *const T) -> usize { + if MallocSizeOfOps::is_empty(ptr) { + 0 + } else { + (self.size_of_op)(ptr as *const c_void) + } + } + + /// Is an `enclosing_size_of_op` available? + pub fn has_malloc_enclosing_size_of(&self) -> bool { + self.enclosing_size_of_op.is_some() + } + + /// Call `enclosing_size_of_op`, which must be available, on `ptr`, which + /// must not be empty. + pub unsafe fn malloc_enclosing_size_of(&self, ptr: *const T) -> usize { + assert!(!MallocSizeOfOps::is_empty(ptr)); + (self.enclosing_size_of_op.unwrap())(ptr as *const c_void) + } +} + +/// Trait for measuring the "deep" heap usage of a data structure. This is the +/// most commonly-used of the traits. +pub trait MallocSizeOf { + /// Measure the heap usage of all descendant heap-allocated structures, but + /// not the space taken up by the value itself. + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +/// Trait for measuring the "shallow" heap usage of a container. +pub trait MallocShallowSizeOf { + /// Measure the heap usage of immediate heap-allocated descendant + /// structures, but not the space taken up by the value itself. Anything + /// beyond the immediate descendants must be measured separately, using + /// iteration. + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize; +} + +impl MallocSizeOf for String { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + unsafe { ops.malloc_size_of(self.as_ptr()) } + } +} + +impl MallocShallowSizeOf for Box { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + unsafe { ops.malloc_size_of(&**self) } + } +} + +impl MallocSizeOf for Box { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.shallow_size_of(ops) + (**self).size_of(ops) + } +} + +impl MallocSizeOf for () { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} + +impl MallocSizeOf for (T1, T2) +where + T1: MallocSizeOf, + T2: MallocSizeOf, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + self.1.size_of(ops) + } +} + +impl MallocSizeOf for (T1, T2, T3) +where + T1: MallocSizeOf, + T2: MallocSizeOf, + T3: MallocSizeOf, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + } +} + +impl MallocSizeOf for (T1, T2, T3, T4) +where + T1: MallocSizeOf, + T2: MallocSizeOf, + T3: MallocSizeOf, + T4: MallocSizeOf, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + self.3.size_of(ops) + } +} + +impl MallocSizeOf for Option { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if let Some(val) = self.as_ref() { + val.size_of(ops) + } else { + 0 + } + } +} + +impl MallocSizeOf for Result { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + match *self { + Ok(ref x) => x.size_of(ops), + Err(ref e) => e.size_of(ops), + } + } +} + +impl MallocSizeOf for std::cell::Cell { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.get().size_of(ops) + } +} + +impl MallocSizeOf for std::cell::RefCell { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.borrow().size_of(ops) + } +} + +impl<'a, B: ?Sized + ToOwned> MallocSizeOf for std::borrow::Cow<'a, B> +where + B::Owned: MallocSizeOf, +{ + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + match *self { + std::borrow::Cow::Borrowed(_) => 0, + std::borrow::Cow::Owned(ref b) => b.size_of(ops), + } + } +} + +impl MallocSizeOf for [T] { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = 0; + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + +impl MallocShallowSizeOf for Vec { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + unsafe { ops.malloc_size_of(self.as_ptr()) } + } +} + +impl MallocSizeOf for Vec { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for elem in self.iter() { + n += elem.size_of(ops); + } + n + } +} + +macro_rules! malloc_size_of_hash_set { + ($ty:ty) => { + impl MallocShallowSizeOf for $ty + where + T: Eq + Hash, + S: BuildHasher, + { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + if ops.has_malloc_enclosing_size_of() { + // The first value from the iterator gives us an interior pointer. + // `ops.malloc_enclosing_size_of()` then gives us the storage size. + // This assumes that the `HashSet`'s contents (values and hashes) + // are all stored in a single contiguous heap allocation. + self.iter() + .next() + .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) }) + } else { + // An estimate. + self.capacity() * (size_of::() + size_of::()) + } + } + } + + impl MallocSizeOf for $ty + where + T: Eq + Hash + MallocSizeOf, + S: BuildHasher, + { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for t in self.iter() { + n += t.size_of(ops); + } + n + } + } + }; +} + +malloc_size_of_hash_set!(std::collections::HashSet); + +macro_rules! malloc_size_of_hash_map { + ($ty:ty) => { + impl MallocShallowSizeOf for $ty + where + K: Eq + Hash, + S: BuildHasher, + { + fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + // See the implementation for std::collections::HashSet for details. + if ops.has_malloc_enclosing_size_of() { + self.values() + .next() + .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) }) + } else { + self.capacity() * (size_of::() + size_of::() + size_of::()) + } + } + } + + impl MallocSizeOf for $ty + where + K: Eq + Hash + MallocSizeOf, + V: MallocSizeOf, + S: BuildHasher, + { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut n = self.shallow_size_of(ops); + for (k, v) in self.iter() { + n += k.size_of(ops); + n += v.size_of(ops); + } + n + } + } + }; +} + +malloc_size_of_hash_map!(std::collections::HashMap); + +// PhantomData is always 0. +impl MallocSizeOf for std::marker::PhantomData { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} + +impl MallocSizeOf for euclid::Length { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedScale { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.0.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedPoint2D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.x.size_of(ops) + self.y.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedRect { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.origin.size_of(ops) + self.size.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedSideOffsets2D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.top.size_of(ops) + + self.right.size_of(ops) + + self.bottom.size_of(ops) + + self.left.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedSize2D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.width.size_of(ops) + self.height.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedTransform2D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.m11.size_of(ops) + + self.m12.size_of(ops) + + self.m21.size_of(ops) + + self.m22.size_of(ops) + + self.m31.size_of(ops) + + self.m32.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedTransform3D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.m11.size_of(ops) + + self.m12.size_of(ops) + + self.m13.size_of(ops) + + self.m14.size_of(ops) + + self.m21.size_of(ops) + + self.m22.size_of(ops) + + self.m23.size_of(ops) + + self.m24.size_of(ops) + + self.m31.size_of(ops) + + self.m32.size_of(ops) + + self.m33.size_of(ops) + + self.m34.size_of(ops) + + self.m41.size_of(ops) + + self.m42.size_of(ops) + + self.m43.size_of(ops) + + self.m44.size_of(ops) + } +} + +impl MallocSizeOf for euclid::TypedVector2D { + fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + self.x.size_of(ops) + self.y.size_of(ops) + } +} + +/// For use on types where size_of() returns 0. +#[macro_export] +macro_rules! malloc_size_of_is_0( + ($($ty:ty),+) => ( + $( + impl $crate::MallocSizeOf for $ty { + #[inline(always)] + fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize { + 0 + } + } + )+ + ); + ($($ty:ident<$($gen:ident),+>),+) => ( + $( + impl<$($gen: $crate::MallocSizeOf),+> $crate::MallocSizeOf for $ty<$($gen),+> { + #[inline(always)] + fn size_of(&self, _: &mut $crate::MallocSizeOfOps) -> usize { + 0 + } + } + )+ + ); +); + +malloc_size_of_is_0!(bool, char, str); +malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize); +malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize); +malloc_size_of_is_0!(f32, f64); + +malloc_size_of_is_0!(std::sync::atomic::AtomicBool); +malloc_size_of_is_0!(std::sync::atomic::AtomicIsize); +malloc_size_of_is_0!(std::sync::atomic::AtomicUsize); + +malloc_size_of_is_0!(std::num::NonZeroUsize); +malloc_size_of_is_0!(std::num::NonZeroU32); + +malloc_size_of_is_0!(std::time::Duration); +malloc_size_of_is_0!(std::time::Instant); +malloc_size_of_is_0!(std::time::SystemTime); + +malloc_size_of_is_0!(Range, Range, Range, Range, Range); +malloc_size_of_is_0!(Range, Range, Range, Range, Range); +malloc_size_of_is_0!(Range, Range); + +malloc_size_of_is_0!(app_units::Au);