Bug 1501322 - Update webrender to 9b1a2f7e46cfb3496d43421b828543b08bb45810. r=kats

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
WR Updater Bot 2018-10-23 15:13:53 +00:00
Родитель 2ee98a6df4
Коммит b0e8d7dd2d
10 изменённых файлов: 485 добавлений и 268 удалений

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

@ -4,8 +4,8 @@
#include shared,clip_shared
varying vec3 vLocalPos;
varying vec3 vClipMaskImageUv;
varying vec2 vLocalPos;
varying vec2 vClipMaskImageUv;
flat varying vec4 vClipMaskUvRect;
flat varying vec4 vClipMaskUvInnerRect;
@ -13,13 +13,15 @@ flat varying float vLayer;
#ifdef WR_VERTEX_SHADER
struct ImageMaskData {
RectWithSize local_rect;
RectWithSize local_mask_rect;
RectWithSize local_tile_rect;
};
ImageMaskData fetch_mask_data(ivec2 address) {
vec4 data = fetch_from_gpu_cache_1_direct(address);
RectWithSize local_rect = RectWithSize(data.xy, data.zw);
ImageMaskData mask_data = ImageMaskData(local_rect);
vec4 data[2] = fetch_from_gpu_cache_2_direct(address);
RectWithSize mask_rect = RectWithSize(data[0].xy, data[0].zw);
RectWithSize tile_rect = RectWithSize(data[1].xy, data[1].zw);
ImageMaskData mask_data = ImageMaskData(mask_rect, tile_rect);
return mask_data;
}
@ -29,7 +31,7 @@ void main(void) {
Transform clip_transform = fetch_transform(cmi.clip_transform_id);
Transform prim_transform = fetch_transform(cmi.prim_transform_id);
ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
RectWithSize local_rect = mask.local_rect;
RectWithSize local_rect = mask.local_mask_rect;
ImageResource res = fetch_image_resource_direct(cmi.resource_address);
ClipVertexInfo vi = write_clip_tile_vertex(
@ -38,12 +40,9 @@ void main(void) {
clip_transform,
area
);
vLocalPos = vi.local_pos;
vLocalPos = vi.local_pos.xy / vi.local_pos.z;
vLayer = res.layer;
vec2 local_pos = vLocalPos.xy / vLocalPos.z;
vClipMaskImageUv = vec3((local_pos - local_rect.p0) / local_rect.size, 0.0);
vClipMaskImageUv = (vLocalPos - mask.local_tile_rect.p0) / mask.local_tile_rect.size;
vec2 texture_size = vec2(textureSize(sColor0, 0));
vClipMaskUvRect = vec4(res.uv_rect.p0, res.uv_rect.p1 - res.uv_rect.p0) / texture_size.xyxy;
// applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
@ -54,17 +53,19 @@ void main(void) {
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 local_pos = vLocalPos.xy / vLocalPos.z;
float alpha = init_transform_fs(vLocalPos);
float alpha = init_transform_fs(local_pos);
// TODO: Handle repeating masks?
vec2 clamped_mask_uv = clamp(vClipMaskImageUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
// Ensure we don't draw outside of our tile.
// FIXME(emilio): Can we do this earlier?
if (clamped_mask_uv != vClipMaskImageUv)
discard;
bool repeat_mask = false; //TODO
vec2 clamped_mask_uv = repeat_mask ? fract(vClipMaskImageUv.xy) :
clamp(vClipMaskImageUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw);
float clip_alpha = texture(sColor0, vec3(source_uv, vLayer)).r; //careful: texture has type A8
oFragColor = vec4(alpha * clip_alpha, 1.0, 1.0, 1.0);
}
#endif

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

@ -1949,37 +1949,51 @@ impl ClipBatcher {
resource_address: GpuCacheAddress::invalid(),
};
let gpu_address = gpu_cache.get_address(&clip_node.gpu_cache_handle);
match clip_node.item {
ClipItem::Image(ref mask, is_valid) => {
if is_valid {
if let Ok(cache_item) = resource_cache.get_cached_image(
ImageRequest {
key: mask.image,
rendering: ImageRendering::Auto,
tile: None,
ClipItem::Image { ref mask, ref visible_tiles } => {
let request = ImageRequest {
key: mask.image,
rendering: ImageRendering::Auto,
tile: None,
};
let mut add_image = |request: ImageRequest, clip_data_address: GpuCacheAddress| {
let cache_item = match resource_cache.get_cached_image(request) {
Ok(item) => item,
Err(..) => {
warn!("Warnings: skip a image mask");
debug!("Mask: {:?}, request: {:?}", mask, request);
return;
}
};
self.images
.entry(cache_item.texture_id)
.or_insert(Vec::new())
.push(ClipMaskInstance {
clip_data_address,
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
..instance
});
};
match *visible_tiles {
Some(ref tiles) => {
for tile in tiles {
add_image(
request.with_tile(tile.tile_offset),
gpu_cache.get_address(&tile.handle),
)
}
) {
self.images
.entry(cache_item.texture_id)
.or_insert(Vec::new())
.push(ClipMaskInstance {
clip_data_address: gpu_address,
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
..instance
});
} else {
warn!("Warnings: skip a image mask");
debug!("Key:{:?} Rect::{:?}", mask.image, mask.rect);
continue;
}
} else {
warn!("Warnings: clip masks that are tiled blobs are not yet supported (#2852)");
continue;
None => {
let gpu_address =
gpu_cache.get_address(&clip_node.gpu_cache_handle);
add_image(request, gpu_address)
}
}
}
ClipItem::BoxShadow(ref info) => {
let gpu_address =
gpu_cache.get_address(&clip_node.gpu_cache_handle);
let rt_handle = info
.cache_handle
.as_ref()
@ -2002,6 +2016,8 @@ impl ClipBatcher {
ClipItem::Rectangle(_, mode) => {
if !clip_instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) ||
mode == ClipMode::ClipOut {
let gpu_address =
gpu_cache.get_address(&clip_node.gpu_cache_handle);
self.rectangles.push(ClipMaskInstance {
clip_data_address: gpu_address,
..instance
@ -2009,6 +2025,8 @@ impl ClipBatcher {
}
}
ClipItem::RoundedRectangle(..) => {
let gpu_address =
gpu_cache.get_address(&clip_node.gpu_cache_handle);
self.rectangles.push(ClipMaskInstance {
clip_data_address: gpu_address,
..instance

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

@ -14,9 +14,10 @@ use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, ROOT_SPATIAL_NODE_IND
use ellipse::Ellipse;
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use gpu_types::{BoxShadowStretchMode};
use image::{self, Repetition};
use intern;
use internal_types::FastHashSet;
use prim_store::{ClipData, ImageMaskData, SpaceMapper};
use prim_store::{ClipData, ImageMaskData, SpaceMapper, VisibleMaskImageTile};
use render_task::to_cache_size;
use resource_cache::{ImageRequest, ResourceCache};
use std::{cmp, u32};
@ -145,14 +146,14 @@ impl From<ClipItemKey> for ClipNode {
)
}
ClipItemKey::ImageMask(rect, image, repeat) => {
ClipItem::Image(
ImageMask {
ClipItem::Image {
mask: ImageMask {
image,
rect: LayoutRect::from_au(rect),
repeat,
},
true,
)
visible_tiles: None,
}
}
ClipItemKey::BoxShadow(shadow_rect, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => {
ClipItem::new_box_shadow(
@ -263,14 +264,79 @@ impl ClipNode {
gpu_cache: &mut GpuCache,
resource_cache: &mut ResourceCache,
device_pixel_scale: DevicePixelScale,
clipped_rect: &LayoutRect,
) {
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
match self.item {
ClipItem::Image(ref mask, ..) => {
let data = ImageMaskData { local_rect: mask.rect };
data.write_gpu_blocks(request);
match self.item {
ClipItem::Image { ref mask, ref mut visible_tiles } => {
let request = ImageRequest {
key: mask.image,
rendering: ImageRendering::Auto,
tile: None,
};
*visible_tiles = None;
if let Some(props) = resource_cache.get_image_properties(mask.image) {
if let Some(tile_size) = props.tiling {
let mut mask_tiles = Vec::new();
let device_image_size = props.descriptor.size;
let visible_rect = if mask.repeat {
*clipped_rect
} else {
clipped_rect.intersection(&mask.rect).unwrap()
};
let repetitions = image::repetitions(
&mask.rect,
&visible_rect,
mask.rect.size,
);
for Repetition { origin, .. } in repetitions {
let image_rect = LayoutRect {
origin,
size: mask.rect.size,
};
let tiles = image::tiles(
&image_rect,
&visible_rect,
&device_image_size,
tile_size as u32,
);
for tile in tiles {
resource_cache.request_image(
request.with_tile(tile.offset),
gpu_cache,
);
let mut handle = GpuCacheHandle::new();
if let Some(request) = gpu_cache.request(&mut handle) {
let data = ImageMaskData {
local_mask_rect: mask.rect,
local_tile_rect: tile.rect,
};
data.write_gpu_blocks(request);
}
mask_tiles.push(VisibleMaskImageTile {
tile_offset: tile.offset,
handle,
});
}
}
*visible_tiles = Some(mask_tiles);
} else {
if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) {
let data = ImageMaskData {
local_mask_rect: mask.rect,
local_tile_rect: mask.rect,
};
data.write_gpu_blocks(request);
}
resource_cache.request_image(request, gpu_cache);
}
}
ClipItem::BoxShadow(ref info) => {
}
ClipItem::BoxShadow(ref mut info) => {
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
request.push([
info.shadow_rect_alloc_size.width,
info.shadow_rect_alloc_size.height,
@ -285,39 +351,7 @@ impl ClipNode {
]);
request.push(info.prim_shadow_rect);
}
ClipItem::Rectangle(rect, mode) => {
let data = ClipData::uniform(rect, 0.0, mode);
data.write(&mut request);
}
ClipItem::RoundedRectangle(ref rect, ref radius, mode) => {
let data = ClipData::rounded_rect(rect, radius, mode);
data.write(&mut request);
}
}
}
match self.item {
ClipItem::Image(ref mask, ref mut is_valid) => {
if let Some(properties) = resource_cache.get_image_properties(mask.image) {
// Clip masks with tiled blob images are not currently supported.
// This results in them being ignored, which is not ideal, but
// is better than crashing in resource cache!
// See https://github.com/servo/webrender/issues/2852.
*is_valid = properties.tiling.is_none();
}
if *is_valid {
resource_cache.request_image(
ImageRequest {
key: mask.image,
rendering: ImageRendering::Auto,
tile: None,
},
gpu_cache,
);
}
}
ClipItem::BoxShadow(ref mut info) => {
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
// "the image that would be generated by applying to the shadow a
// Gaussian blur with a standard deviation equal to half the blur radius."
@ -348,8 +382,18 @@ impl ClipNode {
data.write(&mut request);
}
}
ClipItem::Rectangle(..) |
ClipItem::RoundedRectangle(..) => {}
ClipItem::Rectangle(rect, mode) => {
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
let data = ClipData::uniform(rect, 0.0, mode);
data.write(&mut request);
}
}
ClipItem::RoundedRectangle(ref rect, ref radius, mode) => {
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
let data = ClipData::rounded_rect(rect, radius, mode);
data.write(&mut request);
}
}
}
}
}
@ -568,6 +612,7 @@ impl ClipStore {
gpu_cache,
resource_cache,
device_pixel_scale,
&local_bounding_rect,
);
// Calculate some flags that are required for the segment
@ -593,7 +638,7 @@ impl ClipStore {
needs_mask |= match node.item {
ClipItem::Rectangle(_, ClipMode::ClipOut) |
ClipItem::RoundedRectangle(..) |
ClipItem::Image(..) |
ClipItem::Image { .. } |
ClipItem::BoxShadow(..) => {
true
}
@ -767,15 +812,13 @@ impl ClipItemKey {
}
}
#[derive(Debug, Clone)]
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum ClipItem {
Rectangle(LayoutRect, ClipMode),
RoundedRectangle(LayoutRect, BorderRadius, ClipMode),
/// The boolean below is a crash workaround for #2852, will be true unless
/// the mask is a tiled blob.
Image(ImageMask, bool),
Image { mask: ImageMask, visible_tiles: Option<Vec<VisibleMaskImageTile>> },
BoxShadow(BoxShadowClipSource),
}
@ -888,8 +931,8 @@ impl ClipItem {
ClipItem::Rectangle(_, ClipMode::ClipOut) => None,
ClipItem::RoundedRectangle(clip_rect, _, ClipMode::Clip) => Some(clip_rect),
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) => None,
ClipItem::Image(ref mask, ..) if mask.repeat => None,
ClipItem::Image(ref mask, ..) => Some(mask.rect),
ClipItem::Image { ref mask, .. } if mask.repeat => None,
ClipItem::Image { ref mask, .. } => Some(mask.rect),
ClipItem::BoxShadow(..) => None,
}
}
@ -910,7 +953,7 @@ impl ClipItem {
}
ClipItem::Rectangle(_, ClipMode::ClipOut) |
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) |
ClipItem::Image(..) |
ClipItem::Image { .. } |
ClipItem::BoxShadow(..) => {
return ClipResult::Partial
}
@ -1021,7 +1064,7 @@ impl ClipItem {
}
}
}
ClipItem::Image(ref mask, ..) => {
ClipItem::Image { ref mask, .. } => {
if mask.repeat {
ClipResult::Partial
} else {

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

@ -39,7 +39,8 @@ impl HitTestClipNode {
ClipItem::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
ClipItem::RoundedRectangle(ref rect, ref radii, ref mode) =>
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
ClipItem::Image(ref mask, ..) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
ClipItem::Image { ref mask, .. } =>
HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
ClipItem::BoxShadow(_) => HitTestRegion::Invalid,
};

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

@ -29,18 +29,85 @@ pub fn simplify_repeated_primitive(
}
}
pub fn for_each_repetition(
pub struct Repetition {
pub origin: LayoutPoint,
pub edge_flags: EdgeAaSegmentMask,
}
pub struct RepetitionIterator {
current_x: i32,
x_count: i32,
current_y: i32,
y_count: i32,
row_flags: EdgeAaSegmentMask,
current_origin: LayoutPoint,
initial_origin: LayoutPoint,
stride: LayoutSize,
}
impl Iterator for RepetitionIterator {
type Item = Repetition;
fn next(&mut self) -> Option<Self::Item> {
if self.current_x == self.x_count {
self.current_y += 1;
if self.current_y >= self.y_count {
return None;
}
self.current_x = 0;
self.row_flags = EdgeAaSegmentMask::empty();
if self.current_y == self.y_count - 1 {
self.row_flags |= EdgeAaSegmentMask::BOTTOM;
}
self.current_origin.x = self.initial_origin.x;
self.current_origin.y += self.stride.height;
}
let mut edge_flags = self.row_flags;
if self.current_x == 0 {
edge_flags |= EdgeAaSegmentMask::LEFT;
}
if self.current_x == self.x_count - 1 {
edge_flags |= EdgeAaSegmentMask::RIGHT;
}
let repetition = Repetition {
origin: self.current_origin,
edge_flags: edge_flags,
};
self.current_origin.x += self.stride.width;
self.current_x += 1;
Some(repetition)
}
}
pub fn repetitions(
prim_rect: &LayoutRect,
visible_rect: &LayoutRect,
stride: &LayoutSize,
callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
stride: LayoutSize,
) -> RepetitionIterator {
assert!(stride.width > 0.0);
assert!(stride.height > 0.0);
let visible_rect = match prim_rect.intersection(&visible_rect) {
Some(rect) => rect,
None => return,
Some(rect) => rect,
None => {
return RepetitionIterator {
current_origin: LayoutPoint::zero(),
initial_origin: LayoutPoint::zero(),
current_x: 0,
current_y: 0,
x_count: 0,
y_count: 0,
stride,
row_flags: EdgeAaSegmentMask::empty(),
}
}
};
let nx = if visible_rect.origin.x > prim_rect.origin.x {
@ -58,49 +125,109 @@ pub fn for_each_repetition(
let x0 = prim_rect.origin.x + nx * stride.width;
let y0 = prim_rect.origin.y + ny * stride.height;
let mut p = LayoutPoint::new(x0, y0);
let x_most = visible_rect.max_x();
let y_most = visible_rect.max_y();
let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
let y_count = f32::ceil((y_most - y0) / stride.height) as i32;
for y in 0..y_count {
let mut row_flags = EdgeAaSegmentMask::empty();
if y == 0 {
row_flags |= EdgeAaSegmentMask::TOP;
}
if y == y_count - 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}
let mut row_flags = EdgeAaSegmentMask::TOP;
if y_count == 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}
for x in 0..x_count {
let mut edge_flags = row_flags;
if x == 0 {
edge_flags |= EdgeAaSegmentMask::LEFT;
}
if x == x_count - 1 {
edge_flags |= EdgeAaSegmentMask::RIGHT;
}
callback(&p, edge_flags);
p.x += stride.width;
}
p.x = x0;
p.y += stride.height;
RepetitionIterator {
current_origin: LayoutPoint::new(x0, y0),
initial_origin: LayoutPoint::new(x0, y0),
current_x: 0,
current_y: 0,
x_count,
y_count,
row_flags,
stride,
}
}
pub fn for_each_tile(
#[derive(Debug)]
pub struct Tile {
pub rect: LayoutRect,
pub offset: TileOffset,
pub edge_flags: EdgeAaSegmentMask,
}
pub struct TileIterator {
current_x: u16,
x_count: u16,
current_y: u16,
y_count: u16,
origin: TileOffset,
tile_size: LayoutSize,
leftover_offset: TileOffset,
leftover_size: LayoutSize,
local_origin: LayoutPoint,
row_flags: EdgeAaSegmentMask,
}
impl Iterator for TileIterator {
type Item = Tile;
fn next(&mut self) -> Option<Self::Item> {
if self.current_x == self.x_count {
self.current_y += 1;
if self.current_y >= self.y_count {
return None;
}
self.current_x = 0;
self.row_flags = EdgeAaSegmentMask::empty();
if self.current_y == self.y_count - 1 {
self.row_flags |= EdgeAaSegmentMask::BOTTOM;
}
}
let tile_offset = self.origin + vec2(self.current_x, self.current_y);
let mut segment_rect = LayoutRect {
origin: LayoutPoint::new(
self.local_origin.x + tile_offset.x as f32 * self.tile_size.width,
self.local_origin.y + tile_offset.y as f32 * self.tile_size.height,
),
size: self.tile_size,
};
if tile_offset.x == self.leftover_offset.x {
segment_rect.size.width = self.leftover_size.width;
}
if tile_offset.y == self.leftover_offset.y {
segment_rect.size.height = self.leftover_size.height;
}
let mut edge_flags = self.row_flags;
if self.current_x == 0 {
edge_flags |= EdgeAaSegmentMask::LEFT;
}
if self.current_x == self.x_count - 1 {
edge_flags |= EdgeAaSegmentMask::RIGHT;
}
let tile = Tile {
rect: segment_rect,
offset: tile_offset,
edge_flags,
};
self.current_x += 1;
Some(tile)
}
}
pub fn tiles(
prim_rect: &LayoutRect,
visible_rect: &LayoutRect,
device_image_size: &DeviceUintSize,
device_tile_size: u32,
callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
) -> TileIterator {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
// We need to do this because the image is broken up into smaller tiles in the texture
@ -130,8 +257,21 @@ pub fn for_each_tile(
// the image in layer space intead of iterating over device tiles.
let visible_rect = match prim_rect.intersection(&visible_rect) {
Some(rect) => rect,
None => return,
Some(rect) => rect,
None => {
return TileIterator {
current_x: 0,
current_y: 0,
x_count: 0,
y_count: 0,
row_flags: EdgeAaSegmentMask::empty(),
origin: TileOffset::zero(),
tile_size: LayoutSize::zero(),
leftover_offset: TileOffset::zero(),
leftover_size: LayoutSize::zero(),
local_origin: LayoutPoint::zero(),
}
}
};
let device_tile_size_f32 = device_tile_size as f32;
@ -183,46 +323,21 @@ pub fn for_each_tile(
let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;
for y in 0..y_count {
let mut row_flags = EdgeAaSegmentMask::empty();
if y == 0 {
row_flags |= EdgeAaSegmentMask::TOP;
}
if y == y_count - 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}
for x in 0..x_count {
let tile_offset = t0 + vec2(x, y);
let mut segment_rect = LayoutRect {
origin: LayoutPoint::new(
prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
),
size: layer_tile_size,
};
if tile_offset.x == leftover_offset.x {
segment_rect.size.width = leftover_layer_size.width;
}
if tile_offset.y == leftover_offset.y {
segment_rect.size.height = leftover_layer_size.height;
}
let mut edge_flags = row_flags;
if x == 0 {
edge_flags |= EdgeAaSegmentMask::LEFT;
}
if x == x_count - 1 {
edge_flags |= EdgeAaSegmentMask::RIGHT;
}
callback(&segment_rect, tile_offset, edge_flags);
}
let mut row_flags = EdgeAaSegmentMask::TOP;
if y_count == 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}
TileIterator {
current_x: 0,
current_y: 0,
x_count,
y_count,
row_flags,
origin: t0,
tile_size: layer_tile_size,
leftover_offset,
leftover_size: leftover_layer_size,
local_origin: prim_rect.origin,
}
}
@ -252,7 +367,7 @@ pub fn compute_tile_range(
pub fn for_each_tile_in_range(
range: &TileRange,
callback: &mut FnMut(TileOffset),
mut callback: impl FnMut(TileOffset),
) {
for y in 0..range.size.height {
for x in 0..range.size.width {
@ -277,20 +392,20 @@ mod tests {
callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
let mut coverage = LayoutRect::zero();
let mut tiles = HashSet::new();
for_each_tile(prim_rect,
visible_rect,
device_image_size,
device_tile_size,
&mut |tile_rect, tile_offset, tile_flags| {
// make sure we don't get sent duplicate tiles
assert!(!tiles.contains(&tile_offset));
tiles.insert(tile_offset);
coverage = coverage.union(tile_rect);
assert!(prim_rect.contains_rect(&tile_rect));
callback(tile_rect, tile_offset, tile_flags);
},
);
let mut seen_tiles = HashSet::new();
for tile in tiles(
prim_rect,
visible_rect,
device_image_size,
device_tile_size,
) {
// make sure we don't get sent duplicate tiles
assert!(!seen_tiles.contains(&tile.offset));
seen_tiles.insert(tile.offset);
coverage = coverage.union(&tile.rect);
assert!(prim_rect.contains_rect(&tile.rect));
callback(&tile.rect, tile.offset, tile.edge_flags);
}
assert!(prim_rect.contains_rect(&coverage));
assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
}

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

@ -20,7 +20,7 @@ use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use gpu_types::BrushFlags;
use image::{for_each_tile, for_each_repetition};
use image::{self, Repetition};
use intern;
use picture::{PictureCompositeMode, PicturePrimitive};
#[cfg(debug_assertions)]
@ -359,6 +359,8 @@ impl OpacityBinding {
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct VisibleImageTile {
pub tile_offset: TileOffset,
pub handle: GpuCacheHandle,
@ -367,6 +369,14 @@ pub struct VisibleImageTile {
pub local_clip_rect: LayoutRect,
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct VisibleMaskImageTile {
pub tile_offset: TileOffset,
pub handle: GpuCacheHandle,
}
#[derive(Debug)]
pub struct VisibleGradientTile {
pub handle: GpuCacheHandle,
@ -539,6 +549,8 @@ bitflags! {
///
/// *Note*: the bit values have to match the shader logic in
/// `write_transform_vertex()` function.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct EdgeAaSegmentMask: u8 {
const LEFT = 0x1;
const TOP = 0x2;
@ -1262,12 +1274,16 @@ impl ClipCorner {
#[derive(Debug)]
#[repr(C)]
pub struct ImageMaskData {
pub local_rect: LayoutRect,
/// The local rect of the whole masked area.
pub local_mask_rect: LayoutRect,
/// The local rect of an individual tile.
pub local_tile_rect: LayoutRect,
}
impl ToGpuBlocks for ImageMaskData {
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
request.push(self.local_rect);
request.push(self.local_mask_rect);
request.push(self.local_tile_rect);
}
}
@ -2159,28 +2175,24 @@ fn decompose_repeated_primitive(
);
let stride = *stretch_size + *tile_spacing;
for_each_repetition(
prim_local_rect,
&visible_rect,
&stride,
&mut |origin, _| {
let repetitions = image::repetitions(prim_local_rect, &visible_rect, stride);
for Repetition { origin, .. } in repetitions {
let mut handle = GpuCacheHandle::new();
let rect = LayoutRect {
origin: origin,
size: *stretch_size,
};
let mut handle = GpuCacheHandle::new();
let rect = LayoutRect {
origin: *origin,
size: *stretch_size,
};
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
callback(&rect, request);
}
visible_tiles.push(VisibleGradientTile {
local_rect: rect,
local_clip_rect: tight_clip_rect,
handle
});
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
callback(&rect, request);
}
);
visible_tiles.push(VisibleGradientTile {
local_rect: rect,
local_clip_rect: tight_clip_rect,
handle
});
}
if visible_tiles.is_empty() {
// At this point if we don't have tiles to show it means we could probably
@ -2329,7 +2341,7 @@ impl BrushPrimitive {
continue;
}
ClipItem::Image(..) => {
ClipItem::Image { .. } => {
rect_clips_only = false;
continue;
}
@ -2686,50 +2698,51 @@ impl Primitive {
visible_tiles.clear();
for_each_repetition(
let repetitions = image::repetitions(
&self.local_rect,
&visible_rect,
&stride,
&mut |origin, edge_flags| {
let edge_flags = base_edge_flags | edge_flags;
let image_rect = LayoutRect {
origin: *origin,
size: stretch_size,
};
for_each_tile(
&image_rect,
&visible_rect,
&device_image_size,
tile_size as u32,
&mut |tile_rect, tile_offset, tile_flags| {
frame_state.resource_cache.request_image(
request.with_tile(tile_offset),
frame_state.gpu_cache,
);
let mut handle = GpuCacheHandle::new();
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]);
request.write_segment(*tile_rect, [0.0; 4]);
}
visible_tiles.push(VisibleImageTile {
tile_offset,
handle,
edge_flags: tile_flags & edge_flags,
local_rect: *tile_rect,
local_clip_rect: tight_clip_rect,
});
}
);
}
stride,
);
for Repetition { origin, edge_flags } in repetitions {
let edge_flags = base_edge_flags | edge_flags;
let image_rect = LayoutRect {
origin,
size: stretch_size,
};
let tiles = image::tiles(
&image_rect,
&visible_rect,
&device_image_size,
tile_size as u32,
);
for tile in tiles {
frame_state.resource_cache.request_image(
request.with_tile(tile.offset),
frame_state.gpu_cache,
);
let mut handle = GpuCacheHandle::new();
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([tile.rect.size.width, tile.rect.size.height, 0.0, 0.0]);
request.write_segment(tile.rect, [0.0; 4]);
}
visible_tiles.push(VisibleImageTile {
tile_offset: tile.offset,
handle,
edge_flags: tile.edge_flags & edge_flags,
local_rect: tile.rect,
local_clip_rect: tight_clip_rect,
});
}
}
if visible_tiles.is_empty() {
// At this point if we don't have tiles to show it means we could probably
// have done a better a job at culling during an earlier stage.

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

@ -554,7 +554,7 @@ impl RenderTask {
}
ClipItem::Rectangle(..) |
ClipItem::RoundedRectangle(..) |
ClipItem::Image(..) => {}
ClipItem::Image { .. } => {}
}
}

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

@ -1082,7 +1082,7 @@ impl ResourceCache {
}
}
for_each_tile_in_range(&tiles, &mut|tile| {
for_each_tile_in_range(&tiles, |tile| {
let descriptor = BlobImageDescriptor {
offset: DevicePoint::new(
tile.x as f32 * tile_size as f32,

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

@ -1 +1 @@
838ce479e6ef8eed44d68e5d283649d0963152b6
9b1a2f7e46cfb3496d43421b828543b08bb45810

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

@ -72,12 +72,18 @@ fn broadcast<T: Clone>(base_vals: &[T], num_items: usize) -> Vec<T> {
vals
}
enum CheckerboardKind {
BlackGrey,
BlackTransparent,
}
fn generate_checkerboard_image(
border: u32,
tile_x_size: u32,
tile_y_size: u32,
tile_x_count: u32,
tile_y_count: u32,
kind: CheckerboardKind,
) -> (ImageDescriptor, ImageData) {
let width = 2 * border + tile_x_size * tile_x_count;
let height = 2 * border + tile_y_size * tile_y_count;
@ -94,11 +100,22 @@ fn generate_checkerboard_image(
} else {
let xon = ((x - border) % (2 * tile_x_size)) < tile_x_size;
let yon = ((y - border) % (2 * tile_y_size)) < tile_y_size;
let value = if xon ^ yon { 0xff } else { 0x7f };
pixels.push(value);
pixels.push(value);
pixels.push(value);
pixels.push(0xff);
match kind {
CheckerboardKind::BlackGrey => {
let value = if xon ^ yon { 0xff } else { 0x7f };
pixels.push(value);
pixels.push(value);
pixels.push(value);
pixels.push(0xff);
}
CheckerboardKind::BlackTransparent => {
let value = if xon ^ yon { 0xff } else { 0x00 };
pixels.push(value);
pixels.push(value);
pixels.push(value);
pixels.push(value);
}
}
}
}
}
@ -405,10 +422,10 @@ impl YamlFrameReader {
}
pub fn add_or_get_image(
&mut self,
file: &Path,
tiling: Option<i64>,
wrench: &mut Wrench,
&mut self,
file: &Path,
tiling: Option<i64>,
wrench: &mut Wrench,
) -> (ImageKey, LayoutSize) {
let key = (file.to_owned(), tiling);
if let Some(k) = self.image_map.get(&key) {
@ -476,7 +493,8 @@ impl YamlFrameReader {
args.get(4).unwrap_or(&"1000").parse::<u32>().unwrap(),
args.get(5).unwrap_or(&"1000").parse::<u32>().unwrap(),
),
("checkerboard", args, _) => {
(name @ "transparent-checkerboard", args, _) |
(name @ "checkerboard", args, _) => {
let border = args.get(0).unwrap_or(&"4").parse::<u32>().unwrap();
let (x_size, y_size, x_count, y_count) = match args.len() {
@ -497,12 +515,19 @@ impl YamlFrameReader {
}
};
let kind = if name == "transparent-checkerboard" {
CheckerboardKind::BlackTransparent
} else {
CheckerboardKind::BlackGrey
};
generate_checkerboard_image(
border,
x_size,
y_size,
x_count,
y_count,
kind,
)
}
_ => {
@ -600,8 +625,9 @@ impl YamlFrameReader {
}
};
let tiling = item["tile-size"].as_i64();
let (image_key, image_dims) =
self.add_or_get_image(&file, None, wrench);
self.add_or_get_image(&file, tiling, wrench);
let image_rect = item["rect"]
.as_rect()
.unwrap_or(LayoutRect::new(LayoutPoint::zero(), image_dims));