Bug 1526593 - WR capture frame builder state r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Mon, 11 Feb 2019 19:54:19 +0000
changeset 458560 6eca46400d21ca9f789d8f8f3e13f9291ec40305
parent 458559 a856e1763485f529c7418494783bb8e68d0b23d9
child 458561 0361c4f078f2aa49786589345701547d19387113
push id35538
push userbtara@mozilla.com
push dateTue, 12 Feb 2019 05:25:24 +0000
treeherdermozilla-central@09beaf742eae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1526593
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1526593 - WR capture frame builder state r=gw Saves a whole lot of useful data to peek in "builder-X-Y.ron" Differential Revision: https://phabricator.services.mozilla.com/D19256
Cargo.lock
gfx/wr/Cargo.lock
gfx/wr/webrender/Cargo.toml
gfx/wr/webrender/src/clip.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/image.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/prim_store/text_run.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/storage.rs
gfx/wr/webrender/src/util.rs
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2429,16 +2429,17 @@ name = "smallbitvec"
 version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "smallvec"
 version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
+ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "stable_deref_trait"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
--- a/gfx/wr/Cargo.lock
+++ b/gfx/wr/Cargo.lock
@@ -1325,16 +1325,17 @@ name = "slab"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "smallvec"
 version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
+ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
  "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "smithay-client-toolkit"
 version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
--- a/gfx/wr/webrender/Cargo.toml
+++ b/gfx/wr/webrender/Cargo.toml
@@ -7,17 +7,17 @@ repository = "https://github.com/servo/w
 description = "A GPU accelerated 2D renderer for web content"
 build = "build.rs"
 
 [features]
 default = ["freetype-lib"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 profiler = ["thread_profiler/thread_profiler"]
 debugger = ["ws", "serde_json", "serde", "image", "base64"]
-capture = ["webrender_api/serialize", "ron", "serde"]
+capture = ["webrender_api/serialize", "ron", "serde", "smallvec/serde"]
 replay = ["webrender_api/deserialize", "ron", "serde"]
 pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"]
 serialize_program = ["serde", "webrender_build/serialize_program"]
 no_static_freetype = []
 
 [build-dependencies]
 webrender_build = { version = "0.0.1", path = "../webrender_build" }
 
--- a/gfx/wr/webrender/src/clip.rs
+++ b/gfx/wr/webrender/src/clip.rs
@@ -185,30 +185,32 @@ bitflags! {
         const SAME_COORD_SYSTEM = 0x2;
     }
 }
 
 // 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, MallocSizeOf, PartialEq, Hash)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ClipChainId(pub u32);
 
 // The root of each clip chain is the NONE id. The
 // value is specifically set to u32::MAX so that if
 // any code accidentally tries to access the root
 // node, a bounds error will occur.
 impl ClipChainId {
     pub const NONE: Self = ClipChainId(u32::MAX);
     pub const INVALID: Self = ClipChainId(0xDEADBEEF);
 }
 
 // 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, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ClipChainNode {
     pub handle: ClipDataHandle,
     pub local_pos: LayoutPoint,
     pub spatial_node_index: SpatialNodeIndex,
     pub parent_clip_chain_id: ClipChainId,
 }
 
 // When a clip node is found to be valid for a
@@ -240,25 +242,27 @@ pub struct ClipNodeRange {
 }
 
 // A helper struct for converting between coordinate systems
 // of clip sources and primitives.
 // todo(gw): optimize:
 //  separate arrays for matrices
 //  cache and only build as needed.
 #[derive(Debug, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 enum ClipSpaceConversion {
     Local,
     ScaleOffset(ScaleOffset),
     Transform(LayoutToWorldTransform),
 }
 
 // Temporary information that is cached and reused
 // during building of a clip chain instance.
 #[derive(MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 struct ClipNodeInfo {
     conversion: ClipSpaceConversion,
     handle: ClipDataHandle,
     local_pos: LayoutPoint,
     spatial_node_index: SpatialNodeIndex,
 }
 
 impl ClipNodeInfo {
@@ -426,16 +430,17 @@ impl ClipNode {
                 }
             }
         }
     }
 }
 
 /// The main clipping public interface that other modules access.
 #[derive(MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ClipStore {
     pub clip_chain_nodes: Vec<ClipChainNode>,
     clip_node_instances: Vec<ClipNodeInstance>,
     clip_node_info: Vec<ClipNodeInfo>,
 }
 
 // A clip chain instance is what gets built for a given clip
 // chain id + local primitive region + positioning node.
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -53,26 +53,28 @@ pub struct FrameBuilderConfig {
     pub dual_source_blending_is_enabled: bool,
     pub chase_primitive: ChasePrimitive,
     pub enable_picture_caching: bool,
     /// True if we're running tests (i.e. via wrench).
     pub testing: bool,
 }
 
 /// A builder structure for `tiling::Frame`
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct FrameBuilder {
     screen_rect: DeviceIntRect,
     background_color: Option<ColorF>,
     window_size: DeviceIntSize,
     root_pic_index: PictureIndex,
     /// Cache of surface tiles from the previous frame builder
     /// that can optionally be consumed by this frame builder.
     pending_retained_tiles: RetainedTiles,
     pub prim_store: PrimitiveStore,
     pub clip_store: ClipStore,
+    #[cfg_attr(feature = "capture", serde(skip))] //TODO
     pub hit_testing_runs: Vec<HitTestingRun>,
     pub config: FrameBuilderConfig,
 }
 
 pub struct FrameVisibilityContext<'a> {
     pub clip_scroll_tree: &'a ClipScrollTree,
     pub screen_world_rect: WorldRect,
     pub device_pixel_scale: DevicePixelScale,
