Bug 1526235 - WR draw image tiles as segments r=gw,nical
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Tue, 12 Feb 2019 15:38:12 +0000
changeset 458751 e4db508a2d78
parent 458750 bac61e8bf3a1
child 458752 7f9e50bfaad1
push id35548
push useropoprus@mozilla.com
push dateWed, 13 Feb 2019 09:48:26 +0000
treeherdermozilla-central@93e37c529818 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw, nical
bugs1526235
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 1526235 - WR draw image tiles as segments r=gw,nical We are currently drawing tiles as separate primitives. This doesn't work well for masking out edge AA between tiles, since they aren't aware of each other. The change switches image tiles to be drawn as segments sharing the same header. Differential Revision: https://phabricator.services.mozilla.com/D19458
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/prim_store/image.rs
gfx/wr/webrender/src/prim_store/mod.rs
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -1,33 +1,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntPoint, DeviceIntSize, WorldRect};
 use api::{ExternalImageType, FilterOp, ImageRendering, LayoutRect, DeviceRect, DevicePixelScale};
 use api::{YuvColorSpace, YuvFormat, PictureRect, ColorDepth, LayoutPoint, DevicePoint, LayoutSize};
+use api::{PremultipliedColorF};
 use clip::{ClipDataStore, ClipNodeFlags, ClipNodeRange, ClipItem, ClipStore, ClipNodeInstance};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex, CoordinateSystemId};
 use glyph_rasterizer::GlyphFormat;
-use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
+use gpu_cache::{GpuBlockData, GpuCache, GpuCacheHandle, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance, SnapOffsets};
 use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
 use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
 use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
 use prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex};
 use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
 use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
 use prim_store::image::ImageSource;
 use render_backend::DataStores;
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree, TileBlit};
 use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
-use renderer::BLOCKS_PER_UV_RECT;
+use renderer::{BLOCKS_PER_UV_RECT, MAX_VERTEX_TEXTURE_WIDTH};
 use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
 use scene::FilterOpHelpers;
 use smallvec::SmallVec;
 use std::{f32, i32, usize};
 use tiling::{RenderTargetContext};
 use util::{project_rect, TransformedRectKind};
 
 // Special sentinel value recognized by the shader. It is considered to be
@@ -1748,17 +1749,17 @@ impl AlphaBatchBuilder {
                     prim_info.clip_task_index != ClipTaskIndex::INVALID ||
                     transform_kind == TransformedRectKind::Complex
                 {
                     specified_blend_mode
                 } else {
                     BlendMode::None
                 };
 
-                debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID);
+                debug_assert_ne!(segment_instance_index, SegmentInstanceIndex::INVALID);
                 let (prim_cache_address, segments) = if segment_instance_index == SegmentInstanceIndex::UNUSED {
                     (gpu_cache.get_address(&prim_common_data.gpu_cache_handle), None)
                 } else {
                     let segment_instance = &ctx.scratch.segment_instances[segment_instance_index];
                     let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]);
                     (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
                 };
 
@@ -1802,16 +1803,21 @@ impl AlphaBatchBuilder {
                     AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha,
                     AlphaType::Alpha => BlendMode::Alpha,
                 };
                 let request = ImageRequest {
                     key: image_data.key,
                     rendering: image_data.image_rendering,
                     tile: None,
                 };
