New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce the DirtyRect type #3277

Merged
merged 6 commits into from Nov 23, 2018

Introduce the DirtyRect type.

Previously dirty rects were set up in a subtle way where early in the
pipeline None is used to mean "no information" and therefore "all clean",
but then later on is used to mean "all dirty" on the assumption that if
a texture is still being handled, some dirty information must have been
sent. None is therefore used by the internals as a way to signal
things like missing cache entries without actually bothering to look up
the dimensions of the image (note that "clean" can always be expressed
without knowing dimensions, as it is always the same empty rect).

I change the system to just consistently use a custom enum that has
AllDirty and SomeDirty(empty_rect) to represent these two states. As
a result the code seems much easier to understand.
  • Loading branch information...
nical committed Nov 5, 2018
commit 108fc446b033485b4d2937908f2eb8120db3dc30
Copy path View file
@@ -135,7 +135,7 @@ impl api::BlobImageHandler for CheckerboardRenderer {
.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
}
fn update(&mut self, key: api::ImageKey, cmds: Arc<api::BlobImageData>, _dirty_rect: Option<api::DeviceIntRect>) {
fn update(&mut self, key: api::ImageKey, cmds: Arc<api::BlobImageData>, _dirty_rect: &api::DirtyRect) {
// Here, updating is just replacing the current version of the commands with
// the new one (no incremental updates).
self.image_cmds
Copy path View file
@@ -105,7 +105,7 @@ impl Example for App {
self.image_key,
ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true, false),
ImageData::new(image_data),
None,
&DirtyRect::AllDirty,
);
let mut txn = Transaction::new();
txn.generate_frame();
@@ -243,7 +243,7 @@ impl Example for App {
image_key,
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
ImageData::new(self.image_generator.take()),
None,
&DirtyRect::AllDirty,
);
},
winit::VirtualKeyCode::E => {
@@ -5,7 +5,7 @@
//! Module only available when pathfinder is deactivated when webrender is
//! compiled regularly (i.e. any configuration without feature = "pathfinder")
use api::{ImageData, ImageDescriptor, ImageFormat};
use api::{ImageData, ImageDescriptor, ImageFormat, DirtyRect};
use device::TextureFilter;
use euclid::size2;
use gpu_types::UvRectKind;
@@ -184,7 +184,7 @@ impl GlyphRasterizer {
TextureFilter::Linear,
Some(ImageData::Raw(Arc::new(glyph.bytes))),
[glyph.left, -glyph.top, glyph.scale],
None,
DirtyRect::AllDirty,
gpu_cache,
Some(glyph_key_cache.eviction_notice()),
UvRectKind::Rect,
Copy path View file
@@ -205,4 +205,3 @@ pub use renderer::MAX_VERTEX_TEXTURE_WIDTH;
pub use shade::{Shaders, WrShaders};
pub use webrender_api as api;
pub use webrender_api::euclid;
pub use resource_cache::intersect_for_tile;
Copy path View file
@@ -4,7 +4,7 @@
use api::{DeviceRect, FilterOp, MixBlendMode, PipelineId, PremultipliedColorF, PictureRect, PicturePoint};
use api::{DeviceIntRect, DevicePoint, LayoutRect, PictureToRasterTransform, LayoutPixel, PropertyBinding, PropertyBindingId};
use api::{DevicePixelScale, RasterRect, RasterSpace, PictureSize, DeviceIntPoint, ColorF, ImageKey};
use api::{DevicePixelScale, RasterRect, RasterSpace, PictureSize, DeviceIntPoint, ColorF, ImageKey, DirtyRect};
use api::{PicturePixel, RasterPixel, WorldPixel, WorldRect, ImageFormat, ImageDescriptor};
use box_shadow::{BLUR_SAMPLE_SCALE};
use clip::{ClipNodeCollector, ClipStore, ClipChainId, ClipChainNode};
@@ -1843,7 +1843,7 @@ impl PicturePrimitive {
TextureFilter::Linear,
None,
[0.0; 3],
None,
DirtyRect::AllDirty,
frame_state.gpu_cache,
None,
UvRectKind::Rect,
Copy path View file
@@ -4,7 +4,7 @@
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, DeviceIntSideOffsets};
use api::{DevicePixelScale, ImageDescriptor, ImageFormat};
use api::{LineStyle, LineOrientation, LayoutSize, ColorF};
use api::{LineStyle, LineOrientation, LayoutSize, ColorF, DirtyRect};
#[cfg(feature = "pathfinder")]
use api::FontRenderMode;
use border::{BorderCornerCacheKey, BorderEdgeCacheKey};
@@ -1255,7 +1255,7 @@ impl RenderTaskCache {
TextureFilter::Linear,
None,
entry.user_data.unwrap_or([0.0; 3]),
None,
DirtyRect::AllDirty,
gpu_cache,
None,
render_task.uv_rect_kind(),
Copy path View file
@@ -9,7 +9,7 @@ use api::{DebugFlags, FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
use api::{ExternalImageData, ExternalImageType, BlobImageResult, BlobImageParams};
use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
use api::{GlyphDimensions, IdNamespace};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering, DirtyRect};
use api::{MemoryReport, VoidPtrToSizeFn};
use api::{TileOffset, TileSize, TileRange, BlobImageData};
use app_units::Au;
@@ -113,7 +113,7 @@ enum RasterizedBlob {
struct BlobImageTemplate {
descriptor: ImageDescriptor,
tiling: Option<TileSize>,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: DirtyRect,
viewport_tiles: Option<TileRange>,
}
@@ -157,7 +157,7 @@ impl ImageTemplates {
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct CachedImageInfo {
texture_cache_handle: TextureCacheHandle,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: DirtyRect,
manual_eviction: bool,
}
@@ -175,46 +175,6 @@ pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
pub user_data: U,
}
pub fn intersect_for_tile(
dirty: DeviceIntRect,
clipped_tile_size: DeviceIntSize,
tile_size: TileSize,
tile_offset: TileOffset,
) -> Option<DeviceIntRect> {
dirty.intersection(&DeviceIntRect::new(
DeviceIntPoint::new(
tile_offset.x as i32 * tile_size as i32,
tile_offset.y as i32 * tile_size as i32
),
clipped_tile_size,
)).map(|mut r| {
// we can't translate by a negative size so do it manually
r.origin.x -= tile_offset.x as i32 * tile_size as i32;
r.origin.y -= tile_offset.y as i32 * tile_size as i32;
r
})
}
fn merge_dirty_rect(
prev_dirty_rect: &Option<DeviceIntRect>,
dirty_rect: &DeviceIntRect,
dst_size: &DeviceIntSize,
) -> Option<DeviceIntRect> {
// It is important to never assume a dirty rect equal to None implies a full reupload here,
// although we are able to do so elsewhere. We store the image or tile's full rect instead
// There are update sequences which could cause us to forget the correct dirty regions
// regions if we cleared the dirty rect when we received None, e.g.:
// 1) Update with no dirty rect. We want to reupload everything.
// 2) Update with dirty rect B. We still want to reupload everything, not just B.
// 3) Perform the upload some time later.
let full_rect = DeviceIntRect::from(*dst_size);
match *prev_dirty_rect {
Some(ref prev_rect) => dirty_rect.union(&prev_rect),
None => *dirty_rect,
}.intersection(&full_rect)
}
impl<K, V, U> ResourceClassCache<K, V, U>
where
K: Clone + Hash + Eq + Debug,
@@ -516,7 +476,7 @@ impl ResourceCache {
self.add_image_template(img.key, img.descriptor, img.data, img.tiling);
}
ResourceUpdate::UpdateImage(img) => {
self.update_image_template(img.key, img.descriptor, img.data, img.dirty_rect);
self.update_image_template(img.key, img.descriptor, img.data, &img.dirty_rect);
}
ResourceUpdate::DeleteImage(img) => {
self.delete_image_template(img);
@@ -754,11 +714,8 @@ impl ResourceCache {
image_key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: &DirtyRect,
) {
let dirty_rect = dirty_rect.unwrap_or_else(|| {
descriptor.full_rect()
});
let max_texture_size = self.max_texture_size();
let image = match self.resources.image_templates.get_mut(image_key) {
Some(res) => res,
@@ -774,25 +731,27 @@ impl ResourceCache {
// updated independently.
match self.cached_images.try_get_mut(&image_key) {
Some(&mut ImageResult::UntiledAuto(ref mut entry)) => {
entry.dirty_rect = merge_dirty_rect(&entry.dirty_rect, &dirty_rect, &descriptor.size);
entry.dirty_rect = entry.dirty_rect.union(dirty_rect);
}
Some(&mut ImageResult::Multi(ref mut entries)) => {
let tile_size = tiling.unwrap();
for (key, entry) in entries.iter_mut() {
let (local_dirty_rect, local_size) = match key.tile {
// We want the dirty rect relative to the tile and not the whole image.
let local_dirty_rect = match key.tile {
Some(tile) => {
let tile_offset = DeviceIntPoint::new(tile.x as i32, tile.y as i32) * tile_size as i32;
let mut tile_dirty_rect = dirty_rect;
tile_dirty_rect.origin -= tile_offset.to_vector();
(tile_dirty_rect, compute_tile_size(&descriptor, tile_size, tile))
dirty_rect.map(|mut rect|{
let tile_offset = DeviceIntPoint::new(
tile.x as i32,
tile.y as i32,
) * tile_size as i32;
rect.origin -= tile_offset.to_vector();
rect
})
}
None => (dirty_rect, descriptor.size),
None => *dirty_rect,
};
entry.dirty_rect = merge_dirty_rect(
&entry.dirty_rect,
&local_dirty_rect,
&local_size
);
entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
}
}
_ => {}
@@ -824,12 +783,7 @@ impl ResourceCache {
BlobImageTemplate {
descriptor: *descriptor,
tiling,
dirty_rect: Some(
DeviceIntRect::new(
DeviceIntPoint::zero(),
descriptor.size,
)
),
dirty_rect: DirtyRect::AllDirty,
viewport_tiles: None,
},
);
@@ -840,10 +794,10 @@ impl ResourceCache {
&mut self,
key: ImageKey,
descriptor: &ImageDescriptor,
dirty_rect: &Option<DeviceIntRect>,
dirty_rect: &DirtyRect,
data: Arc<BlobImageData>,
) {
self.blob_image_handler.as_mut().unwrap().update(key, data, *dirty_rect);
self.blob_image_handler.as_mut().unwrap().update(key, data, dirty_rect);
let max_texture_size = self.max_texture_size();
@@ -856,11 +810,7 @@ impl ResourceCache {
*image = BlobImageTemplate {
descriptor: *descriptor,
tiling,
dirty_rect: match (*dirty_rect, image.dirty_rect) {
(Some(rect), Some(prev_rect)) => Some(rect.union(&prev_rect)),
(Some(rect), None) => Some(rect),
(None, _) => None,
},
dirty_rect: dirty_rect.union(&image.dirty_rect),
viewport_tiles: image.viewport_tiles,
};
}
@@ -894,11 +844,11 @@ impl ResourceCache {
) -> bool {
match self.cached_images.try_get(&image_key) {
Some(ImageResult::UntiledAuto(ref info)) => {
info.dirty_rect.is_some()
!info.dirty_rect.is_empty()
}
Some(ImageResult::Multi(ref entries)) => {
for (_, entry) in &entries.resources {
if entry.dirty_rect.is_some() {
if !entry.dirty_rect.is_empty() {
return true;
}
}
@@ -957,7 +907,7 @@ impl ResourceCache {
&mut ImageResult::UntiledAuto(ref mut entry) => {
Some(mem::replace(entry, CachedImageInfo {
texture_cache_handle: TextureCacheHandle::invalid(),
dirty_rect: None,
dirty_rect: DirtyRect::AllDirty,
manual_eviction: false,
}))
}
@@ -980,7 +930,7 @@ impl ResourceCache {
entry.insert(if request.is_untiled_auto() {
ImageResult::UntiledAuto(CachedImageInfo {
texture_cache_handle: TextureCacheHandle::invalid(),
dirty_rect: Some(template.descriptor.full_rect()),
dirty_rect: DirtyRect::AllDirty,
manual_eviction: false,
})
} else {
@@ -997,7 +947,7 @@ impl ResourceCache {
entries.entry(request.into())
.or_insert(CachedImageInfo {
texture_cache_handle: TextureCacheHandle::invalid(),
dirty_rect: Some(template.descriptor.full_rect()),
dirty_rect: DirtyRect::AllDirty,
manual_eviction: false,
})
},
@@ -1006,7 +956,7 @@ impl ResourceCache {
let needs_upload = self.texture_cache.request(&entry.texture_cache_handle, gpu_cache);
if !needs_upload && entry.dirty_rect.is_none() {
if !needs_upload && entry.dirty_rect.is_empty() {
return
}
@@ -1056,7 +1006,7 @@ impl ResourceCache {
BlobImageParams {
request,
descriptor,
dirty_rect: None,
dirty_rect: DirtyRect::AllDirty,
}
);
}
@@ -1090,7 +1040,7 @@ impl ResourceCache {
});
// Don't request tiles that weren't invalidated.
if let Some(dirty_rect) = template.dirty_rect {
if let DirtyRect::SomeDirty(dirty_rect) = template.dirty_rect {
let dirty_rect = DeviceIntRect {
origin: point2(
dirty_rect.origin.x,
@@ -1148,7 +1098,7 @@ impl ResourceCache {
tile: Some(tile),
},
descriptor,
dirty_rect: None,
dirty_rect: DirtyRect::AllDirty,
}
);
});
@@ -1181,7 +1131,7 @@ impl ResourceCache {
let dirty_rect = if needs_upload {
// The texture cache entry has been evicted, treat it as all dirty.
None
DirtyRect::AllDirty
} else {
template.dirty_rect
};
@@ -1201,7 +1151,7 @@ impl ResourceCache {
}
);
}
template.dirty_rect = None;
template.dirty_rect = DirtyRect::empty();
}
let handler = self.blob_image_handler.as_mut().unwrap();
handler.prepare_resources(&self.resources, &blob_request_params);
@@ -1558,7 +1508,7 @@ impl ResourceCache {
};
let mut descriptor = image_template.descriptor.clone();
let mut dirty_rect = entry.dirty_rect.take();
let mut dirty_rect = entry.dirty_rect.replace_with_empty();
if let Some(tile) = request.tile {
let tile_size = image_template.tiling.unwrap();
@@ -1583,8 +1533,8 @@ impl ResourceCache {
// If we are uploading the dirty region of a blob image we might have several
// rects to upload so we use each of these rasterized rects rather than the
// overall dirty rect of the image.
if blob_rasterized_rect.is_some() {
dirty_rect = blob_rasterized_rect;
if let Some(rect) = blob_rasterized_rect {
dirty_rect = DirtyRect::SomeDirty(rect);
}
let filter = match request.rendering {
@@ -1941,7 +1891,7 @@ impl ResourceCache {
offset: DevicePoint::zero(),
format: desc.format,
},
dirty_rect: None,
dirty_rect: DirtyRect::AllDirty,
}
];
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.