Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions webrender/src/display_list_flattener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use euclid::{SideOffsets2D, vec2};
use frame_builder::{FrameBuilder, FrameBuilderConfig};
use glyph_rasterizer::FontInstance;
use hit_test::{HitTestingItem, HitTestingRun};
use image::{decompose_image, TiledImageInfo};
use image::{decompose_image, TiledImageInfo, simplify_repeated_primitive};
use internal_types::{FastHashMap, FastHashSet};
use picture::PictureCompositeMode;
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
Expand Down Expand Up @@ -1892,11 +1892,18 @@ impl<'a> DisplayListFlattener<'a> {
stops_count: usize,
extend_mode: ExtendMode,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
mut tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());

let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};

if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
Expand Down Expand Up @@ -1925,7 +1932,7 @@ impl<'a> DisplayListFlattener<'a> {

self.add_gradient_impl(
clip_and_scroll,
info,
&info,
start_point,
end_point,
stops,
Expand Down Expand Up @@ -1982,11 +1989,18 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
stretch_size: LayoutSize,
tile_spacing: LayoutSize,
mut tile_spacing: LayoutSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());

let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};

if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
Expand Down Expand Up @@ -2016,7 +2030,7 @@ impl<'a> DisplayListFlattener<'a> {

self.add_radial_gradient_impl(
clip_and_scroll,
info,
&info,
center,
start_radius,
end_radius,
Expand Down Expand Up @@ -2123,13 +2137,12 @@ impl<'a> DisplayListFlattener<'a> {
alpha_type: AlphaType,
tile_offset: Option<TileOffset>,
) {
// If the tile spacing is the same as the rect size,
// then it is effectively zero. We use this later on
// in prim_store to detect if an image can be considered
// opaque.
if tile_spacing == info.rect.size {
tile_spacing = LayoutSize::zero();
}
let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};

let request = ImageRequest {
key: image_key,
Expand All @@ -2152,8 +2165,7 @@ impl<'a> DisplayListFlattener<'a> {

// See if conditions are met to run through the new
// image brush shader, which supports segments.
if tile_spacing == LayoutSize::zero() &&
tile_offset.is_none() {
if tile_offset.is_none() {
let prim = BrushPrimitive::new(
BrushKind::Image {
request,
Expand All @@ -2170,7 +2182,7 @@ impl<'a> DisplayListFlattener<'a> {

self.add_primitive(
clip_and_scroll,
info,
&info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
Expand All @@ -2189,7 +2201,7 @@ impl<'a> DisplayListFlattener<'a> {

self.add_primitive(
clip_and_scroll,
info,
&info,
Vec::new(),
PrimitiveContainer::Image(prim_cpu),
);
Expand Down
22 changes: 22 additions & 0 deletions webrender/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@
use api::{TileOffset, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize};
use euclid::rect;

/// If repetitions are far enough apart that only one is within
/// the primitive rect, then we can simplify the parameters and
/// treat the primitive as not repeated.
/// This can let us avoid unnecessary work later to handle some
/// of the parameters.
pub fn simplify_repeated_primitive(
stretch_size: &LayoutSize,
tile_spacing: &mut LayoutSize,
prim_rect: &mut LayoutRect,
) {
let stride = *stretch_size + *tile_spacing;

if stride.width >= prim_rect.size.width {
tile_spacing.width = 0.0;
prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width);
}
if stride.height >= prim_rect.size.height {
tile_spacing.height = 0.0;
prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height);
}
}

pub struct DecomposedTile {
pub rect: LayoutRect,
pub stretch_size: LayoutSize,
Expand Down
59 changes: 50 additions & 9 deletions webrender/src/prim_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat, DeviceIntSideOffsets};
use border::{BorderCornerInstance, BorderEdgeKind};
use box_shadow::BLUR_SAMPLE_SCALE;
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
Expand Down Expand Up @@ -430,10 +430,15 @@ impl BrushPrimitive {
}
// Images are drawn as a white color, modulated by the total
// opacity coming from any collapsed property bindings.
BrushKind::Image { stretch_size, ref opacity_binding, .. } => {
BrushKind::Image { stretch_size, tile_spacing, ref opacity_binding, .. } => {
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([stretch_size.width, stretch_size.height, 0.0, 0.0]);
request.push([
stretch_size.width + tile_spacing.width,
stretch_size.height + tile_spacing.height,
0.0,
0.0,
]);
}
// Solid rects also support opacity collapsing.
BrushKind::Solid { color, ref opacity_binding, .. } => {
Expand Down Expand Up @@ -1519,7 +1524,16 @@ impl PrimitiveStore {
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];

match brush.kind {
BrushKind::Image { request, sub_rect, ref mut current_epoch, ref mut source, ref mut opacity_binding, .. } => {
BrushKind::Image {
request,
sub_rect,
stretch_size,
ref mut tile_spacing,
ref mut current_epoch,
ref mut source,
ref mut opacity_binding,
..
} => {
let image_properties = frame_state
.resource_cache
.get_image_properties(request.key);
Expand All @@ -1540,6 +1554,17 @@ impl PrimitiveStore {
image_properties.descriptor.is_opaque &&
opacity_binding.current == 1.0;

if *tile_spacing != LayoutSize::zero() {
*source = ImageSource::Cache {
// Size in device-pixels we need to allocate in render task cache.
size: DeviceIntSize::new(
image_properties.descriptor.width as i32,
image_properties.descriptor.height as i32
),
handle: None,
};
}

// Work out whether this image is a normal / simple type, or if
// we need to pre-render it to the render task cache.
if let Some(rect) = sub_rect {
Expand All @@ -1557,7 +1582,22 @@ impl PrimitiveStore {
// time through, and any time the render task output has been
// evicted from the texture cache.
match *source {
ImageSource::Cache { size, ref mut handle } => {
ImageSource::Cache { ref mut size, ref mut handle } => {
let padding = DeviceIntSideOffsets::new(
0,
(tile_spacing.width * size.width as f32 / stretch_size.width) as i32,
(tile_spacing.height * size.height as f32 / stretch_size.height) as i32,
0,
);

let inner_size = *size;
size.width += padding.horizontal();
size.height += padding.vertical();

if padding != DeviceIntSideOffsets::zero() {
metadata.opacity.is_opaque = false;
}

let image_cache_key = ImageCacheKey {
request,
texel_rect: sub_rect,
Expand All @@ -1566,7 +1606,7 @@ impl PrimitiveStore {
// Request a pre-rendered image task.
*handle = Some(frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
size,
size: *size,
kind: RenderTaskCacheKeyKind::Image(image_cache_key),
},
frame_state.gpu_cache,
Expand All @@ -1581,8 +1621,9 @@ impl PrimitiveStore {
// Create a task to blit from the texture cache to
// a normal transient render task surface. This will
// copy only the sub-rect, if specified.
let cache_to_target_task = RenderTask::new_blit(
size,
let cache_to_target_task = RenderTask::new_blit_with_padding(
inner_size,
&padding,
BlitSource::Image { key: image_cache_key },
);
let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
Expand All @@ -1591,7 +1632,7 @@ impl PrimitiveStore {
// task above back into the right spot in the persistent
// render target cache.
let target_to_cache_task = RenderTask::new_blit(
size,
*size,
BlitSource::RenderTask {
task_id: cache_to_target_task_id,
},
Expand Down
15 changes: 14 additions & 1 deletion webrender/src/render_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* 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::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, ImageDescriptor, ImageFormat};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, DeviceIntSideOffsets, ImageDescriptor, ImageFormat};
#[cfg(feature = "pathfinder")]
use api::FontRenderMode;
use box_shadow::{BoxShadowCacheKey};
Expand Down Expand Up @@ -254,6 +254,7 @@ pub enum BlitSource {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BlitTask {
pub source: BlitSource,
pub padding: DeviceIntSideOffsets,
}

#[derive(Debug)]
Expand Down Expand Up @@ -337,6 +338,14 @@ impl RenderTask {
pub fn new_blit(
size: DeviceIntSize,
source: BlitSource,
) -> Self {
RenderTask::new_blit_with_padding(size, &DeviceIntSideOffsets::zero(), source)
}

pub fn new_blit_with_padding(
mut size: DeviceIntSize,
padding: &DeviceIntSideOffsets,
source: BlitSource,
) -> Self {
let mut children = Vec::new();

Expand All @@ -349,11 +358,15 @@ impl RenderTask {
children.push(task_id);
}

size.width += padding.horizontal();
size.height += padding.vertical();

RenderTask {
children,
location: RenderTaskLocation::Dynamic(None, Some(size)),
kind: RenderTaskKind::Blit(BlitTask {
source,
padding: *padding,
}),
clear_mode: ClearMode::Transparent,
saved_index: None,
Expand Down
4 changes: 2 additions & 2 deletions webrender/src/tiling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ impl RenderTarget for ColorRenderTarget {
cache_item.texture_layer,
source_rect,
),
target_rect,
target_rect: target_rect.inner_rect(task_info.padding)
});
}
BlitSource::RenderTask { .. } => {
Expand Down Expand Up @@ -673,7 +673,7 @@ impl TextureCacheRenderTarget {
// task to this target.
self.blits.push(BlitJob {
source: BlitJobSource::RenderTask(task_id),
target_rect: target_rect.0,
target_rect: target_rect.0.inner_rect(task_info.padding),
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion webrender_api/src/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use app_units::Au;
use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D};
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D};
use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D};

/// Geometry in the coordinate system of the render target (screen or intermediate
/// surface) in physical pixels.
Expand All @@ -25,6 +25,7 @@ pub type DeviceIntRect = TypedRect<i32, DevicePixel>;
pub type DeviceIntPoint = TypedPoint2D<i32, DevicePixel>;
pub type DeviceIntSize = TypedSize2D<i32, DevicePixel>;
pub type DeviceIntLength = Length<i32, DevicePixel>;
pub type DeviceIntSideOffsets = TypedSideOffsets2D<i32, DevicePixel>;

pub type DeviceUintRect = TypedRect<u32, DevicePixel>;
pub type DeviceUintPoint = TypedPoint2D<u32, DevicePixel>;
Expand Down