+                let prim_user_data = [
+                    ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16),
+                    RasterizationSpace::Local as i32,
+                    get_shader_opacity(opacity_binding),
+                ];
 
                 if image_instance.visible_tiles.is_empty() {
                     let cache_item = match image_data.source {
                         ImageSource::Default => {
                             resolve_image(
                                 request,
                                 ctx.resource_cache,
                                 gpu_cache,
@@ -1844,25 +1850,21 @@ impl AlphaBatchBuilder {
                         specified_blend_mode
                     } else {
                         BlendMode::None
                     };
 
                     let batch_params = BrushBatchParameters::shared(
                         BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
                         textures,
-                        [
-                            ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16),
-                            RasterizationSpace::Local as i32,
-                            get_shader_opacity(opacity_binding),
-                        ],
+                        prim_user_data,
                         cache_item.uv_rect_handle.as_int(gpu_cache),
                     );
 
-                    debug_assert!(image_instance.segment_instance_index != SegmentInstanceIndex::INVALID);
+                    debug_assert_ne!(image_instance.segment_instance_index, SegmentInstanceIndex::INVALID);
                     let (prim_cache_address, segments) = if image_instance.segment_instance_index == SegmentInstanceIndex::UNUSED {
                         (gpu_cache.get_address(&common_data.gpu_cache_handle), None)
                     } else {
                         let segment_instance = &ctx.scratch.segment_instances[image_instance.segment_instance_index];
                         let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]);
                         (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
                     };
 
@@ -1892,47 +1894,72 @@ impl AlphaBatchBuilder {
                         bounding_rect,
                         transform_kind,
                         render_tasks,
                         z_id,
                         prim_info.clip_task_index,
                         ctx,
                     );
                 } else {
-                    for tile in &image_instance.visible_tiles {
-                        if let Some((batch_kind, textures, user_data, uv_rect_address)) = get_image_tile_params(
-                            ctx.resource_cache,
-                            gpu_cache,
-                            deferred_resolves,
-                            request.with_tile(tile.tile_offset),
-                            image_data.alpha_type,
-                            get_shader_opacity(opacity_binding),
-                        ) {
-                            let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
-                            let prim_header = PrimitiveHeader {
-                                specific_prim_address: prim_cache_address,
-                                local_rect: tile.local_rect,
-                                local_clip_rect: tile.local_clip_rect,
-                                task_address,
-                                clip_task_address,
-                                transform_id,
-                            };
-                            let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
+                    const VECS_PER_SPECIFIC_BRUSH: usize = 3;
+                    const VECS_PER_SEGMENT: usize = 2;
+                    let max_tiles_per_header = (MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_SPECIFIC_BRUSH) / VECS_PER_SEGMENT;
+
+                    // use temporary block storage since we don't know the number of visible tiles beforehand
+                    let mut gpu_blocks = Vec::<GpuBlockData>::new();
+                    for chunk in image_instance.visible_tiles.chunks(max_tiles_per_header) {
+                        gpu_blocks.clear();
+                        gpu_blocks.push(PremultipliedColorF::WHITE.into()); //color
+                        gpu_blocks.push(PremultipliedColorF::WHITE.into()); //bg color
+                        gpu_blocks.push([-1.0, 0.0, 0.0, 0.0].into()); //stretch size
+                        // negative first value makes the shader code ignore it and use the local size instead
+                        for tile in chunk {
+                            let tile_rect = tile.local_rect.translate(&-prim_rect.origin.to_vector());
+                            gpu_blocks.push(tile_rect.into());
+                            gpu_blocks.push(GpuBlockData::EMPTY);
+                        }
 
-                            self.add_image_tile_to_batch(
-                                batch_kind,
-                                specified_blend_mode,
-                                textures,
-                                prim_header_index,
-                                clip_task_address,
-                                bounding_rect,
-                                tile.edge_flags,
-                                uv_rect_address,
-                                z_id,
-                            );
+                        let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
+                        let prim_header = PrimitiveHeader {
+                            local_rect: prim_rect,
+                            local_clip_rect: image_instance.tight_local_clip_rect,
+                            task_address,
+                            specific_prim_address: gpu_cache.get_address(&gpu_handle),
+                            clip_task_address,
+                            transform_id,
+                        };
+                        let prim_header_index = prim_headers.push(&prim_header, z_id, prim_user_data);
+
+                        for (i, tile) in chunk.iter().enumerate() {
+                            if let Some((batch_kind, textures, uv_rect_address)) = get_image_tile_params(
+                                ctx.resource_cache,
+                                gpu_cache,
+                                deferred_resolves,
+                                request.with_tile(tile.tile_offset),
+                            ) {
+                                let base_instance = BrushInstance {
+                                    prim_header_index,
+                                    clip_task_address,
+                                    segment_index: i as i32,
+                                    edge_flags: tile.edge_flags,
+                                    brush_flags: BrushFlags::SEGMENT_RELATIVE | BrushFlags::PERSPECTIVE_INTERPOLATION,
+                                    user_data: uv_rect_address.as_int(),
+                                };
+                                let batch_key = BatchKey {
+                                    blend_mode: specified_blend_mode,
+                                    kind: BatchKind::Brush(batch_kind),
+                                    textures,
+                                };
+                                self.current_batch_list().push_single_instance(
+                                    batch_key,
+                                    bounding_rect,
+                                    z_id,
+                                    base_instance.into(),
+                                );
+                            }
                         }
                     }
                 }
             }
             PrimitiveInstanceKind::LinearGradient { data_handle, ref visible_tiles_range, .. } => {
                 let prim_data = &ctx.data_stores.linear_grad[data_handle];
                 let specified_blend_mode = BlendMode::PremultipliedAlpha;
 
@@ -2092,50 +2119,16 @@ impl AlphaBatchBuilder {
                         prim_headers,
                         z_id,
                     );
                 }
             }
         }
     }
 
