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

Decompose repeated gradients during frame building.

  • Loading branch information
nical committed Apr 4, 2018
commit f6f938a8ad0863e6b604d46d75d775674bdc3c45
@@ -39,9 +39,14 @@ void brush_vs(
mat4 transform,
PictureTask pic_task
) {
vec2 origin = prim_local_rect.p0;
if (user_data.y == SEGMENT_SOURCE_FULL) {
origin = segment_local_rect.p0;
}

Gradient gradient = fetch_gradient(prim_address);

vPos = vi.local_pos - prim_local_rect.p0;
vPos = vi.local_pos - origin;

vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw;
@@ -40,9 +40,14 @@ void brush_vs(
mat4 transform,
PictureTask pic_task
) {
vec2 origin = prim_local_rect.p0;
if (user_data.y == SEGMENT_SOURCE_FULL) {
origin = segment_local_rect.p0;
}

RadialGradient gradient = fetch_radial_gradient(prim_address);

vPos = vi.local_pos - prim_local_rect.p0;
vPos = vi.local_pos - origin;

vCenter = gradient.center_start_end_radius.xy;
vStartRadius = gradient.center_start_end_radius.z;
@@ -1375,25 +1375,35 @@ impl BrushPrimitive {
))
}
BrushKind::RadialGradient { gradient_index, .. } => {
let segment_src = match self.segment_desc {
Some(ref desc) => { desc.src }
None => SegmentSrc::Auto,
};

let stops_handle = &cached_gradients[gradient_index.0].handle;
Some((
BrushBatchKind::RadialGradient,
BatchTextures::no_texture(),
[
stops_handle.as_int(gpu_cache),
0,
segment_src as i32,
0,
],
))
}
BrushKind::LinearGradient { gradient_index, .. } => {
let segment_src = match self.segment_desc {
Some(ref desc) => { desc.src }
None => SegmentSrc::Auto,
};

let stops_handle = &cached_gradients[gradient_index.0].handle;
Some((
BrushBatchKind::LinearGradient,
BatchTextures::no_texture(),
[
stops_handle.as_int(gpu_cache),
0,
segment_src as i32,
0,
],
))
@@ -8,7 +8,7 @@ use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, Devi
use api::{DevicePixelScale, DeviceUintRect, DisplayItemRef, Epoch, ExtendMode, ExternalScrollId};
use api::{FilterOp, FontInstanceKey, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop};
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo};
use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform};
use api::{LayerRect, LayerSize, LayerVector2D, LayoutSize, LayoutTransform};
use api::{LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding};
use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
@@ -1843,7 +1843,7 @@ impl<'a> DisplayListFlattener<'a> {
}
}

fn add_gradient_impl(
pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
@@ -1852,8 +1852,12 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayerSize,
tile_spacing: LayerSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());

// Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this,
// a reference orientation for the gradient line must be chosen, somewhat arbitrarily, so
@@ -1881,6 +1885,8 @@ impl<'a> DisplayListFlattener<'a> {
start_point: sp,
end_point: ep,
gradient_index,
stretch_size,
tile_spacing,
},
None,
);
@@ -1890,54 +1896,6 @@ impl<'a> DisplayListFlattener<'a> {
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
}

pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayerPrimitiveInfo,
start_point: LayerPoint,
end_point: LayerPoint,
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
tile_size: LayerSize,
tile_spacing: LayerSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());

let prim_infos = info.decompose(
tile_size,
tile_spacing,
64 * 64,
);

if prim_infos.is_empty() {
self.add_gradient_impl(
clip_and_scroll,
info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
);
} else {
for prim_info in prim_infos {
self.add_gradient_impl(
clip_and_scroll,
&prim_info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
);
}
}
}

fn add_radial_gradient_impl(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
@@ -1949,6 +1907,8 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayerSize,
tile_spacing: LayerSize,
) {
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
@@ -1959,6 +1919,8 @@ impl<'a> DisplayListFlattener<'a> {
end_radius,
ratio_xy,
gradient_index,
stretch_size,
tile_spacing
},
None,
);
@@ -1981,45 +1943,25 @@ impl<'a> DisplayListFlattener<'a> {
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
tile_size: LayerSize,
stretch_size: LayerSize,
tile_spacing: LayerSize,
) {
let gradient_index = CachedGradientIndex(self.cached_gradients.len());
self.cached_gradients.push(CachedGradient::new());

let prim_infos = info.decompose(
tile_size,
self.add_radial_gradient_impl(
clip_and_scroll,
info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
tile_spacing,
64 * 64,
);

if prim_infos.is_empty() {
self.add_radial_gradient_impl(
clip_and_scroll,
info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
);
} else {
for prim_info in prim_infos {
self.add_radial_gradient_impl(
clip_and_scroll,
&prim_info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
);
}
}
}

pub fn add_text(
@@ -2259,72 +2201,6 @@ pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltS
}
}

trait PrimitiveInfoTiler {
fn decompose(
&self,
tile_size: LayerSize,
tile_spacing: LayerSize,
max_prims: usize,
) -> Vec<LayerPrimitiveInfo>;
}

impl PrimitiveInfoTiler for LayerPrimitiveInfo {
fn decompose(
&self,
tile_size: LayerSize,
tile_spacing: LayerSize,
max_prims: usize,
) -> Vec<LayerPrimitiveInfo> {
let mut prims = Vec::new();
let tile_repeat = tile_size + tile_spacing;

if tile_repeat.width <= 0.0 ||
tile_repeat.height <= 0.0 {
return prims;
}

if tile_repeat.width < self.rect.size.width ||
tile_repeat.height < self.rect.size.height {
let clip_rect = self.clip_rect
.intersection(&self.rect)
.unwrap_or_else(LayoutRect::zero);
let rect_p0 = self.rect.origin;
let rect_p1 = self.rect.bottom_right();

let mut y0 = rect_p0.y;
while y0 < rect_p1.y {
let mut x0 = rect_p0.x;

while x0 < rect_p1.x {
prims.push(LayerPrimitiveInfo {
rect: LayerRect::new(
LayerPoint::new(x0, y0),
tile_size,
),
clip_rect,
is_backface_visible: self.is_backface_visible,
tag: self.tag,
});

// Mostly a safety against a crazy number of primitives
// being generated. If we exceed that amount, just bail
// out and only draw the maximum amount.
if prims.len() > max_prims {
warn!("too many prims found due to repeat/tile. dropping extra prims!");
return prims;
}

x0 += tile_repeat.width;
}

y0 += tile_repeat.height;
}
}

prims
}
}

/// Properties of a stacking context that are maintained
/// during creation of the scene. These structures are
/// not persisted after the initial scene build.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.