mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 08:13:35 +00:00
Bug 1642308 - Fix some snapping related picture cache tile rect calculations. r=gw
Our fract offset for the tiles should be a simple mapping of the snapped device position back to picture space. If no snapping is required, then the position will be precisely the origin. When using this value to decide if the position has changed for glyph subpixel offset purposes, we must consider it in device space, since picture to device space can be effectively arbitrary. We update the stored fract offset at which a tile was rendered whenever we invalidate the whole tile, not just when we detect the fract offset has changed by a notable amount. This should reduce spurious invalidations since the tile was actually rendered at a different offset that we had recorded prior to this patch. Also, when evaluating the tile's valid rect, we cannot use the local valid rect. The device valid rect we use is the local mapped from picture space, but also snapped. Thus it makes far more sense to compare that which we used for drawing purposes which has the bonus of avoiding floating point errors. Differential Revision: https://phabricator.services.mozilla.com/D91156
This commit is contained in:
parent
0eb1b28da9
commit
45dd1ce875
@ -521,6 +521,7 @@ struct TilePreUpdateContext {
|
||||
/// The fractional position of the picture cache, which may
|
||||
/// require invalidation of all tiles.
|
||||
fract_offset: PictureVector2D,
|
||||
device_fract_offset: DeviceVector2D,
|
||||
|
||||
/// The optional background color of the picture cache instance
|
||||
background_color: Option<ColorF>,
|
||||
@ -824,8 +825,8 @@ pub enum PrimitiveCompareResultDetail {
|
||||
pub enum InvalidationReason {
|
||||
/// The fractional offset changed
|
||||
FractionalOffset {
|
||||
old: PictureVector2D,
|
||||
new: PictureVector2D,
|
||||
old: DeviceVector2D,
|
||||
new: DeviceVector2D,
|
||||
},
|
||||
/// The background color changed
|
||||
BackgroundColor {
|
||||
@ -863,7 +864,7 @@ pub enum InvalidationReason {
|
||||
pub struct TileSerializer {
|
||||
pub rect: PictureRect,
|
||||
pub current_descriptor: TileDescriptor,
|
||||
pub fract_offset: PictureVector2D,
|
||||
pub device_fract_offset: DeviceVector2D,
|
||||
pub id: TileId,
|
||||
pub root: TileNode,
|
||||
pub background_color: Option<ColorF>,
|
||||
@ -898,6 +899,9 @@ pub struct Tile {
|
||||
pub device_dirty_rect: DeviceRect,
|
||||
/// Device space rect that contains valid pixels region of this tile.
|
||||
pub device_valid_rect: DeviceRect,
|
||||
/// Device space rect that contains valid pixels region of this tile
|
||||
/// from the previous frame.
|
||||
pub prev_device_valid_rect: DeviceRect,
|
||||
/// Uniquely describes the content of this tile, in a way that can be
|
||||
/// (reasonably) efficiently hashed and compared.
|
||||
pub current_descriptor: TileDescriptor,
|
||||
@ -915,7 +919,7 @@ pub struct Tile {
|
||||
/// The current fractional offset of the cache transform root. If this changes,
|
||||
/// all tiles need to be invalidated and redrawn, since snapping differences are
|
||||
/// likely to occur.
|
||||
fract_offset: PictureVector2D,
|
||||
device_fract_offset: DeviceVector2D,
|
||||
/// The tile id is stable between display lists and / or frames,
|
||||
/// if the tile is retained. Useful for debugging tile evictions.
|
||||
pub id: TileId,
|
||||
@ -954,6 +958,7 @@ impl Tile {
|
||||
local_tile_box: PictureBox2D::zero(),
|
||||
world_tile_rect: WorldRect::zero(),
|
||||
device_valid_rect: DeviceRect::zero(),
|
||||
prev_device_valid_rect: DeviceRect::zero(),
|
||||
local_dirty_rect: PictureRect::zero(),
|
||||
device_dirty_rect: DeviceRect::zero(),
|
||||
surface: None,
|
||||
@ -961,7 +966,7 @@ impl Tile {
|
||||
prev_descriptor: TileDescriptor::new(),
|
||||
is_valid: false,
|
||||
is_visible: false,
|
||||
fract_offset: PictureVector2D::zero(),
|
||||
device_fract_offset: DeviceVector2D::zero(),
|
||||
id,
|
||||
is_opaque: false,
|
||||
root: TileNode::new_leaf(Vec::new()),
|
||||
@ -979,7 +984,7 @@ impl Tile {
|
||||
fn print(&self, pt: &mut dyn PrintTreePrinter) {
|
||||
pt.new_level(format!("Tile {:?}", self.id));
|
||||
pt.add_item(format!("local_tile_rect: {:?}", self.local_tile_rect));
|
||||
pt.add_item(format!("fract_offset: {:?}", self.fract_offset));
|
||||
pt.add_item(format!("device_fract_offset: {:?}", self.device_fract_offset));
|
||||
pt.add_item(format!("background_color: {:?}", self.background_color));
|
||||
pt.add_item(format!("invalidation_reason: {:?}", self.invalidation_reason));
|
||||
self.current_descriptor.print(pt);
|
||||
@ -1045,7 +1050,7 @@ impl Tile {
|
||||
}
|
||||
// TODO(gw): We can avoid invalidating the whole tile in some cases here,
|
||||
// but it should be a fairly rare invalidation case.
|
||||
if self.current_descriptor.local_valid_rect != self.prev_descriptor.local_valid_rect {
|
||||
if self.device_valid_rect != self.prev_device_valid_rect {
|
||||
self.invalidate(None, InvalidationReason::ValidRectChanged);
|
||||
state.composite_state.dirty_rects_are_valid = false;
|
||||
}
|
||||
@ -1113,15 +1118,16 @@ impl Tile {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if the fractional offset of the transform is different this frame
|
||||
// from the currently cached tile set.
|
||||
let fract_changed = (self.fract_offset.x - ctx.fract_offset.x).abs() > 0.01 ||
|
||||
(self.fract_offset.y - ctx.fract_offset.y).abs() > 0.01;
|
||||
// We may need to rerender if glyph subpixel positions have changed. Note
|
||||
// that we update the tile fract offset itself after we have completed
|
||||
// invalidation. This allows for other whole tile invalidation cases to
|
||||
// update the fract offset appropriately.
|
||||
let fract_delta = self.device_fract_offset - ctx.device_fract_offset;
|
||||
let fract_changed = fract_delta.x.abs() > 0.01 || fract_delta.y.abs() > 0.01;
|
||||
if fract_changed {
|
||||
self.invalidate(None, InvalidationReason::FractionalOffset {
|
||||
old: self.fract_offset,
|
||||
new: ctx.fract_offset });
|
||||
self.fract_offset = ctx.fract_offset;
|
||||
old: self.device_fract_offset,
|
||||
new: ctx.device_fract_offset });
|
||||
}
|
||||
|
||||
if ctx.background_color != self.background_color {
|
||||
@ -1137,6 +1143,7 @@ impl Tile {
|
||||
&mut self.current_descriptor,
|
||||
&mut self.prev_descriptor,
|
||||
);
|
||||
self.prev_device_valid_rect = self.device_valid_rect;
|
||||
self.current_descriptor.clear();
|
||||
self.root.clear(self.local_tile_rect.to_box2d());
|
||||
|
||||
@ -2324,6 +2331,8 @@ pub struct TileCacheInstance {
|
||||
frames_until_size_eval: usize,
|
||||
/// The current fractional offset of the cached picture
|
||||
fract_offset: PictureVector2D,
|
||||
/// The current device fractional offset of the cached picture
|
||||
device_fract_offset: DeviceVector2D,
|
||||
/// For DirectComposition, virtual surfaces don't support negative coordinates. However,
|
||||
/// picture cache tile coordinates can be negative. To handle this, we apply an offset
|
||||
/// to each tile in DirectComposition. We want to change this as little as possible,
|
||||
@ -2399,6 +2408,7 @@ impl TileCacheInstance {
|
||||
current_tile_size: DeviceIntSize::zero(),
|
||||
frames_until_size_eval: 0,
|
||||
fract_offset: PictureVector2D::zero(),
|
||||
device_fract_offset: DeviceVector2D::zero(),
|
||||
// Default to centering the virtual offset in the middle of the DC virtual surface
|
||||
virtual_offset: DeviceIntPoint::new(
|
||||
params.virtual_surface_size / 2,
|
||||
@ -2648,6 +2658,7 @@ impl TileCacheInstance {
|
||||
let device_origin = world_origin * frame_context.global_device_pixel_scale;
|
||||
let desired_device_origin = device_origin.round();
|
||||
self.device_position = desired_device_origin;
|
||||
self.device_fract_offset = desired_device_origin - device_origin;
|
||||
|
||||
// Unmap from device space to world space rect
|
||||
let ref_world_rect = WorldRect::new(
|
||||
@ -2655,17 +2666,13 @@ impl TileCacheInstance {
|
||||
WorldSize::new(1.0, 1.0),
|
||||
);
|
||||
|
||||
// Unmap from world space to picture space
|
||||
let ref_point = pic_to_world_mapper
|
||||
// Unmap from world space to picture space; this should be the fractional offset
|
||||
// required in picture space to align in device space
|
||||
self.fract_offset = pic_to_world_mapper
|
||||
.unmap(&ref_world_rect)
|
||||
.expect("bug: unable to unmap ref world rect")
|
||||
.origin;
|
||||
|
||||
// Extract the fractional offset required in picture space to align in device space
|
||||
self.fract_offset = PictureVector2D::new(
|
||||
ref_point.x.fract(),
|
||||
ref_point.y.fract(),
|
||||
);
|
||||
.origin
|
||||
.to_vector();
|
||||
|
||||
// Do a hacky diff of opacity binding values from the last frame. This is
|
||||
// used later on during tile invalidation tests.
|
||||
@ -2841,6 +2848,7 @@ impl TileCacheInstance {
|
||||
let ctx = TilePreUpdateContext {
|
||||
pic_to_world_mapper,
|
||||
fract_offset: self.fract_offset,
|
||||
device_fract_offset: self.device_fract_offset,
|
||||
background_color: self.background_color,
|
||||
global_screen_world_rect: frame_context.global_screen_world_rect,
|
||||
tile_size: self.tile_size,
|
||||
@ -5442,6 +5450,12 @@ impl PicturePrimitive {
|
||||
}
|
||||
}
|
||||
|
||||
// If the entire tile valid region is dirty, we can update the fract offset
|
||||
// at which the tile was rendered.
|
||||
if tile.device_dirty_rect.contains_rect(&tile.device_valid_rect) {
|
||||
tile.device_fract_offset = tile_cache.device_fract_offset;
|
||||
}
|
||||
|
||||
// Now that the tile is valid, reset the dirty rect.
|
||||
tile.local_dirty_rect = PictureRect::zero();
|
||||
tile.is_valid = true;
|
||||
@ -5567,7 +5581,7 @@ impl PicturePrimitive {
|
||||
tile_cache_tiny.tiles.insert(*key, TileSerializer {
|
||||
rect: tile.local_tile_rect,
|
||||
current_descriptor: tile.current_descriptor.clone(),
|
||||
fract_offset: tile.fract_offset,
|
||||
device_fract_offset: tile.device_fract_offset,
|
||||
id: tile.id,
|
||||
root: tile.root.clone(),
|
||||
background_color: tile.background_color,
|
||||
|
Loading…
Reference in New Issue
Block a user