-    fn add_image_tile_to_batch(
-        &mut self,
-        batch_kind: BrushBatchKind,
-        blend_mode: BlendMode,
-        textures: BatchTextures,
-        prim_header_index: PrimitiveHeaderIndex,
-        clip_task_address: RenderTaskAddress,
-        bounding_rect: &PictureRect,
-        edge_flags: EdgeAaSegmentMask,
-        uv_rect_address: GpuCacheAddress,
-        z_id: ZBufferId,
-    ) {
-        let base_instance = BrushInstance {
-            prim_header_index,
-            clip_task_address,
-            segment_index: INVALID_SEGMENT_INDEX,
-            edge_flags,
-            brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
-            user_data: uv_rect_address.as_int(),
-        };
-
-        let batch_key = BatchKey {
-            blend_mode,
-            kind: BatchKind::Brush(batch_kind),
-            textures,
-        };
-        self.current_batch_list().push_single_instance(
-            batch_key,
-            bounding_rect,
-            z_id,
-            PrimitiveInstanceData::from(base_instance),
-        );
-    }
-
     /// Add a single segment instance to a batch.
     fn add_segment_to_batch(
         &mut self,
         segment: &BrushSegment,
         segment_data: &SegmentInstanceData,
         segment_index: i32,
         batch_kind: BrushBatchKind,
         prim_header_index: PrimitiveHeaderIndex,
@@ -2338,39 +2331,32 @@ fn add_gradient_tiles(
     }
 }
 
 fn get_image_tile_params(
     resource_cache: &ResourceCache,
     gpu_cache: &mut GpuCache,
     deferred_resolves: &mut Vec<DeferredResolve>,
     request: ImageRequest,
-    alpha_type: AlphaType,
-    shader_opacity: i32,
-) -> Option<(BrushBatchKind, BatchTextures, [i32; 3], GpuCacheAddress)> {
+) -> Option<(BrushBatchKind, BatchTextures, GpuCacheAddress)> {
 
     let cache_item = resolve_image(
         request,
         resource_cache,
         gpu_cache,
         deferred_resolves,
     );
 
     if cache_item.texture_id == TextureSource::Invalid {
         None
     } else {
         let textures = BatchTextures::color(cache_item.texture_id);
         Some((
             BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
             textures,
-            [
-                ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16),
-                RasterizationSpace::Local as i32,
-                shader_opacity,
-            ],
             gpu_cache.get_address(&cache_item.uv_rect_handle),
         ))
     }
 }
 
 /// Either a single texture / user data for all segments,
 /// or a list of one per segment.
 enum SegmentDataKind {
--- a/gfx/wr/webrender/src/prim_store/image.rs
+++ b/gfx/wr/webrender/src/prim_store/image.rs
@@ -58,16 +58,17 @@ pub struct ImageCacheKey {
 ///     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 tight_local_clip_rect: LayoutRect,
     pub visible_tiles: Vec<VisibleImageTile>,
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, Eq, PartialEq, MallocSizeOf, Hash)]
 pub struct Image {
     pub key: ApiImageKey,
@@ -109,16 +110,17 @@ impl AsInstanceKind<ImageDataHandle> for
         prim_store: &mut PrimitiveStore,
         _reference_frame_relative_offset: LayoutVector2D,
     ) -> PrimitiveInstanceKind {
         // TODO(gw): Refactor this to not need a separate image
         //           instance (see ImageInstance struct).
         let image_instance_index = prim_store.images.push(ImageInstance {
             opacity_binding_index: OpacityBindingIndex::INVALID,
             segment_instance_index: SegmentInstanceIndex::INVALID,
+            tight_local_clip_rect: LayoutRect::zero(),
             visible_tiles: Vec::new(),
         });
 
         PrimitiveInstanceKind::Image {
             data_handle,
             image_instance_index,
         }
     }
