mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1447998 - Update webrender to commit 22493328352ba432a7cd89491d81bfaa19bc1bce. r=jrmuizel
MozReview-Commit-ID: 4krUpVqWkr --HG-- extra : rebase_source : 55990a227f280c2c9c1f92c9f2c1f52b6e91c184
This commit is contained in:
parent
05c79c044e
commit
9fa8fde9e9
@ -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(
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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))]
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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],
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -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" ],
|
||||
|
@ -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]
|
||||
|
@ -1 +1 @@
|
||||
30cfecc343e407ce277d07cf09f27ad9dd1917a1
|
||||
22493328352ba432a7cd89491d81bfaa19bc1bce
|
||||
|
@ -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!("");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -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)];
|
||||
|
@ -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),
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user