Bug 1509495 - Update webrender to commit af2b372624db589115511b4705849a33e6acd35d (WR PR #3277). r=kats

https://github.com/servo/webrender/pull/3277

Differential Revision: https://phabricator.services.mozilla.com/D12809

--HG--
extra : moz-landing-system : lando
This commit is contained in:
WR Updater Bot 2018-11-23 23:32:57 +00:00
Родитель 79fce9d9bb
Коммит aada6c49ca
19 изменённых файлов: 596 добавлений и 427 удалений

Просмотреть файл

@ -1 +1 @@
523be3a9461de2716828cd2271aabaffc5e4caa0
af2b372624db589115511b4705849a33e6acd35d

Просмотреть файл

@ -17,7 +17,8 @@ use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, RenderApi, Transaction};
use webrender::api::{ColorF, DeviceIntRect, DeviceIntPoint};
use webrender::api::ColorF;
use webrender::euclid::size2;
// This example shows how to implement a very basic BlobImageHandler that can only render
// a checkerboard pattern.
@ -28,8 +29,8 @@ type ImageRenderingCommands = api::ColorU;
// Serialize/deserialize the blob.
// For real usecases you should probably use serde rather than doing it by hand.
fn serialize_blob(color: api::ColorU) -> Vec<u8> {
vec![color.r, color.g, color.b, color.a]
fn serialize_blob(color: api::ColorU) -> Arc<Vec<u8>> {
Arc::new(vec![color.r, color.g, color.b, color.a])
}
fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
@ -50,9 +51,13 @@ fn render_blob(
) -> api::BlobImageResult {
let color = *commands;
// Note: This implementation ignores the dirty rect which isn't incorrect
// but is a missed optimization.
// Allocate storage for the result. Right now the resource cache expects the
// tiles to have have no stride or offset.
let mut texels = Vec::with_capacity((descriptor.size.width * descriptor.size.height * 4) as usize);
let bpp = 4;
let mut texels = Vec::with_capacity((descriptor.rect.size.area() * bpp) as usize);
// Generate a per-tile pattern to see it in the demo. For a real use case it would not
// make sense for the rendered content to depend on its tile.
@ -61,12 +66,15 @@ fn render_blob(
None => true,
};
for y in 0 .. descriptor.size.height {
for x in 0 .. descriptor.size.width {
let [w, h] = descriptor.rect.size.to_array();
let offset = descriptor.rect.origin;
for y in 0..h {
for x in 0..w {
// Apply the tile's offset. This is important: all drawing commands should be
// translated by this offset to give correct results with tiled blob images.
let x2 = x + descriptor.offset.x as i32;
let y2 = y + descriptor.offset.y as i32;
let x2 = x + offset.x;
let y2 = y + offset.y;
// Render a simple checkerboard pattern
let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) {
@ -98,10 +106,7 @@ fn render_blob(
Ok(api::RasterizedBlobImage {
data: Arc::new(texels),
rasterized_rect: DeviceIntRect {
origin: DeviceIntPoint::origin(),
size: descriptor.size,
},
rasterized_rect: size2(w, h).into(),
})
}
@ -117,7 +122,7 @@ struct CheckerboardRenderer {
// case the command list is a simple 32 bits value and would be cheap to clone before sending
// to the workers. But in a more realistic scenario the commands would typically be bigger
// and more expensive to clone, so let's pretend it is also the case here.
image_cmds: HashMap<api::ImageKey, Arc<ImageRenderingCommands>>,
image_cmds: HashMap<api::BlobImageKey, Arc<ImageRenderingCommands>>,
}
impl CheckerboardRenderer {
@ -130,19 +135,19 @@ impl CheckerboardRenderer {
}
impl api::BlobImageHandler for CheckerboardRenderer {
fn add(&mut self, key: api::ImageKey, cmds: Arc<api::BlobImageData>, _: Option<api::TileSize>) {
fn add(&mut self, key: api::BlobImageKey, cmds: Arc<api::BlobImageData>, _: Option<api::TileSize>) {
self.image_cmds
.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::BlobImageKey, cmds: Arc<api::BlobImageData>, _dirty_rect: &api::BlobDirtyRect) {
// Here, updating is just replacing the current version of the commands with
// the new one (no incremental updates).
self.image_cmds
.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
}
fn delete(&mut self, key: api::ImageKey) {
fn delete(&mut self, key: api::BlobImageKey) {
self.image_cmds.remove(&key);
}
@ -165,7 +170,7 @@ impl api::BlobImageHandler for CheckerboardRenderer {
struct Rasterizer {
workers: Arc<ThreadPool>,
image_cmds: HashMap<api::ImageKey, Arc<ImageRenderingCommands>>,
image_cmds: HashMap<api::BlobImageKey, Arc<ImageRenderingCommands>>,
}
impl api::AsyncBlobImageRasterizer for Rasterizer {
@ -198,19 +203,19 @@ impl Example for App {
_pipeline_id: PipelineId,
_document_id: DocumentId,
) {
let blob_img1 = api.generate_image_key();
txn.add_image(
let blob_img1 = api.generate_blob_image_key();
txn.add_blob_image(
blob_img1,
api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true, false),
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 50, 150, 255))),
serialize_blob(api::ColorU::new(50, 50, 150, 255)),
Some(128),
);
let blob_img2 = api.generate_image_key();
txn.add_image(
let blob_img2 = api.generate_blob_image_key();
txn.add_blob_image(
blob_img2,
api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true, false),
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 150, 50, 255))),
serialize_blob(api::ColorU::new(50, 150, 50, 255)),
None,
);
@ -232,7 +237,7 @@ impl Example for App {
api::LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img1,
blob_img1.as_image(),
ColorF::WHITE,
);
@ -243,7 +248,7 @@ impl Example for App {
api::LayoutSize::new(0.0, 0.0),
api::ImageRendering::Auto,
api::AlphaType::PremultipliedAlpha,
blob_img2,
blob_img2.as_image(),
ColorF::WHITE,
);

Просмотреть файл

@ -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::All,
);
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::All,
);
},
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::{ImageDescriptor, ImageFormat, DirtyRect};
use device::TextureFilter;
use euclid::size2;
use gpu_types::UvRectKind;
@ -15,6 +15,7 @@ use platform::font::FontContext;
use glyph_rasterizer::{FontInstance, FontContexts, GlyphKey};
use glyph_rasterizer::{GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs, GlyphRasterResult};
use glyph_cache::{GlyphCache, CachedGlyphInfo, GlyphCacheEntry};
use resource_cache::CachedImageData;
use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
use gpu_cache::GpuCache;
use render_task::{RenderTaskTree, RenderTaskCache};
@ -182,9 +183,9 @@ impl GlyphRasterizer {
offset: 0,
},
TextureFilter::Linear,
Some(ImageData::Raw(Arc::new(glyph.bytes))),
Some(CachedImageData::Raw(Arc::new(glyph.bytes))),
[glyph.left, -glyph.top, glyph.scale],
None,
DirtyRect::All,
gpu_cache,
Some(glyph_key_cache.eviction_notice()),
UvRectKind::Rect,

Просмотреть файл

@ -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;

Просмотреть файл

@ -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::All,
frame_state.gpu_cache,
None,
UvRectKind::Rect,

Просмотреть файл

@ -15,7 +15,7 @@ use api::{DevicePixelScale, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestFlags, HitTestResult};
use api::{IdNamespace, LayoutPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
use api::{MemoryReport, VoidPtrToSizeFn};
use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, ImageKey};
use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, BlobImageKey};
use api::{NotificationRequest, Checkpoint};
use api::channel::{MsgReceiver, Payload};
#[cfg(feature = "capture")]
@ -1393,19 +1393,15 @@ impl RenderBackend {
}
}
fn get_blob_image_updates(updates: &[ResourceUpdate]) -> Vec<ImageKey> {
fn get_blob_image_updates(updates: &[ResourceUpdate]) -> Vec<BlobImageKey> {
let mut requests = Vec::new();
for update in updates {
match *update {
ResourceUpdate::AddImage(ref img) => {
if img.data.is_blob() {
requests.push(img.key);
}
ResourceUpdate::AddBlobImage(ref img) => {
requests.push(img.key);
}
ResourceUpdate::UpdateImage(ref img) => {
if img.data.is_blob() {
requests.push(img.key);
}
ResourceUpdate::UpdateBlobImage(ref img) => {
requests.push(img.key);
}
_ => {}
}

Просмотреть файл

@ -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::All,
gpu_cache,
None,
render_task.uv_rect_kind(),

Просмотреть файл

@ -4,14 +4,14 @@
use api::{AddFont, BlobImageResources, AsyncBlobImageRasterizer, ResourceUpdate};
use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest, RasterizedBlobImage};
use api::{ClearCache, ColorF, DevicePoint, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{ClearCache, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
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::{MemoryReport, VoidPtrToSizeFn};
use api::{TileOffset, TileSize, TileRange, BlobImageData};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering, ImageDirtyRect, DirtyRect};
use api::{BlobImageKey, BlobDirtyRect, MemoryReport, VoidPtrToSizeFn};
use api::{TileOffset, TileSize, TileRange, BlobImageData, LayoutIntRect, LayoutIntSize};
use app_units::Au;
#[cfg(feature = "capture")]
use capture::ExternalCaptureImage;
@ -86,6 +86,57 @@ impl CacheItem {
}
}
/// Represents the backing store of an image in the cache.
/// This storage can take several forms.
#[derive(Clone, Debug)]
pub enum CachedImageData {
/// A simple series of bytes, provided by the embedding and owned by WebRender.
/// The format is stored out-of-band, currently in ImageDescriptor.
Raw(Arc<Vec<u8>>),
/// An series of commands that can be rasterized into an image via an
/// embedding-provided callback.
///
/// The commands are stored elsewhere and this variant is used as a placeholder.
Blob,
/// An image owned by the embedding, and referenced by WebRender. This may
/// take the form of a texture or a heap-allocated buffer.
External(ExternalImageData),
}
impl From<ImageData> for CachedImageData {
fn from(img_data: ImageData) -> Self {
match img_data {
ImageData::Raw(data) => CachedImageData::Raw(data),
ImageData::External(data) => CachedImageData::External(data),
}
}
}
impl CachedImageData {
/// Returns true if this represents a blob.
#[inline]
pub fn is_blob(&self) -> bool {
match *self {
CachedImageData::Blob => true,
_ => false,
}
}
/// Returns true if this variant of CachedImageData should go through the texture
/// cache.
#[inline]
pub fn uses_texture_cache(&self) -> bool {
match *self {
CachedImageData::External(ref ext_data) => match ext_data.image_type {
ExternalImageType::TextureHandle(_) => false,
ExternalImageType::Buffer => true,
},
CachedImageData::Blob => true,
CachedImageData::Raw(_) => true,
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -113,12 +164,12 @@ enum RasterizedBlob {
struct BlobImageTemplate {
descriptor: ImageDescriptor,
tiling: Option<TileSize>,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: BlobDirtyRect,
viewport_tiles: Option<TileRange>,
}
struct ImageResource {
data: ImageData,
data: CachedImageData,
descriptor: ImageDescriptor,
tiling: Option<TileSize>,
viewport_tiles: Option<TileRange>,
@ -157,7 +208,7 @@ impl ImageTemplates {
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct CachedImageInfo {
texture_cache_handle: TextureCacheHandle,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: ImageDirtyRect,
manual_eviction: bool,
}
@ -175,46 +226,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: &Option<DeviceIntRect>,
descriptor: &ImageDescriptor,
) -> Option<DeviceIntRect> {
// It is important to never assume an empty dirty rect implies a full reupload here,
// although we are able to do so elsewhere. We store the descriptor'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.
match (dirty_rect, prev_dirty_rect) {
(&Some(ref rect), &Some(ref prev_rect)) => Some(rect.union(&prev_rect)),
(&Some(ref rect), &None) => Some(*rect),
(&None, _) => Some(descriptor.full_rect()),
}
}
impl<K, V, U> ResourceClassCache<K, V, U>
where
K: Clone + Hash + Eq + Debug,
@ -307,7 +318,7 @@ impl ImageRequest {
impl Into<BlobImageRequest> for ImageRequest {
fn into(self) -> BlobImageRequest {
BlobImageRequest {
key: self.key,
key: BlobImageKey(self.key),
tile: self.tile,
}
}
@ -387,11 +398,6 @@ impl BlobImageResources for Resources {
None => None,
}
}
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)> {
self.image_templates
.get(key)
.map(|resource| (&resource.data, &resource.descriptor))
}
}
pub type GlyphDimensionsCache = FastHashMap<(FontInstance, GlyphIndex), Option<GlyphDimensions>>;
@ -422,8 +428,8 @@ pub struct ResourceCache {
pending_image_requests: FastHashSet<ImageRequest>,
blob_image_handler: Option<Box<BlobImageHandler>>,
rasterized_blob_images: FastHashMap<ImageKey, RasterizedBlob>,
blob_image_templates: FastHashMap<ImageKey, BlobImageTemplate>,
rasterized_blob_images: FastHashMap<BlobImageKey, RasterizedBlob>,
blob_image_templates: FastHashMap<BlobImageKey, BlobImageTemplate>,
// If while building a frame we encounter blobs that we didn't already
// rasterize, add them to this list and rasterize them synchronously.
@ -461,11 +467,11 @@ impl ResourceCache {
self.texture_cache.max_texture_size()
}
fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &ImageData) -> bool {
fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool {
let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
match *data {
ImageData::Raw(_) | ImageData::Blob(_) => size_check,
ImageData::External(info) => {
CachedImageData::Raw(_) | CachedImageData::Blob => size_check,
CachedImageData::External(info) => {
// External handles already represent existing textures so it does
// not make sense to tile them into smaller ones.
info.image_type == ExternalImageType::Buffer && size_check
@ -513,10 +519,28 @@ 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, img.tiling);
self.add_image_template(img.key, img.descriptor, img.data.into(), 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.into(), &img.dirty_rect);
}
ResourceUpdate::AddBlobImage(img) => {
self.add_image_template(
img.key.as_image(),
img.descriptor,
CachedImageData::Blob,
img.tiling,
);
}
ResourceUpdate::UpdateBlobImage(img) => {
self.update_image_template(
img.key.as_image(),
img.descriptor,
CachedImageData::Blob,
&to_image_dirty_rect(
&img.dirty_rect
),
);
}
ResourceUpdate::DeleteImage(img) => {
self.delete_image_template(img);
@ -527,7 +551,7 @@ impl ResourceCache {
ResourceUpdate::DeleteFontInstance(font) => {
self.delete_font_instance(font);
}
ResourceUpdate::SetImageVisibleArea(key, area) => {
ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
self.discard_tiles_outside_visible_area(key, &area);
}
ResourceUpdate::AddFont(_) |
@ -545,27 +569,23 @@ impl ResourceCache {
) {
for update in updates.iter() {
match *update {
ResourceUpdate::AddImage(ref img) => {
if let ImageData::Blob(ref blob_data) = img.data {
self.add_blob_image(
img.key,
&img.descriptor,
img.tiling,
Arc::clone(blob_data),
);
}
ResourceUpdate::AddBlobImage(ref img) => {
self.add_blob_image(
img.key,
&img.descriptor,
img.tiling,
Arc::clone(&img.data),
);
}
ResourceUpdate::UpdateImage(ref img) => {
if let ImageData::Blob(ref blob_data) = img.data {
self.update_blob_image(
img.key,
&img.descriptor,
&img.dirty_rect,
Arc::clone(blob_data)
);
}
ResourceUpdate::UpdateBlobImage(ref img) => {
self.update_blob_image(
img.key,
&img.descriptor,
&img.dirty_rect,
Arc::clone(&img.data),
);
}
ResourceUpdate::SetImageVisibleArea(ref key, ref area) => {
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(
@ -730,7 +750,7 @@ impl ResourceCache {
&mut self,
image_key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
data: CachedImageData,
mut tiling: Option<TileSize>,
) {
if tiling.is_none() && Self::should_tile(self.max_texture_size(), &descriptor, &data) {
@ -753,8 +773,8 @@ impl ResourceCache {
&mut self,
image_key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
dirty_rect: Option<DeviceIntRect>,
data: CachedImageData,
dirty_rect: &ImageDirtyRect,
) {
let max_texture_size = self.max_texture_size();
let image = match self.resources.image_templates.get_mut(image_key) {
@ -771,24 +791,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);
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 merged_rect = merge_dirty_rect(&entry.dirty_rect, &dirty_rect, &descriptor);
// We want the dirty rect relative to the tile and not the whole image.
let local_dirty_rect = match key.tile {
Some(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();
entry.dirty_rect = match (key.tile, merged_rect) {
(Some(tile), Some(rect)) => {
let tile_size = image.tiling.unwrap();
let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
rect.intersection(&DeviceIntRect::new(
DeviceIntPoint::new(tile.x as i32, tile.y as i32) * tile_size as i32,
clipped_tile_size,
))
rect
})
}
_ => merged_rect,
None => *dirty_rect,
};
entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
}
}
_ => {}
@ -805,7 +828,7 @@ impl ResourceCache {
// Happens before scene building.
pub fn add_blob_image(
&mut self,
key: ImageKey,
key: BlobImageKey,
descriptor: &ImageDescriptor,
mut tiling: Option<TileSize>,
data: Arc<BlobImageData>,
@ -820,12 +843,7 @@ impl ResourceCache {
BlobImageTemplate {
descriptor: *descriptor,
tiling,
dirty_rect: Some(
DeviceIntRect::new(
DeviceIntPoint::zero(),
descriptor.size,
)
),
dirty_rect: DirtyRect::All,
viewport_tiles: None,
},
);
@ -834,12 +852,12 @@ impl ResourceCache {
// Happens before scene building.
pub fn update_blob_image(
&mut self,
key: ImageKey,
key: BlobImageKey,
descriptor: &ImageDescriptor,
dirty_rect: &Option<DeviceIntRect>,
dirty_rect: &BlobDirtyRect,
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();
@ -852,11 +870,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,
};
}
@ -872,9 +886,10 @@ impl ResourceCache {
match value {
Some(image) => if image.data.is_blob() {
self.blob_image_handler.as_mut().unwrap().delete(image_key);
self.blob_image_templates.remove(&image_key);
self.rasterized_blob_images.remove(&image_key);
let blob_key = BlobImageKey(image_key);
self.blob_image_handler.as_mut().unwrap().delete(blob_key);
self.blob_image_templates.remove(&blob_key);
self.rasterized_blob_images.remove(&blob_key);
},
None => {
warn!("Delete the non-exist key");
@ -890,11 +905,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;
}
}
@ -953,7 +968,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::All,
manual_eviction: false,
}))
}
@ -976,7 +991,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::All,
manual_eviction: false,
})
} else {
@ -993,7 +1008,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::All,
manual_eviction: false,
})
},
@ -1002,7 +1017,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
}
@ -1021,38 +1036,31 @@ impl ResourceCache {
// For some reason the blob image is missing. We'll fall back to
// rasterizing it on the render backend thread.
if missing {
let descriptor = match template.tiling {
Some(tile_size) => {
let tile = request.tile.unwrap();
BlobImageDescriptor {
offset: DevicePoint::new(
tile.x as f32 * tile_size as f32,
tile.y as f32 * tile_size as f32,
),
size: compute_tile_size(
&template.descriptor,
tile_size,
tile,
),
format: template.descriptor.format,
let descriptor = BlobImageDescriptor {
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,
tile_size,
tile,
)),
}
}
}
None => {
BlobImageDescriptor {
offset: DevicePoint::origin(),
size: template.descriptor.size,
format: template.descriptor.format,
}
}
None => blob_size(template.descriptor.size).into(),
},
format: template.descriptor.format,
};
assert!(descriptor.size.width != 0 && descriptor.size.height != 0);
assert!(!descriptor.rect.is_empty());
self.missing_blob_images.push(
BlobImageParams {
request,
descriptor,
dirty_rect: None,
dirty_rect: DirtyRect::All,
}
);
}
@ -1061,7 +1069,7 @@ impl ResourceCache {
pub fn create_blob_scene_builder_requests(
&mut self,
keys: &[ImageKey]
keys: &[BlobImageKey]
) -> (Option<Box<AsyncBlobImageRasterizer>>, Vec<BlobImageParams>) {
if self.blob_image_handler.is_none() {
return (None, Vec::new());
@ -1085,8 +1093,9 @@ impl ResourceCache {
)
});
let image_dirty_rect = to_image_dirty_rect(&template.dirty_rect);
// Don't request tiles that weren't invalidated.
if let Some(dirty_rect) = template.dirty_rect {
if let DirtyRect::Partial(dirty_rect) = image_dirty_rect {
let dirty_rect = DeviceIntRect {
origin: point2(
dirty_rect.origin.x,
@ -1122,15 +1131,14 @@ impl ResourceCache {
for_each_tile_in_range(&tiles, |tile| {
let descriptor = BlobImageDescriptor {
offset: DevicePoint::new(
tile.x as f32 * tile_size as f32,
tile.y as f32 * tile_size as f32,
),
size: compute_tile_size(
&template.descriptor,
tile_size,
tile,
),
rect: LayoutIntRect {
origin: point2(tile.x, tile.y) * tile_size as i32,
size: blob_size(compute_tile_size(
&template.descriptor,
tile_size,
tile,
)),
},
format: template.descriptor.format,
};
@ -1144,12 +1152,12 @@ impl ResourceCache {
tile: Some(tile),
},
descriptor,
dirty_rect: None,
dirty_rect: DirtyRect::All,
}
);
});
} else {
let mut needs_upload = match self.cached_images.try_get(&key) {
let mut needs_upload = match self.cached_images.try_get(&key.as_image()) {
Some(&ImageResult::UntiledAuto(ref entry)) => {
self.texture_cache.needs_upload(&entry.texture_cache_handle)
}
@ -1166,7 +1174,7 @@ impl ResourceCache {
//
// We do the latter here but it's not ideal and might want to revisit and do
// the former instead.
match self.rasterized_blob_images.get(&key) {
match self.rasterized_blob_images.get(key) {
Some(RasterizedBlob::NonTiled(ref queue)) => {
if queue.len() > 2 {
needs_upload = true;
@ -1177,7 +1185,7 @@ impl ResourceCache {
let dirty_rect = if needs_upload {
// The texture cache entry has been evicted, treat it as all dirty.
None
DirtyRect::All
} else {
template.dirty_rect
};
@ -1189,15 +1197,14 @@ impl ResourceCache {
tile: None,
},
descriptor: BlobImageDescriptor {
offset: DevicePoint::zero(),
size: template.descriptor.size,
rect: blob_size(template.descriptor.size).into(),
format: template.descriptor.format,
},
dirty_rect,
}
);
}
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);
@ -1206,7 +1213,7 @@ impl ResourceCache {
fn discard_tiles_outside_visible_area(
&mut self,
key: ImageKey,
key: BlobImageKey,
area: &DeviceIntRect
) {
let template = match self.blob_image_templates.get(&key) {
@ -1234,7 +1241,7 @@ impl ResourceCache {
tiles.retain(|tile, _| { tile_range.contains(tile) });
let texture_cache = &mut self.texture_cache;
match self.cached_images.try_get_mut(&key) {
match self.cached_images.try_get_mut(&key.as_image()) {
Some(&mut ImageResult::Multi(ref mut entries)) => {
entries.retain(|key, entry| {
if key.tile.is_none() || tile_range.contains(&key.tile.unwrap()) {
@ -1426,13 +1433,13 @@ impl ResourceCache {
image_template.map(|image_template| {
let external_image = match image_template.data {
ImageData::External(ext_image) => match ext_image.image_type {
CachedImageData::External(ext_image) => match ext_image.image_type {
ExternalImageType::TextureHandle(_) => Some(ext_image),
// external buffer uses resource_cache.
ExternalImageType::Buffer => None,
},
// raw and blob image are all using resource_cache.
ImageData::Raw(..) | ImageData::Blob(..) => None,
CachedImageData::Raw(..) | CachedImageData::Blob => None,
};
ImageProperties {
@ -1511,29 +1518,29 @@ impl ResourceCache {
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
debug_assert!(image_template.data.uses_texture_cache());
let mut updates: SmallVec<[(ImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
let mut updates: SmallVec<[(CachedImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
match image_template.data {
ImageData::Raw(..) | ImageData::External(..) => {
CachedImageData::Raw(..) | CachedImageData::External(..) => {
// Safe to clone here since the Raw image data is an
// Arc, and the external image data is small.
updates.push((image_template.data.clone(), None));
}
ImageData::Blob(..) => {
CachedImageData::Blob => {
let blob_image = self.rasterized_blob_images.get_mut(&request.key).unwrap();
let blob_image = self.rasterized_blob_images.get_mut(&BlobImageKey(request.key)).unwrap();
match (blob_image, request.tile) {
(RasterizedBlob::Tiled(ref tiles), Some(tile)) => {
let img = &tiles[&tile];
updates.push((
ImageData::Raw(Arc::clone(&img.data)),
CachedImageData::Raw(Arc::clone(&img.data)),
Some(img.rasterized_rect)
));
}
(RasterizedBlob::NonTiled(ref mut queue), None) => {
for img in queue.drain(..) {
updates.push((
ImageData::Raw(img.data),
CachedImageData::Raw(img.data),
Some(img.rasterized_rect)
));
}
@ -1554,23 +1561,12 @@ impl ResourceCache {
};
let mut descriptor = image_template.descriptor.clone();
let mut local_dirty_rect;
let mut dirty_rect = entry.dirty_rect.replace_with_empty();
if let Some(tile) = request.tile {
let tile_size = image_template.tiling.unwrap();
let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
local_dirty_rect = if let Some(rect) = entry.dirty_rect.take() {
// We should either have a dirty rect, or we are re-uploading where the dirty
// rect is ignored anyway.
let intersection = intersect_for_tile(rect, clipped_tile_size, tile_size, tile);
debug_assert!(intersection.is_some() ||
self.texture_cache.needs_upload(&entry.texture_cache_handle));
intersection
} else {
None
};
// 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.
@ -1585,15 +1581,13 @@ impl ResourceCache {
}
descriptor.size = clipped_tile_size;
} else {
local_dirty_rect = entry.dirty_rect.take();
}
// 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() {
local_dirty_rect = blob_rasterized_rect;
if let Some(rect) = blob_rasterized_rect {
dirty_rect = DirtyRect::Partial(rect);
}
let filter = match request.rendering {
@ -1636,7 +1630,7 @@ impl ResourceCache {
filter,
Some(image_data),
[0.0; 3],
local_dirty_rect,
dirty_rect,
gpu_cache,
None,
UvRectKind::Rect,
@ -1714,9 +1708,8 @@ impl ResourceCache {
// Measure images.
for (_, image) in self.resources.image_templates.images.iter() {
report.images += match image.data {
ImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
ImageData::Blob(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
ImageData::External(..) => 0,
CachedImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
CachedImageData::Blob | CachedImageData::External(..) => 0,
}
}
@ -1747,11 +1740,11 @@ impl ResourceCache {
self.delete_image_template(key);
}
let blob_f = |key: &BlobImageKey| { f(&key.as_image()) };
debug_assert!(!self.resources.image_templates.images.keys().any(&f));
debug_assert!(!self.cached_images.resources.keys().any(&f));
debug_assert!(!self.blob_image_templates.keys().any(&f));
debug_assert!(!self.rasterized_blob_images.keys().any(&f));
debug_assert!(!self.blob_image_templates.keys().any(&blob_f));
debug_assert!(!self.rasterized_blob_images.keys().any(&blob_f));
}
}
@ -1855,6 +1848,19 @@ pub struct PlainCacheOwn {
#[cfg(feature = "replay")]
const NATIVE_FONT: &'static [u8] = include_bytes!("../res/Proggy.ttf");
// This currently only casts the unit but will soon apply an offset
fn to_image_dirty_rect(blob_dirty_rect: &BlobDirtyRect) -> ImageDirtyRect {
match *blob_dirty_rect {
DirtyRect::Partial(rect) => DirtyRect::Partial(
DeviceIntRect {
origin: DeviceIntPoint::new(rect.origin.x, rect.origin.y),
size: DeviceIntSize::new(rect.size.width, rect.size.height),
}
),
DirtyRect::All => DirtyRect::All,
}
}
impl ResourceCache {
#[cfg(feature = "capture")]
pub fn save_capture(
@ -1913,7 +1919,7 @@ impl ResourceCache {
for (&key, template) in res.image_templates.images.iter() {
let desc = &template.descriptor;
match template.data {
ImageData::Raw(ref arc) => {
CachedImageData::Raw(ref arc) => {
let image_id = image_paths.len() + 1;
let entry = match image_paths.entry(arc.as_ptr()) {
Entry::Occupied(_) => continue,
@ -1935,22 +1941,21 @@ impl ResourceCache {
.unwrap();
entry.insert(short_path);
}
ImageData::Blob(_) => {
CachedImageData::Blob => {
assert_eq!(template.tiling, None);
let blob_request_params = &[
BlobImageParams {
request: BlobImageRequest {
key,
key: BlobImageKey(key),
//TODO: support tiled blob images
// https://github.com/servo/webrender/issues/2236
tile: None,
},
descriptor: BlobImageDescriptor {
size: desc.size,
offset: DevicePoint::zero(),
rect: blob_size(desc.size).into(),
format: desc.format,
},
dirty_rect: None,
dirty_rect: DirtyRect::All,
}
];
@ -1980,7 +1985,7 @@ impl ResourceCache {
.unwrap();
other_paths.insert(key, short_path);
}
ImageData::External(ref ext) => {
CachedImageData::External(ref ext) => {
let short_path = format!("externals/{}", external_images.len() + 1);
other_paths.insert(key, short_path.clone());
external_images.push(ExternalCaptureImage {
@ -2015,7 +2020,7 @@ impl ResourceCache {
.map(|(key, template)| {
(*key, PlainImageTemplate {
data: match template.data {
ImageData::Raw(ref arc) => image_paths[&arc.as_ptr()].clone(),
CachedImageData::Raw(ref arc) => image_paths[&arc.as_ptr()].clone(),
_ => other_paths[key].clone(),
},
descriptor: template.descriptor.clone(),
@ -2121,7 +2126,7 @@ impl ResourceCache {
Some(plain) => {
let ext_data = plain.external;
external_images.push(plain);
ImageData::External(ext_data)
CachedImageData::External(ext_data)
}
None => {
let arc = match raw_map.entry(template.data) {
@ -2138,7 +2143,7 @@ impl ResourceCache {
.clone()
}
};
ImageData::Raw(arc)
CachedImageData::Raw(arc)
}
};
@ -2153,3 +2158,12 @@ impl ResourceCache {
external_images
}
}
/// For now the blob's coordinate space have the same pixel sizes as the
/// rendered texture's device space (only a translation is applied).
/// So going from one to the other is only a matter of casting away the unit
/// for sizes.
#[inline]
fn blob_size(device_size: DeviceIntSize) -> LayoutIntSize {
size2(device_size.width, device_size.height)
}

Просмотреть файл

@ -2,8 +2,8 @@
* 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::{DebugFlags, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{ExternalImageType, ImageData, ImageFormat};
use api::{DebugFlags, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DirtyRect, ImageDirtyRect};
use api::{ExternalImageType, ImageFormat};
use api::ImageDescriptor;
use device::{TextureFilter, total_gpu_bytes_allocated};
use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
@ -13,7 +13,7 @@ use internal_types::{CacheTextureId, LayerIndex, TextureUpdateList, TextureUpdat
use internal_types::{TextureSource, TextureCacheAllocInfo, TextureCacheUpdate};
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
use render_backend::{FrameId, FrameStamp};
use resource_cache::CacheItem;
use resource_cache::{CacheItem, CachedImageData};
use std::cell::Cell;
use std::cmp;
use std::mem;
@ -673,9 +673,9 @@ impl TextureCache {
handle: &mut TextureCacheHandle,
descriptor: ImageDescriptor,
filter: TextureFilter,
data: Option<ImageData>,
data: Option<CachedImageData>,
user_data: [f32; 3],
mut dirty_rect: Option<DeviceIntRect>,
mut dirty_rect: ImageDirtyRect,
gpu_cache: &mut GpuCache,
eviction_notice: Option<&EvictionNotice>,
uv_rect_kind: UvRectKind,
@ -702,7 +702,7 @@ impl TextureCache {
self.allocate(&params, handle);
// If we reallocated, we need to upload the whole item again.
dirty_rect = None;
dirty_rect = DirtyRect::All;
}
let entry = self.entries.get_opt_mut(handle)
@ -742,7 +742,7 @@ impl TextureCache {
entry.size,
entry.texture_id,
layer_index as i32,
dirty_rect,
&dirty_rect,
);
self.pending_updates.push_update(op);
}
@ -1385,19 +1385,19 @@ impl TextureCacheUpdate {
// rendering thread in order to do an upload to the right
// location in the texture cache.
fn new_update(
data: ImageData,
data: CachedImageData,
descriptor: &ImageDescriptor,
origin: DeviceIntPoint,
size: DeviceIntSize,
texture_id: CacheTextureId,
layer_index: i32,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: &ImageDirtyRect,
) -> TextureCacheUpdate {
let source = match data {
ImageData::Blob(..) => {
CachedImageData::Blob => {
panic!("The vector image should have been rasterized.");
}
ImageData::External(ext_image) => match ext_image.image_type {
CachedImageData::External(ext_image) => match ext_image.image_type {
ExternalImageType::TextureHandle(_) => {
panic!("External texture handle should not go through texture_cache.");
}
@ -1406,7 +1406,7 @@ impl TextureCacheUpdate {
channel_index: ext_image.channel_index,
},
},
ImageData::Raw(bytes) => {
CachedImageData::Raw(bytes) => {
let finish = descriptor.offset +
descriptor.size.width * descriptor.format.bytes_per_pixel() +
(descriptor.size.height - 1) * descriptor.compute_stride();
@ -1416,8 +1416,8 @@ impl TextureCacheUpdate {
}
};
let update_op = match dirty_rect {
Some(dirty) => {
let update_op = match *dirty_rect {
DirtyRect::Partial(dirty) => {
// the dirty rectangle doesn't have to be within the area but has to intersect it, at least
let stride = descriptor.compute_stride();
let offset = descriptor.offset + dirty.origin.y * stride + dirty.origin.x * descriptor.format.bytes_per_pixel();
@ -1437,7 +1437,7 @@ impl TextureCacheUpdate {
layer_index,
}
}
None => {
DirtyRect::All => {
TextureCacheUpdate {
id: texture_id,
rect: DeviceIntRect::new(origin, size),

Просмотреть файл

@ -11,11 +11,13 @@ use std::fmt;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::sync::Arc;
use std::u32;
use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceIntRect};
use {DeviceIntSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphIndex, ImageData};
use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
use {ImageDescriptor, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
use {BlobDirtyRect, ImageDirtyRect, ImageKey, BlobImageKey, BlobImageData};
use {NativeFontHandle, WorldPoint};
pub type TileSize = u16;
@ -26,8 +28,10 @@ pub type DocumentLayer = i8;
pub enum ResourceUpdate {
AddImage(AddImage),
UpdateImage(UpdateImage),
AddBlobImage(AddBlobImage),
UpdateBlobImage(UpdateBlobImage),
DeleteImage(ImageKey),
SetImageVisibleArea(ImageKey, DeviceIntRect),
SetBlobImageVisibleArea(BlobImageKey, DeviceIntRect),
AddFont(AddFont),
DeleteFont(FontKey),
AddFontInstance(AddFontInstance),
@ -321,13 +325,13 @@ impl Transaction {
key: ImageKey,
descriptor: ImageDescriptor,
data: ImageData,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: &ImageDirtyRect,
) {
self.resource_updates.push(ResourceUpdate::UpdateImage(UpdateImage {
key,
descriptor,
data,
dirty_rect,
dirty_rect: *dirty_rect,
}));
}
@ -335,8 +339,46 @@ impl Transaction {
self.resource_updates.push(ResourceUpdate::DeleteImage(key));
}
pub fn set_image_visible_area(&mut self, key: ImageKey, area: DeviceIntRect) {
self.resource_updates.push(ResourceUpdate::SetImageVisibleArea(key, area))
pub fn add_blob_image(
&mut self,
key: BlobImageKey,
descriptor: ImageDescriptor,
data: Arc<BlobImageData>,
tiling: Option<TileSize>,
) {
self.resource_updates.push(
ResourceUpdate::AddBlobImage(AddBlobImage {
key,
descriptor,
data,
tiling,
})
);
}
pub fn update_blob_image(
&mut self,
key: BlobImageKey,
descriptor: ImageDescriptor,
data: Arc<BlobImageData>,
dirty_rect: &BlobDirtyRect,
) {
self.resource_updates.push(
ResourceUpdate::UpdateBlobImage(UpdateBlobImage {
key,
descriptor,
data,
dirty_rect: *dirty_rect,
})
);
}
pub fn delete_blob_image(&mut self, key: BlobImageKey) {
self.resource_updates.push(ResourceUpdate::DeleteImage(key.as_image()));
}
pub fn set_blob_image_visible_area(&mut self, key: BlobImageKey, area: DeviceIntRect) {
self.resource_updates.push(ResourceUpdate::SetBlobImageVisibleArea(key, area))
}
pub fn add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32) {
@ -464,7 +506,25 @@ pub struct UpdateImage {
pub key: ImageKey,
pub descriptor: ImageDescriptor,
pub data: ImageData,
pub dirty_rect: Option<DeviceIntRect>,
pub dirty_rect: ImageDirtyRect,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AddBlobImage {
pub key: BlobImageKey,
pub descriptor: ImageDescriptor,
//#[serde(with = "serde_image_data_raw")]
pub data: Arc<BlobImageData>,
pub tiling: Option<TileSize>,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct UpdateBlobImage {
pub key: BlobImageKey,
pub descriptor: ImageDescriptor,
//#[serde(with = "serde_image_data_raw")]
pub data: Arc<BlobImageData>,
pub dirty_rect: BlobDirtyRect,
}
#[derive(Clone, Deserialize, Serialize)]
@ -1011,6 +1071,11 @@ impl RenderApi {
ImageKey::new(self.namespace_id, new_id)
}
/// Creates a `BlobImageKey`.
pub fn generate_blob_image_key(&self) -> BlobImageKey {
BlobImageKey(self.generate_image_key())
}
/// Add/remove/update resources such as images and fonts.
pub fn update_resources(&self, resources: Vec<ResourceUpdate>) {
if resources.is_empty() {

Просмотреть файл

@ -8,9 +8,10 @@ extern crate serde_bytes;
use font::{FontInstanceKey, FontInstanceData, FontKey, FontTemplate};
use std::sync::Arc;
use {DevicePoint, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use {IdNamespace, TileOffset, TileSize};
use euclid::size2;
use {DeviceIntPoint, DeviceIntRect, DeviceIntSize, LayoutIntRect};
use {BlobDirtyRect, IdNamespace, TileOffset, TileSize};
use euclid::{size2, TypedRect, num::Zero};
use std::ops::{Add, Sub};
/// An opaque identifier describing an image registered with WebRender.
/// This is used as a handle to reference images, and is used as the
@ -29,6 +30,20 @@ impl ImageKey {
}
}
/// An opaque identifier describing a blob image registered with WebRender.
/// This is used as a handle to reference blob images, and can be used as an
/// image in display items.
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct BlobImageKey(pub ImageKey);
impl BlobImageKey {
/// Interpret this blob image as an image for a display item.
pub fn as_image(&self) -> ImageKey {
self.0
}
}
/// An arbitrary identifier for an external image provided by the
/// application. It must be a unique identifier for each external
/// image.
@ -228,9 +243,6 @@ pub enum ImageData {
/// A simple series of bytes, provided by the embedding and owned by WebRender.
/// The format is stored out-of-band, currently in ImageDescriptor.
Raw(#[serde(with = "serde_image_data_raw")] Arc<Vec<u8>>),
/// An series of commands that can be rasterized into an image via an
/// embedding-provided callback.
Blob(#[serde(with = "serde_image_data_raw")] Arc<BlobImageData>),
/// An image owned by the embedding, and referenced by WebRender. This may
/// take the form of a texture or a heap-allocated buffer.
External(ExternalImageData),
@ -261,34 +273,6 @@ impl ImageData {
pub fn new_shared(bytes: Arc<Vec<u8>>) -> Self {
ImageData::Raw(bytes)
}
/// Mints a new Blob ImageData.
pub fn new_blob_image(commands: BlobImageData) -> Self {
ImageData::Blob(Arc::new(commands))
}
/// Returns true if this ImageData represents a blob.
#[inline]
pub fn is_blob(&self) -> bool {
match *self {
ImageData::Blob(_) => true,
_ => false,
}
}
/// Returns true if this variant of ImageData should go through the texture
/// cache.
#[inline]
pub fn uses_texture_cache(&self) -> bool {
match *self {
ImageData::External(ref ext_data) => match ext_data.image_type {
ExternalImageType::TextureHandle(_) => false,
ExternalImageType::Buffer => true,
},
ImageData::Blob(_) => true,
ImageData::Raw(_) => true,
}
}
}
/// The resources exposed by the resource cache available for use by the blob rasterizer.
@ -297,8 +281,6 @@ pub trait BlobImageResources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate;
/// Returns the `FontInstanceData` for the given key, if found.
fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData>;
/// Returns the image metadata and backing store for the given key, if found.
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}
/// A handler on the render backend that can create rasterizer objects which will
@ -319,13 +301,13 @@ pub trait BlobImageHandler: Send {
);
/// Register a blob image.
fn add(&mut self, key: ImageKey, data: Arc<BlobImageData>, tiling: Option<TileSize>);
fn add(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, tiling: Option<TileSize>);
/// Update an already registered blob image.
fn update(&mut self, key: ImageKey, data: Arc<BlobImageData>, dirty_rect: Option<DeviceIntRect>);
fn update(&mut self, key: BlobImageKey, data: Arc<BlobImageData>, dirty_rect: &BlobDirtyRect);
/// Delete an already registered blob image.
fn delete(&mut self, key: ImageKey);
fn delete(&mut self, key: BlobImageKey);
/// A hook to let the handler clean up any state related to a font which the resource
/// cache is about to delete.
@ -365,7 +347,100 @@ pub struct BlobImageParams {
/// the entire image when only a portion is updated.
///
/// If set to None the entire image is rasterized.
pub dirty_rect: Option<DeviceIntRect>,
pub dirty_rect: BlobDirtyRect,
}
/// The possible states of a Dirty rect.
///
/// This exists because people kept getting confused with `Option<Rect>`.
#[derive(Debug, Serialize, Deserialize)]
pub enum DirtyRect<T: Copy, U> {
/// Everything is Dirty, equivalent to Partial(image_bounds)
All,
/// Some specific amount is dirty
Partial(TypedRect<T, U>)
}
impl<T, U> DirtyRect<T, U>
where
T: Copy + Clone
+ PartialOrd + PartialEq
+ Add<T, Output = T>
+ Sub<T, Output = T>
+ Zero
{
/// Creates an empty DirtyRect (indicating nothing is invalid)
pub fn empty() -> Self {
DirtyRect::Partial(TypedRect::zero())
}
/// Returns whether the dirty rect is empty
pub fn is_empty(&self) -> bool {
match self {
DirtyRect::All => false,
DirtyRect::Partial(rect) => rect.is_empty(),
}
}
/// Replaces self with the empty rect and returns the old value.
pub fn replace_with_empty(&mut self) -> Self {
::std::mem::replace(self, DirtyRect::empty())
}
/// Maps over the contents of Partial.
pub fn map<F>(self, func: F) -> Self
where F: FnOnce(TypedRect<T, U>) -> TypedRect<T, U>,
{
use DirtyRect::*;
match self {
All => All,
Partial(rect) => Partial(func(rect)),
}
}
/// Unions the dirty rects.
pub fn union(&self, other: &Self) -> Self {
use DirtyRect::*;
match (*self, *other) {
(All, _) | (_, All) => All,
(Partial(rect1), Partial(rect2)) => Partial(rect1.union(&rect2)),
}
}
/// Intersects the dirty rects.
pub fn intersection(&self, other: &Self) -> Self {
use DirtyRect::*;
match (*self, *other) {
(All, rect) | (rect, All) => rect,
(Partial(rect1), Partial(rect2)) => Partial(rect1.intersection(&rect2)
.unwrap_or(TypedRect::zero()))
}
}
/// Converts the dirty rect into a subrect of the given one via intersection.
pub fn to_subrect_of(&self, rect: &TypedRect<T, U>) -> TypedRect<T, U> {
use DirtyRect::*;
match *self {
All => *rect,
Partial(dirty_rect) => dirty_rect.intersection(rect)
.unwrap_or(TypedRect::zero()),
}
}
}
impl<T: Copy, U> Copy for DirtyRect<T, U> {}
impl<T: Copy, U> Clone for DirtyRect<T, U> {
fn clone(&self) -> Self { *self }
}
impl<T: Copy, U> From<TypedRect<T, U>> for DirtyRect<T, U> {
fn from(rect: TypedRect<T, U>) -> Self {
DirtyRect::Partial(rect)
}
}
/// Backing store for blob image command streams.
@ -378,11 +453,9 @@ pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct BlobImageDescriptor {
/// Size in device pixels of the blob's output image.
pub size: DeviceIntSize,
/// When tiling, offset point in device pixels of this tile in the full
/// image. Generally (0, 0) outside of tiling.
pub offset: DevicePoint,
/// Surface of the image or tile to render in the same coordinate space as
/// the drawing commands.
pub rect: LayoutIntRect,
/// Format for the data in the backing store.
pub format: ImageFormat,
}
@ -390,7 +463,8 @@ pub struct BlobImageDescriptor {
/// Representation of a rasterized blob image. This is obtained by passing
/// `BlobImageData` to the embedding via the rasterization callback.
pub struct RasterizedBlobImage {
/// The bounding rectangle for this blob image.
/// The rectangle that was rasterized in device pixels, relative to the
/// image or tile.
pub rasterized_rect: DeviceIntRect,
/// Backing store. The format is stored out of band in `BlobImageDescriptor`.
pub data: Arc<Vec<u8>>,
@ -412,7 +486,7 @@ pub enum BlobImageError {
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BlobImageRequest {
/// Unique handle to the image.
pub key: ImageKey,
pub key: BlobImageKey,
/// Tiling offset in number of tiles, if applicable.
///
/// `None` if the image will not be tiled.

Просмотреть файл

@ -13,12 +13,13 @@
//! in the context of coordinate systems.
use app_units::Au;
use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D};
use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D, TypedTranslation2D};
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D};
use DirtyRect;
/// Geometry in the coordinate system of the render target (screen or intermediate
/// surface) in physical pixels.
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct DevicePixel;
pub type DeviceIntRect = TypedRect<i32, DevicePixel>;
@ -75,6 +76,10 @@ pub type LayoutVector3D = TypedVector3D<f32, LayoutPixel>;
pub type LayoutSize = TypedSize2D<f32, LayoutPixel>;
pub type LayoutSideOffsets = TypedSideOffsets2D<f32, LayoutPixel>;
pub type LayoutIntRect = TypedRect<i32, LayoutPixel>;
pub type LayoutIntPoint = TypedPoint2D<i32, LayoutPixel>;
pub type LayoutIntSize = TypedSize2D<i32, LayoutPixel>;
/// Geometry in the document's coordinate space (logical pixels).
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct WorldPixel;
@ -119,6 +124,11 @@ pub type LayoutRectAu = TypedRect<Au, LayoutPixel>;
pub type LayoutSizeAu = TypedSize2D<Au, LayoutPixel>;
pub type LayoutVector2DAu = TypedVector2D<Au, LayoutPixel>;
pub type ImageDirtyRect = DirtyRect<i32, DevicePixel>;
pub type BlobDirtyRect = DirtyRect<i32, LayoutPixel>;
pub type BlobToDeviceTranslation = TypedTranslation2D<i32, LayoutPixel, DevicePixel>;
/// Stores two coordinates in texel space. The coordinates
/// are stored in texel coordinates because the texture atlas
/// may grow. Storing them as texel coords and normalizing

Просмотреть файл

@ -8,13 +8,11 @@ use std::collections::HashMap;
use std::sync::Arc;
use std::sync::Mutex;
use webrender::api::*;
use webrender::intersect_for_tile;
use euclid::size2;
// Serialize/deserialize the blob.
pub fn serialize_blob(color: ColorU) -> Vec<u8> {
vec![color.r, color.g, color.b, color.a]
pub fn serialize_blob(color: ColorU) -> Arc<Vec<u8>> {
Arc::new(vec![color.r, color.g, color.b, color.a])
}
fn deserialize_blob(blob: &[u8]) -> Result<ColorU, ()> {
@ -38,12 +36,11 @@ fn render_blob(
color: ColorU,
descriptor: &BlobImageDescriptor,
tile: Option<(TileSize, TileOffset)>,
dirty_rect: Option<DeviceIntRect>,
dirty_rect: &BlobDirtyRect,
) -> BlobImageResult {
// Allocate storage for the result. Right now the resource cache expects the
// tiles to have have no stride or offset.
let buf_size = descriptor.size.width *
descriptor.size.height *
let buf_size = descriptor.rect.size.area() *
descriptor.format.bytes_per_pixel();
let mut texels = vec![0u8; (buf_size) as usize];
@ -54,23 +51,19 @@ fn render_blob(
None => true,
};
let mut dirty_rect = dirty_rect.unwrap_or(DeviceIntRect::new(
descriptor.offset.to_i32(),
descriptor.size,
));
let dirty_rect = dirty_rect.to_subrect_of(&descriptor.rect);
if let Some((tile_size, tile)) = tile {
dirty_rect = intersect_for_tile(dirty_rect, size2(tile_size as i32, tile_size as i32),
tile_size, tile)
.expect("empty rects should be culled by webrender");
}
// We want the dirty rect local to the tile rather than the whole image.
let tx: BlobToDeviceTranslation = (-descriptor.rect.origin.to_vector()).into();
for y in dirty_rect.min_y() .. dirty_rect.max_y() {
for x in dirty_rect.min_x() .. dirty_rect.max_x() {
let rasterized_rect = tx.transform_rect(&dirty_rect);
for y in rasterized_rect.min_y() .. rasterized_rect.max_y() {
for x in rasterized_rect.min_x() .. rasterized_rect.max_x() {
// Apply the tile's offset. This is important: all drawing commands should be
// translated by this offset to give correct results with tiled blob images.
let x2 = x + descriptor.offset.x as i32;
let y2 = y + descriptor.offset.y as i32;
let x2 = x + descriptor.rect.origin.x;
let y2 = y + descriptor.rect.origin.y;
// Render a simple checkerboard pattern
let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) {
@ -84,13 +77,14 @@ fn render_blob(
match descriptor.format {
ImageFormat::BGRA8 => {
let a = color.a * checker + tc;
texels[((y * descriptor.size.width + x) * 4 + 0) as usize] = premul(color.b * checker + tc, a);
texels[((y * descriptor.size.width + x) * 4 + 1) as usize] = premul(color.g * checker + tc, a);
texels[((y * descriptor.size.width + x) * 4 + 2) as usize] = premul(color.r * checker + tc, a);
texels[((y * descriptor.size.width + x) * 4 + 3) as usize] = a;
let pixel_offset = ((y * descriptor.rect.size.width + x) * 4) as usize;
texels[pixel_offset + 0] = premul(color.b * checker + tc, a);
texels[pixel_offset + 1] = premul(color.g * checker + tc, a);
texels[pixel_offset + 2] = premul(color.r * checker + tc, a);
texels[pixel_offset + 3] = a;
}
ImageFormat::R8 => {
texels[(y * descriptor.size.width + x) as usize] = color.a * checker + tc;
texels[(y * descriptor.rect.size.width + x) as usize] = color.a * checker + tc;
}
_ => {
return Err(BlobImageError::Other(
@ -103,7 +97,7 @@ fn render_blob(
Ok(RasterizedBlobImage {
data: Arc::new(texels),
rasterized_rect: dirty_rect,
rasterized_rect,
})
}
@ -120,7 +114,7 @@ impl BlobCallbacks {
}
pub struct CheckerboardRenderer {
image_cmds: HashMap<ImageKey, (ColorU, Option<TileSize>)>,
image_cmds: HashMap<BlobImageKey, (ColorU, Option<TileSize>)>,
callbacks: Arc<Mutex<BlobCallbacks>>,
}
@ -134,18 +128,18 @@ impl CheckerboardRenderer {
}
impl BlobImageHandler for CheckerboardRenderer {
fn add(&mut self, key: ImageKey, cmds: Arc<BlobImageData>, tile_size: Option<TileSize>) {
fn add(&mut self, key: BlobImageKey, cmds: Arc<BlobImageData>, tile_size: Option<TileSize>) {
self.image_cmds
.insert(key, (deserialize_blob(&cmds[..]).unwrap(), tile_size));
}
fn update(&mut self, key: ImageKey, cmds: Arc<BlobImageData>, _dirty_rect: Option<DeviceIntRect>) {
fn update(&mut self, key: BlobImageKey, cmds: Arc<BlobImageData>, _dirty_rect: &BlobDirtyRect) {
// Here, updating is just replacing the current version of the commands with
// the new one (no incremental updates).
self.image_cmds.get_mut(&key).unwrap().0 = deserialize_blob(&cmds[..]).unwrap();
}
fn delete(&mut self, key: ImageKey) {
fn delete(&mut self, key: BlobImageKey) {
self.image_cmds.remove(&key);
}
@ -175,11 +169,11 @@ struct Command {
color: ColorU,
descriptor: BlobImageDescriptor,
tile: Option<(TileSize, TileOffset)>,
dirty_rect: Option<DeviceIntRect>
dirty_rect: BlobDirtyRect,
}
struct Rasterizer {
image_cmds: HashMap<ImageKey, (ColorU, Option<TileSize>)>,
image_cmds: HashMap<BlobImageKey, (ColorU, Option<TileSize>)>,
}
impl AsyncBlobImageRasterizer for Rasterizer {
@ -205,7 +199,7 @@ impl AsyncBlobImageRasterizer for Rasterizer {
).collect();
requests.iter().map(|cmd| {
(cmd.request, render_blob(cmd.color, &cmd.descriptor, cmd.tile, cmd.dirty_rect))
(cmd.request, render_blob(cmd.color, &cmd.descriptor, cmd.tile, &cmd.dirty_rect))
}).collect()
}
}

Просмотреть файл

@ -120,7 +120,7 @@ impl JsonFrameWriter {
);
let bytes = match img.data {
ImageData::Raw(ref v) => (**v).clone(),
ImageData::External(_) | ImageData::Blob(_) => {
ImageData::External(_) => {
return;
}
};
@ -154,6 +154,10 @@ impl JsonFrameWriter {
}
}
}
ResourceUpdate::AddBlobImage(..)
| ResourceUpdate::UpdateBlobImage(..) => {
println!("Blob images not supported (ignoring command).");
}
ResourceUpdate::DeleteImage(img) => {
self.images.remove(&img);
}
@ -177,7 +181,7 @@ impl JsonFrameWriter {
);
}
ResourceUpdate::DeleteFontInstance(_) => {}
ResourceUpdate::SetImageVisibleArea(..) => {}
ResourceUpdate::SetBlobImageVisibleArea(..) => {}
}
}
}

Просмотреть файл

@ -94,11 +94,11 @@ impl<'a> RawtestHarness<'a> {
let layout_size = LayoutSize::new(800., 800.);
let mut txn = Transaction::new();
let blob_img = self.wrench.api.generate_image_key();
txn.add_image(
let blob_img = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
blob_img,
ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
Some(128),
);
@ -113,7 +113,7 @@ impl<'a> RawtestHarness<'a> {
size(151.0, 56.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -127,7 +127,7 @@ impl<'a> RawtestHarness<'a> {
// Leaving a tiled blob image in the resource cache
// confuses the `test_capture`. TODO: remove this
txn = Transaction::new();
txn.delete_image(blob_img);
txn.delete_blob_image(blob_img);
self.wrench.api.update_resources(txn.resource_updates);
}
@ -149,11 +149,11 @@ impl<'a> RawtestHarness<'a> {
let layout_size = LayoutSize::new(800., 800.);
let mut txn = Transaction::new();
let blob_img = self.wrench.api.generate_image_key();
txn.add_image(
let blob_img = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
blob_img,
ImageDescriptor::new(1510, 111256, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
Some(31),
);
@ -180,10 +180,10 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
txn.set_image_visible_area(
txn.set_blob_image_visible_area(
blob_img,
DeviceIntRect {
origin: point2(0, 111256 / 30),
@ -235,7 +235,7 @@ impl<'a> RawtestHarness<'a> {
// Leaving a tiled blob image in the resource cache
// confuses the `test_capture`. TODO: remove this
txn = Transaction::new();
txn.delete_image(blob_img);
txn.delete_blob_image(blob_img);
self.wrench.api.update_resources(txn.resource_updates);
*self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
@ -265,8 +265,8 @@ impl<'a> RawtestHarness<'a> {
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
let mut txn = Transaction::new();
let blob_img1 = self.wrench.api.generate_image_key();
txn.add_image(
let blob_img1 = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
blob_img1,
ImageDescriptor::new(
image_size.width as i32,
@ -275,7 +275,7 @@ impl<'a> RawtestHarness<'a> {
false,
false
),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
Some(100),
);
@ -285,7 +285,7 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img1,
blob_img1.as_image(),
ColorF::WHITE,
);
@ -295,8 +295,8 @@ impl<'a> RawtestHarness<'a> {
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
let mut txn = Transaction::new();
let blob_img2 = self.wrench.api.generate_image_key();
txn.add_image(
let blob_img2 = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
blob_img2,
ImageDescriptor::new(
image_size.width as i32,
@ -305,12 +305,12 @@ impl<'a> RawtestHarness<'a> {
false,
false
),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
Some(100),
);
// Set a visible rectangle that is too small.
// This will force sync rasterization of the missing tiles during frame building.
txn.set_image_visible_area(blob_img2, DeviceIntRect {
txn.set_blob_image_visible_area(blob_img2, DeviceIntRect {
origin: point2(200, 200),
size: size2(80, 80),
});
@ -321,7 +321,7 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img2,
blob_img2.as_image(),
ColorF::WHITE,
);
@ -331,8 +331,8 @@ impl<'a> RawtestHarness<'a> {
assert!(pixels1 == pixels2);
txn = Transaction::new();
txn.delete_image(blob_img1);
txn.delete_image(blob_img2);
txn.delete_blob_image(blob_img1);
txn.delete_blob_image(blob_img2);
self.wrench.api.update_resources(txn.resource_updates);
}
@ -354,11 +354,11 @@ impl<'a> RawtestHarness<'a> {
let mut txn = Transaction::new();
let layout_size = LayoutSize::new(800., 800.);
let blob_img = self.wrench.api.generate_image_key();
txn.add_image(
let blob_img = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
blob_img,
ImageDescriptor::new(1510, 1510, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
None,
);
@ -375,7 +375,7 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -400,7 +400,7 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -410,11 +410,11 @@ impl<'a> RawtestHarness<'a> {
let mut txn = Transaction::new();
txn.update_image(
txn.update_blob_image(
blob_img,
ImageDescriptor::new(1510, 1510, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
Some(rect(10, 10, 100, 100)),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
&rect(10, 10, 100, 100).into(),
);
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
@ -430,7 +430,7 @@ impl<'a> RawtestHarness<'a> {
image_size,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -445,7 +445,7 @@ impl<'a> RawtestHarness<'a> {
// Leaving a tiled blob image in the resource cache
// confuses the `test_capture`. TODO: remove this
txn = Transaction::new();
txn.delete_image(blob_img);
txn.delete_blob_image(blob_img);
self.wrench.api.update_resources(txn.resource_updates);
}
@ -465,11 +465,11 @@ impl<'a> RawtestHarness<'a> {
{
let api = &self.wrench.api;
blob_img = api.generate_image_key();
txn.add_image(
blob_img = api.generate_blob_image_key();
txn.add_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
None,
);
}
@ -491,7 +491,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -514,7 +514,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -553,18 +553,18 @@ impl<'a> RawtestHarness<'a> {
let (blob_img, blob_img2) = {
let api = &self.wrench.api;
blob_img = api.generate_image_key();
txn.add_image(
blob_img = api.generate_blob_image_key();
txn.add_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
None,
);
blob_img2 = api.generate_image_key();
txn.add_image(
blob_img2 = api.generate_blob_image_key();
txn.add_blob_image(
blob_img2,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(80, 50, 150, 255))),
blob::serialize_blob(ColorU::new(80, 50, 150, 255)),
None,
);
(blob_img, blob_img2)
@ -599,7 +599,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
builder.push_image(
@ -608,7 +608,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img2,
blob_img2.as_image(),
ColorF::WHITE,
);
};
@ -623,17 +623,17 @@ impl<'a> RawtestHarness<'a> {
// update and redraw both images
let mut txn = Transaction::new();
txn.update_image(
txn.update_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
Some(rect(100, 100, 100, 100)),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
&rect(100, 100, 100, 100).into(),
);
txn.update_image(
txn.update_blob_image(
blob_img2,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(59, 50, 150, 255))),
Some(rect(100, 100, 100, 100)),
blob::serialize_blob(ColorU::new(59, 50, 150, 255)),
&rect(100, 100, 100, 100).into(),
);
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
@ -644,11 +644,11 @@ impl<'a> RawtestHarness<'a> {
// only update the first image
let mut txn = Transaction::new();
txn.update_image(
txn.update_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
Some(rect(200, 200, 100, 100)),
blob::serialize_blob(ColorU::new(50, 150, 150, 255)),
&rect(200, 200, 100, 100).into(),
);
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
@ -679,11 +679,11 @@ impl<'a> RawtestHarness<'a> {
let mut txn = Transaction::new();
let blob_img = {
let img = self.wrench.api.generate_image_key();
txn.add_image(
let img = self.wrench.api.generate_blob_image_key();
txn.add_blob_image(
img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
None,
);
img
@ -699,7 +699,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -710,11 +710,11 @@ impl<'a> RawtestHarness<'a> {
// draw the blob image a second time after updating it with the same color
let mut txn = Transaction::new();
txn.update_image(
txn.update_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
Some(rect(100, 100, 100, 100)),
blob::serialize_blob(ColorU::new(50, 50, 150, 255)),
&rect(100, 100, 100, 100).into(),
);
// make a new display list that refers to the first image
@ -726,7 +726,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);
@ -735,11 +735,11 @@ impl<'a> RawtestHarness<'a> {
// draw the blob image a third time after updating it with a different color
let mut txn = Transaction::new();
txn.update_image(
txn.update_blob_image(
blob_img,
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
Some(rect(200, 200, 100, 100)),
blob::serialize_blob(ColorU::new(50, 150, 150, 255)),
&rect(200, 200, 100, 100).into(),
);
// make a new display list that refers to the first image
@ -751,7 +751,7 @@ impl<'a> RawtestHarness<'a> {
size(0.0, 0.0),
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
blob_img,
blob_img.as_image(),
ColorF::WHITE,
);

Просмотреть файл

@ -93,7 +93,7 @@ impl RonFrameWriter {
ResourceUpdate::AddImage(ref img) => {
let bytes = match img.data {
ImageData::Raw(ref v) => (**v).clone(),
ImageData::External(_) | ImageData::Blob(_) => {
ImageData::External(_) => {
return;
}
};
@ -118,7 +118,6 @@ impl RonFrameWriter {
data.path = None;
data.bytes = Some((**bytes).clone());
} else {
// Other existing image types only make sense within the gecko integration.
println!(
"Wrench only supports updating buffer images ({}).",
"ignoring update commands"
@ -126,6 +125,10 @@ impl RonFrameWriter {
}
}
}
ResourceUpdate::AddBlobImage(..)
| ResourceUpdate::UpdateBlobImage(..) => {
println!("Blob images not supported (ignoring command).");
}
ResourceUpdate::DeleteImage(img) => {
self.images.remove(&img);
}
@ -141,7 +144,7 @@ impl RonFrameWriter {
ResourceUpdate::DeleteFont(_) => {}
ResourceUpdate::AddFontInstance(_) => {}
ResourceUpdate::DeleteFontInstance(_) => {}
ResourceUpdate::SetImageVisibleArea(..) => {}
ResourceUpdate::SetBlobImageVisibleArea(..) => {}
}
}
}

Просмотреть файл

@ -550,7 +550,7 @@ impl YamlFrameWriter {
);
let bytes = match img.data {
ImageData::Raw(ref v) => (**v).clone(),
ImageData::External(_) | ImageData::Blob(_) => {
ImageData::External(_) => {
return;
}
};
@ -586,6 +586,10 @@ impl YamlFrameWriter {
}
}
}
ResourceUpdate::AddBlobImage(..)
| ResourceUpdate::UpdateBlobImage(..) => {
println!("Blob images not supported (ignoring command).");
}
ResourceUpdate::DeleteImage(img) => {
self.images.remove(&img);
}
@ -609,7 +613,7 @@ impl YamlFrameWriter {
);
}
ResourceUpdate::DeleteFontInstance(_) => {}
ResourceUpdate::SetImageVisibleArea(..) => {}
ResourceUpdate::SetBlobImageVisibleArea(..) => {}
}
}
}