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
Next

Decompose repeated images into brush segments.

  • Loading branch information
nical committed Apr 4, 2018
commit 7038206328a80c2cc5f6c62cc48edb6b34ac0e8d
@@ -7,7 +7,8 @@
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
@@ -18,6 +19,9 @@ void brush_vs(

#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1

#define SEGMENT_SOURCE_AUTO 0
#define SEGMENT_SOURCE_FULL 1

struct BrushInstance {
int picture_address;
int prim_address;
@@ -146,6 +150,7 @@ void main(void) {
vi,
brush.prim_address + VECS_PER_BRUSH_PRIM,
brush_prim.local_rect,
local_segment_rect,
brush.user_data,
scroll_node.transform,
pic_task
@@ -20,7 +20,8 @@ flat varying vec4 vUvClipBounds;
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
@@ -57,11 +57,21 @@ vec2 transform_point_snapped(
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
) {
// We will derive the uv coordinates from the local rect, using either the segment or
// the primitive's local rect depending on whether we want each segment to sample from
// the entire image or parts of it.
RectWithSize local_rect = prim_local_rect;
int segment_source = (user_data.y >> 8) & 0xff;
if (segment_source == SEGMENT_SOURCE_FULL) {
local_rect = segment_local_rect;
}

// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
// non-normalized texture coordinates.
#ifdef WR_FEATURE_TEXTURE_RECT
@@ -89,8 +99,8 @@ void brush_vs(
vec2 f;

#ifdef WR_FEATURE_ALPHA_PASS
int image_source = user_data.y >> 16;
int raster_space = user_data.y & 0xffff;
int image_source = (user_data.y >> 16) & 0xff;
int raster_space = user_data.y & 0xff;

// Derive the texture coordinates for this image, based on
// whether the source image is a local-space or screen-space
@@ -33,14 +33,15 @@ Gradient fetch_gradient(int address) {
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
) {
Gradient gradient = fetch_gradient(prim_address);

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

vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw;
@@ -15,7 +15,8 @@ flat varying int vOp;
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
@@ -34,14 +34,15 @@ RadialGradient fetch_radial_gradient(int address) {
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
) {
RadialGradient gradient = fetch_radial_gradient(prim_address);

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

vCenter = gradient.center_start_end_radius.xy;
vStartRadius = gradient.center_start_end_radius.z;
@@ -26,7 +26,8 @@ SolidBrush fetch_solid_primitive(int address) {
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
@@ -73,12 +73,13 @@ void write_uv_rect(
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
RectWithSize prim_local_rect,
RectWithSize segment_local_rect,
ivec3 user_data,
mat4 transform,
PictureTask pic_task
) {
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
vec2 f = (vi.local_pos - prim_local_rect.p0) / prim_local_rect.size;

#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = vi.local_pos;
@@ -19,7 +19,7 @@ use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PicturePrimitive};
use plane_split::{BspSplitter, Polygon, Splitter};
use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun, SegmentSrc};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind};
use renderer::BLOCKS_PER_UV_RECT;
@@ -47,7 +47,7 @@ pub enum TransformBatchKind {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BrushImageSourceKind {
Color = 0,
//Alpha = 1, // Unused for now, but left here as shaders need to match.
//Alpha = 0x1, // Unused for now, but left here as shaders need to match.
ColorAlphaMask = 2,
}

@@ -1255,6 +1255,11 @@ impl BrushPrimitive {
) -> 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,
@@ -1266,13 +1271,13 @@ impl BrushPrimitive {
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|
(BrushImageSourceKind::Color as i32) << 16 |
(segment_src as i32) << 8 |
RasterizationSpace::Local as i32,
0,
],
@@ -9,7 +9,7 @@ use ellipse::Ellipse;
use display_list_flattener::DisplayListFlattener;
use gpu_cache::GpuDataRequest;
use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor};
use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain, SegmentSrc};
use util::{lerp, pack_as_float};

#[repr(u8)]
@@ -458,6 +458,7 @@ impl<'a> DisplayListFlattener<'a> {
segment(p1.x, p0.y, p2.x, p1.y),
],
clip_mask_kind: BrushClipMaskKind::Unknown,
src: SegmentSrc::Auto,
};

self.add_solid_rectangle(
@@ -474,6 +475,7 @@ impl<'a> DisplayListFlattener<'a> {
segment(p0.x, p1.y, p1.x, p2.y),
],
clip_mask_kind: BrushClipMaskKind::Unknown,
src: SegmentSrc::Auto,
};

self.add_solid_rectangle(
@@ -490,6 +492,7 @@ impl<'a> DisplayListFlattener<'a> {
segment(p2.x, p1.y, p3.x, p2.y),
],
clip_mask_kind: BrushClipMaskKind::Unknown,
src: SegmentSrc::Auto,
};

self.add_solid_rectangle(
@@ -508,6 +511,7 @@ impl<'a> DisplayListFlattener<'a> {
segment(p0.x, p2.y, p1.x, p3.y),
],
clip_mask_kind: BrushClipMaskKind::Unknown,
src: SegmentSrc::Auto,
};

self.add_solid_rectangle(
@@ -2177,17 +2177,21 @@ impl<'a> DisplayListFlattener<'a> {
tile: tile_offset,
};

// 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;

// See if conditions are met to run through the new
// image brush shader, which supports segments.
if tile_spacing == LayerSize::zero() &&
stretch_size == info.rect.size &&
sub_rect.is_none() &&
tile_offset.is_none() {
if sub_rect.is_none() && !many_repetitions && tile_offset.is_none() {
let prim = BrushPrimitive::new(
BrushKind::Image {
request,
current_epoch: Epoch::invalid(),
alpha_type,
stretch_size,
tile_spacing,
},
None,
);
@@ -2,8 +2,9 @@
* 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::{TileOffset, LayerRect, LayerSize, LayerVector2D, DeviceUintSize};
use api::{TileOffset, LayerRect, LayerSize, LayerPoint, LayerVector2D, DeviceUintSize};
use euclid::rect;
use prim_store::EdgeAaSegmentMask;

pub struct DecomposedTile {
pub rect: LayerRect,
@@ -278,3 +279,68 @@ fn add_device_tile(
});
}
}

pub fn for_each_repetition(
prim_rect: &LayerRect,
visible_rect: &LayerRect,
stride: &LayerSize,
callback: &mut FnMut(&LayerPoint, EdgeAaSegmentMask),
) {
assert!(stride.width > 0.0);
assert!(stride.height > 0.0);

let visible_rect = match prim_rect.intersection(&visible_rect) {
Some(rect) => rect,
None => return,
};

let nx = if visible_rect.origin.x > prim_rect.origin.x {
f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width)
} else {
0.0
};

let ny = if visible_rect.origin.y > prim_rect.origin.y {
f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height)
} else {
0.0
};

let x0 = prim_rect.origin.x + nx * stride.width;
let y0 = prim_rect.origin.y + ny * stride.height;

let mut p = LayerPoint::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;
}

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;
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.