Bug 1447998 - Update webrender to commit 22493328352ba432a7cd89491d81bfaa19bc1bce. r=jrmuizel

MozReview-Commit-ID: 4krUpVqWkr

--HG--
extra : rebase_source : 55990a227f280c2c9c1f92c9f2c1f52b6e91c184
This commit is contained in:
Kartikaya Gupta 2018-03-28 09:11:21 -04:00
parent 05c79c044e
commit 9fa8fde9e9
24 changed files with 1049 additions and 1135 deletions

View File

@ -11,7 +11,6 @@ flat varying float vLayer;
flat varying vec4 vEdge;
flat varying vec4 vUvBounds_NoClamp;
flat varying float vClipMode;
flat varying int vStretchMode;
#define MODE_STRETCH 0
#define MODE_SIMPLE 1
@ -21,14 +20,21 @@ flat varying int vStretchMode;
struct BoxShadowData {
vec2 src_rect_size;
float clip_mode;
int stretch_mode;
int stretch_mode_x;
int stretch_mode_y;
RectWithSize dest_rect;
};
BoxShadowData fetch_data(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
RectWithSize dest_rect = RectWithSize(data[1].xy, data[1].zw);
BoxShadowData bs_data = BoxShadowData(data[0].xy, data[0].z, int(data[0].w), dest_rect);
vec4 data[3] = fetch_from_resource_cache_3_direct(address);
RectWithSize dest_rect = RectWithSize(data[2].xy, data[2].zw);
BoxShadowData bs_data = BoxShadowData(
data[0].xy,
data[0].z,
int(data[1].x),
int(data[1].y),
dest_rect
);
return bs_data;
}
@ -46,7 +52,6 @@ void main(void) {
vLayer = res.layer;
vPos = vi.local_pos;
vClipMode = bs_data.clip_mode;
vStretchMode = bs_data.stretch_mode;
vec2 uv0 = res.uv_rect.p0;
vec2 uv1 = res.uv_rect.p1;
@ -54,17 +59,32 @@ void main(void) {
vec2 texture_size = vec2(textureSize(sColor0, 0));
vec2 local_pos = vPos.xy / vPos.z;
switch (bs_data.stretch_mode) {
switch (bs_data.stretch_mode_x) {
case MODE_STRETCH: {
vEdge.xy = vec2(0.5);
vEdge.zw = (bs_data.dest_rect.size / bs_data.src_rect_size) - vec2(0.5);
vUv = (local_pos - bs_data.dest_rect.p0) / bs_data.src_rect_size;
vEdge.x = 0.5;
vEdge.z = (bs_data.dest_rect.size.x / bs_data.src_rect_size.x) - 0.5;
vUv.x = (local_pos.x - bs_data.dest_rect.p0.x) / bs_data.src_rect_size.x;
break;
}
case MODE_SIMPLE:
default: {
vec2 f = (local_pos - bs_data.dest_rect.p0) / bs_data.dest_rect.size;
vUv = mix(uv0, uv1, f) / texture_size;
vEdge.xz = vec2(1.0);
vUv.x = (local_pos.x - bs_data.dest_rect.p0.x) / bs_data.dest_rect.size.x;
break;
}
}
switch (bs_data.stretch_mode_y) {
case MODE_STRETCH: {
vEdge.y = 0.5;
vEdge.w = (bs_data.dest_rect.size.y / bs_data.src_rect_size.y) - 0.5;
vUv.y = (local_pos.y - bs_data.dest_rect.p0.y) / bs_data.src_rect_size.y;
break;
}
case MODE_SIMPLE:
default: {
vEdge.yw = vec2(1.0);
vUv.y = (local_pos.y - bs_data.dest_rect.p0.y) / bs_data.dest_rect.size.y;
break;
}
}
@ -77,22 +97,10 @@ void main(void) {
#ifdef WR_FRAGMENT_SHADER
void main(void) {
vec2 local_pos = vPos.xy / vPos.z;
vec2 uv;
switch (vStretchMode) {
case MODE_STRETCH: {
uv = clamp(vUv.xy, vec2(0.0), vEdge.xy);
uv += max(vec2(0.0), vUv.xy - vEdge.zw);
uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
break;
}
case MODE_SIMPLE:
default: {
uv = vUv.xy;
break;
}
}
vec2 uv = clamp(vUv.xy, vec2(0.0), vEdge.xy);
uv += max(vec2(0.0), vUv.xy - vEdge.zw);
uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
float in_shadow_rect = point_inside_rect(

View File

@ -2,13 +2,10 @@
* 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/. */
#define VECS_PER_SPECIFIC_BRUSH 2
#include shared,prim_shared,clip_shared
#include shared,prim_shared,brush
varying vec3 vLocalPos;
varying vec2 vLocalPos;
flat varying vec4 vColor;
flat varying int vStyle;
flat varying float vAxisSelect;
flat varying vec4 vParams;
@ -19,51 +16,50 @@ flat varying vec2 vLocalOrigin;
#define LINE_ORIENTATION_VERTICAL 0
#define LINE_ORIENTATION_HORIZONTAL 1
struct Line {
vec4 color;
struct LineDecorationData {
RectWithSize local_rect;
float wavyLineThickness;
float style;
float orientation;
};
Line fetch_line(int address) {
vec4 data[2] = fetch_from_resource_cache_2(address);
return Line(data[0], data[1].x, data[1].y, data[1].z);
LineDecorationData fetch_data(ivec2 address) {
vec4 data[2] = fetch_from_resource_cache_2_direct(address);
RectWithSize local_rect = RectWithSize(data[0].xy, data[0].zw);
LineDecorationData line_data = LineDecorationData(
local_rect,
data[1].x,
data[1].y,
data[1].z
);
return line_data;
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize local_rect,
ivec3 user_data,
PictureTask pic_task
) {
void main(void) {
ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
LineDecorationData data = fetch_data(cmi.clip_data_address);
ClipVertexInfo vi = write_clip_tile_vertex(data.local_rect,
scroll_node,
area);
vLocalPos = vi.local_pos;
// Note: `line` name is reserved in HLSL
Line line_prim = fetch_line(prim_address);
switch (int(abs(pic_task.pic_kind_and_raster_mode))) {
case PIC_TYPE_TEXT_SHADOW:
vColor = pic_task.color;
break;
default:
vColor = line_prim.color;
break;
}
vec2 pos, size;
switch (int(line_prim.orientation)) {
switch (int(data.orientation)) {
case LINE_ORIENTATION_HORIZONTAL:
vAxisSelect = 0.0;
pos = local_rect.p0;
size = local_rect.size;
pos = data.local_rect.p0;
size = data.local_rect.size;
break;
case LINE_ORIENTATION_VERTICAL:
vAxisSelect = 1.0;
pos = local_rect.p0.yx;
size = local_rect.size.yx;
pos = data.local_rect.p0.yx;
size = data.local_rect.size.yx;
break;
default:
vAxisSelect = 0.0;
@ -71,7 +67,7 @@ void brush_vs(
}
vLocalOrigin = pos;
vStyle = int(line_prim.style);
vStyle = int(data.style);
switch (vStyle) {
case LINE_STYLE_SOLID: {
@ -98,7 +94,7 @@ void brush_vs(
}
case LINE_STYLE_WAVY: {
// This logic copied from gecko to get the same results
float line_thickness = max(line_prim.wavyLineThickness, 1.0);
float line_thickness = max(data.wavyLineThickness, 1.0);
// Difference in height between peaks and troughs
// (and since slopes are 45 degrees, the length of each slope)
float slope_length = size.y - line_thickness;
@ -121,9 +117,9 @@ void brush_vs(
#define MAGIC_WAVY_LINE_AA_SNAP 0.5
vec4 brush_fs() {
void main(void) {
// Find the appropriate distance to apply the step over.
vec2 local_pos = vLocalPos;
vec2 local_pos = vLocalPos.xy / vLocalPos.z;
float aa_range = compute_aa_range(local_pos);
float alpha = 1.0;
@ -200,6 +196,6 @@ vec4 brush_fs() {
default: break;
}
return vColor * alpha;
oFragColor = vec4(alpha);
}
#endif

View File

@ -76,7 +76,7 @@ vec4[2] fetch_from_resource_cache_2(int address) {
#define VECS_PER_CLIP_SCROLL_NODE 9
#define VECS_PER_LOCAL_CLIP_RECT 1
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_RENDER_TASK 2
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
#define VECS_PER_GRADIENT_STOP 2
@ -203,7 +203,6 @@ struct RenderTaskCommonData {
struct RenderTaskData {
RenderTaskCommonData common_data;
vec3 data1;
vec4 data2;
};
RenderTaskData fetch_render_task_data(int index) {
@ -211,7 +210,6 @@ RenderTaskData fetch_render_task_data(int index) {
vec4 texel0 = TEXEL_FETCH(sRenderTasks, uv, 0, ivec2(0, 0));
vec4 texel1 = TEXEL_FETCH(sRenderTasks, uv, 0, ivec2(1, 0));
vec4 texel2 = TEXEL_FETCH(sRenderTasks, uv, 0, ivec2(2, 0));
RectWithSize task_rect = RectWithSize(
texel0.xy,
@ -225,8 +223,7 @@ RenderTaskData fetch_render_task_data(int index) {
RenderTaskData data = RenderTaskData(
common_data,
texel1.yzw,
texel2
texel1.yzw
);
return data;
@ -262,8 +259,6 @@ RenderTaskCommonData fetch_render_task_common_data(int index) {
struct PictureTask {
RenderTaskCommonData common_data;
vec2 content_origin;
float pic_kind_and_raster_mode;
vec4 color;
};
PictureTask fetch_picture_task(int address) {
@ -271,9 +266,7 @@ PictureTask fetch_picture_task(int address) {
PictureTask task = PictureTask(
task_data.common_data,
task_data.data1.xy,
task_data.data1.z,
task_data.data2
task_data.data1.xy
);
return task;

View File

@ -12,11 +12,11 @@ use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ZBufferId, ZBufferIdGenerator};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive};
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};
@ -56,7 +56,6 @@ pub enum BrushImageSourceKind {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BrushBatchKind {
Solid,
Line,
Image(ImageBufferKind),
Blend,
MixBlend {
@ -457,6 +456,7 @@ impl AlphaBatchBuilder {
gpu_cache: &mut GpuCache,
render_tasks: &RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>,
z_generator: &mut ZBufferIdGenerator,
) {
let task_address = render_tasks.get_task_address(task_id);
@ -489,6 +489,7 @@ impl AlphaBatchBuilder {
deferred_resolves,
&mut splitter,
content_origin,
z_generator,
);
}
@ -524,7 +525,7 @@ impl AlphaBatchBuilder {
RenderTaskAddress(0),
gpu_address,
0,
prim_index.0 as i32,
z_generator.next(),
0,
0,
);
@ -548,6 +549,7 @@ impl AlphaBatchBuilder {
deferred_resolves: &mut Vec<DeferredResolve>,
splitter: &mut BspSplitter<f64, WorldPixel>,
content_origin: DeviceIntPoint,
z_generator: &mut ZBufferIdGenerator,
) {
for i in 0 .. run.count {
let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
@ -566,6 +568,7 @@ impl AlphaBatchBuilder {
deferred_resolves,
splitter,
content_origin,
z_generator,
);
}
}
@ -588,8 +591,9 @@ impl AlphaBatchBuilder {
deferred_resolves: &mut Vec<DeferredResolve>,
splitter: &mut BspSplitter<f64, WorldPixel>,
content_origin: DeviceIntPoint,
z_generator: &mut ZBufferIdGenerator,
) {
let z = prim_index.0 as i32;
let z = z_generator.next();
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
let scroll_node = &ctx.node_data[scroll_id.0 as usize];
// TODO(gw): Calculating this for every primitive is a bit
@ -644,281 +648,39 @@ impl AlphaBatchBuilder {
let cache_task_address = render_tasks.get_task_address(cache_task_id);
let textures = BatchTextures::render_target_cache();
match picture.kind {
PictureKind::TextShadow { .. } => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
// If this picture is participating in a 3D rendering context,
// then don't add it to any batches here. Instead, create a polygon
// for it and add it to the current plane splitter.
if picture.is_in_3d_context {
// Push into parent plane splitter.
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let real_xf = &ctx.clip_scroll_tree
.nodes[picture.reference_frame_index.0]
.world_content_transform
.into();
let polygon = make_polygon(
picture.real_local_rect,
&real_xf,
prim_index.0,
);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
BrushImageSourceKind::Color as i32,
RasterizationSpace::Screen as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
PictureKind::Image {
composite_mode,
secondary_render_task_id,
is_in_3d_context,
reference_frame_index,
real_local_rect,
ref extra_gpu_data_handle,
..
} => {
// If this picture is participating in a 3D rendering context,
// then don't add it to any batches here. Instead, create a polygon
// for it and add it to the current plane splitter.
if is_in_3d_context {
// Push into parent plane splitter.
splitter.add(polygon);
let real_xf = &ctx.clip_scroll_tree
.nodes[reference_frame_index.0]
.world_content_transform
.into();
let polygon = make_polygon(
real_local_rect,
&real_xf,
prim_index.0,
);
return;
}
splitter.add(polygon);
// Depending on the composite mode of the picture, we generate the
// old style Composite primitive instances. In the future, we'll
// remove these and pass them through the brush batching pipeline.
// This will allow us to unify some of the shaders, apply clip masks
// when compositing pictures, and also correctly apply pixel snapping
// to picture compositing operations.
let source_id = cache_task_id;
return;
}
// Depending on the composite mode of the picture, we generate the
// old style Composite primitive instances. In the future, we'll
// remove these and pass them through the brush batching pipeline.
// This will allow us to unify some of the shaders, apply clip masks
// when compositing pictures, and also correctly apply pixel snapping
// to picture compositing operations.
let source_id = cache_task_id;
match composite_mode.expect("bug: only composites here") {
PictureCompositeMode::Filter(filter) => {
match filter {
FilterOp::Blur(..) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
BrushImageSourceKind::Color as i32,
RasterizationSpace::Screen as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
FilterOp::DropShadow(offset, _, _) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
uv_rect_address,
BrushImageSourceKind::ColorAlphaMask as i32,
// TODO(gw): This is totally wrong, but the drop-shadow code itself
// is completely wrong, and doesn't work correctly with
// transformed Picture sources. I'm leaving this as is for
// now, and will fix drop-shadows properly, as a follow up.
RasterizationSpace::Local as i32,
],
};
{
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(PrimitiveInstance::from(instance));
}
let secondary_id = secondary_render_task_id.expect("no secondary!?");
let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
let secondary_task_address = render_tasks.get_task_address(secondary_id);
let secondary_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCache(saved_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
};
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
secondary_textures,
);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let content_rect = prim_metadata.local_rect.translate(&-offset);
let rect =
(content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round()
.to_i32();
let instance = CompositePrimitiveInstance::new(
task_address,
secondary_task_address,
RenderTaskAddress(0),
rect.origin.x,
rect.origin.y,
z,
rect.size.width,
rect.size.height,
);
batch.push(PrimitiveInstance::from(instance));
}
_ => {
let key = BatchKey::new(
BatchKind::Brush(BrushBatchKind::Blend),
BlendMode::PremultipliedAlpha,
BatchTextures::render_target_cache(),
);
let filter_mode = match filter {
FilterOp::Blur(..) => 0,
FilterOp::Contrast(..) => 1,
FilterOp::Grayscale(..) => 2,
FilterOp::HueRotate(..) => 3,
FilterOp::Invert(..) => 4,
FilterOp::Saturate(..) => 5,
FilterOp::Sepia(..) => 6,
FilterOp::Brightness(..) => 7,
FilterOp::Opacity(..) => 8,
FilterOp::DropShadow(..) => 9,
FilterOp::ColorMatrix(..) => 10,
};
let user_data = match filter {
FilterOp::Contrast(amount) |
FilterOp::Grayscale(amount) |
FilterOp::Invert(amount) |
FilterOp::Saturate(amount) |
FilterOp::Sepia(amount) |
FilterOp::Brightness(amount) |
FilterOp::Opacity(_, amount) => {
(amount * 65536.0) as i32
}
FilterOp::HueRotate(angle) => {
(0.01745329251 * angle * 65536.0) as i32
}
// Go through different paths
FilterOp::Blur(..) |
FilterOp::DropShadow(..) => {
unreachable!();
}
FilterOp::ColorMatrix(_) => {
extra_gpu_data_handle.as_int(gpu_cache)
}
};
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
cache_task_address.0 as i32,
filter_mode,
user_data,
],
};
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(PrimitiveInstance::from(instance));
}
}
}
PictureCompositeMode::MixBlend(mode) => {
let backdrop_id = secondary_render_task_id.expect("no backdrop!?");
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id,
source_id,
backdrop_id,
},
),
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(source_id);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
PictureCompositeMode::Blit => {
match picture.composite_mode.expect("bug: only composites here") {
PictureCompositeMode::Filter(filter) => {
match filter {
FilterOp::Blur(..) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
@ -947,8 +709,209 @@ impl AlphaBatchBuilder {
};
batch.push(PrimitiveInstance::from(instance));
}
FilterOp::DropShadow(offset, _, _) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: [
uv_rect_address,
BrushImageSourceKind::ColorAlphaMask as i32,
// TODO(gw): This is totally wrong, but the drop-shadow code itself
// is completely wrong, and doesn't work correctly with
// transformed Picture sources. I'm leaving this as is for
// now, and will fix drop-shadows properly, as a follow up.
RasterizationSpace::Local as i32,
],
};
{
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(PrimitiveInstance::from(instance));
}
let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
let secondary_task_address = render_tasks.get_task_address(secondary_id);
let secondary_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCache(saved_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
};
let key = BatchKey::new(
BatchKind::HardwareComposite,
BlendMode::PremultipliedAlpha,
secondary_textures,
);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let content_rect = prim_metadata.local_rect.translate(&-offset);
let rect =
(content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round()
.to_i32();
let instance = CompositePrimitiveInstance::new(
task_address,
secondary_task_address,
RenderTaskAddress(0),
rect.origin.x,
rect.origin.y,
z,
rect.size.width,
rect.size.height,
);
batch.push(PrimitiveInstance::from(instance));
}
_ => {
let key = BatchKey::new(
BatchKind::Brush(BrushBatchKind::Blend),
BlendMode::PremultipliedAlpha,
BatchTextures::render_target_cache(),
);
let filter_mode = match filter {
FilterOp::Blur(..) => 0,
FilterOp::Contrast(..) => 1,
FilterOp::Grayscale(..) => 2,
FilterOp::HueRotate(..) => 3,
FilterOp::Invert(..) => 4,
FilterOp::Saturate(..) => 5,
FilterOp::Sepia(..) => 6,
FilterOp::Brightness(..) => 7,
FilterOp::Opacity(..) => 8,
FilterOp::DropShadow(..) => 9,
FilterOp::ColorMatrix(..) => 10,
};
let user_data = match filter {
FilterOp::Contrast(amount) |
FilterOp::Grayscale(amount) |
FilterOp::Invert(amount) |
FilterOp::Saturate(amount) |
FilterOp::Sepia(amount) |
FilterOp::Brightness(amount) |
FilterOp::Opacity(_, amount) => {
(amount * 65536.0) as i32
}
FilterOp::HueRotate(angle) => {
(0.01745329251 * angle * 65536.0) as i32
}
// Go through different paths
FilterOp::Blur(..) |
FilterOp::DropShadow(..) => {
unreachable!();
}
FilterOp::ColorMatrix(_) => {
picture.extra_gpu_data_handle.as_int(gpu_cache)
}
};
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
cache_task_address.0 as i32,
filter_mode,
user_data,
],
};
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
batch.push(PrimitiveInstance::from(instance));
}
}
}
PictureCompositeMode::MixBlend(mode) => {
let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id,
source_id,
backdrop_id,
},
),
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(source_id);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
PictureCompositeMode::Blit => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(kind, non_segmented_blend_mode, textures);
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_handle()
.as_int(gpu_cache);
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
BrushImageSourceKind::Color as i32,
RasterizationSpace::Screen as i32,
],
};
batch.push(PrimitiveInstance::from(instance));
}
}
}
None => {
@ -961,6 +924,7 @@ impl AlphaBatchBuilder {
gpu_cache,
render_tasks,
deferred_resolves,
z_generator,
);
}
}
@ -1181,7 +1145,7 @@ impl AlphaBatchBuilder {
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
transform_kind: TransformedRectKind,
z: i32,
z: ZBufferId,
render_tasks: &RenderTaskTree,
user_data: [i32; 3],
) {
@ -1281,13 +1245,6 @@ impl BrushPrimitive {
cached_gradients: &[CachedGradient],
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {
match self.kind {
BrushKind::Line { .. } => {
Some((
BrushBatchKind::Line,
BatchTextures::no_texture(),
[0; 3],
))
}
BrushKind::Image { request, .. } => {
let cache_item = resolve_image(
request,
@ -1440,7 +1397,6 @@ impl AlphaBatchHelpers for PrimitiveStore {
}
}
BrushKind::Solid { .. } |
BrushKind::Line { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } |
@ -1552,6 +1508,7 @@ pub struct ClipBatcher {
pub border_clears: Vec<ClipMaskInstance>,
pub borders: Vec<ClipMaskInstance>,
pub box_shadows: FastHashMap<SourceTexture, Vec<ClipMaskInstance>>,
pub line_decorations: Vec<ClipMaskInstance>,
}
impl ClipBatcher {
@ -1562,6 +1519,7 @@ impl ClipBatcher {
border_clears: Vec::new(),
borders: Vec::new(),
box_shadows: FastHashMap::default(),
line_decorations: Vec::new(),
}
}
@ -1629,6 +1587,12 @@ impl ClipBatcher {
continue;
}
}
ClipSource::LineDecoration(..) => {
self.line_decorations.push(ClipMaskInstance {
clip_data_address: gpu_address,
..instance
});
}
ClipSource::BoxShadow(ref info) => {
debug_assert_ne!(info.cache_item.texture_id, SourceTexture::Invalid);

View File

@ -19,7 +19,8 @@ pub struct BoxShadowClipSource {
pub shadow_radius: BorderRadius,
pub blur_radius: f32,
pub clip_mode: BoxShadowClipMode,
pub stretch_mode: BoxShadowStretchMode,
pub stretch_mode_x: BoxShadowStretchMode,
pub stretch_mode_y: BoxShadowStretchMode,
// The current cache key (in device-pixels), and handles
// to the cached clip region and blurred texture.

View File

@ -4,7 +4,7 @@
use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelScale, ImageMask};
use api::{ImageRendering, LayerRect, LayerSize, LayoutPoint, LayoutVector2D, LocalClip};
use api::{BoxShadowClipMode, LayerPoint, LayerToWorldScale};
use api::{BoxShadowClipMode, LayerPoint, LayerToWorldScale, LineOrientation, LineStyle};
use border::{BorderCornerClipSource, ensure_no_corner_overlap};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
@ -16,13 +16,21 @@ use prim_store::{ClipData, ImageMaskData};
use render_task::to_cache_size;
use resource_cache::{CacheItem, ImageRequest, ResourceCache};
use util::{LayerToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
use util::extract_inner_rect_safe;
use util::{extract_inner_rect_safe, pack_as_float};
use std::sync::Arc;
pub type ClipStore = FreeList<ClipSources>;
pub type ClipSourcesHandle = FreeListHandle<ClipSources>;
pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipSources>;
#[derive(Debug)]
pub struct LineDecorationClipSource {
rect: LayerRect,
style: LineStyle,
orientation: LineOrientation,
wavy_line_thickness: f32,
}
#[derive(Clone, Debug)]
pub struct ClipRegion {
pub main: LayerRect,
@ -82,6 +90,7 @@ pub enum ClipSource {
/// and different styles per edge.
BorderCorner(BorderCornerClipSource),
BoxShadow(BoxShadowClipSource),
LineDecoration(LineDecorationClipSource),
}
impl From<ClipRegion> for ClipSources {
@ -120,6 +129,22 @@ impl ClipSource {
)
}
pub fn new_line_decoration(
rect: LayerRect,
style: LineStyle,
orientation: LineOrientation,
wavy_line_thickness: f32,
) -> ClipSource {
ClipSource::LineDecoration(
LineDecorationClipSource {
rect,
style,
orientation,
wavy_line_thickness,
}
)
}
pub fn new_box_shadow(
shadow_rect: LayerRect,
shadow_radius: BorderRadius,
@ -178,14 +203,20 @@ impl ClipSource {
);
// If the width or height ends up being bigger than the original
// primitive shadow rect, just blur the entire rect and draw that
// as a simple blit. This is necessary for correctness, since the
// blur of one corner may affect the blur in another corner.
let mut stretch_mode = BoxShadowStretchMode::Stretch;
if shadow_rect.size.width < minimal_shadow_rect.size.width ||
shadow_rect.size.height < minimal_shadow_rect.size.height {
minimal_shadow_rect.size = shadow_rect.size;
stretch_mode = BoxShadowStretchMode::Simple;
// primitive shadow rect, just blur the entire rect along that
// axis and draw that as a simple blit. This is necessary for
// correctness, since the blur of one corner may affect the blur
// in another corner.
let mut stretch_mode_x = BoxShadowStretchMode::Stretch;
if shadow_rect.size.width < minimal_shadow_rect.size.width {
minimal_shadow_rect.size.width = shadow_rect.size.width;
stretch_mode_x = BoxShadowStretchMode::Simple;
}
let mut stretch_mode_y = BoxShadowStretchMode::Stretch;
if shadow_rect.size.height < minimal_shadow_rect.size.height {
minimal_shadow_rect.size.height = shadow_rect.size.height;
stretch_mode_y = BoxShadowStretchMode::Simple;
}
// Expand the shadow rect by enough room for the blur to take effect.
@ -200,13 +231,30 @@ impl ClipSource {
prim_shadow_rect,
blur_radius,
clip_mode,
stretch_mode,
stretch_mode_x,
stretch_mode_y,
cache_item: CacheItem::invalid(),
cache_key: None,
clip_data_handle: GpuCacheHandle::new(),
minimal_shadow_rect,
})
}
// Return a modified clip source that is the same as self
// but offset in local-space by a specified amount.
pub fn offset(&self, offset: &LayoutVector2D) -> ClipSource {
match *self {
ClipSource::LineDecoration(ref info) => {
ClipSource::LineDecoration(LineDecorationClipSource {
rect: info.rect.translate(offset),
..*info
})
}
_ => {
panic!("bug: other clip sources not expected here yet");
}
}
}
}
#[derive(Debug)]
@ -279,7 +327,8 @@ impl ClipSources {
.and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner)));
}
ClipSource::BoxShadow(..) |
ClipSource::BorderCorner { .. } => {
ClipSource::BorderCorner { .. } |
ClipSource::LineDecoration(..) => {
can_calculate_inner_rect = false;
break;
}
@ -317,7 +366,13 @@ impl ClipSources {
info.shadow_rect_alloc_size.width,
info.shadow_rect_alloc_size.height,
info.clip_mode as i32 as f32,
info.stretch_mode as i32 as f32,
0.0,
]);
request.push([
info.stretch_mode_x as i32 as f32,
info.stretch_mode_y as i32 as f32,
0.0,
0.0,
]);
request.push(info.prim_shadow_rect);
}
@ -332,6 +387,15 @@ impl ClipSources {
ClipSource::BorderCorner(ref mut source) => {
source.write(request);
}
ClipSource::LineDecoration(ref info) => {
request.push(info.rect);
request.push([
info.wavy_line_thickness,
pack_as_float(info.style as u32),
pack_as_float(info.orientation as u32),
0.0,
]);
}
}
}

View File

@ -15,7 +15,6 @@ use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRec
use api::{TransformStyle, YuvColorSpace, YuvData};
use app_units::Au;
use border::ImageBorderSegment;
use box_shadow::{BLUR_SAMPLE_SCALE};
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
@ -25,7 +24,7 @@ use glyph_rasterizer::FontInstance;
use hit_test::{HitTestingItem, HitTestingRun};
use image::{decompose_image, TiledImageInfo};
use internal_types::{FastHashMap, FastHashSet};
use picture::{PictureCompositeMode, PictureKind};
use picture::PictureCompositeMode;
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
use prim_store::{CachedGradientIndex, ImageCacheKey, ImagePrimitiveCpu, ImageSource};
use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
@ -169,14 +168,6 @@ pub struct DisplayListFlattener<'a> {
/// types that the ClipScrollTree uses.
id_to_index_mapper: ClipIdToIndexMapper,
/// A stack of the current shadow primitives. The sub-Vec stores
/// a buffer of fast-path primitives to be appended on pop.
shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ScrollNodeAndClipChain)>)>,
/// A buffer of "real" content when doing fast-path shadows. This is appended
/// when the shadow stack is empty.
pending_shadow_contents: Vec<(PrimitiveIndex, ScrollNodeAndClipChain, LayerPrimitiveInfo)>,
/// A stack of scroll nodes used during display list processing to properly
/// parent new scroll nodes.
reference_frame_stack: Vec<(ClipId, ClipScrollNodeIndex)>,
@ -187,6 +178,9 @@ pub struct DisplayListFlattener<'a> {
/// A stack of the current pictures.
picture_stack: Vec<PictureIndex>,
/// A stack of the currently active shadows
shadow_stack: Vec<(Shadow, PictureIndex)>,
/// A list of scrollbar primitives.
pub scrollbar_prims: Vec<ScrollbarPrimitive>,
@ -240,12 +234,11 @@ impl<'a> DisplayListFlattener<'a> {
output_pipelines,
id_to_index_mapper: ClipIdToIndexMapper::default(),
hit_testing_runs: recycle_vec(old_builder.hit_testing_runs),
shadow_prim_stack: Vec::new(),
cached_gradients: recycle_vec(old_builder.cached_gradients),
pending_shadow_contents: Vec::new(),
scrollbar_prims: recycle_vec(old_builder.scrollbar_prims),
reference_frame_stack: Vec::new(),
picture_stack: Vec::new(),
shadow_stack: Vec::new(),
sc_stack: Vec::new(),
prim_store: old_builder.prim_store.recycle(),
clip_store: old_builder.clip_store.recycle(),
@ -930,12 +923,42 @@ impl<'a> DisplayListFlattener<'a> {
info: &LayerPrimitiveInfo,
clip_sources: Vec<ClipSource>,
container: PrimitiveContainer,
) -> PrimitiveIndex {
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
let prim_index = self.create_primitive(info, clip_sources, container);
) {
if !self.shadow_stack.is_empty() {
// TODO(gw): Restructure this so we don't need to move the shadow
// stack out (borrowck due to create_primitive below).
let shadow_stack = mem::replace(&mut self.shadow_stack, Vec::new());
for &(ref shadow, shadow_pic_index) in &shadow_stack {
// Offset the local rect and clip rect by the shadow offset.
let mut info = info.clone();
info.rect = info.rect.translate(&shadow.offset);
info.clip_rect = info.clip_rect.translate(&shadow.offset);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
prim_index
// Offset any local clip sources by the shadow offset.
let clip_sources: Vec<ClipSource> = clip_sources
.iter()
.map(|cs| cs.offset(&shadow.offset))
.collect();
// Construct and add a primitive for the given shadow.
let shadow_prim_index = self.create_primitive(
&info,
clip_sources,
container.create_shadow(shadow),
);
// Add the new primitive to the shadow picture.
let shadow_pic = &mut self.prim_store.pictures[shadow_pic_index.0];
shadow_pic.add_primitive(shadow_prim_index, clip_and_scroll);
}
self.shadow_stack = shadow_stack;
}
if container.is_visible() {
let prim_index = self.create_primitive(info, clip_sources, container);
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
}
}
pub fn push_stacking_context(
@ -973,6 +996,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
current_reference_frame_index,
None,
true,
);
self.picture_stack.push(pic_index);
@ -986,17 +1010,10 @@ impl<'a> DisplayListFlattener<'a> {
let parent_pic_index = self.picture_stack.last().unwrap();
let parent_pic = &mut self.prim_store.pictures[parent_pic_index.0];
match parent_pic.kind {
PictureKind::Image { ref mut composite_mode, .. } => {
// If not already isolated for some other reason,
// make this picture as isolated.
if composite_mode.is_none() {
*composite_mode = Some(PictureCompositeMode::Blit);
}
}
PictureKind::TextShadow { .. } => {
panic!("bug: text pictures invalid here");
}
// If not already isolated for some other reason,
// make this picture as isolated.
if parent_pic.composite_mode.is_none() {
parent_pic.composite_mode = Some(PictureCompositeMode::Blit);
}
}
@ -1035,6 +1052,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
current_reference_frame_index,
None,
true,
);
let prim = BrushPrimitive::new_picture(container_index);
@ -1087,6 +1105,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
current_reference_frame_index,
None,
true,
);
let src_prim = BrushPrimitive::new_picture(src_pic_index);
@ -1118,6 +1137,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
current_reference_frame_index,
None,
true,
);
let src_prim = BrushPrimitive::new_picture(src_pic_index);
@ -1171,6 +1191,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
current_reference_frame_index,
frame_output_pipeline_id,
true,
);
// Create a brush primitive that draws this picture.
@ -1237,7 +1258,7 @@ impl<'a> DisplayListFlattener<'a> {
}
assert!(
self.shadow_prim_stack.is_empty(),
self.shadow_stack.is_empty(),
"Found unpopped text shadows when popping stacking context!"
);
}
@ -1381,44 +1402,47 @@ impl<'a> DisplayListFlattener<'a> {
info: &LayerPrimitiveInfo,
) {
let pipeline_id = self.sc_stack.last().unwrap().pipeline_id;
let pic_index = self.prim_store.add_shadow_picture(shadow, pipeline_id);
let current_reference_frame_index = self.current_reference_frame_index();
let max_clip = LayerRect::max_rect();
let prim = BrushPrimitive::new_picture(pic_index);
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
// "the image that would be generated by applying to the shadow a
// Gaussian blur with a standard deviation equal to half the blur radius."
let std_deviation = shadow.blur_radius * 0.5;
// Create an empty shadow primitive. Insert it into
// the draw lists immediately so that it will be drawn
// before any visual text elements that are added as
// part of this shadow context.
let prim_index = self.create_primitive(
info,
Vec::new(),
PrimitiveContainer::Brush(prim),
// Create a picture that the shadow primitives will be added to. If the
// blur radius is 0, the code in Picture::prepare_for_render will
// detect this and mark the picture to be drawn directly into the
// parent picture, which avoids an intermediate surface and blur.
let shadow_pic_index = self.prim_store.add_image_picture(
Some(PictureCompositeMode::Filter(FilterOp::Blur(std_deviation))),
false,
pipeline_id,
current_reference_frame_index,
None,
false,
);
let pending = vec![(prim_index, clip_and_scroll)];
self.shadow_prim_stack.push((prim_index, pending));
// Create the primitive to draw the shadow picture into the scene.
let shadow_prim = BrushPrimitive::new_picture(shadow_pic_index);
let shadow_prim_index = self.prim_store.add_primitive(
&LayerRect::zero(),
&max_clip,
info.is_backface_visible,
None,
None,
PrimitiveContainer::Brush(shadow_prim),
);
// Add the shadow primitive. This must be done before pushing this
// picture on to the shadow stack, to avoid infinite recursion!
self.add_primitive_to_draw_list(shadow_prim_index, clip_and_scroll);
self.shadow_stack.push((shadow, shadow_pic_index));
}
pub fn pop_all_shadows(&mut self) {
assert!(self.shadow_prim_stack.len() > 0, "popped shadows, but none were present");
// Borrowcheck dance
let mut shadows = mem::replace(&mut self.shadow_prim_stack, Vec::new());
for (_, pending_primitives) in shadows.drain(..) {
// Push any fast-path shadows now
for (prim_index, clip_and_scroll) in pending_primitives {
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
}
}
let mut pending_primitives = mem::replace(&mut self.pending_shadow_contents, Vec::new());
for (prim_index, clip_and_scroll, info) in pending_primitives.drain(..) {
self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
}
mem::replace(&mut self.pending_shadow_contents, pending_primitives);
mem::replace(&mut self.shadow_prim_stack, shadows);
assert!(self.shadow_stack.len() > 0, "popped shadows, but none were present");
self.shadow_stack.clear();
}
pub fn add_solid_rectangle(
@ -1486,13 +1510,17 @@ impl<'a> DisplayListFlattener<'a> {
None,
);
let prim_index = self.add_primitive(
clip_and_scroll,
let prim_index = self.create_primitive(
info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
self.add_primitive_to_draw_list(
prim_index,
clip_and_scroll,
);
self.scrollbar_prims.push(ScrollbarPrimitive {
prim_index,
scroll_frame_index: scrollbar_info.0,
@ -1509,97 +1537,37 @@ impl<'a> DisplayListFlattener<'a> {
line_color: &ColorF,
style: LineStyle,
) {
let line = BrushPrimitive::new(
BrushKind::Line {
wavy_line_thickness,
color: line_color.premultiplied(),
style,
orientation,
let prim = BrushPrimitive::new(
BrushKind::Solid {
color: *line_color,
},
None,
);
let mut fast_shadow_prims = Vec::new();
let mut slow_shadow_prims = Vec::new();
for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
let pic_index = brush.get_picture_index();
let picture = &self.prim_store.pictures[pic_index.0];
match picture.kind {
PictureKind::TextShadow { offset, color, blur_radius, .. } => {
if blur_radius == 0.0 {
fast_shadow_prims.push((idx, offset, color));
} else {
slow_shadow_prims.push((pic_index, offset, color));
}
}
_ => {}
let extra_clips = match style {
LineStyle::Solid => {
Vec::new()
}
}
for (idx, shadow_offset, shadow_color) in fast_shadow_prims {
let line = BrushPrimitive::new(
BrushKind::Line {
wavy_line_thickness,
color: shadow_color.premultiplied(),
style,
orientation,
},
None,
);
let mut info = info.clone();
info.rect = info.rect.translate(&shadow_offset);
info.clip_rect = info.clip_rect.translate(&shadow_offset);
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::Brush(line),
);
self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
}
if line_color.a > 0.0 {
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::Brush(line),
);
if self.shadow_prim_stack.is_empty() {
self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
} else {
self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info));
LineStyle::Wavy |
LineStyle::Dotted |
LineStyle::Dashed => {
vec![
ClipSource::new_line_decoration(
info.rect,
style,
orientation,
wavy_line_thickness,
),
]
}
}
};
for (pic_index, shadow_offset, shadow_color) in slow_shadow_prims {
let line = BrushPrimitive::new(
BrushKind::Line {
wavy_line_thickness,
color: shadow_color.premultiplied(),
style,
orientation,
},
None,
);
let mut info = info.clone();
info.rect = info.rect.translate(&shadow_offset);
info.clip_rect = info.clip_rect.translate(&shadow_offset);
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::Brush(line),
);
let picture = &mut self.prim_store.pictures[pic_index.0];
picture.add_primitive(
prim_index,
clip_and_scroll,
);
}
self.add_primitive(
clip_and_scroll,
info,
extra_clips,
PrimitiveContainer::Brush(prim),
);
}
pub fn add_border(
@ -2118,102 +2086,12 @@ impl<'a> DisplayListFlattener<'a> {
}
};
// Text shadows that have a blur radius of 0 need to be rendered as normal
// text elements to get pixel perfect results for reftests. It's also a big
// performance win to avoid blurs and render target allocations where
// possible. For any text shadows that have zero blur, create a normal text
// primitive with the shadow's color and offset. These need to be added
// *before* the visual text primitive in order to get the correct paint
// order. Store them in a Vec first to work around borrowck issues.
// TODO(gw): Refactor to avoid having to store them in a Vec first.
let mut fast_shadow_prims = Vec::new();
let mut slow_shadow_prims = Vec::new();
for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() {
let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0];
let pic_index = brush.get_picture_index();
let picture_prim = &self.prim_store.pictures[pic_index.0];
match picture_prim.kind {
PictureKind::TextShadow { offset, color, blur_radius, .. } => {
let mut text_prim = prim.clone();
text_prim.font.color = color.into();
text_prim.shadow = true;
text_prim.offset += offset;
if blur_radius == 0.0 {
fast_shadow_prims.push((idx, text_prim, offset));
} else {
text_prim.font.render_mode = text_prim
.font
.render_mode
.limit_by(FontRenderMode::Alpha);
slow_shadow_prims.push((pic_index, text_prim, offset, blur_radius));
}
}
_ => {}
}
}
for (idx, text_prim, offset) in fast_shadow_prims {
let rect = prim_info.rect;
let mut info = prim_info.clone();
info.rect = rect.translate(&offset);
info.clip_rect = info.clip_rect.translate(&offset);
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::TextRun(text_prim),
);
self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll));
}
// Only add a visual element if it can contribute to the scene.
if text_color.a > 0.0 {
// Create (and add to primitive store) the primitive that will be
// used for both the visual element and also the shadow(s).
let prim_index = self.create_primitive(
prim_info,
Vec::new(),
PrimitiveContainer::TextRun(prim),
);
if self.shadow_prim_stack.is_empty() {
self.add_primitive_to_hit_testing_list(prim_info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
} else {
self.pending_shadow_contents.push((prim_index, clip_and_scroll, *prim_info));
}
}
// Now add this primitive index to all the currently active text shadow
// primitives. Although we're adding the indices *after* the visual
// primitive here, they will still draw before the visual text, since
// the shadow primitive itself has been added to the draw cmd
// list *before* the visual element, during push_shadow. We need
// the primitive index of the visual element here before we can add
// the indices as sub-primitives to the shadow primitives.
for (pic_index, shadow_prim, offset, blur_radius) in slow_shadow_prims {
let blur_region = blur_radius * BLUR_SAMPLE_SCALE;
let rect = prim_info.rect;
let mut info = prim_info.clone();
info.rect = rect.translate(&offset).inflate(blur_region, blur_region);
info.clip_rect = info.clip_rect.translate(&offset);
let prim_index = self.create_primitive(
&info,
Vec::new(),
PrimitiveContainer::TextRun(shadow_prim),
);
let picture = &mut self.prim_store.pictures[pic_index.0];
picture.add_primitive(
prim_index,
clip_and_scroll,
);
}
self.add_primitive(
clip_and_scroll,
prim_info,
Vec::new(),
PrimitiveContainer::TextRun(prim),
);
}
pub fn add_image(

View File

@ -10,7 +10,7 @@ use clip_scroll_node::{ClipScrollNode};
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
use display_list_flattener::{DisplayListFlattener};
use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType};
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
use hit_test::{HitTester, HitTestingRun};
use internal_types::{FastHashMap};
use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveRun, PrimitiveStore};
@ -74,6 +74,7 @@ pub struct PictureContext<'a> {
pub display_list: &'a BuiltDisplayList,
pub inv_world_transform: Option<WorldToLayerFastTransform>,
pub apply_local_clip_rect: bool,
pub inflation_factor: f32,
}
pub struct PictureState {
@ -203,6 +204,7 @@ impl FrameBuilder {
display_list,
inv_world_transform: None,
apply_local_clip_rect: true,
inflation_factor: 0.0,
};
let mut pic_state = PictureState::new();
@ -226,7 +228,6 @@ impl FrameBuilder {
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(root_render_task);
@ -310,7 +311,7 @@ impl FrameBuilder {
self.update_scroll_bars(clip_scroll_tree, gpu_cache);
let mut render_tasks = RenderTaskTree::new();
let mut render_tasks = RenderTaskTree::new(frame_id);
let main_render_task_id = self.build_layer_screen_rects_and_cull_layers(
clip_scroll_tree,

View File

@ -9,6 +9,28 @@ use render_task::RenderTaskAddress;
// Contains type that must exactly match the same structures declared in GLSL.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct ZBufferId(i32);
pub struct ZBufferIdGenerator {
next: i32,
}
impl ZBufferIdGenerator {
pub fn new() -> ZBufferIdGenerator {
ZBufferIdGenerator {
next: 0
}
}
pub fn next(&mut self) -> ZBufferId {
let id = ZBufferId(self.next);
self.next += 1;
id
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -75,7 +97,7 @@ pub struct SimplePrimitiveInstance {
pub clip_task_address: RenderTaskAddress,
pub clip_chain_rect_index: ClipChainRectIndex,
pub scroll_id: ClipScrollNodeIndex,
pub z_sort_index: i32,
pub z: ZBufferId,
}
impl SimplePrimitiveInstance {
@ -85,7 +107,7 @@ impl SimplePrimitiveInstance {
clip_task_address: RenderTaskAddress,
clip_chain_rect_index: ClipChainRectIndex,
scroll_id: ClipScrollNodeIndex,
z_sort_index: i32,
z: ZBufferId,
) -> Self {
SimplePrimitiveInstance {
specific_prim_address,
@ -93,7 +115,7 @@ impl SimplePrimitiveInstance {
clip_task_address,
clip_chain_rect_index,
scroll_id,
z_sort_index,
z,
}
}
@ -104,7 +126,7 @@ impl SimplePrimitiveInstance {
self.task_address.0 as i32,
self.clip_task_address.0 as i32,
((self.clip_chain_rect_index.0 as i32) << 16) | self.scroll_id.0 as i32,
self.z_sort_index,
self.z.0,
data0,
data1,
data2,
@ -119,7 +141,7 @@ pub struct CompositePrimitiveInstance {
pub backdrop_task_address: RenderTaskAddress,
pub data0: i32,
pub data1: i32,
pub z: i32,
pub z: ZBufferId,
pub data2: i32,
pub data3: i32,
}
@ -131,7 +153,7 @@ impl CompositePrimitiveInstance {
backdrop_task_address: RenderTaskAddress,
data0: i32,
data1: i32,
z: i32,
z: ZBufferId,
data2: i32,
data3: i32,
) -> Self {
@ -155,7 +177,7 @@ impl From<CompositePrimitiveInstance> for PrimitiveInstance {
instance.task_address.0 as i32,
instance.src_task_address.0 as i32,
instance.backdrop_task_address.0 as i32,
instance.z,
instance.z.0,
instance.data0,
instance.data1,
instance.data2,
@ -187,7 +209,7 @@ pub struct BrushInstance {
pub clip_chain_rect_index: ClipChainRectIndex,
pub scroll_id: ClipScrollNodeIndex,
pub clip_task_address: RenderTaskAddress,
pub z: i32,
pub z: ZBufferId,
pub segment_index: i32,
pub edge_flags: EdgeAaSegmentMask,
pub brush_flags: BrushFlags,
@ -201,7 +223,7 @@ impl From<BrushInstance> for PrimitiveInstance {
instance.picture_address.0 as i32 | (instance.clip_task_address.0 as i32) << 16,
instance.prim_address.as_int(),
((instance.clip_chain_rect_index.0 as i32) << 16) | instance.scroll_id.0 as i32,
instance.z,
instance.z.0,
instance.segment_index |
((instance.edge_flags.bits() as i32) << 16) |
((instance.brush_flags.bits() as i32) << 24),
@ -245,15 +267,6 @@ impl ClipScrollNodeData {
#[repr(C)]
pub struct ClipChainRectIndex(pub usize);
#[derive(Copy, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub enum PictureType {
Image = 1,
TextShadow = 2,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]

View File

@ -302,8 +302,9 @@ fn get_regions_for_clip_scroll_node(
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
ClipSource::Image(ref mask) => HitTestRegion::Rectangle(mask.rect),
ClipSource::BorderCorner(_) |
ClipSource::LineDecoration(_) |
ClipSource::BoxShadow(_) => {
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow");
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow / LineDecoration");
}
}
}).collect()

View File

@ -2,14 +2,12 @@
* 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::{ColorF, FilterOp, MixBlendMode, PipelineId};
use api::{DeviceIntRect, LayerRect, LayerToWorldScale, LayerVector2D};
use api::{PremultipliedColorF, Shadow};
use api::{FilterOp, MixBlendMode, PipelineId, PremultipliedColorF};
use api::{DeviceIntRect, LayerRect, LayerToWorldScale};
use box_shadow::{BLUR_SAMPLE_SCALE};
use clip_scroll_tree::ClipScrollNodeIndex;
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
use gpu_cache::{GpuCacheHandle, GpuDataRequest};
use gpu_types::{PictureType};
use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain};
use render_task::{ClearMode, RenderTask};
@ -40,95 +38,67 @@ pub enum PictureCompositeMode {
Blit,
}
#[derive(Debug)]
pub enum PictureKind {
TextShadow {
offset: LayerVector2D,
color: ColorF,
blur_radius: f32,
},
Image {
// If a mix-blend-mode, contains the render task for
// the readback of the framebuffer that we use to sample
// from in the mix-blend-mode shader.
// For drop-shadow filter, this will store the original
// picture task which would be rendered on screen after
// blur pass.
secondary_render_task_id: Option<RenderTaskId>,
/// How this picture should be composited.
/// If None, don't composite - just draw directly on parent surface.
composite_mode: Option<PictureCompositeMode>,
// If true, this picture is part of a 3D context.
is_in_3d_context: bool,
// If requested as a frame output (for rendering
// pages to a texture), this is the pipeline this
// picture is the root of.
frame_output_pipeline_id: Option<PipelineId>,
// The original reference frame ID for this picture.
// It is only different if this is part of a 3D
// rendering context.
reference_frame_index: ClipScrollNodeIndex,
real_local_rect: LayerRect,
// An optional cache handle for storing extra data
// in the GPU cache, depending on the type of
// picture.
extra_gpu_data_handle: GpuCacheHandle,
},
}
#[derive(Debug)]
pub struct PicturePrimitive {
// If this picture is drawn to an intermediate surface,
// the associated target information.
pub surface: Option<RenderTaskId>,
// Details specific to this type of picture.
pub kind: PictureKind,
// List of primitive runs that make up this picture.
pub runs: Vec<PrimitiveRun>,
// The pipeline that the primitives on this picture belong to.
pub pipeline_id: PipelineId,
// If true, apply the local clip rect to primitive drawn
// in this picture.
pub apply_local_clip_rect: bool,
// The current screen-space rect of the rendered
// portion of this picture.
task_rect: DeviceIntRect,
// If a mix-blend-mode, contains the render task for
// the readback of the framebuffer that we use to sample
// from in the mix-blend-mode shader.
// For drop-shadow filter, this will store the original
// picture task which would be rendered on screen after
// blur pass.
pub secondary_render_task_id: Option<RenderTaskId>,
/// How this picture should be composited.
/// If None, don't composite - just draw directly on parent surface.
pub composite_mode: Option<PictureCompositeMode>,
// If true, this picture is part of a 3D context.
pub is_in_3d_context: bool,
// If requested as a frame output (for rendering
// pages to a texture), this is the pipeline this
// picture is the root of.
pub frame_output_pipeline_id: Option<PipelineId>,
// The original reference frame ID for this picture.
// It is only different if this is part of a 3D
// rendering context.
pub reference_frame_index: ClipScrollNodeIndex,
pub real_local_rect: LayerRect,
// An optional cache handle for storing extra data
// in the GPU cache, depending on the type of
// picture.
pub extra_gpu_data_handle: GpuCacheHandle,
}
impl PicturePrimitive {
pub fn new_text_shadow(shadow: Shadow, pipeline_id: PipelineId) -> Self {
PicturePrimitive {
runs: Vec::new(),
surface: None,
kind: PictureKind::TextShadow {
offset: shadow.offset,
color: shadow.color,
blur_radius: shadow.blur_radius,
},
pipeline_id,
task_rect: DeviceIntRect::zero(),
}
}
pub fn resolve_scene_properties(&mut self, properties: &SceneProperties) -> bool {
match self.kind {
PictureKind::Image { ref mut composite_mode, .. } => {
match composite_mode {
&mut Some(PictureCompositeMode::Filter(ref mut filter)) => {
match filter {
&mut FilterOp::Opacity(ref binding, ref mut value) => {
*value = properties.resolve_float(binding, *value);
}
_ => {}
}
filter.is_visible()
match self.composite_mode {
Some(PictureCompositeMode::Filter(ref mut filter)) => {
match filter {
&mut FilterOp::Opacity(ref binding, ref mut value) => {
*value = properties.resolve_float(binding, *value);
}
_ => true,
_ => {}
}
filter.is_visible()
}
_ => true
_ => true,
}
}
@ -138,19 +108,19 @@ impl PicturePrimitive {
pipeline_id: PipelineId,
reference_frame_index: ClipScrollNodeIndex,
frame_output_pipeline_id: Option<PipelineId>,
apply_local_clip_rect: bool,
) -> Self {
PicturePrimitive {
runs: Vec::new(),
surface: None,
kind: PictureKind::Image {
secondary_render_task_id: None,
composite_mode,
is_in_3d_context,
frame_output_pipeline_id,
reference_frame_index,
real_local_rect: LayerRect::zero(),
extra_gpu_data_handle: GpuCacheHandle::new(),
},
secondary_render_task_id: None,
composite_mode,
is_in_3d_context,
frame_output_pipeline_id,
reference_frame_index,
real_local_rect: LayerRect::zero(),
extra_gpu_data_handle: GpuCacheHandle::new(),
apply_local_clip_rect,
pipeline_id,
task_rect: DeviceIntRect::zero(),
}
@ -182,32 +152,20 @@ impl PicturePrimitive {
) -> LayerRect {
let local_content_rect = prim_run_rect.local_rect_in_actual_parent_space;
match self.kind {
PictureKind::Image { composite_mode, ref mut real_local_rect, .. } => {
*real_local_rect = prim_run_rect.local_rect_in_original_parent_space;
self.real_local_rect = prim_run_rect.local_rect_in_original_parent_space;
match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
.translate(&offset)
}
_ => {
local_content_rect
}
}
match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let inflate_size = (blur_radius * BLUR_SAMPLE_SCALE).ceil();
local_content_rect.inflate(inflate_size, inflate_size)
}
PictureKind::TextShadow { blur_radius, .. } => {
let blur_offset = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(
blur_offset,
blur_offset,
)
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
.translate(&offset)
}
_ => {
local_content_rect
}
}
}
@ -226,239 +184,178 @@ impl PicturePrimitive {
.screen_rect
.as_ref()
.expect("bug: trying to draw an off-screen picture!?");
let device_rect;
let device_rect = match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
// If blur radius is 0, we can skip drawing this an an
// intermediate surface.
if blur_radius == 0.0 {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
match self.kind {
PictureKind::Image {
ref mut secondary_render_task_id,
ref mut extra_gpu_data_handle,
composite_mode,
..
} => {
device_rect = match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
// If blur radius is 0, we can skip drawing this an an
// intermediate surface.
if blur_radius == 0.0 {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
DeviceIntRect::zero()
} else {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
DeviceIntRect::zero()
} else {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = prim_screen_rect
.clipped
.inflate(blur_range, blur_range)
.intersection(&prim_screen_rect.unclipped)
.unwrap();
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = prim_screen_rect
.clipped
.inflate(blur_range, blur_range)
.intersection(&prim_screen_rect.unclipped)
.unwrap();
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
prim_index,
RenderTargetKind::Color,
device_rect.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
prim_index,
RenderTargetKind::Color,
device_rect.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
PictureType::Image,
);
let picture_task_id = frame_state.render_tasks.add(picture_task);
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
device_rect
}
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
// TODO(gw): This is totally wrong and can never work with
// transformed drop-shadow elements. Fix me!
let rect = (prim_metadata.local_rect.translate(&-offset) * content_scale).round().to_i32();
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, rect.size),
prim_index,
RenderTargetKind::Color,
rect.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
PictureType::Image,
);
picture_task.mark_for_saving();
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation.round(),
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
*secondary_render_task_id = Some(picture_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
rect
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
PictureType::Image,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(prim_screen_rect.clipped)
);
*secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
prim_screen_rect.clipped
}
Some(PictureCompositeMode::Filter(filter)) => {
// If this filter is not currently going to affect
// the picture, just collapse this picture into the
// current render task. This most commonly occurs
// when opacity == 1.0, but can also occur on other
// filters and be a significant performance win.
if filter.is_noop() {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
} else {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
}
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
}
prim_screen_rect.clipped
}
Some(PictureCompositeMode::Blit) => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
PictureType::Image,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
prim_screen_rect.clipped
}
None => {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
DeviceIntRect::zero()
}
};
device_rect
}
}
PictureKind::TextShadow { blur_radius, color, .. } => {
// This is a shadow element. Create a render task that will
// render the text run to a target, and then apply a gaussian
// blur to that text run in order to build the actual primitive
// which will be blitted to the framebuffer.
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
// "the image that would be generated by applying to the shadow a
// Gaussian blur with a standard deviation equal to half the blur radius."
let device_radius = (blur_radius * frame_context.device_pixel_scale.0).round();
let blur_std_deviation = device_radius * 0.5;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
device_rect = prim_screen_rect
.clipped
.inflate(blur_range, blur_range)
.intersection(&prim_screen_rect.unclipped)
.unwrap();
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => {
// TODO(gw): This is totally wrong and can never work with
// transformed drop-shadow elements. Fix me!
let rect = (prim_metadata.local_rect.translate(&-offset) * content_scale).round().to_i32();
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, rect.size),
prim_index,
RenderTargetKind::Color,
device_rect.origin,
color.premultiplied(),
rect.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
Vec::new(),
PictureType::TextShadow,
pic_state_for_children.tasks,
);
picture_task.mark_for_saving();
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
blur_std_deviation.round(),
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
self.secondary_render_task_id = Some(picture_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
rect
}
}
Some(PictureCompositeMode::MixBlend(..)) => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(prim_screen_rect.clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
prim_screen_rect.clipped
}
Some(PictureCompositeMode::Filter(filter)) => {
// If this filter is not currently going to affect
// the picture, just collapse this picture into the
// current render task. This most commonly occurs
// when opacity == 1.0, but can also occur on other
// filters and be a significant performance win.
if filter.is_noop() {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
} else {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
}
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
}
prim_screen_rect.clipped
}
Some(PictureCompositeMode::Blit) => {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size),
prim_index,
RenderTargetKind::Color,
prim_screen_rect.clipped.origin,
PremultipliedColorF::TRANSPARENT,
ClearMode::Transparent,
pic_state_for_children.tasks,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(render_task_id);
prim_screen_rect.clipped
}
None => {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
DeviceIntRect::zero()
}
};
// If scrolling or property animation has resulted in the task
// rect being different than last time, invalidate the GPU
@ -473,22 +370,15 @@ impl PicturePrimitive {
pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push(self.task_rect.to_f32());
match self.kind {
PictureKind::TextShadow { .. } => {
request.push(PremultipliedColorF::WHITE);
let color = match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, _, color))) => {
color.premultiplied()
}
PictureKind::Image { composite_mode, .. } => {
let color = match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, _, color))) => {
color.premultiplied()
}
_ => {
PremultipliedColorF::WHITE
}
};
_ => {
PremultipliedColorF::WHITE
}
};
request.push(color);
}
}
request.push(color);
}
}

View File

@ -4,10 +4,11 @@
use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
use api::{LineStyle, PipelineId, PremultipliedColorF, Shadow, YuvColorSpace, YuvFormat};
use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D};
use api::{PipelineId, PremultipliedColorF, Shadow, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderEdgeKind};
use box_shadow::BLUR_SAMPLE_SCALE;
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
use clip_scroll_node::ClipScrollNode;
use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
@ -18,7 +19,7 @@ use glyph_rasterizer::{FontInstance, FontTransform};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use gpu_types::{ClipChainRectIndex};
use picture::{PictureCompositeMode, PictureKind, PicturePrimitive};
use picture::{PictureCompositeMode, PicturePrimitive};
use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind};
use render_task::RenderTaskId;
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
@ -198,12 +199,6 @@ pub enum BrushKind {
color: ColorF,
},
Clear,
Line {
color: PremultipliedColorF,
wavy_line_thickness: f32,
style: LineStyle,
orientation: LineOrientation,
},
Picture {
pic_index: PictureIndex,
},
@ -248,8 +243,7 @@ impl BrushKind {
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } => true,
BrushKind::Clear |
BrushKind::Line { .. } => false,
BrushKind::Clear => false,
}
}
}
@ -355,15 +349,6 @@ impl BrushPrimitive {
// Opaque black with operator dest out
request.push(PremultipliedColorF::BLACK);
}
BrushKind::Line { color, wavy_line_thickness, style, orientation } => {
request.push(color);
request.push([
wavy_line_thickness,
pack_as_float(style as u32),
pack_as_float(orientation as u32),
0.0,
]);
}
BrushKind::LinearGradient { start_point, end_point, extend_mode, .. } => {
request.push([
start_point.x,
@ -919,6 +904,95 @@ pub enum PrimitiveContainer {
Brush(BrushPrimitive),
}
impl PrimitiveContainer {
// Return true if the primary primitive is visible.
// Used to trivially reject non-visible primitives.
// TODO(gw): Currently, primitives other than those
// listed here are handled before the
// add_primitive() call. In the future
// we should move the logic for all other
// primitive types to use this.
pub fn is_visible(&self) -> bool {
match *self {
PrimitiveContainer::TextRun(ref info) => {
info.font.color.a > 0
}
PrimitiveContainer::Brush(ref brush) => {
match brush.kind {
BrushKind::Solid { ref color } => {
color.a > 0.0
}
BrushKind::Clear |
BrushKind::Picture { .. } |
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } => {
true
}
}
}
PrimitiveContainer::Image(..) |
PrimitiveContainer::Border(..) => {
true
}
}
}
// Create a clone of this PrimitiveContainer, applying whatever
// changes are necessary to the primitive to support rendering
// it as part of the supplied shadow.
pub fn create_shadow(&self, shadow: &Shadow) -> PrimitiveContainer {
match *self {
PrimitiveContainer::TextRun(ref info) => {
let mut render_mode = info.font.render_mode;
if shadow.blur_radius > 0.0 {
render_mode = render_mode.limit_by(FontRenderMode::Alpha);
}
PrimitiveContainer::TextRun(TextRunPrimitiveCpu {
font: FontInstance {
color: shadow.color.into(),
render_mode,
..info.font.clone()
},
offset: info.offset + shadow.offset,
glyph_range: info.glyph_range,
glyph_count: info.glyph_count,
glyph_keys: info.glyph_keys.clone(),
glyph_gpu_blocks: Vec::new(),
shadow: true,
})
}
PrimitiveContainer::Brush(ref brush) => {
match brush.kind {
BrushKind::Solid { .. } => {
PrimitiveContainer::Brush(BrushPrimitive::new(
BrushKind::Solid {
color: shadow.color,
},
None,
))
}
BrushKind::Clear |
BrushKind::Picture { .. } |
BrushKind::Image { .. } |
BrushKind::YuvImage { .. } |
BrushKind::RadialGradient { .. } |
BrushKind::LinearGradient { .. } => {
panic!("bug: other brush kinds not expected here yet");
}
}
}
PrimitiveContainer::Image(..) |
PrimitiveContainer::Border(..) => {
panic!("bug: other primitive containers not expected here");
}
}
}
}
pub struct PrimitiveStore {
/// CPU side information only.
pub cpu_brushes: Vec<BrushPrimitive>,
@ -962,6 +1036,7 @@ impl PrimitiveStore {
pipeline_id: PipelineId,
reference_frame_index: ClipScrollNodeIndex,
frame_output_pipeline_id: Option<PipelineId>,
apply_local_clip_rect: bool,
) -> PictureIndex {
let pic = PicturePrimitive::new_image(
composite_mode,
@ -969,22 +1044,7 @@ impl PrimitiveStore {
pipeline_id,
reference_frame_index,
frame_output_pipeline_id,
);
let pic_index = PictureIndex(self.pictures.len());
self.pictures.push(pic);
pic_index
}
pub fn add_shadow_picture(
&mut self,
shadow: Shadow,
pipeline_id: PipelineId,
) -> PictureIndex {
let pic = PicturePrimitive::new_text_shadow(
shadow,
pipeline_id,
apply_local_clip_rect,
);
let pic_index = PictureIndex(self.pictures.len());
@ -1024,7 +1084,6 @@ impl PrimitiveStore {
let opacity = match brush.kind {
BrushKind::Clear => PrimitiveOpacity::translucent(),
BrushKind::Solid { ref color } => PrimitiveOpacity::from_alpha(color.a),
BrushKind::Line { .. } => PrimitiveOpacity::translucent(),
BrushKind::Image { .. } => PrimitiveOpacity::translucent(),
BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(),
BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(),
@ -1300,8 +1359,7 @@ impl PrimitiveStore {
);
}
BrushKind::Solid { .. } |
BrushKind::Clear |
BrushKind::Line { .. } => {}
BrushKind::Clear => {}
}
}
}
@ -1427,6 +1485,7 @@ impl PrimitiveStore {
continue;
}
ClipSource::BorderCorner(..) |
ClipSource::LineDecoration(..) |
ClipSource::Image(..) => {
// TODO(gw): We can easily extend the segment builder
// to support these clip sources in the
@ -1560,6 +1619,18 @@ impl PrimitiveStore {
true
}
fn reset_clip_task(&mut self, prim_index: PrimitiveIndex) {
let metadata = &mut self.cpu_metadata[prim_index.0];
metadata.clip_task_id = None;
if metadata.prim_kind == PrimitiveKind::Brush {
if let Some(ref mut desc) = self.cpu_brushes[metadata.cpu_prim_index.0].segment_desc {
for segment in &mut desc.segments {
segment.clip_task_id = None;
}
}
}
}
fn update_clip_task(
&mut self,
prim_index: PrimitiveIndex,
@ -1569,7 +1640,8 @@ impl PrimitiveStore {
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) -> bool {
self.cpu_metadata[prim_index.0].clip_task_id = None;
// Reset clips from previous frames since we may clip differently each frame.
self.reset_clip_task(prim_index);
let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
Some(rect) => rect,
@ -1733,13 +1805,16 @@ impl PrimitiveStore {
return None;
}
let (apply_local_clip_rect, original_reference_frame_index) = match pic.kind {
PictureKind::Image { reference_frame_index, composite_mode, .. } => {
may_need_clip_mask = composite_mode.is_some();
(true, Some(reference_frame_index))
may_need_clip_mask = pic.composite_mode.is_some();
let inflation_factor = match pic.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
// The amount of extra space needed for primitives inside
// this picture to ensure the visibility check is correct.
BLUR_SAMPLE_SCALE * blur_radius
}
PictureKind::TextShadow { .. } => {
(false, None)
_ => {
0.0
}
};
@ -1757,10 +1832,11 @@ impl PrimitiveStore {
PictureContext {
pipeline_id: pic.pipeline_id,
prim_runs: mem::replace(&mut pic.runs, Vec::new()),
original_reference_frame_index,
original_reference_frame_index: Some(pic.reference_frame_index),
display_list,
inv_world_transform,
apply_local_clip_rect,
apply_local_clip_rect: pic.apply_local_clip_rect,
inflation_factor,
}
};
@ -1788,7 +1864,14 @@ impl PrimitiveStore {
return None;
}
let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect);
// Inflate the local rect for this primitive by the inflation factor of
// the picture context. This ensures that even if the primitive itself
// is not visible, any effects from the blur radius will be correctly
// taken into account.
let local_rect = metadata
.local_rect
.inflate(pic_context.inflation_factor, pic_context.inflation_factor)
.intersection(&metadata.local_clip_rect);
let local_rect = match local_rect {
Some(local_rect) => local_rect,
None => return None,

View File

@ -73,7 +73,7 @@ struct SceneData {
removed_pipelines: Vec<PipelineId>,
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Eq, Ord)]
#[derive(Copy, Clone, Hash, PartialEq, PartialOrd, Debug, Eq, Ord)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct FrameId(pub u32);

View File

@ -9,25 +9,26 @@ use clip::{ClipSource, ClipStore, ClipWorkItem};
use clip_scroll_tree::CoordinateSystemId;
use device::TextureFilter;
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use gpu_types::{ImageSource, PictureType, RasterizationSpace};
use gpu_types::{ImageSource, RasterizationSpace};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use prim_store::{PrimitiveIndex, ImageCacheKey};
#[cfg(feature = "debugger")]
use print_tree::{PrintTreePrinter};
use render_backend::FrameId;
use resource_cache::{CacheItem, ResourceCache};
use std::{cmp, ops, usize, f32, i32};
use texture_cache::{TextureCache, TextureCacheHandle};
use tiling::{RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind};
const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
const FLOATS_PER_RENDER_TASK_INFO: usize = 8;
pub const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
pub const MIN_DOWNSCALING_RT_SIZE: i32 = 128;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskId(pub u32); // TODO(gw): Make private when using GPU cache!
pub struct RenderTaskId(pub u32, FrameId); // TODO(gw): Make private when using GPU cache!
#[derive(Debug, Copy, Clone)]
#[repr(C)]
@ -42,24 +43,27 @@ pub struct RenderTaskTree {
pub tasks: Vec<RenderTask>,
pub task_data: Vec<RenderTaskData>,
next_saved: SavedTargetIndex,
frame_id: FrameId,
}
impl RenderTaskTree {
pub fn new() -> Self {
pub fn new(frame_id: FrameId) -> Self {
RenderTaskTree {
tasks: Vec::new(),
task_data: Vec::new(),
next_saved: SavedTargetIndex(0),
frame_id,
}
}
pub fn add(&mut self, task: RenderTask) -> RenderTaskId {
let id = RenderTaskId(self.tasks.len() as u32);
let id = self.tasks.len();
self.tasks.push(task);
id
RenderTaskId(id as _, self.frame_id)
}
pub fn max_depth(&self, id: RenderTaskId, depth: usize, max_depth: &mut usize) {
debug_assert_eq!(self.frame_id, id.1);
let depth = depth + 1;
*max_depth = cmp::max(*max_depth, depth);
let task = &self.tasks[id.0 as usize];
@ -74,6 +78,7 @@ impl RenderTaskTree {
pass_index: usize,
passes: &mut Vec<RenderPass>,
) {
debug_assert_eq!(self.frame_id, id.1);
let task = &self.tasks[id.0 as usize];
for child in &task.children {
@ -106,6 +111,7 @@ impl RenderTaskTree {
}
pub fn get_task_address(&self, id: RenderTaskId) -> RenderTaskAddress {
debug_assert_eq!(self.frame_id, id.1);
RenderTaskAddress(id.0)
}
@ -125,12 +131,14 @@ impl RenderTaskTree {
impl ops::Index<RenderTaskId> for RenderTaskTree {
type Output = RenderTask;
fn index(&self, id: RenderTaskId) -> &RenderTask {
debug_assert_eq!(self.frame_id, id.1);
&self.tasks[id.0 as usize]
}
}
impl ops::IndexMut<RenderTaskId> for RenderTaskTree {
fn index_mut(&mut self, id: RenderTaskId) -> &mut RenderTask {
debug_assert_eq!(self.frame_id, id.1);
&mut self.tasks[id.0 as usize]
}
}
@ -168,7 +176,6 @@ pub struct PictureTask {
pub target_kind: RenderTargetKind,
pub content_origin: DeviceIntPoint,
pub color: PremultipliedColorF,
pub pic_type: PictureType,
pub uv_rect_handle: GpuCacheHandle,
}
@ -262,7 +269,6 @@ impl RenderTask {
color: PremultipliedColorF,
clear_mode: ClearMode,
children: Vec<RenderTaskId>,
pic_type: PictureType,
) -> Self {
RenderTask {
children,
@ -272,7 +278,6 @@ impl RenderTask {
target_kind,
content_origin,
color,
pic_type,
uv_rect_handle: GpuCacheHandle::new(),
}),
clear_mode,
@ -385,6 +390,7 @@ impl RenderTask {
ClipSource::Rectangle(..) |
ClipSource::RoundedRectangle(..) |
ClipSource::Image(..) |
ClipSource::LineDecoration(..) |
ClipSource::BorderCorner(..) => {}
}
}
@ -523,56 +529,41 @@ impl RenderTask {
// more type-safe. Although, it will always need
// to be kept in sync with the GLSL code anyway.
let (data1, data2) = match self.kind {
let data = match self.kind {
RenderTaskKind::Picture(ref task) => {
(
// Note: has to match `PICTURE_TYPE_*` in shaders
[
task.content_origin.x as f32,
task.content_origin.y as f32,
task.pic_type as u32 as f32,
],
task.color.to_array()
)
// Note: has to match `PICTURE_TYPE_*` in shaders
[
task.content_origin.x as f32,
task.content_origin.y as f32,
0.0,
]
}
RenderTaskKind::CacheMask(ref task) => {
(
[
task.actual_rect.origin.x as f32,
task.actual_rect.origin.y as f32,
RasterizationSpace::Screen as i32 as f32,
],
[0.0; 4],
)
[
task.actual_rect.origin.x as f32,
task.actual_rect.origin.y as f32,
RasterizationSpace::Screen as i32 as f32,
]
}
RenderTaskKind::ClipRegion(..) => {
(
[
0.0,
0.0,
RasterizationSpace::Local as i32 as f32,
],
[0.0; 4],
)
[
0.0,
0.0,
RasterizationSpace::Local as i32 as f32,
]
}
RenderTaskKind::VerticalBlur(ref task) |
RenderTaskKind::HorizontalBlur(ref task) => {
(
[
task.blur_std_deviation,
0.0,
0.0,
],
[0.0; 4],
)
[
task.blur_std_deviation,
0.0,
0.0,
]
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) => {
(
[0.0; 3],
[0.0; 4],
)
[0.0; 3]
}
};
@ -585,13 +576,9 @@ impl RenderTask {
target_rect.size.width as f32,
target_rect.size.height as f32,
target_index.0 as f32,
data1[0],
data1[1],
data1[2],
data2[0],
data2[1],
data2[2],
data2[3],
data[0],
data[1],
data[2],
]
}
}

View File

@ -112,10 +112,6 @@ const GPU_TAG_BRUSH_SOLID: GpuProfileTag = GpuProfileTag {
label: "B_Solid",
color: debug_colors::RED,
};
const GPU_TAG_BRUSH_LINE: GpuProfileTag = GpuProfileTag {
label: "Line",
color: debug_colors::DARKRED,
};
const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
label: "C_Clip",
color: debug_colors::PURPLE,
@ -209,7 +205,6 @@ impl BatchKind {
BatchKind::Brush(kind) => {
match kind {
BrushBatchKind::Solid => "Brush (Solid)",
BrushBatchKind::Line => "Brush (Line)",
BrushBatchKind::Image(..) => "Brush (Image)",
BrushBatchKind::Blend => "Brush (Blend)",
BrushBatchKind::MixBlend { .. } => "Brush (Composite)",
@ -229,7 +224,6 @@ impl BatchKind {
BatchKind::Brush(kind) => {
match kind {
BrushBatchKind::Solid => GPU_TAG_BRUSH_SOLID,
BrushBatchKind::Line => GPU_TAG_BRUSH_LINE,
BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE,
BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND,
BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND,
@ -1762,6 +1756,11 @@ impl Renderer {
"BoxShadows",
target.clip_batcher.box_shadows.len(),
);
debug_target.add(
debug_server::BatchKind::Clip,
"LineDecorations",
target.clip_batcher.line_decorations.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Vertical Blur",
@ -3085,6 +3084,22 @@ impl Renderer {
);
}
// draw line decoration clips
if !target.clip_batcher.line_decorations.is_empty() {
let _gm2 = self.gpu_profile.start_marker("clip lines");
self.shaders.cs_clip_line.bind(
&mut self.device,
projection,
&mut self.renderer_errors,
);
self.draw_instanced_batch(
&target.clip_batcher.line_decorations,
VertexArrayKind::Clip,
&BatchTextures::no_texture(),
stats,
);
}
// draw image masks
for (mask_texture_id, items) in target.clip_batcher.images.iter() {
let _gm2 = self.gpu_profile.start_marker("clip images");

View File

@ -418,7 +418,6 @@ pub struct Shaders {
// Brush shaders
brush_solid: BrushShader,
brush_line: BrushShader,
brush_image: Vec<Option<BrushShader>>,
brush_blend: BrushShader,
brush_mix_blend: BrushShader,
@ -433,6 +432,7 @@ pub struct Shaders {
pub cs_clip_box_shadow: LazilyCompiledShader,
pub cs_clip_image: LazilyCompiledShader,
pub cs_clip_border: LazilyCompiledShader,
pub cs_clip_line: LazilyCompiledShader,
// The are "primitive shaders". These shaders draw and blend
// final results on screen. They are aware of tile boundaries.
@ -464,13 +464,6 @@ impl Shaders {
options.precache_shaders,
)?;
let brush_line = BrushShader::new(
"brush_line",
device,
&[],
options.precache_shaders,
)?;
let brush_blend = BrushShader::new(
"brush_blend",
device,
@ -539,6 +532,14 @@ impl Shaders {
options.precache_shaders,
)?;
let cs_clip_line = LazilyCompiledShader::new(
ShaderKind::ClipCache,
"cs_clip_line",
&[],
device,
options.precache_shaders,
)?;
let cs_clip_image = LazilyCompiledShader::new(
ShaderKind::ClipCache,
"cs_clip_image",
@ -676,7 +677,6 @@ impl Shaders {
cs_blur_a8,
cs_blur_rgba8,
brush_solid,
brush_line,
brush_image,
brush_blend,
brush_mix_blend,
@ -687,6 +687,7 @@ impl Shaders {
cs_clip_box_shadow,
cs_clip_border,
cs_clip_image,
cs_clip_line,
ps_text_run,
ps_text_run_dual_source,
ps_image,
@ -724,9 +725,6 @@ impl Shaders {
.as_mut()
.expect("Unsupported image shader kind")
}
BrushBatchKind::Line => {
&mut self.brush_line
}
BrushBatchKind::Blend => {
&mut self.brush_blend
}
@ -775,7 +773,6 @@ impl Shaders {
self.cs_blur_a8.deinit(device);
self.cs_blur_rgba8.deinit(device);
self.brush_solid.deinit(device);
self.brush_line.deinit(device);
self.brush_blend.deinit(device);
self.brush_mix_blend.deinit(device);
self.brush_radial_gradient.deinit(device);
@ -784,6 +781,7 @@ impl Shaders {
self.cs_clip_box_shadow.deinit(device);
self.cs_clip_image.deinit(device);
self.cs_clip_border.deinit(device);
self.cs_clip_line.deinit(device);
self.ps_text_run.deinit(device);
self.ps_text_run_dual_source.deinit(device);
for shader in self.brush_image {

View File

@ -11,9 +11,8 @@ use clip_scroll_tree::{ClipScrollTree, ClipScrollNodeIndex};
use device::{FrameId, Texture};
use gpu_cache::{GpuCache};
use gpu_types::{BlurDirection, BlurInstance};
use gpu_types::{ClipScrollNodeData};
use gpu_types::{ClipScrollNodeData, ZBufferIdGenerator};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::PictureKind;
use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveKind, PrimitiveStore};
use prim_store::{BrushKind, DeferredResolve};
use profiler::FrameProfileCounters;
@ -314,6 +313,7 @@ impl RenderTarget for ColorRenderTarget {
deferred_resolves: &mut Vec<DeferredResolve>,
) {
let mut merged_batches = AlphaBatchContainer::new(None);
let mut z_generator = ZBufferIdGenerator::new();
for task_id in &self.alpha_tasks {
let task = &render_tasks[*task_id];
@ -336,6 +336,7 @@ impl RenderTarget for ColorRenderTarget {
gpu_cache,
render_tasks,
deferred_resolves,
&mut z_generator,
);
if let Some(batch_container) = batch_builder.build(&mut merged_batches) {
@ -395,15 +396,13 @@ impl RenderTarget for ColorRenderTarget {
self.alpha_tasks.push(task_id);
if let PictureKind::Image { frame_output_pipeline_id, .. } = pic.kind {
// If this pipeline is registered as a frame output
// store the information necessary to do the copy.
if let Some(pipeline_id) = frame_output_pipeline_id {
self.outputs.push(FrameOutput {
pipeline_id,
task_id,
});
}
// If this pipeline is registered as a frame output
// store the information necessary to do the copy.
if let Some(pipeline_id) = pic.frame_output_pipeline_id {
self.outputs.push(FrameOutput {
pipeline_id,
task_id,
});
}
}
_ => {

View File

@ -40,6 +40,10 @@ const SHADERS: &[Shader] = &[
name: "cs_clip_border",
features: CLIP_FEATURES,
},
Shader {
name: "cs_clip_line",
features: CLIP_FEATURES,
},
// Cache shaders
Shader {
name: "cs_blur",
@ -91,10 +95,6 @@ const SHADERS: &[Shader] = &[
name: "brush_composite",
features: &[],
},
Shader {
name: "brush_line",
features: &[],
},
Shader {
name: "brush_radial_gradient",
features: &[ "DITHERING" ],

View File

@ -18,8 +18,8 @@ bitflags = "1.0"
byteorder = "1.2.1"
ipc-channel = {version = "0.10.0", optional = true}
euclid = { version = "0.17", features = ["serde"] }
serde = { version = "=1.0.27", features = ["rc"] }
serde_derive = { version = "=1.0.27", features = ["deserialize_in_place"] }
serde = { version = "=1.0.35", features = ["rc"] }
serde_derive = { version = "=1.0.35", features = ["deserialize_in_place"] }
time = "0.1"
[target.'cfg(target_os = "macos")'.dependencies]

View File

@ -1 +1 @@
30cfecc343e407ce277d07cf09f27ad9dd1917a1
22493328352ba432a7cd89491d81bfaa19bc1bce

View File

@ -349,8 +349,8 @@ impl RenderNotifier for Notifier {
self.tx.send(NotifierEvent::ShutDown).unwrap();
}
fn new_document_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
if !scrolled {
fn new_document_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) {
if composite_needed {
self.wake_up();
}
}
@ -504,6 +504,7 @@ fn main() {
let mut show_help = false;
let mut do_loop = false;
let mut cpu_profile_index = 0;
let mut cursor_position = WorldPoint::zero();
let dim = window.get_inner_size();
wrench.update(dim);
@ -527,13 +528,14 @@ fn main() {
glutin::WindowEvent::Closed => {
return glutin::ControlFlow::Break;
}
glutin::WindowEvent::Refresh |
glutin::WindowEvent::Focused(..) |
glutin::WindowEvent::CursorMoved { .. } => {
glutin::WindowEvent::Focused(..) => {
do_render = true;
}
glutin::WindowEvent::CursorMoved { position: (x, y), .. } => {
cursor_position = WorldPoint::new(x as f32, y as f32);
do_render = true;
}
glutin::WindowEvent::KeyboardInput {
input: glutin::KeyboardInput {
state: glutin::ElementState::Pressed,
@ -614,6 +616,20 @@ fn main() {
wrench.set_page_zoom(new_zoom_factor);
do_frame = true;
}
VirtualKeyCode::X => {
let results = wrench.api.hit_test(
wrench.document_id,
None,
cursor_position,
HitTestFlags::FIND_ALL
);
println!("Hit test results:");
for item in &results.items {
println!("{:?}", item);
}
println!("");
}
_ => {}
}
_ => {}

View File

@ -515,27 +515,11 @@ impl Wrench {
false,
);
}
// TODO(nical) - Need to separate the set_display_list from the scrolling
// operations into separate transactions for mysterious -but probably related
// to the other comment below- reasons.
self.api.send_transaction(self.document_id, txn);
let mut txn = Transaction::new();
for (id, offset) in scroll_offsets {
txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping);
}
// TODO(nical) - Wrench does not notify frames when there was scrolling
// in the transaction (See RenderNotifier implementations). If we don't
// generate a frame after scrolling, wrench just stops and some tests
// will time out.
// I suppose this was to avoid taking the snapshot after scrolling if
// there was other updates coming in a subsequent messages but it's very
// error-prone with transactions.
// For now just send two transactions to avoid the deadlock, but we should
// figure this out.
self.api.send_transaction(self.document_id, txn);
let mut txn = Transaction::new();
txn.generate_frame();
self.api.send_transaction(self.document_id, txn);
}
@ -575,6 +559,7 @@ impl Wrench {
"M - Trigger memory pressure event",
"T - Save CPU profile to a file",
"C - Save a capture to captures/wrench/",
"X - Do a hit test at the current cursor position",
];
let color_and_offset = [(*BLACK_COLOR, 2.0), (*WHITE_COLOR, 0.0)];

View File

@ -373,6 +373,19 @@ impl YamlFrameReader {
}
}
fn to_hit_testing_tag(&self, item: &Yaml) -> Option<ItemTag> {
match *item {
Yaml::Array(ref array) if array.len() == 2 => {
match (array[0].as_i64(), array[1].as_i64()) {
(Some(first), Some(second)) => Some((first as u64, second as u16)),
_ => None,
}
}
_ => None,
}
}
pub fn add_or_get_image(
&mut self,
file: &Path,
@ -387,7 +400,7 @@ impl YamlFrameReader {
if self.list_resources { println!("{}", file.to_string_lossy()); }
let (descriptor, image_data) = match image::open(file) {
Ok(image) => {
let image_dims = image.dimensions();
let (image_width, image_height) = image.dimensions();
let (format, bytes) = match image {
image::ImageLuma8(_) => {
(ImageFormat::R8, image.raw_pixels())
@ -399,7 +412,7 @@ impl YamlFrameReader {
}
image::ImageRgb8(_) => {
let bytes = image.raw_pixels();
let mut pixels = Vec::new();
let mut pixels = Vec::with_capacity(image_width as usize * image_height as usize * 4);
for bgr in bytes.chunks(3) {
pixels.extend_from_slice(&[
bgr[2],
@ -413,8 +426,8 @@ impl YamlFrameReader {
_ => panic!("We don't support whatever your crazy image type is, come on"),
};
let descriptor = ImageDescriptor::new(
image_dims.0,
image_dims.1,
image_width,
image_height,
format,
is_image_opaque(format, &bytes[..]),
self.allow_mipmaps,
@ -1290,6 +1303,8 @@ impl YamlFrameReader {
let mut info = LayoutPrimitiveInfo::with_clip_rect(LayoutRect::zero(), clip_rect);
info.is_backface_visible = item["backface-visible"].as_bool().unwrap_or(true);;
info.tag = self.to_hit_testing_tag(&item["hit-testing-tag"]);
match item_type {
"rect" => self.handle_rect(dl, item, &mut info),
"clear-rect" => self.handle_clear_rect(dl, item, &mut info),

View File

@ -687,9 +687,17 @@ impl YamlFrameWriter {
};
let mut v = new_table();
rect_node(&mut v, "bounds", &base.rect());
let info = base.get_layer_primitive_info(&LayoutVector2D::zero());
rect_node(&mut v, "bounds", &info.rect);
rect_node(&mut v, "clip-rect", &info.clip_rect);
rect_node(&mut v, "clip-rect", base.clip_rect());
if let Some(tag) = info.tag {
yaml_node(
&mut v,
"hit-testing-tag",
Yaml::Array(vec![Yaml::Integer(tag.0 as i64), Yaml::Integer(tag.1 as i64)])
);
}
let clip_and_scroll_yaml = match clip_id_mapper.map_info(&base.clip_and_scroll()) {
(scroll_id, Some(clip_id)) => {
@ -1000,7 +1008,6 @@ impl YamlFrameWriter {
Clip(item) => {
str_node(&mut v, "type", "clip");
usize_node(&mut v, "id", clip_id_mapper.add_id(item.id));
size_node(&mut v, "content-size", &base.rect().size);
let (complex_clips, complex_clip_count) = base.complex_clip();
if let Some(complex) = self.make_complex_clips_node(