@@ -306,16 +308,17 @@ impl ImageData {
                 }
             }
         };
     }
 
     pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) {
         // Images are drawn as a white color, modulated by the total
         // opacity coming from any collapsed property bindings.
+        // Size has to match `VECS_PER_SPECIFIC_BRUSH` from `brush_image.glsl` exactly.
         request.push(self.color.premultiplied());
         request.push(PremultipliedColorF::WHITE);
         request.push([
             self.stretch_size.width + self.tile_spacing.width,
             self.stretch_size.height + self.tile_spacing.height,
             0.0,
             0.0,
         ]);
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -2660,92 +2660,87 @@ impl PrimitiveStore {
                 );
 
                 image_instance.visible_tiles.clear();
 
                 let image_properties = frame_state
                     .resource_cache
                     .get_image_properties(image_data.key);
 
-                if let Some(image_properties) = image_properties {
-                    if let Some(tile_size) = image_properties.tiling {
-                        let device_image_size = image_properties.descriptor.size;
-
-                        // Tighten the clip rect because decomposing the repeated image can
-                        // produce primitives that are partially covering the original image
-                        // rect and we want to clip these extra parts out.
-                        let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
-                        let prim_rect = LayoutRect::new(
-                            prim_instance.prim_origin,
-                            common_data.prim_size,
-                        );
-                        let tight_clip_rect = prim_info
-                            .combined_local_clip_rect
-                            .intersection(&prim_rect).unwrap();
-
-                        let visible_rect = compute_conservative_visible_rect(
-                            prim_context,
-                            &frame_state.current_dirty_region().combined.world_rect,
-                            &tight_clip_rect
-                        );
-
-                        let base_edge_flags = edge_flags_for_tile_spacing(&image_data.tile_spacing);
-
-                        let stride = image_data.stretch_size + image_data.tile_spacing;
-
-                        let repetitions = ::image::repetitions(
-                            &prim_rect,
-                            &visible_rect,
-                            stride,
-                        );
-
-                        let request = ImageRequest {
-                            key: image_data.key,
-                            rendering: image_data.image_rendering,
-                            tile: None,
+                if let Some(ImageProperties { descriptor, tiling: Some(tile_size), .. }) = image_properties {
+                    let device_image_size = descriptor.size;
+
+                    // Tighten the clip rect because decomposing the repeated image can
+                    // produce primitives that are partially covering the original image
+                    // rect and we want to clip these extra parts out.
+                    let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
+                    let prim_rect = LayoutRect::new(
+                        prim_instance.prim_origin,
+                        common_data.prim_size,
+                    );
+                    let tight_clip_rect = prim_info
+                        .combined_local_clip_rect
+                        .intersection(&prim_rect).unwrap();
+                    image_instance.tight_local_clip_rect = tight_clip_rect;
+
+                    let visible_rect = compute_conservative_visible_rect(
+                        prim_context,
+                        &frame_state.current_dirty_region().combined.world_rect,
+                        &tight_clip_rect
+                    );
+
+                    let base_edge_flags = edge_flags_for_tile_spacing(&image_data.tile_spacing);
+
+                    let stride = image_data.stretch_size + image_data.tile_spacing;
+
+                    let repetitions = ::image::repetitions(
+                        &prim_rect,
+                        &visible_rect,
+                        stride,
+                    );
+
+                    let request = ImageRequest {
+                        key: image_data.key,
+                        rendering: image_data.image_rendering,
+                        tile: None,
+                    };
+
+                    for Repetition { origin, edge_flags } in repetitions {
+                        let edge_flags = base_edge_flags | edge_flags;
+
+                        let image_rect = LayoutRect {
+                            origin,
+                            size: image_data.stretch_size,
                         };
 
-                        for Repetition { origin, edge_flags } in repetitions {
-                            let edge_flags = base_edge_flags | edge_flags;
-
-                            let image_rect = LayoutRect {
-                                origin,
-                                size: image_data.stretch_size,
-                            };
-
-                            let tiles = ::image::tiles(
-                                &image_rect,
-                                &visible_rect,
-                                &device_image_size,
-                                tile_size as i32,
+                        let tiles = ::image::tiles(
+                            &image_rect,
+                            &visible_rect,
+                            &device_image_size,
+                            tile_size as i32,
+                        );
+
+                        for tile in tiles {
+                            frame_state.resource_cache.request_image(
+                                request.with_tile(tile.offset),
+                                frame_state.gpu_cache,
                             );
 
-                            for tile in tiles {
-                                frame_state.resource_cache.request_image(
-                                    request.with_tile(tile.offset),
-                                    frame_state.gpu_cache,
-                                );
-
-                                image_instance.visible_tiles.push(VisibleImageTile {
-                                    tile_offset: tile.offset,
-                                    edge_flags: tile.edge_flags & edge_flags,
-                                    local_rect: tile.rect,
-                                    local_clip_rect: tight_clip_rect,
-                                });
-                            }
+                            image_instance.visible_tiles.push(VisibleImageTile {
+                                tile_offset: tile.offset,
+                                edge_flags: tile.edge_flags & edge_flags,
+                                local_rect: tile.rect,
+                                local_clip_rect: tight_clip_rect,
+                            });
                         }
-
-                        if image_instance.visible_tiles.is_empty() {
-                            // At this point if we don't have tiles to show it means we could probably
-                            // have done a better a job at culling during an earlier stage.
-                            // Clearing the screen rect has the effect of "culling out" the primitive
-                            // from the point of view of the batch builder, and ensures we don't hit
-                            // assertions later on because we didn't request any image.
-                            prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
-                        }
+                    }
+
+                    if image_instance.visible_tiles.is_empty() {
+                        // Mark as invisible
+                        prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
                     }
                 }
 
                 write_segment(image_instance.segment_instance_index, frame_state, scratch, |request| {
                     image_data.write_prim_gpu_blocks(request);
                 });
             }
             PrimitiveInstanceKind::LinearGradient { data_handle, ref mut visible_tiles_range, .. } => {
@@ -2848,17 +2843,17 @@ impl PrimitiveStore {
 }
 
 fn write_segment<F>(
     segment_instance_index: SegmentInstanceIndex,
     frame_state: &mut FrameBuildingState,
     scratch: &mut PrimitiveScratchBuffer,
     f: F,
 ) where F: Fn(&mut GpuDataRequest) {
-    debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID);
+    debug_assert_ne!(segment_instance_index, SegmentInstanceIndex::INVALID);
     if segment_instance_index != SegmentInstanceIndex::UNUSED {
         let segment_instance = &mut scratch.segment_instances[segment_instance_index];
 
         if let Some(mut request) = frame_state.gpu_cache.request(&mut segment_instance.gpu_cache_handle) {
             let segments = &scratch.segments[segment_instance.segments_range];
 
             f(&mut request);
 
@@ -3120,25 +3115,27 @@ impl PrimitiveInstance {
         let segment_instance_index = match self.kind {
             PrimitiveInstanceKind::Rectangle { ref mut segment_instance_index, .. } |
             PrimitiveInstanceKind::YuvImage { ref mut segment_instance_index, .. } => {
                 segment_instance_index
             }
             PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => {
                 let image_data = &data_stores.image[data_handle].kind;
                 let image_instance = &mut prim_store.images[image_instance_index];
-                // tiled images don't support segmentation
+                //Note: tiled images don't support automatic segmentation,
+                // they strictly produce one segment per visible tile instead.
                 if frame_state
                     .resource_cache
                     .get_image_properties(image_data.key)
                     .and_then(|properties| properties.tiling)
-                    .is_some() {
-                        image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED;
-                        return;
-                    }
+                    .is_some()
+                {
+                    image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED;
+                    return;
+                }
                 &mut image_instance.segment_instance_index
             }
             PrimitiveInstanceKind::Picture { .. } |
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::Clear { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
@@ -3158,17 +3155,17 @@ impl PrimitiveInstance {
                 prim_clip_chain,
                 &mut frame_state.segment_builder,
                 frame_state.clip_store,
                 data_stores,
             ) {
                 frame_state.segment_builder.build(|segment| {
                     segments.push(
                         BrushSegment::new(
-                            segment.rect.translate(&LayoutVector2D::new(-prim_local_rect.origin.x, -prim_local_rect.origin.y)),
+                            segment.rect.translate(&-prim_local_rect.origin.to_vector()),
                             segment.has_mask,
                             segment.edge_flags,
                             [0.0; 4],
                             BrushFlags::PERSPECTIVE_INTERPOLATION,
                         ),
                     );
                 });
             }