mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Bug 1570081 - Support changing the blob image visible rect in WebRender. r=jrmuizel
Differential Revision: https://phabricator.services.mozilla.com/D39911 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
e9850ca2ee
commit
e9915eb02b
@ -336,21 +336,23 @@ struct Reader {
|
||||
};
|
||||
|
||||
static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
||||
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
const mozilla::wr::DeviceIntRect* aVisibleRect,
|
||||
const mozilla::wr::LayoutIntRect* aRenderRect,
|
||||
const uint16_t* aTileSize,
|
||||
const mozilla::wr::TileOffset* aTileOffset,
|
||||
const mozilla::wr::LayoutIntRect* aDirtyRect,
|
||||
Range<uint8_t> aOutput) {
|
||||
IntSize size(aRenderRect->size.width, aRenderRect->size.height);
|
||||
AUTO_PROFILER_TRACING("WebRender", "RasterizeSingleBlob", GRAPHICS);
|
||||
MOZ_RELEASE_ASSERT(aSize.width > 0 && aSize.height > 0);
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
MOZ_RELEASE_ASSERT(size.width > 0 && size.height > 0);
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stride = aSize.width * gfx::BytesPerPixel(aFormat);
|
||||
auto stride = size.width * gfx::BytesPerPixel(aFormat);
|
||||
|
||||
if (aOutput.length() < static_cast<size_t>(aSize.height * stride)) {
|
||||
if (aOutput.length() < static_cast<size_t>(size.height * stride)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -358,7 +360,7 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
||||
bool uninitialized = false;
|
||||
|
||||
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTargetForData(
|
||||
gfx::BackendType::SKIA, aOutput.begin().get(), aSize, stride, aFormat,
|
||||
gfx::BackendType::SKIA, aOutput.begin().get(), size, stride, aFormat,
|
||||
uninitialized);
|
||||
|
||||
if (!dt) {
|
||||
@ -370,22 +372,18 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
||||
size_t footerSize = sizeof(size_t) + sizeof(IntPoint);
|
||||
MOZ_RELEASE_ASSERT(aBlob.length() >= footerSize);
|
||||
size_t indexOffset = ConvertFromBytes<size_t>(aBlob.end().get() - footerSize);
|
||||
IntPoint origin = ConvertFromBytes<IntPoint>(aBlob.end().get() - footerSize +
|
||||
sizeof(size_t));
|
||||
// Apply the visibleRect's offset to make (0, 0) in the DT correspond to (0,
|
||||
// 0) in the texture
|
||||
|
||||
// aRenderRect is the part of the blob that we are currently rendering
|
||||
// (for example a tile) in the same coordinate space as aVisibleRect.
|
||||
IntPoint origin = gfx::IntPoint(aRenderRect->origin.x, aRenderRect->origin.y);
|
||||
|
||||
MOZ_RELEASE_ASSERT(indexOffset <= aBlob.length() - footerSize);
|
||||
Reader reader(aBlob.begin().get() + indexOffset,
|
||||
aBlob.length() - footerSize - indexOffset);
|
||||
|
||||
if (aTileOffset) {
|
||||
origin +=
|
||||
gfx::IntPoint(aTileOffset->x * *aTileSize, aTileOffset->y * *aTileSize);
|
||||
}
|
||||
dt = gfx::Factory::CreateOffsetDrawTarget(dt, origin);
|
||||
|
||||
auto bounds = gfx::IntRect(origin, aSize);
|
||||
auto bounds = gfx::IntRect(origin, size);
|
||||
|
||||
if (aDirtyRect) {
|
||||
gfx::Rect dirty(aDirtyRect->origin.x, aDirtyRect->origin.y,
|
||||
@ -436,7 +434,7 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
||||
float r = float(rand()) / float(RAND_MAX);
|
||||
float g = float(rand()) / float(RAND_MAX);
|
||||
float b = float(rand()) / float(RAND_MAX);
|
||||
dt->FillRect(gfx::Rect(origin.x, origin.y, aSize.width, aSize.height),
|
||||
dt->FillRect(gfx::Rect(origin.x, origin.y, size.width, size.height),
|
||||
gfx::ColorPattern(gfx::Color(r, g, b, 0.5)));
|
||||
}
|
||||
|
||||
@ -459,17 +457,19 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool wr_moz2d_render_cb(const mozilla::wr::ByteSlice blob, int32_t width,
|
||||
int32_t height, mozilla::wr::ImageFormat aFormat,
|
||||
bool wr_moz2d_render_cb(const mozilla::wr::ByteSlice blob,
|
||||
mozilla::wr::ImageFormat aFormat,
|
||||
const mozilla::wr::LayoutIntRect* aRenderRect,
|
||||
const mozilla::wr::DeviceIntRect* aVisibleRect,
|
||||
const uint16_t* aTileSize,
|
||||
const mozilla::wr::TileOffset* aTileOffset,
|
||||
const mozilla::wr::LayoutIntRect* aDirtyRect,
|
||||
mozilla::wr::MutByteSlice output) {
|
||||
return mozilla::wr::Moz2DRenderCallback(
|
||||
mozilla::wr::ByteSliceToRange(blob), mozilla::gfx::IntSize(width, height),
|
||||
mozilla::wr::ImageFormatToSurfaceFormat(aFormat), aVisibleRect, aTileSize,
|
||||
aTileOffset, aDirtyRect, mozilla::wr::MutByteSliceToRange(output));
|
||||
mozilla::wr::ByteSliceToRange(blob),
|
||||
mozilla::wr::ImageFormatToSurfaceFormat(aFormat), aVisibleRect,
|
||||
aRenderRect, aTileSize, aTileOffset, aDirtyRect,
|
||||
mozilla::wr::MutByteSliceToRange(output));
|
||||
}
|
||||
|
||||
} // extern
|
||||
|
@ -3258,9 +3258,8 @@ pub unsafe extern "C" fn wr_dec_ref_arc(arc: *const VecU8) {
|
||||
extern "C" {
|
||||
// TODO: figure out the API for tiled blob images.
|
||||
pub fn wr_moz2d_render_cb(blob: ByteSlice,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: ImageFormat,
|
||||
render_rect: &LayoutIntRect,
|
||||
visible_rect: &DeviceIntRect,
|
||||
tile_size: Option<&u16>,
|
||||
tile_offset: Option<&TileOffset>,
|
||||
|
@ -553,9 +553,8 @@ fn rasterize_blob(job: Job) -> (BlobImageRequest, BlobImageResult) {
|
||||
let result = unsafe {
|
||||
if wr_moz2d_render_cb(
|
||||
ByteSlice::new(&job.commands[..]),
|
||||
descriptor.rect.size.width,
|
||||
descriptor.rect.size.height,
|
||||
descriptor.format,
|
||||
&descriptor.rect,
|
||||
&job.visible_rect,
|
||||
job.tile_size.as_ref(),
|
||||
job.request.tile.as_ref(),
|
||||
|
@ -380,10 +380,6 @@ impl ClipNodeInfo {
|
||||
rect.size,
|
||||
);
|
||||
|
||||
// TODO: As a followup, if the image is a tiled blob, the device_image_rect below
|
||||
// will be set to the blob's visible area.
|
||||
let device_image_rect = DeviceIntRect::from_size(props.descriptor.size);
|
||||
|
||||
for Repetition { origin, .. } in repetitions {
|
||||
let layout_image_rect = LayoutRect {
|
||||
origin,
|
||||
@ -392,7 +388,7 @@ impl ClipNodeInfo {
|
||||
let tiles = image::tiles(
|
||||
&layout_image_rect,
|
||||
&visible_rect,
|
||||
&device_image_rect,
|
||||
&props.visible_rect,
|
||||
tile_size as i32,
|
||||
);
|
||||
for tile in tiles {
|
||||
|
@ -491,6 +491,37 @@ fn last_tile_size_1d(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn compute_tile_rect(
|
||||
image_rect: &DeviceIntRect,
|
||||
regular_tile_size: TileSize,
|
||||
tile: TileOffset,
|
||||
) -> DeviceIntRect {
|
||||
let regular_tile_size = regular_tile_size as i32;
|
||||
DeviceIntRect {
|
||||
origin: point2(
|
||||
compute_tile_origin_1d(image_rect.x_range(), regular_tile_size, tile.x as i32),
|
||||
compute_tile_origin_1d(image_rect.y_range(), regular_tile_size, tile.y as i32),
|
||||
),
|
||||
size: size2(
|
||||
compute_tile_size_1d(image_rect.x_range(), regular_tile_size, tile.x as i32),
|
||||
compute_tile_size_1d(image_rect.y_range(), regular_tile_size, tile.y as i32),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_tile_origin_1d(
|
||||
img_range: Range<i32>,
|
||||
regular_tile_size: i32,
|
||||
tile_offset: i32,
|
||||
) -> i32 {
|
||||
let tile_range = tile_range_1d(&img_range, regular_tile_size);
|
||||
if tile_offset == tile_range.start {
|
||||
img_range.start
|
||||
} else {
|
||||
tile_offset * regular_tile_size
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the width and height in pixels of a tile depending on its position in the image.
|
||||
pub fn compute_tile_size(
|
||||
image_rect: &DeviceIntRect,
|
||||
@ -551,6 +582,47 @@ pub fn for_each_tile_in_range(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_valid_tiles_if_bounds_change(
|
||||
prev_rect: &DeviceIntRect,
|
||||
new_rect: &DeviceIntRect,
|
||||
tile_size: u16,
|
||||
) -> Option<TileRange> {
|
||||
let intersection = prev_rect.intersection(new_rect);
|
||||
|
||||
if intersection.is_none() {
|
||||
return Some(TileRange::zero());
|
||||
}
|
||||
|
||||
let intersection = intersection.unwrap_or(DeviceIntRect::zero());
|
||||
|
||||
let left = prev_rect.min_x() != new_rect.min_x();
|
||||
let right = prev_rect.max_x() != new_rect.max_x();
|
||||
let top = prev_rect.min_y() != new_rect.min_y();
|
||||
let bottom = prev_rect.max_y() != new_rect.max_y();
|
||||
|
||||
if !left && !right && !top && !bottom {
|
||||
// Bounds have not changed.
|
||||
return None;
|
||||
}
|
||||
|
||||
let tw = 1.0 / (tile_size as f32);
|
||||
let th = 1.0 / (tile_size as f32);
|
||||
|
||||
let tiles = intersection
|
||||
.cast::<f32>()
|
||||
.scale(tw, th);
|
||||
|
||||
let min_x = if left { f32::ceil(tiles.min_x()) } else { f32::floor(tiles.min_x()) };
|
||||
let min_y = if top { f32::ceil(tiles.min_y()) } else { f32::floor(tiles.min_y()) };
|
||||
let max_x = if right { f32::floor(tiles.max_x()) } else { f32::ceil(tiles.max_x()) };
|
||||
let max_y = if bottom { f32::floor(tiles.max_y()) } else { f32::ceil(tiles.max_y()) };
|
||||
|
||||
Some(TileRange {
|
||||
origin: point2(min_x as i32, min_y as i32),
|
||||
size: size2((max_x - min_x) as i32, (max_y - min_y) as i32),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -714,4 +786,26 @@ mod tests {
|
||||
assert_eq!(result.first_tile_layout_size, 10.0);
|
||||
assert_eq!(result.last_tile_layout_size, 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smaller_than_tile_size_at_origin() {
|
||||
let r = compute_tile_rect(
|
||||
&rect(0, 0, 80, 80),
|
||||
256,
|
||||
point2(0, 0),
|
||||
);
|
||||
|
||||
assert_eq!(r, rect(0, 0, 80, 80));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smaller_than_tile_size_with_offset() {
|
||||
let r = compute_tile_rect(
|
||||
&rect(20, 20, 80, 80),
|
||||
256,
|
||||
point2(0, 0),
|
||||
);
|
||||
|
||||
assert_eq!(r, rect(20, 20, 80, 80));
|
||||
}
|
||||
}
|
||||
|
@ -2289,9 +2289,12 @@ impl PrimitiveStore {
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
Some(ImageProperties { descriptor, tiling: Some(tile_size), .. }) => {
|
||||
Some(ImageProperties { tiling: Some(tile_size), visible_rect, .. }) => {
|
||||
image_instance.visible_tiles.clear();
|
||||
let device_image_rect = DeviceIntRect::from_size(descriptor.size);
|
||||
// TODO: rename the blob's visible_rect into something that doesn't conflict
|
||||
// with the terminology we use during culling since it's not really the same
|
||||
// thing.
|
||||
let active_rect = visible_rect;
|
||||
|
||||
// Tighten the clip rect because decomposing the repeated image can
|
||||
// produce primitives that are partially covering the original image
|
||||
@ -2344,7 +2347,7 @@ impl PrimitiveStore {
|
||||
let tiles = crate::image::tiles(
|
||||
&layout_image_rect,
|
||||
&visible_rect,
|
||||
&device_image_rect,
|
||||
&active_rect,
|
||||
tile_size as i32,
|
||||
);
|
||||
|
||||
|
@ -24,7 +24,8 @@ use crate::glyph_cache::GlyphCacheEntry;
|
||||
use crate::glyph_rasterizer::{BaseFontInstance, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
|
||||
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||
use crate::gpu_types::UvRectKind;
|
||||
use crate::image::{compute_tile_size, compute_tile_range, for_each_tile_in_range};
|
||||
use crate::image::{compute_tile_size, compute_tile_rect, compute_tile_range, for_each_tile_in_range};
|
||||
use crate::image::compute_valid_tiles_if_bounds_change;
|
||||
use crate::internal_types::{FastHashMap, FastHashSet, TextureSource, TextureUpdateList};
|
||||
use crate::profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
|
||||
use crate::render_backend::{FrameId, FrameStamp};
|
||||
@ -143,6 +144,9 @@ pub struct ImageProperties {
|
||||
pub descriptor: ImageDescriptor,
|
||||
pub external_image: Option<ExternalImageData>,
|
||||
pub tiling: Option<TileSize>,
|
||||
// Potentially a subset of the image's total rectangle. This rectangle is what
|
||||
// we map to the (layout space) display item bounds.
|
||||
pub visible_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -164,13 +168,24 @@ struct BlobImageTemplate {
|
||||
descriptor: ImageDescriptor,
|
||||
tiling: Option<TileSize>,
|
||||
dirty_rect: BlobDirtyRect,
|
||||
viewport_tiles: Option<TileRange>,
|
||||
/// See ImageResource::visible_rect.
|
||||
visible_rect: DeviceIntRect,
|
||||
// If the active rect of the blob changes, this represents the
|
||||
// range of tiles that remain valid. This must be taken into
|
||||
// account in addition to the valid rect when submitting blob
|
||||
// rasterization requests.
|
||||
// `None` means the bounds have not changed (tiles are still valid).
|
||||
// `Some(TileRange::zero())` means all of the tiles are invalid.
|
||||
valid_tiles_after_bounds_change: Option<TileRange>,
|
||||
}
|
||||
|
||||
struct ImageResource {
|
||||
data: CachedImageData,
|
||||
descriptor: ImageDescriptor,
|
||||
tiling: Option<TileSize>,
|
||||
/// This is used to express images that are virtually very large
|
||||
/// but with only a visible sub-set that is valid at a given time.
|
||||
visible_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -586,7 +601,13 @@ impl ResourceCache {
|
||||
if let ImageData::Raw(ref bytes) = img.data {
|
||||
profile_counters.image_templates.inc(bytes.len());
|
||||
}
|
||||
self.add_image_template(img.key, img.descriptor, img.data.into(), img.tiling);
|
||||
self.add_image_template(
|
||||
img.key,
|
||||
img.descriptor,
|
||||
img.data.into(),
|
||||
&img.descriptor.size.into(),
|
||||
img.tiling,
|
||||
);
|
||||
}
|
||||
ResourceUpdate::UpdateImage(img) => {
|
||||
self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
|
||||
@ -596,6 +617,7 @@ impl ResourceCache {
|
||||
img.key.as_image(),
|
||||
img.descriptor,
|
||||
CachedImageData::Blob,
|
||||
&img.visible_rect,
|
||||
img.tiling,
|
||||
);
|
||||
}
|
||||
@ -608,7 +630,8 @@ impl ResourceCache {
|
||||
&img.dirty_rect
|
||||
),
|
||||
);
|
||||
self.discard_tiles_outside_visible_area(img.key, &img.visible_rect);
|
||||
self.discard_tiles_outside_visible_area(img.key, &img.visible_rect); // TODO: remove?
|
||||
self.set_image_visible_rect(img.key.as_image(), &img.visible_rect);
|
||||
}
|
||||
ResourceUpdate::DeleteImage(img) => {
|
||||
self.delete_image_template(img);
|
||||
@ -621,6 +644,7 @@ impl ResourceCache {
|
||||
}
|
||||
ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
|
||||
self.discard_tiles_outside_visible_area(key, &area);
|
||||
self.set_image_visible_rect(key.as_image(), &area);
|
||||
}
|
||||
ResourceUpdate::AddFont(_) |
|
||||
ResourceUpdate::AddFontInstance(_) => {
|
||||
@ -657,12 +681,7 @@ impl ResourceCache {
|
||||
}
|
||||
ResourceUpdate::SetBlobImageVisibleArea(ref key, ref area) => {
|
||||
if let Some(template) = self.blob_image_templates.get_mut(&key) {
|
||||
if let Some(tile_size) = template.tiling {
|
||||
template.viewport_tiles = Some(compute_tile_range(
|
||||
&area,
|
||||
tile_size,
|
||||
));
|
||||
}
|
||||
template.visible_rect = *area;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -773,6 +792,20 @@ impl ResourceCache {
|
||||
if let RasterizedBlob::Tiled(ref mut tiles) = *image {
|
||||
tiles.insert(tile, data);
|
||||
}
|
||||
|
||||
match self.cached_images.try_get_mut(&request.key.as_image()) {
|
||||
Some(&mut ImageResult::Multi(ref mut entries)) => {
|
||||
let cached_key = CachedImageKey {
|
||||
rendering: ImageRendering::Auto, // TODO(nical)
|
||||
tile: Some(tile),
|
||||
};
|
||||
if let Some(entry) = entries.try_get_mut(&cached_key) {
|
||||
entry.dirty_rect = DirtyRect::All;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
} else {
|
||||
if let RasterizedBlob::NonTiled(ref mut queue) = *image {
|
||||
// If our new rasterized rect overwrites items in the queue, discard them.
|
||||
@ -862,6 +895,7 @@ impl ResourceCache {
|
||||
image_key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: CachedImageData,
|
||||
visible_rect: &DeviceIntRect,
|
||||
mut tiling: Option<TileSize>,
|
||||
) {
|
||||
if tiling.is_none() && Self::should_tile(self.max_texture_size(), &descriptor, &data) {
|
||||
@ -874,6 +908,7 @@ impl ResourceCache {
|
||||
descriptor,
|
||||
data,
|
||||
tiling,
|
||||
visible_rect: *visible_rect,
|
||||
};
|
||||
|
||||
self.resources.image_templates.insert(image_key, resource);
|
||||
@ -941,6 +976,7 @@ impl ResourceCache {
|
||||
descriptor,
|
||||
data,
|
||||
tiling,
|
||||
visible_rect: descriptor.size.into(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -956,8 +992,6 @@ impl ResourceCache {
|
||||
let max_texture_size = self.max_texture_size();
|
||||
tiling = get_blob_tiling(tiling, descriptor, max_texture_size);
|
||||
|
||||
let viewport_tiles = tiling.map(|tile_size| compute_tile_range(&visible_rect, tile_size));
|
||||
|
||||
self.blob_image_handler.as_mut().unwrap().add(key, data, visible_rect, tiling);
|
||||
|
||||
self.blob_image_templates.insert(
|
||||
@ -966,7 +1000,8 @@ impl ResourceCache {
|
||||
descriptor: *descriptor,
|
||||
tiling,
|
||||
dirty_rect: DirtyRect::All,
|
||||
viewport_tiles,
|
||||
valid_tiles_after_bounds_change: None,
|
||||
visible_rect: *visible_rect,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -990,13 +1025,32 @@ impl ResourceCache {
|
||||
|
||||
let tiling = get_blob_tiling(image.tiling, descriptor, max_texture_size);
|
||||
|
||||
let viewport_tiles = image.tiling.map(|tile_size| compute_tile_range(&visible_rect, tile_size));
|
||||
let mut valid_tiles_after_bounds_change = None;
|
||||
|
||||
if let Some(tile_size) = image.tiling {
|
||||
valid_tiles_after_bounds_change = compute_valid_tiles_if_bounds_change(
|
||||
&image.visible_rect,
|
||||
visible_rect,
|
||||
tile_size,
|
||||
);
|
||||
}
|
||||
|
||||
match (image.valid_tiles_after_bounds_change, valid_tiles_after_bounds_change) {
|
||||
(Some(old), Some(ref mut new)) => {
|
||||
*new = new.intersection(&old).unwrap_or(TileRange::zero());
|
||||
}
|
||||
(Some(old), None) => {
|
||||
valid_tiles_after_bounds_change = Some(old);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
*image = BlobImageTemplate {
|
||||
descriptor: *descriptor,
|
||||
tiling,
|
||||
dirty_rect: dirty_rect.union(&image.dirty_rect),
|
||||
viewport_tiles,
|
||||
valid_tiles_after_bounds_change,
|
||||
visible_rect: *visible_rect,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1166,14 +1220,11 @@ impl ResourceCache {
|
||||
rect: match template.tiling {
|
||||
Some(tile_size) => {
|
||||
let tile = request.tile.unwrap();
|
||||
LayoutIntRect {
|
||||
origin: point2(tile.x, tile.y) * tile_size as i32,
|
||||
size: blob_size(compute_tile_size(
|
||||
&template.descriptor.size.into(),
|
||||
tile_size,
|
||||
tile,
|
||||
)),
|
||||
}
|
||||
blob_rect(compute_tile_rect(
|
||||
&template.visible_rect,
|
||||
tile_size,
|
||||
tile,
|
||||
))
|
||||
}
|
||||
None => blob_size(template.descriptor.size).into(),
|
||||
},
|
||||
@ -1213,37 +1264,33 @@ impl ResourceCache {
|
||||
if let Some(tile_size) = template.tiling {
|
||||
// If we know that only a portion of the blob image is in the viewport,
|
||||
// only request these visible tiles since blob images can be huge.
|
||||
let mut tiles = template.viewport_tiles.unwrap_or_else(|| {
|
||||
// Default to requesting the full range of tiles.
|
||||
compute_tile_range(
|
||||
&DeviceIntRect {
|
||||
origin: point2(0, 0),
|
||||
size: template.descriptor.size,
|
||||
},
|
||||
tile_size,
|
||||
)
|
||||
});
|
||||
let mut tiles = compute_tile_range(
|
||||
&template.visible_rect,
|
||||
tile_size,
|
||||
);
|
||||
|
||||
let image_dirty_rect = to_image_dirty_rect(&template.dirty_rect);
|
||||
// Don't request tiles that weren't invalidated.
|
||||
if let DirtyRect::Partial(dirty_rect) = image_dirty_rect {
|
||||
let dirty_rect = DeviceIntRect {
|
||||
origin: point2(
|
||||
dirty_rect.origin.x,
|
||||
dirty_rect.origin.y,
|
||||
),
|
||||
size: size2(
|
||||
dirty_rect.size.width,
|
||||
dirty_rect.size.height,
|
||||
),
|
||||
};
|
||||
let dirty_tiles = compute_tile_range(
|
||||
&dirty_rect,
|
||||
tile_size,
|
||||
);
|
||||
let dirty_tiles = match image_dirty_rect {
|
||||
DirtyRect::Partial(dirty_rect) => {
|
||||
let dirty_rect = DeviceIntRect {
|
||||
origin: point2(
|
||||
dirty_rect.origin.x,
|
||||
dirty_rect.origin.y,
|
||||
),
|
||||
size: size2(
|
||||
dirty_rect.size.width,
|
||||
dirty_rect.size.height,
|
||||
),
|
||||
};
|
||||
|
||||
tiles = tiles.intersection(&dirty_tiles).unwrap_or_else(TileRange::zero);
|
||||
}
|
||||
compute_tile_range(
|
||||
&dirty_rect,
|
||||
tile_size,
|
||||
)
|
||||
}
|
||||
DirtyRect::All => tiles,
|
||||
};
|
||||
|
||||
let original_tile_range = tiles;
|
||||
|
||||
@ -1284,16 +1331,22 @@ impl ResourceCache {
|
||||
blob_tiles_clear_requests.push(clear_params);
|
||||
}
|
||||
|
||||
|
||||
for_each_tile_in_range(&tiles, |tile| {
|
||||
let still_valid = template.valid_tiles_after_bounds_change
|
||||
.map(|valid_tiles| valid_tiles.contains(tile))
|
||||
.unwrap_or(true);
|
||||
|
||||
if still_valid && !dirty_tiles.contains(tile) {
|
||||
return;
|
||||
}
|
||||
|
||||
let descriptor = BlobImageDescriptor {
|
||||
rect: LayoutIntRect {
|
||||
origin: point2(tile.x, tile.y) * tile_size as i32,
|
||||
size: blob_size(compute_tile_size(
|
||||
&template.descriptor.size.into(),
|
||||
tile_size,
|
||||
tile,
|
||||
)),
|
||||
},
|
||||
rect: blob_rect(compute_tile_rect(
|
||||
&template.visible_rect,
|
||||
tile_size,
|
||||
tile,
|
||||
)),
|
||||
format: template.descriptor.format,
|
||||
};
|
||||
|
||||
@ -1312,6 +1365,8 @@ impl ResourceCache {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
template.valid_tiles_after_bounds_change = None;
|
||||
} else {
|
||||
let mut needs_upload = match self.cached_images.try_get(&key.as_image()) {
|
||||
Some(&ImageResult::UntiledAuto(ref entry)) => {
|
||||
@ -1320,7 +1375,7 @@ impl ResourceCache {
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// If the queue of ratserized updates is growing it probably means that
|
||||
// If the queue of rasterized updates is growing it probably means that
|
||||
// the texture is not getting uploaded because the display item is off-screen.
|
||||
// In that case we are better off
|
||||
// - Either not kicking rasterization for that image (avoid wasted cpu work
|
||||
@ -1417,6 +1472,12 @@ impl ResourceCache {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_image_visible_rect(&mut self, key: ImageKey, rect: &DeviceIntRect) {
|
||||
if let Some(image) = self.resources.image_templates.get_mut(key) {
|
||||
image.visible_rect = * rect;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_glyphs(
|
||||
&mut self,
|
||||
mut font: FontInstance,
|
||||
@ -1555,6 +1616,7 @@ impl ResourceCache {
|
||||
descriptor: image_template.descriptor,
|
||||
external_image,
|
||||
tiling: image_template.tiling,
|
||||
visible_rect: image_template.visible_rect,
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1698,13 +1760,15 @@ impl ResourceCache {
|
||||
|
||||
if let Some(tile) = request.tile {
|
||||
let tile_size = image_template.tiling.unwrap();
|
||||
let clipped_tile_size = compute_tile_size(&descriptor.size.into(), tile_size, tile);
|
||||
|
||||
let clipped_tile_size = compute_tile_size(&image_template.visible_rect, tile_size, tile);
|
||||
// The tiled image could be stored on the CPU as one large image or be
|
||||
// already broken up into tiles. This affects the way we compute the stride
|
||||
// and offset.
|
||||
let tiled_on_cpu = image_template.data.is_blob();
|
||||
if !tiled_on_cpu {
|
||||
// we don't expect to have partial tiles at the top and left of non-blob
|
||||
// images.
|
||||
debug_assert_eq!(image_template.visible_rect.origin, point2(0, 0));
|
||||
let bpp = descriptor.format.bytes_per_pixel();
|
||||
let stride = descriptor.compute_stride();
|
||||
descriptor.stride = Some(stride);
|
||||
@ -2283,6 +2347,7 @@ impl ResourceCache {
|
||||
data,
|
||||
descriptor: template.descriptor,
|
||||
tiling: template.tiling,
|
||||
visible_rect: template.descriptor.size.into(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -2298,3 +2363,11 @@ impl ResourceCache {
|
||||
fn blob_size(device_size: DeviceIntSize) -> LayoutIntSize {
|
||||
size2(device_size.width, device_size.height)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn blob_rect(device_rect: DeviceIntRect) -> LayoutIntRect {
|
||||
LayoutIntRect {
|
||||
origin: point2(device_rect.origin.x, device_rect.origin.y),
|
||||
size: blob_size(device_rect.size),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user