@@ -152,17 +154,17 @@ pub struct PictureContext {
 /// Mutable state of a picture that gets modified when
 /// the children are processed.
 pub struct PictureState {
     pub is_cacheable: bool,
     pub map_local_to_pic: SpaceMapper<LayoutPixel, PicturePixel>,
     pub map_pic_to_world: SpaceMapper<PicturePixel, WorldPixel>,
     pub map_pic_to_raster: SpaceMapper<PicturePixel, RasterPixel>,
     pub map_raster_to_world: SpaceMapper<RasterPixel, WorldPixel>,
-    /// If the plane splitter, the primitives get added to it insted of
+    /// If the plane splitter, the primitives get added to it instead of
     /// batching into their parent pictures.
     pub plane_splitter: Option<PlaneSplitter>,
 }
 
 pub struct PrimitiveContext<'a> {
     pub spatial_node: &'a SpatialNode,
     pub spatial_node_index: SpatialNodeIndex,
 }
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -53,18 +53,20 @@ use util::{ComparableVec, TransformedRec
 /// PictureUpdateState during picture traversal pass.
 struct PictureInfo {
     /// The spatial node for this picture.
     spatial_node_index: SpatialNodeIndex,
 }
 
 /// Stores a list of cached picture tiles that are retained
 /// between new scenes.
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct RetainedTiles {
     /// The tiles retained between display lists.
+    #[cfg_attr(feature = "capture", serde(skip))] //TODO
     pub tiles: Vec<Tile>,
     /// List of reference primitives that we will compare
     /// to try and correlate the positioning of items
     /// between display lists.
     pub ref_prims: FastHashMap<ItemUid, WorldPoint>,
 }
 
 impl RetainedTiles {
@@ -1760,16 +1762,17 @@ impl<'a> PictureUpdateState<'a> {
 
         for (child_pic_index, _) in &picture.prim_list.pictures {
             self.assign_raster_roots(*child_pic_index, picture_primitives, new_fallback);
         }
     }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct SurfaceIndex(pub usize);
 
 pub const ROOT_SURFACE_INDEX: SurfaceIndex = SurfaceIndex(0);
 
 /// Information about an offscreen surface. For now,
 /// it contains information about the size and coordinate
 /// system of the surface. In the future, it will contain
 /// information about the contents of the surface, which
@@ -1833,43 +1836,46 @@ impl SurfaceInfo {
     /// Take the set of child render tasks for this surface. This is
     /// used when constructing the render task tree.
     pub fn take_render_tasks(&mut self) -> Vec<RenderTaskId> {
         mem::replace(&mut self.tasks, Vec::new())
     }
 }
 
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct RasterConfig {
     /// How this picture should be composited into
     /// the parent surface.
     pub composite_mode: PictureCompositeMode,
     /// Index to the surface descriptor for this
     /// picture.
     pub surface_index: SurfaceIndex,
     /// Whether this picture establishes a rasterization root.
     pub establishes_raster_root: bool,
 }
 
 bitflags! {
     /// A set of flags describing why a picture may need a backing surface.
+    #[cfg_attr(feature = "capture", derive(Serialize))]
     pub struct BlitReason: u32 {
         /// Mix-blend-mode on a child that requires isolation.
         const ISOLATE = 1;
         /// Clip node that _might_ require a surface.
         const CLIP = 2;
         /// Preserve-3D requires a surface for plane-splitting.
         const PRESERVE3D = 4;
     }
 }
 
 /// Specifies how this Picture should be composited
 /// onto the target it belongs to.
 #[allow(dead_code)]
 #[derive(Debug, Copy, Clone, PartialEq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum PictureCompositeMode {
     /// Apply CSS mix-blend-mode effect.
     MixBlend(MixBlendMode),
     /// Apply a CSS filter.
     Filter(FilterOp),
     /// Draw to intermediate surface, copy straight across. This
     /// is used for CSS isolation, and plane splitting.
     Blit(BlitReason),
@@ -1887,16 +1893,17 @@ pub enum PictureCompositeMode {
 pub enum PictureSurface {
     RenderTask(RenderTaskId),
     #[allow(dead_code)]
     TextureCache(RenderTaskCacheEntryHandle),
 }
 
 /// Enum value describing the place of a picture in a 3D context.
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum Picture3DContext<C> {
     /// The picture is not a part of 3D context sub-hierarchy.
     Out,
     /// The picture is a part of 3D context.
     In {
         /// Additional data per child for the case of this a root of 3D hierarchy.
         root_data: Option<Vec<C>>,
         /// The spatial node index of an "ancestor" element, i.e. one
@@ -1906,16 +1913,17 @@ pub enum Picture3DContext<C> {
         /// https://drafts.csswg.org/css-transforms-2/#accumulated-3d-transformation-matrix-computation
         ancestor_index: SpatialNodeIndex,
     },
 }
 
 /// Information about a preserve-3D hierarchy child that has been plane-split
 /// and ordered according to the view direction.
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct OrderedPictureChild {
     pub anchor: usize,
     pub spatial_node_index: SpatialNodeIndex,
     pub gpu_address: GpuCacheAddress,
 }
 
 /// Defines the grouping key for a cluster of primitives in a picture.
 /// In future this will also contain spatial grouping details.
@@ -1928,16 +1936,17 @@ struct PrimitiveClusterKey {
     /// We want to separate clusters that have different backface visibility properties
     /// so that we can accept / reject an entire cluster at once if the backface is not
     /// visible.
     is_backface_visible: bool,
 }
 
 /// Descriptor for a cluster of primitives. For now, this is quite basic but will be
 /// extended to handle more spatial clustering of primitives.
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PrimitiveCluster {
     /// The positioning node for this cluster.
     spatial_node_index: SpatialNodeIndex,
     /// Whether this cluster is visible when the position node is a backface.
     is_backface_visible: bool,
     /// The bounding rect of the cluster, in the local space of the spatial node.
     /// This is used to quickly determine the overall bounding rect for a picture
     /// during the first picture traversal, which is needed for local scale
@@ -1962,30 +1971,32 @@ impl PrimitiveCluster {
         }
     }
 }
 
 #[derive(Debug, Copy, Clone)]
 pub struct PrimitiveClusterIndex(pub u32);
 
 #[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ClusterIndex(pub u16);
 
 impl ClusterIndex {
     pub const INVALID: ClusterIndex = ClusterIndex(u16::MAX);
 }
 
 /// A list of pictures, stored by the PrimitiveList to enable a
 /// fast traversal of just the pictures.
 pub type PictureList = SmallVec<[(PictureIndex, ClipChainId); 4]>;
 
 /// A list of primitive instances that are added to a picture
 /// This ensures we can keep a list of primitives that
 /// are pictures, for a fast initial traversal of the picture
 /// tree without walking the instance list.
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PrimitiveList {
     /// The primitive instances, in render order.
     pub prim_instances: Vec<PrimitiveInstance>,
     /// List of pictures that are part of this list.
     /// Used to implement the picture traversal pass.
     pub pictures: PictureList,
     /// List of primitives grouped into clusters.
     pub clusters: SmallVec<[PrimitiveCluster; 4]>,
@@ -2108,34 +2119,37 @@ impl PrimitiveList {
             prim_instances,
             pictures,
             clusters,
         }
     }
 }
 
 /// Defines configuration options for a given picture primitive.
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PictureOptions {
     /// If true, WR should inflate the bounding rect of primitives when
     /// using a filter effect that requires inflation.
     pub inflate_if_required: bool,
 }
 
 impl Default for PictureOptions {
     fn default() -> Self {
         PictureOptions {
             inflate_if_required: true,
         }
     }
 }
 
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PicturePrimitive {
     /// List of primitives, and associated info for this picture.
     pub prim_list: PrimitiveList,
 
+    #[cfg_attr(feature = "capture", serde(skip))]
     pub state: Option<(PictureState, PictureContext)>,
 
     // The pipeline that the primitives on this picture belong to.
     pub pipeline_id: PipelineId,
 
     // If true, apply the local clip rect to primitive drawn
     // in this picture.
     pub apply_local_clip_rect: bool,
@@ -2175,16 +2189,17 @@ pub struct PicturePrimitive {
     pub local_rect: LayoutRect,
 
     /// Local clip rect for this picture.
     pub local_clip_rect: LayoutRect,
 
     pub gpu_location: GpuCacheHandle,
 
     /// If Some(..) the tile cache that is associated with this picture.
+    #[cfg_attr(feature = "capture", serde(skip))] //TODO
     pub tile_cache: Option<TileCache>,
 
     /// The config options for this picture.
     options: PictureOptions,
 }
 
 impl PicturePrimitive {
     pub fn print<T: PrintTreePrinter>(
--- a/gfx/wr/webrender/src/prim_store/image.rs
+++ b/gfx/wr/webrender/src/prim_store/image.rs
@@ -55,16 +55,17 @@ pub struct ImageCacheKey {
 ///     Once we have general picture caching, we don't need this.
 /// (b) Change visible_tiles to use Storage in the primitive
 ///     scratch buffer. This will reduce the size of the
 ///     visible_tiles field here, and save memory allocation
 ///     when image tiling is used. I've left it as a Vec for
 ///     now to reduce the number of changes, and because image
 ///     tiling is very rare on real pages.
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ImageInstance {
     pub opacity_binding_index: OpacityBindingIndex,
     pub segment_instance_index: SegmentInstanceIndex,
     pub visible_tiles: Vec<VisibleImageTile>,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -840,16 +840,17 @@ impl intern::Internable for PrimitiveKey
 
 use intern_types::prim::Handle as PrimitiveDataHandle;
 
 // Maintains a list of opacity bindings that have been collapsed into
 // the color of a single primitive. This is an important optimization
 // that avoids allocating an intermediate surface for most common
 // uses of opacity filters.
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct OpacityBinding {
     pub bindings: Vec<PropertyBinding<f32>>,
     pub current: f32,
 }
 
 impl OpacityBinding {
     pub fn new() -> OpacityBinding {
         OpacityBinding {
@@ -882,16 +883,17 @@ impl OpacityBinding {
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct VisibleMaskImageTile {
     pub tile_offset: TileOffset,
     pub tile_rect: LayoutRect,
 }
 
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct VisibleGradientTile {
     pub handle: GpuCacheHandle,
     pub local_rect: LayoutRect,
     pub local_clip_rect: LayoutRect,
 }
 
 /// Information about how to cache a border segment,
 /// along with the current render task cache entry.
@@ -1296,16 +1298,17 @@ impl CreateShadow for PrimitiveKeyKind {
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveDebugId(pub usize);
 
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum PrimitiveInstanceKind {
     /// Direct reference to a Picture
     Picture {
         /// Handle to the common interned data for this primitive.
         data_handle: PictureDataHandle,
         pic_index: PictureIndex,
     },
     /// A run of glyphs, with associated font parameters.
@@ -1368,16 +1371,17 @@ pub enum PrimitiveInstanceKind {
     /// Clear out a rect, used for special effects.
     Clear {
         /// Handle to the common interned data for this primitive.
         data_handle: PrimitiveDataHandle,
     },
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PrimitiveVisibilityIndex(pub u32);
 
 impl PrimitiveVisibilityIndex {
     pub const INVALID: PrimitiveVisibilityIndex = PrimitiveVisibilityIndex(u32::MAX);
 }
 
 /// Information stored for a visible primitive about the visible
 /// rect and associated clip information.
@@ -1399,16 +1403,17 @@ pub struct PrimitiveVisibility {
     pub clip_task_index: ClipTaskIndex,
 
     /// The current combined local clip for this primitive, from
     /// the primitive local clip above and the current clip chain.
     pub combined_local_clip_rect: LayoutRect,
 }
 
 #[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PrimitiveInstance {
     /// Identifies the kind of primitive this
     /// instance is, and references to where
     /// the relevant information for the primitive
     /// can be found.
     pub kind: PrimitiveInstanceKind,
 
     /// Local space origin of this primitive. The size
@@ -1669,16 +1674,17 @@ impl PrimitiveStoreStats {
             picture_count: 0,
             text_run_count: 0,
             opacity_binding_count: 0,
             image_count: 0,
         }
     }
 }
 
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct PrimitiveStore {
     pub pictures: Vec<PicturePrimitive>,
     pub text_runs: TextRunStorage,
 
     /// A list of image instances. These are stored separately as
     /// storing them inline in the instance makes the structure bigger
     /// for other types.
     pub images: ImageInstanceStorage,
--- a/gfx/wr/webrender/src/prim_store/text_run.rs
+++ b/gfx/wr/webrender/src/prim_store/text_run.rs
@@ -202,16 +202,17 @@ impl CreateShadow for TextRun {
 
 impl IsVisible for TextRun {
     fn is_visible(&self) -> bool {
         self.font.color.a > 0
     }
 }
 
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct TextRunPrimitive {
     pub used_font: FontInstance,
     pub glyph_keys_range: storage::Range<GlyphKey>,
     pub reference_frame_relative_offset: LayoutVector2D,
     pub shadow: bool,
     pub raster_space: RasterizationSpace,
 }
 
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -1630,16 +1630,18 @@ impl RenderBackend {
                 );
                 //TODO: write down doc's pipeline info?
                 // it has `pipeline_epoch_map`,
                 // which may capture necessary details for some cases.
                 let file_name = format!("frame-{}-{}", (id.0).0, id.1);
                 config.serialize(&rendered_document.frame, file_name);
                 let file_name = format!("clip-scroll-{}-{}", (id.0).0, id.1);
                 config.serialize_tree(&doc.clip_scroll_tree, file_name);
+                let file_name = format!("builder-{}-{}", (id.0).0, id.1);
+                config.serialize(doc.frame_builder.as_ref().unwrap(), file_name);
             }
 
             let data_stores_name = format!("data-stores-{}-{}", (id.0).0, id.1);
             config.serialize(&doc.data_stores, data_stores_name);
         }
 
         debug!("\tscene builder");
         self.scene_tx.send(SceneBuilderRequest::SaveScene(config.clone())).unwrap();
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -1103,16 +1103,17 @@ pub struct RenderTaskCacheKey {
 pub struct RenderTaskCacheEntry {
     pending_render_task_id: Option<RenderTaskId>,
     user_data: Option<[f32; 3]>,
     is_opaque: bool,
     pub handle: TextureCacheHandle,
 }
 
 #[derive(Debug, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum RenderTaskCacheMarker {}
 
 // A cache of render tasks that are stored in the texture
 // cache for usage across frames.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTaskCache {
--- a/gfx/wr/webrender/src/storage.rs
+++ b/gfx/wr/webrender/src/storage.rs
@@ -30,16 +30,17 @@ impl<T> Index<T> {
         Index(idx as u32, PhantomData)
     }
 
     pub const INVALID: Index<T> = Index(u32::MAX, PhantomData);
     pub const UNUSED: Index<T> = Index(u32::MAX-1, PhantomData);
 }
 
 #[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct Range<T> {
     pub start: Index<T>,
     pub end: Index<T>,
 }
 
 // We explicitly implement Copy + Clone instead of using #[derive(Copy, Clone)]
 // because we don't want to require that T implements Clone + Copy.
 impl<T> Clone for Range<T> {
@@ -59,16 +60,17 @@ impl<T> Range<T> {
     }
 
     /// Check for an empty `Range`
     pub fn is_empty(&self) -> bool {
         !(self.start.0 < self.end.0)
     }
 }
 
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct Storage<T> {
     data: Vec<T>,
 }
 
 impl<T> Storage<T> {
     pub fn new(initial_capacity: usize) -> Self {
         Storage {
             data: Vec::with_capacity(initial_capacity),
--- a/gfx/wr/webrender/src/util.rs
+++ b/gfx/wr/webrender/src/util.rs
@@ -91,16 +91,17 @@ impl<T> VecHelper<T> for Vec<T> {
 // Represents an optimized transform where there is only
 // a scale and translation (which are guaranteed to maintain
 // an axis align rectangle under transformation). The
 // scaling is applied first, followed by the translation.
 // 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, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct ScaleOffset {
     pub scale: Vector2D<f32>,
     pub offset: Vector2D<f32>,
 }
 
 impl ScaleOffset {
     pub fn identity() -> Self {
         ScaleOffset {