Bug 1512010 - snap text positions without device transform in local raster space. r=gw a=lizzard
authorLee Salzman <lsalzman@mozilla.com>
Mon, 28 Jan 2019 22:23:00 -0500
changeset 515713 25a0bd49c1830ac23b3f89b5ccaee4c6009dbb51
parent 515712 7f01068468106a06e36f0027de87d69d1950238b
child 515714 af516292be1c1634c69c9cddb9b5ba69bc8d6867
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw, lizzard
bugs1512010
milestone66.0
Bug 1512010 - snap text positions without device transform in local raster space. r=gw a=lizzard
gfx/wr/webrender/res/ps_text_run.glsl
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/prim_store/text_run.rs
--- a/gfx/wr/webrender/res/ps_text_run.glsl
+++ b/gfx/wr/webrender/res/ps_text_run.glsl
@@ -57,16 +57,17 @@ struct TextRun {
 
 TextRun fetch_text_run(int address) {
     vec4 data[2] = fetch_from_gpu_cache_2(address);
     return TextRun(data[0], data[1]);
 }
 
 VertexInfo write_text_vertex(RectWithSize local_clip_rect,
                              float z,
+                             int raster_space,
                              Transform transform,
                              PictureTask task,
                              vec2 text_offset,
                              vec2 glyph_offset,
                              RectWithSize glyph_rect,
                              vec2 snap_bias) {
     // The offset to snap the glyph rect to a device pixel
     vec2 snap_offset = vec2(0.0);
@@ -74,38 +75,46 @@ VertexInfo write_text_vertex(RectWithSiz
 
 #ifdef WR_FEATURE_GLYPH_TRANSFORM
     bool remove_subpx_offset = true;
 #else
     bool remove_subpx_offset = transform.is_axis_aligned;
 #endif
     // Compute the snapping offset only if the scroll node transform is axis-aligned.
     if (remove_subpx_offset) {
-        // Transform from local space to device space.
-        float device_scale = task.common_data.device_pixel_scale / transform.m[3].w;
-        mat2 device_transform = mat2(transform.m) * device_scale;
+        // Be careful to only snap with the transform when in screen raster space.
+        if (raster_space == RASTER_SCREEN) {
+            // Transform from local space to device space.
+            float device_scale = task.common_data.device_pixel_scale / transform.m[3].w;
+            mat2 device_transform = mat2(transform.m) * device_scale;
 
-        // Ensure the transformed text offset does not contain a subpixel translation
-        // such that glyph snapping is stable for equivalent glyph subpixel positions.
-        vec2 device_text_pos = device_transform * text_offset + transform.m[3].xy * device_scale;
-        snap_offset = floor(device_text_pos + 0.5) - device_text_pos;
+            // Ensure the transformed text offset does not contain a subpixel translation
+            // such that glyph snapping is stable for equivalent glyph subpixel positions.
+            vec2 device_text_pos = device_transform * text_offset + transform.m[3].xy * device_scale;
+            snap_offset = floor(device_text_pos + 0.5) - device_text_pos;
 
-        // Snap the glyph offset to a device pixel, using an appropriate bias depending
-        // on whether subpixel positioning is required.
-        vec2 device_glyph_offset = device_transform * glyph_offset;
-        snap_offset += floor(device_glyph_offset + snap_bias) - device_glyph_offset;
+            // Snap the glyph offset to a device pixel, using an appropriate bias depending
+            // on whether subpixel positioning is required.
+            vec2 device_glyph_offset = device_transform * glyph_offset;
+            snap_offset += floor(device_glyph_offset + snap_bias) - device_glyph_offset;
 
-        // Transform from device space back to local space.
-        local_transform = inverse(device_transform);
+            // Transform from device space back to local space.
+            local_transform = inverse(device_transform);
 
 #ifndef WR_FEATURE_GLYPH_TRANSFORM
-        // If not using transformed subpixels, the glyph rect is actually in local space.
-        // So convert the snap offset back to local space.
-        snap_offset = local_transform * snap_offset;
+            // If not using transformed subpixels, the glyph rect is actually in local space.
+            // So convert the snap offset back to local space.
+            snap_offset = local_transform * snap_offset;
 #endif
+        } else {
+            // Otherwise, when in local raster space, the transform may be animated, so avoid
+            // snapping with the transform to avoid oscillation.
+            snap_offset = floor(text_offset + 0.5) - text_offset;
+            snap_offset += floor(glyph_offset + snap_bias) - glyph_offset;
+        }
     }
 
     // Actually translate the glyph rect to a device pixel using the snap offset.
     glyph_rect.p0 += snap_offset;
 
 #ifdef WR_FEATURE_GLYPH_TRANSFORM
     // The glyph rect is in device space, so transform it back to local space.
     RectWithSize local_rect = transform_rect(glyph_rect, local_transform);
@@ -148,16 +157,17 @@ VertexInfo write_text_vertex(RectWithSiz
 void main(void) {
     int prim_header_address = aData.x;
     int glyph_index = aData.y;
     int resource_address = aData.z;
     int subpx_dir = aData.w >> 16;
     int color_mode = aData.w & 0xffff;
 
     PrimitiveHeader ph = fetch_prim_header(prim_header_address);
+    int raster_space = ph.user_data.z;
 
     Transform transform = fetch_transform(ph.transform_id);
     ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
     PictureTask task = fetch_picture_task(ph.render_task_index);
 
     TextRun text = fetch_text_run(ph.specific_prim_address);
     vec2 text_offset = vec2(ph.user_data.xy) / 256.0;
 
@@ -172,17 +182,16 @@ void main(void) {
 
 #ifdef WR_FEATURE_GLYPH_TRANSFORM
     // Transform from local space to glyph space.
     mat2 glyph_transform = mat2(transform.m) * task.common_data.device_pixel_scale;
 
     // Compute the glyph rect in glyph space.
     RectWithSize glyph_rect = RectWithSize(res.offset + glyph_transform * (text_offset + glyph.offset),
                                            res.uv_rect.zw - res.uv_rect.xy);
-
 #else
     // Scale from glyph space to local space.
     float scale = res.scale / task.common_data.device_pixel_scale;
 
     // Compute the glyph rect in local space.
     RectWithSize glyph_rect = RectWithSize(scale * res.offset + text_offset + glyph.offset,
                                            scale * (res.uv_rect.zw - res.uv_rect.xy));
 #endif
@@ -209,16 +218,17 @@ void main(void) {
             break;
         case SUBPX_DIR_MIXED:
             snap_bias = vec2(0.125);
             break;
     }
 
     VertexInfo vi = write_text_vertex(ph.local_clip_rect,
                                       ph.z,
+                                      raster_space,
                                       transform,
                                       task,
                                       text_offset,
                                       glyph.offset,
                                       glyph_rect,
                                       snap_bias);
     glyph_rect.p0 += vi.snap_offset;
 
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -845,17 +845,17 @@ impl AlphaBatchBuilder {
                         };
 
                         let prim_header_index = prim_headers.push(
                             &prim_header,
                             z_id,
                             [
                                 (run.reference_frame_relative_offset.x * 256.0) as i32,
                                 (run.reference_frame_relative_offset.y * 256.0) as i32,
-                                0,
+                                run.raster_space as i32,
                             ],
                         );
                         let key = BatchKey::new(kind, blend_mode, textures);
                         let base_instance = GlyphInstance::new(
                             prim_header_index,
                         );
                         let batch = alpha_batch_list.set_params_and_get_batch(
                             key,
--- a/gfx/wr/webrender/src/prim_store/text_run.rs
+++ b/gfx/wr/webrender/src/prim_store/text_run.rs
@@ -4,16 +4,17 @@
 
 use api::{ColorF, DevicePixelScale, GlyphInstance, LayoutPrimitiveInfo};
 use api::{LayoutToWorldTransform, RasterSpace};
 use api::{LayoutVector2D, Shadow};
 use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
 use frame_builder::{FrameBuildingState, PictureContext};
 use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
 use gpu_cache::GpuCache;
+use gpu_types::RasterizationSpace;
 use intern;
 use intern_types;
 use prim_store::{PrimitiveOpacity, PrimitiveSceneData,  PrimitiveScratchBuffer};
 use prim_store::{PrimitiveStore, PrimKeyCommonData, PrimTemplateCommonData};
 use render_task::{RenderTaskTree};
 use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
 use resource_cache::{ResourceCache};
 use util::{MatrixHelpers};
@@ -59,18 +60,19 @@ impl AsInstanceKind<TextRunDataHandle> f
         &self,
         data_handle: TextRunDataHandle,
         prim_store: &mut PrimitiveStore,
         reference_frame_relative_offset: LayoutVector2D,
     ) -> PrimitiveInstanceKind {
         let run_index = prim_store.text_runs.push(TextRunPrimitive {
             used_font: self.font.clone(),
             glyph_keys_range: storage::Range::empty(),
+            reference_frame_relative_offset,
             shadow: self.shadow,
-            reference_frame_relative_offset,
+            raster_space: RasterizationSpace::Screen,
         });
 
         PrimitiveInstanceKind::TextRun{ data_handle, run_index }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -205,16 +207,17 @@ impl IsVisible for TextRun {
 }
 
 #[derive(Debug)]
 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,
 }
 
 impl TextRunPrimitive {
     pub fn update_font_instance(
         &mut self,
         specified_font: &FontInstance,
         device_pixel_scale: DevicePixelScale,
         transform: &LayoutToWorldTransform,
@@ -240,16 +243,23 @@ impl TextRunPrimitive {
         // Get the font transform matrix (skew / scale) from the complete transform.
         let font_transform = if transform_glyphs {
             // Quantize the transform to minimize thrashing of the glyph cache.
             FontTransform::from(transform).quantize()
         } else {
             FontTransform::identity()
         };
 
+        // Record the raster space the text needs to be snapped in.
+        self.raster_space = if raster_space == RasterSpace::Screen {
+            RasterizationSpace::Screen
+        } else {
+            RasterizationSpace::Local
+        };
+
         // If the transform or device size is different, then the caller of
         // this method needs to know to rebuild the glyphs.
         let cache_dirty =
             self.used_font.transform != font_transform ||
             self.used_font.size != device_font_size;
 
         // Construct used font instance from the specified font instance
         self.used_font = FontInstance {