Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Decompose repeated images and gradients into brush segments in most cases. #2572

Closed
wants to merge 7 commits into from

Perform image tile decomposition during frame building.

  • Loading branch information
nical committed Apr 4, 2018
commit 8b3d264679eac48e1e36d765c46e0292b4cd663e
@@ -938,6 +938,106 @@ impl AlphaBatchBuilder {
);
}
}
BrushKind::Image { request, ref visible_tiles, .. } => {

let segment_src = match brush.segment_desc {
Some(ref desc) => { desc.src }
None => SegmentSrc::Auto,
};

if visible_tiles.is_empty() {
if let Some((batch_kind, textures, user_data)) = get_image_brush_params(
ctx.resource_cache,
gpu_cache,
deferred_resolves,
segment_src,
request
) {
self.add_brush_to_batch(
brush,
prim_metadata,
batch_kind,
specified_blend_mode,
non_segmented_blend_mode,
textures,
clip_chain_rect_index,
clip_task_address,
&task_relative_bounding_rect,
prim_cache_address,
scroll_id,
task_address,
transform_kind,
z,
render_tasks,
user_data,
);
}
} else {
self.batch_list.add_bounding_rect(&task_relative_bounding_rect);

let segments = &brush.segment_desc.as_ref().unwrap().segments;

let mut i = 0;
for (&tile_offset, segment) in visible_tiles.iter().zip(segments.iter()) {
if let Some((batch_kind, textures, user_data)) = get_image_brush_params(
ctx.resource_cache,
gpu_cache,
deferred_resolves,
segment_src,
request.with_tile(tile_offset),
) {

let is_inner = segment.edge_flags.is_empty();
let needs_blending = !prim_metadata.opacity.is_opaque ||
segment.clip_task_id.is_some() ||
(!is_inner && transform_kind == TransformedRectKind::Complex);

let clip_task_address = segment
.clip_task_id
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));

let batch_key = BatchKey {
blend_mode: if needs_blending {
non_segmented_blend_mode
} else {
BlendMode::None
},
kind: BatchKind::Brush(batch_kind),
textures,
};

let instance = PrimitiveInstance::from(BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
segment_index: i as i32,
edge_flags: segment.edge_flags,
});

if needs_blending {
let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch(
batch_key,
&task_relative_bounding_rect
);
alpha_batch.push(instance);
} else {
let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch(
batch_key,
&task_relative_bounding_rect
);
opaque_batch.push(instance);
}
}

