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 gradients during scene building. #2752

Merged
merged 2 commits into from May 11, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -21,7 +21,8 @@ use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, CachedGradient, DeferredResolve};
use prim_store::{EdgeAaSegmentMask, ImageSource, PictureIndex, PrimitiveIndex, PrimitiveKind};
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore};
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore, VisibleGradientTile};
use prim_store::CachedGradientIndex;
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
use renderer::{BLOCKS_PER_UV_RECT, ShaderColorMode};
@@ -615,6 +616,8 @@ impl AlphaBatchBuilder {
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
match brush.kind {
BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(),
BrushKind::LinearGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
BrushKind::RadialGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
_ => false,
}
}
@@ -1018,6 +1021,40 @@ impl AlphaBatchBuilder {
}
}
}
BrushKind::LinearGradient { gradient_index, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
add_gradient_tiles(
visible_tiles,
gradient_index,
BrushBatchKind::LinearGradient,
specified_blend_mode,
&task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address,
z,
ctx,
gpu_cache,
&mut self.batch_list,
);
}
BrushKind::RadialGradient { gradient_index, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
add_gradient_tiles(
visible_tiles,
gradient_index,
BrushBatchKind::RadialGradient,
specified_blend_mode,
&task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address,
z,
ctx,
gpu_cache,
&mut self.batch_list,
);
}
_ => {
if let Some((batch_kind, textures, user_data)) = brush.get_batch_params(
ctx.resource_cache,
@@ -1348,6 +1385,57 @@ impl AlphaBatchBuilder {
}
}

fn add_gradient_tiles(
visible_tiles: &[VisibleGradientTile],
gradient_index: CachedGradientIndex,
kind: BrushBatchKind,
blend_mode: BlendMode,
task_relative_bounding_rect: &DeviceIntRect,
clip_chain_rect_index: ClipChainRectIndex,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress,
z: ZBufferId,
ctx: &RenderTargetContext,
gpu_cache: &GpuCache,
batch_list: &mut BatchList,
) {
batch_list.add_bounding_rect(task_relative_bounding_rect);
let batch = batch_list.get_suitable_batch(
BatchKey {
blend_mode: blend_mode,
kind: BatchKind::Brush(kind),
textures: BatchTextures::no_texture(),
},
task_relative_bounding_rect
);

let stops_handle = &ctx.cached_gradients[gradient_index.0].handle;
let user_data = [stops_handle.as_int(gpu_cache), 0, 0];

let base_instance = BrushInstance {
picture_address: task_address,
prim_address: GpuCacheAddress::invalid(),
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
};

for tile in visible_tiles {
batch.push(PrimitiveInstance::from(
BrushInstance {
prim_address: gpu_cache.get_address(&tile.handle),
..base_instance
}
));
}
}

fn get_image_tile_params(
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
@@ -1800,7 +1800,7 @@ impl<'a> DisplayListFlattener<'a> {
}
}

fn add_gradient_impl(
pub fn add_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
@@ -1809,9 +1809,19 @@ impl<'a> DisplayListFlattener<'a> {
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: 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
};

// 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
@@ -1840,23 +1850,26 @@ impl<'a> DisplayListFlattener<'a> {
end_point: ep,
gradient_index,
stretch_size,
tile_spacing,
visible_tiles: Vec::new(),
},
None,
);

let prim = PrimitiveContainer::Brush(prim);

self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
self.add_primitive(clip_and_scroll, &info, Vec::new(), prim);
}

pub fn add_gradient(
pub fn add_radial_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
start_point: LayoutPoint,
end_point: LayoutPoint,
center: LayoutPoint,
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange<GradientStop>,
stops_count: usize,
extend_mode: ExtendMode,
stretch_size: LayoutSize,
mut tile_spacing: LayoutSize,
@@ -1871,58 +1884,6 @@ impl<'a> DisplayListFlattener<'a> {
.. *info
};

if tile_spacing != LayoutSize::zero() {
let prim_infos = info.decompose(
stretch_size,
tile_spacing,
64 * 64,
);

if !prim_infos.is_empty() {
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,
prim_info.rect.size,
);
}

return;
}
}

self.add_gradient_impl(
clip_and_scroll,
&info,
start_point,
end_point,
stops,
stops_count,
extend_mode,
gradient_index,
stretch_size,
);
}

fn add_radial_gradient_impl(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
center: LayoutPoint,
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
gradient_index: CachedGradientIndex,
stretch_size: LayoutSize,
) {
let prim = BrushPrimitive::new(
BrushKind::RadialGradient {
stops_range: stops,
@@ -1933,82 +1894,20 @@ impl<'a> DisplayListFlattener<'a> {
ratio_xy,
gradient_index,
stretch_size,
tile_spacing,
visible_tiles: Vec::new(),
},
None,
);

self.add_primitive(
clip_and_scroll,
info,
&info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
}

pub fn add_radial_gradient(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
center: LayoutPoint,
start_radius: f32,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange<GradientStop>,
extend_mode: ExtendMode,
stretch_size: 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,
tile_spacing,
64 * 64,
);

if !prim_infos.is_empty() {
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,
stretch_size,
);
}

return;
}
}

self.add_radial_gradient_impl(
clip_and_scroll,
&info,
center,
start_radius,
end_radius,
ratio_xy,
stops,
extend_mode,
gradient_index,
stretch_size,
);
}

pub fn add_text(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
@@ -2208,72 +2107,6 @@ pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltS
}
}

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

impl PrimitiveInfoTiler for LayoutPrimitiveInfo {
fn decompose(
&self,
tile_size: LayoutSize,
tile_spacing: LayoutSize,
max_prims: usize,
) -> Vec<LayoutPrimitiveInfo> {
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(LayoutPrimitiveInfo {
rect: LayoutRect::new(
LayoutPoint::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.