i += 1;
}
}
}
_ => {
if let Some((batch_kind, textures, user_data)) = brush.get_batch_params(
ctx.resource_cache,
@@ -1254,35 +1354,8 @@ impl BrushPrimitive {
cached_gradients: &[CachedGradient],
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {
match self.kind {
BrushKind::Image { request, .. } => {
let segment_src = match self.segment_desc {
Some(ref desc) => { desc.src }
None => SegmentSrc::Auto,
};

let cache_item = resolve_image(
request,
resource_cache,
gpu_cache,
deferred_resolves,
);

if cache_item.texture_id == SourceTexture::Invalid {
None
} else {
let textures = BatchTextures::color(cache_item.texture_id);
Some((
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
cache_item.uv_rect_handle.as_int(gpu_cache),
(BrushImageSourceKind::Color as i32) << 16 |
(segment_src as i32) << 8 |
RasterizationSpace::Local as i32,
0,
],
))
}
BrushKind::Image { .. } => {
panic!("bug: get_batch_key is handled at higher level for images");
}
BrushKind::Picture { .. } => {
panic!("bug: get_batch_key is handled at higher level for pictures");
@@ -1383,6 +1456,40 @@ impl BrushPrimitive {
}
}


fn get_image_brush_params(
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
segment_src: SegmentSrc,
request: ImageRequest,
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {

let cache_item = resolve_image(
request,
resource_cache,
gpu_cache,
deferred_resolves,
);

if cache_item.texture_id == SourceTexture::Invalid {
None
} else {
let textures = BatchTextures::color(cache_item.texture_id);
Some((
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
cache_item.uv_rect_handle.as_int(gpu_cache),
(BrushImageSourceKind::Color as i32) << 16 |
(segment_src as i32) << 8 |
RasterizationSpace::Local as i32,
0,
],
))
}
}

trait AlphaBatchHelpers {
fn get_blend_mode(
&self,
@@ -11,7 +11,7 @@ use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayerPoint, La
use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform};
use api::{LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding};
use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect, TileOffset};
use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{TransformStyle, YuvColorSpace, YuvData};
use app_units::Au;
use batch::BrushImageSourceKind;
@@ -23,7 +23,6 @@ use euclid::{SideOffsets2D, vec2};
use frame_builder::{FrameBuilder, FrameBuilderConfig};
use glyph_rasterizer::FontInstance;
use hit_test::{HitTestingItem, HitTestingRun};
use image::{decompose_image, TiledImageInfo};
use internal_types::{FastHashMap, FastHashSet};
use picture::PictureCompositeMode;
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
@@ -627,49 +626,16 @@ impl<'a> DisplayListFlattener<'a> {
let prim_info = item.get_layer_primitive_info(&reference_frame_relative_offset);
match *item.item() {
SpecificDisplayItem::Image(ref info) => {
match self.tiled_image_map.get(&info.image_key).cloned() {
Some(tiling) => {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
decompose_image(
&TiledImageInfo {
rect: prim_info.rect,
tile_spacing: info.tile_spacing,
stretch_size: info.stretch_size,
device_image_size: tiling.image_size,
device_tile_size: tiling.tile_size as u32,
},
&mut|tile| {
let mut prim_info = prim_info.clone();
prim_info.rect = tile.rect;
self.add_image(
clip_and_scroll,
&prim_info,
tile.stretch_size,
info.tile_spacing,
None,
info.image_key,
info.image_rendering,
info.alpha_type,
Some(tile.tile_offset),
);
}
);
}
None => {
self.add_image(
clip_and_scroll,
&prim_info,
info.stretch_size,
info.tile_spacing,
None,
info.image_key,
info.image_rendering,
info.alpha_type,
None,
);
}
}
self.add_image(
clip_and_scroll,
&prim_info,
info.stretch_size,
info.tile_spacing,
None,
info.image_key,
info.image_rendering,
info.alpha_type,
);
}
SpecificDisplayItem::YuvImage(ref info) => {
self.add_yuv_image(
@@ -1831,7 +1797,6 @@ impl<'a> DisplayListFlattener<'a> {
border.image_key,
ImageRendering::Auto,
AlphaType::PremultipliedAlpha,
None,
);
}
}
@@ -2161,7 +2126,6 @@ impl<'a> DisplayListFlattener<'a> {
image_key: ImageKey,
image_rendering: ImageRendering,
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
@@ -2174,24 +2138,25 @@ impl<'a> DisplayListFlattener<'a> {
let request = ImageRequest {
key: image_key,
rendering: image_rendering,
tile: tile_offset,
tile: None,
};

// We don't yet have a good way to deal with images with large amount of repetitions using
// brushes, so fallback to the non-brush image shader for now;
let many_repetitions = (stretch_size.width / info.rect.size.width) *
(stretch_size.height / info.rect.size.height) > 200.0;
let many_repetitions = (info.rect.size.width / stretch_size.width) *
(info.rect.size.height / stretch_size.height) > 200.0;

// See if conditions are met to run through the new
// image brush shader, which supports segments.
if sub_rect.is_none() && !many_repetitions && tile_offset.is_none() {
if sub_rect.is_none() && !many_repetitions {
let prim = BrushPrimitive::new(
BrushKind::Image {
request,
current_epoch: Epoch::invalid(),
alpha_type,
stretch_size,
tile_spacing,
visible_tiles: Vec::new(),
},
None,
);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.