Backed out changeset 6878f6294d68 (bug 1519718) for bustages on a CLOSED TREE.

This commit is contained in:
Gurzau Raul 2019-03-06 12:34:28 +02:00
Родитель 56ceba9d51
Коммит 0208b45a04
18 изменённых файлов: 407 добавлений и 363 удалений

Просмотреть файл

@ -6,9 +6,10 @@
#include shared,prim_shared,brush
varying vec3 vSrcUv;
varying vec3 vBackdropUv;
flat varying int vOp;
varying vec4 vSourceAndBackdropUv;
flat varying ivec4 vSourceUvBounds;
flat varying ivec4 vBackdropUvBounds;
flat varying ivec3 vOpAndLayers;
#ifdef WR_VERTEX_SHADER
@ -17,6 +18,10 @@ vec2 snap_device_pos(VertexInfo vi, float device_pixel_scale) {
return vi.world_pos.xy * device_pixel_scale / max(0.0, vi.world_pos.w) + vi.snap_offset;
}
ivec4 rect_to_ivec(RectWithSize rect) {
return ivec4(rect.p0, rect.p0 + rect.size - 1.0);
}
void brush_vs(
VertexInfo vi,
int prim_address,
@ -29,20 +34,25 @@ void brush_vs(
vec4 unused
) {
vec2 snapped_device_pos = snap_device_pos(vi, pic_task.device_pixel_scale);
vec2 texture_size = vec2(textureSize(sPrevPassColor, 0));
vOp = user_data.x;
PictureTask src_task = fetch_picture_task(user_data.z);
PictureTask backdrop_task = fetch_picture_task(user_data.y);
vec2 src_uv = snapped_device_pos +
src_task.common_data.task_rect.p0 -
src_task.content_origin;
vSrcUv = vec3(src_uv / texture_size, src_task.common_data.texture_layer_index);
RenderTaskCommonData backdrop_task = fetch_render_task_common_data(user_data.y);
vec2 backdrop_uv = snapped_device_pos +
backdrop_task.task_rect.p0 -
src_task.content_origin;
vBackdropUv = vec3(backdrop_uv / texture_size, backdrop_task.texture_layer_index);
backdrop_task.common_data.task_rect.p0 -
backdrop_task.content_origin;
vSourceAndBackdropUv = vec4(src_uv, backdrop_uv);
vSourceUvBounds = rect_to_ivec(src_task.common_data.task_rect);
vBackdropUvBounds = rect_to_ivec(backdrop_task.common_data.task_rect);
vOpAndLayers = ivec3(
user_data.x,
int(src_task.common_data.texture_layer_index),
int(backdrop_task.common_data.texture_layer_index)
);
}
#endif
@ -205,82 +215,89 @@ const int MixBlendMode_Color = 14;
const int MixBlendMode_Luminosity = 15;
Fragment brush_fs() {
vec4 Cb = textureLod(sPrevPassColor, vBackdropUv, 0.0);
vec4 Cs = textureLod(sPrevPassColor, vSrcUv, 0.0);
// The mix-blend-mode functions assume no premultiplied alpha
if (Cb.a != 0.0) {
Cb.rgb /= Cb.a;
}
if (Cs.a != 0.0) {
Cs.rgb /= Cs.a;
}
// Return yellow if none of the branches match (shouldn't happen).
vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
switch (vOp) {
case MixBlendMode_Multiply:
result.rgb = Multiply(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Screen:
result.rgb = Screen(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Overlay:
// Overlay is inverse of Hardlight
result.rgb = HardLight(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_Darken:
result.rgb = min(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_Lighten:
result.rgb = max(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_ColorDodge:
result.r = ColorDodge(Cb.r, Cs.r);
result.g = ColorDodge(Cb.g, Cs.g);
result.b = ColorDodge(Cb.b, Cs.b);
break;
case MixBlendMode_ColorBurn:
result.r = ColorBurn(Cb.r, Cs.r);
result.g = ColorBurn(Cb.g, Cs.g);
result.b = ColorBurn(Cb.b, Cs.b);
break;
case MixBlendMode_HardLight:
result.rgb = HardLight(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_SoftLight:
result.r = SoftLight(Cb.r, Cs.r);
result.g = SoftLight(Cb.g, Cs.g);
result.b = SoftLight(Cb.b, Cs.b);
break;
case MixBlendMode_Difference:
result.rgb = Difference(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Exclusion:
result.rgb = Exclusion(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Hue:
result.rgb = Hue(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Saturation:
result.rgb = Saturation(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Color:
result.rgb = Color(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Luminosity:
result.rgb = Luminosity(Cb.rgb, Cs.rgb);
break;
default: break;
ivec2 source_uv = ivec2(floor(vSourceAndBackdropUv.xy));
vec4 Cs = source_uv == clamp(source_uv, vSourceUvBounds.xy, vSourceUvBounds.zw) ?
texelFetch(sPrevPassColor, ivec3(source_uv, vOpAndLayers.y), 0) :
vec4(0.0);
ivec2 backdrop_uv = ivec2(floor(vSourceAndBackdropUv.zw));
vec4 Cb = backdrop_uv == clamp(backdrop_uv, vBackdropUvBounds.xy, vBackdropUvBounds.zw) ?
texelFetch(sPrevPassColor, ivec3(backdrop_uv, vOpAndLayers.z), 0) :
vec4(0.0);
if (Cs.a == 0.0) {
result = Cb;
} else if (Cb.a == 0.0) {
result = Cs;
} else {
vec3 original_backdrop = Cb.rgb;
// The mix-blend-mode functions assume no premultiplied alpha
Cs.rgb /= Cs.a;
Cb.rgb /= Cb.a;
switch (vOpAndLayers.x) {
case MixBlendMode_Multiply:
result.rgb = Multiply(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Screen:
result.rgb = Screen(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Overlay:
// Overlay is inverse of Hardlight
result.rgb = HardLight(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_Darken:
result.rgb = min(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_Lighten:
result.rgb = max(Cs.rgb, Cb.rgb);
break;
case MixBlendMode_ColorDodge:
result.r = ColorDodge(Cb.r, Cs.r);
result.g = ColorDodge(Cb.g, Cs.g);
result.b = ColorDodge(Cb.b, Cs.b);
break;
case MixBlendMode_ColorBurn:
result.r = ColorBurn(Cb.r, Cs.r);
result.g = ColorBurn(Cb.g, Cs.g);
result.b = ColorBurn(Cb.b, Cs.b);
break;
case MixBlendMode_HardLight:
result.rgb = HardLight(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_SoftLight:
result.r = SoftLight(Cb.r, Cs.r);
result.g = SoftLight(Cb.g, Cs.g);
result.b = SoftLight(Cb.b, Cs.b);
break;
case MixBlendMode_Difference:
result.rgb = Difference(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Exclusion:
result.rgb = Exclusion(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Hue:
result.rgb = Hue(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Saturation:
result.rgb = Saturation(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Color:
result.rgb = Color(Cb.rgb, Cs.rgb);
break;
case MixBlendMode_Luminosity:
result.rgb = Luminosity(Cb.rgb, Cs.rgb);
break;
default: break;
}
vec3 rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb;
// simulate alpha-blending with the backdrop
result = mix(vec4(original_backdrop, Cb.a), vec4(rgb, 1.0), Cs.a);
}
result.rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb;
result.a = Cs.a;
result.rgb *= result.a;
return Fragment(result);
}
#endif

Просмотреть файл

@ -29,7 +29,7 @@ use scene::FilterOpHelpers;
use smallvec::SmallVec;
use std::{f32, i32, usize};
use tiling::{RenderTargetContext};
use util::{project_rect, TransformedRectKind};
use util::{project_rect, MaxRect, TransformedRectKind};
// Special sentinel value recognized by the shader. It is considered to be
// a dummy task that doesn't mask out anything.
@ -979,10 +979,10 @@ impl AlphaBatchBuilder {
// Convert all children of the 3D hierarchy root into batches.
Picture3DContext::In { root_data: Some(ref list), .. } => {
for child in list {
let prim_instance = &picture.prim_list.prim_instances[child.anchor];
let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize];
let child_prim_instance = &picture.prim_list.prim_instances[child.anchor];
let child_prim_info = &ctx.scratch.prim_info[child_prim_instance.visibility_info.0 as usize];
let child_pic_index = match prim_instance.kind {
let child_pic_index = match child_prim_instance.kind {
PrimitiveInstanceKind::Picture { pic_index, .. } => pic_index,
PrimitiveInstanceKind::LineDecoration { .. } |
PrimitiveInstanceKind::TextRun { .. } |
@ -1003,14 +1003,14 @@ impl AlphaBatchBuilder {
// Get clip task, if set, for the picture primitive.
let clip_task_address = get_clip_task_address(
&ctx.scratch.clip_mask_instances,
prim_info.clip_task_index,
child_prim_info.clip_task_index,
0,
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
let prim_header = PrimitiveHeader {
let child_header = PrimitiveHeader {
local_rect: pic.local_rect,
local_clip_rect: prim_info.combined_local_clip_rect,
local_clip_rect: child_prim_info.combined_local_clip_rect,
task_address,
specific_prim_address: GpuCacheAddress::invalid(),
clip_task_address,
@ -1037,7 +1037,7 @@ impl AlphaBatchBuilder {
gpu_cache,
);
let prim_header_index = prim_headers.push(&prim_header, z_id, [
let prim_header_index = prim_headers.push(&child_header, z_id, [
uv_rect_address.as_int(),
if raster_config.establishes_raster_root { 1 } else { 0 },
0,
@ -1057,7 +1057,7 @@ impl AlphaBatchBuilder {
self.current_batch_list().push_single_instance(
key,
&prim_info.clip_chain.pic_clip_rect,
&child_prim_info.clip_chain.pic_clip_rect,
z_id,
PrimitiveInstanceData::from(instance),
);
@ -1134,7 +1134,7 @@ impl AlphaBatchBuilder {
// Get the local rect of the tile.
let tile_rect = tile.local_rect;
let prim_header = PrimitiveHeader {
let tile_header = PrimitiveHeader {
local_rect: tile_rect,
local_clip_rect,
task_address,
@ -1143,7 +1143,7 @@ impl AlphaBatchBuilder {
transform_id,
};
let prim_header_index = prim_headers.push(&prim_header, z_id, [
let prim_header_index = prim_headers.push(&tile_header, z_id, [
ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
RasterizationSpace::Local as i32,
get_shader_opacity(1.0),
@ -1515,28 +1515,71 @@ impl AlphaBatchBuilder {
PrimitiveInstanceData::from(instance),
);
}
PictureCompositeMode::MixBlend(mode) => {
let surface = ctx.surfaces[raster_config.surface_index.0]
PictureCompositeMode::Puppet { master: Some(source) } if ctx.is_picture_surface_visible(source) => return,
PictureCompositeMode::MixBlend { mode, backdrop } if ctx.is_picture_surface_visible(backdrop) => {
let backdrop_picture = &ctx.prim_store.pictures[backdrop.0];
let source_id = ctx
.surfaces[raster_config.surface_index.0]
.surface
.as_ref()
.expect("bug: surface must be allocated by now");
let cache_task_id = surface.resolve_render_task_id();
let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
.expect("bug: source surface must be allocated by now")
.resolve_render_task_id();
let backdrop_surface_id = backdrop_picture.raster_config
.as_ref()
.unwrap()
.surface_index;
let backdrop_id = ctx.surfaces[backdrop_surface_id.0]
.surface
.as_ref()
.expect("bug: backdrop surface must be allocated by now")
.resolve_render_task_id();
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id,
source_id: cache_task_id,
source_id,
backdrop_id,
},
),
BlendMode::PremultipliedAlpha,
non_segmented_blend_mode,
BatchTextures::no_texture(),
);
// The trick here is to draw the picture in the space of the backdrop,
// since the source can be attached to a child spatial node.
let expanded_header = PrimitiveHeader {
local_rect: ctx.clip_scroll_tree
.map_rect_to_parent_space(
prim_header.local_rect,
picture.spatial_node_index,
backdrop_picture.spatial_node_index,
&backdrop_picture.local_rect, //Note: this shouldn't be used
)
.unwrap_or_else(LayoutRect::zero)
.union(&backdrop_picture.local_rect),
local_clip_rect: ctx.clip_scroll_tree
.map_rect_to_parent_space(
prim_header.local_clip_rect,
picture.spatial_node_index,
backdrop_picture.spatial_node_index,
&backdrop_picture.local_clip_rect, //Note: this shouldn't be used
)
.unwrap_or_else(LayoutRect::zero)
.union(&backdrop_picture.local_clip_rect),
transform_id: transforms
.get_id(
backdrop_picture.spatial_node_index,
root_spatial_node_index,
ctx.clip_scroll_tree,
),
..prim_header
};
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(cache_task_id);
let prim_header_index = prim_headers.push(&prim_header, z_id, [
let source_task_address = render_tasks.get_task_address(source_id);
let prim_header_index = prim_headers.push(&expanded_header, z_id, [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
@ -1550,14 +1593,20 @@ impl AlphaBatchBuilder {
brush_flags,
user_data: 0,
};
//TODO: investigate if we can do better. We can't use the `bounding_rect`
// here because we effectively merge the call with the backdrop,
// and the instance for the backdrop isn't available here.
let conservative_bounding_rect = PictureRect::max_rect();
self.current_batch_list().push_single_instance(
key,
bounding_rect,
&conservative_bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
);
}
PictureCompositeMode::Puppet { .. } |
PictureCompositeMode::MixBlend { .. } |
PictureCompositeMode::Blit(_) => {
let surface = ctx.surfaces[raster_config.surface_index.0]
.surface

Просмотреть файл

@ -11,7 +11,7 @@ use print_tree::{PrintableTree, PrintTree, PrintTreePrinter};
use scene::SceneProperties;
use spatial_node::{ScrollFrameInfo, SpatialNode, SpatialNodeType, StickyFrameInfo, ScrollFrameKind};
use std::ops;
use util::{LayoutToWorldFastTransform, MatrixHelpers, ScaleOffset};
use util::{project_rect, LayoutToWorldFastTransform, MatrixHelpers, ScaleOffset};
pub type ScrollStates = FastHashMap<ExternalScrollId, ScrollFrameInfo>;
@ -211,6 +211,35 @@ impl ClipScrollTree {
})
}
/// Map a rectangle in some child space to a parent.
/// Doesn't handle preserve-3d islands.
pub fn map_rect_to_parent_space(
&self,
mut rect: LayoutRect,
child_index: SpatialNodeIndex,
parent_index: SpatialNodeIndex,
parent_bounds: &LayoutRect,
) -> Option<LayoutRect> {
if child_index == parent_index {
return Some(rect);
}
assert!(child_index.0 > parent_index.0);
let child = &self.spatial_nodes[child_index.0 as usize];
let parent = &self.spatial_nodes[parent_index.0 as usize];
let mut coordinate_system_id = child.coordinate_system_id;
rect = child.coordinate_system_relative_scale_offset.map_rect(&rect);
while coordinate_system_id != parent.coordinate_system_id {
let coord_system = &self.coord_systems[coordinate_system_id.0 as usize];
coordinate_system_id = coord_system.parent.expect("invalid parent!");
rect = project_rect(&coord_system.transform, &rect, parent_bounds)?;
}
Some(parent.coordinate_system_relative_scale_offset.unmap_rect(&rect))
}
/// Returns true if the spatial node is the same as the parent, or is
/// a child of the parent.
pub fn is_same_or_child_of(

Просмотреть файл

@ -1326,23 +1326,44 @@ impl<'a> DisplayListFlattener<'a> {
None
};
// Get the transform-style of the parent stacking context,
// Figure out if the parent is in 3D context,
// which determines if we *might* need to draw this on
// an intermediate surface for plane splitting purposes.
let (parent_is_3d, extra_3d_instance) = match self.sc_stack.last_mut() {
Some(sc) => {
// Cut the sequence of flat children before starting a child stacking context,
// so that the relative order between them and our current SC is preserved.
let extra_instance = sc.cut_flat_item_sequence(
let (parent_is_3d, extra_3d_picture, backdrop_picture) = match self.sc_stack.last_mut() {
Some(ref mut sc) if composite_ops.mix_blend_mode.is_some() => {
// Cut the sequence of children before starting a mix-blend stacking context,
// so that we have a source picture for applying the blending operator.
let backdrop_picture = sc.cut_item_sequence(
&mut self.prim_store,
&mut self.interners,
PictureCompositeMode::Puppet { master: None },
Picture3DContext::Out,
);
(sc.is_3d(), extra_instance)
},
None => (false, None),
(false, None, backdrop_picture)
}
Some(ref mut sc) if sc.is_3d() => {
let flat_items_context_3d = match sc.context_3d {
Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In {
root_data: None,
ancestor_index,
},
Picture3DContext::Out => panic!("Unexpected out of 3D context"),
};
// Cut the sequence of flat children before starting a child stacking context,
// so that the relative order between them and our current SC is preserved.
let extra_picture = sc.cut_item_sequence(
&mut self.prim_store,
&mut self.interners,
PictureCompositeMode::Blit(BlitReason::PRESERVE3D),
flat_items_context_3d,
);
(true, extra_picture, None)
}
Some(_) | None => (false, None, None),
};
if let Some(instance) = extra_3d_instance {
if let Some((_picture_index, instance)) = extra_3d_picture {
self.add_primitive_instance_to_3d_root(instance);
}
@ -1380,11 +1401,13 @@ impl<'a> DisplayListFlattener<'a> {
// has a clip node. In the future, we may decide during
// prepare step to skip the intermediate surface if the
// clip node doesn't affect the stacking context rect.
let blit_reason = if clip_chain_id == ClipChainId::NONE {
BlitReason::empty()
} else {
BlitReason::CLIP
};
let mut blit_reason = BlitReason::empty();
if clip_chain_id != ClipChainId::NONE {
blit_reason |= BlitReason::CLIP
}
if participating_in_3d_context {
blit_reason |= BlitReason::PRESERVE3D;
}
// Push the SC onto the stack, so we know how to handle things in
// pop_stacking_context.
@ -1397,6 +1420,7 @@ impl<'a> DisplayListFlattener<'a> {
clip_chain_id,
frame_output_pipeline_id,
composite_ops,
backdrop_picture,
blit_reason,
transform_style,
context_3d,
@ -1416,26 +1440,22 @@ impl<'a> DisplayListFlattener<'a> {
// (b) It's useful for the initial version of picture caching in gecko, by enabling
// is to just look for interesting scroll roots on the root stacking context,
// without having to consider cuts at stacking context boundaries.
let parent_is_empty = match self.sc_stack.last_mut() {
Some(parent_sc) => {
if stacking_context.is_redundant(
parent_sc,
self.clip_scroll_tree,
) {
// If the parent context primitives list is empty, it's faster
// to assign the storage of the popped context instead of paying
// the copying cost for extend.
if parent_sc.primitives.is_empty() {
parent_sc.primitives = stacking_context.primitives;
} else {
parent_sc.primitives.extend(stacking_context.primitives);
}
return;
if let Some(parent_sc) = self.sc_stack.last_mut() {
if stacking_context.is_redundant(
parent_sc,
self.clip_scroll_tree,
) {
// If the parent context primitives list is empty, it's faster
// to assign the storage of the popped context instead of paying
// the copying cost for extend.
if parent_sc.primitives.is_empty() {
parent_sc.primitives = stacking_context.primitives;
} else {
parent_sc.primitives.extend(stacking_context.primitives);
}
parent_sc.primitives.is_empty()
},
None => true,
};
return;
}
}
if stacking_context.create_tile_cache {
self.setup_picture_caching(
@ -1451,7 +1471,16 @@ impl<'a> DisplayListFlattener<'a> {
// to correctly handle some CSS cases (see #1957).
let max_clip = LayoutRect::max_rect();
let (leaf_context_3d, leaf_composite_mode, leaf_output_pipeline_id) = match stacking_context.context_3d {
let leaf_composite_mode = if stacking_context.blit_reason.is_empty() {
// By default, this picture will be collapsed into
// the owning target.
None
} else {
// Add a dummy composite filter if the SC has to be isolated.
Some(PictureCompositeMode::Blit(stacking_context.blit_reason))
};
let leaf_context_3d = match stacking_context.context_3d {
// TODO(gw): For now, as soon as this picture is in
// a 3D context, we draw it to an intermediate
// surface and apply plane splitting. However,
@ -1459,25 +1488,17 @@ impl<'a> DisplayListFlattener<'a> {
// During culling, we can check if there is actually
// perspective present, and skip the plane splitting
// completely when that is not the case.
Picture3DContext::In { ancestor_index, .. } => (
Picture3DContext::In { root_data: None, ancestor_index },
Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D | stacking_context.blit_reason)),
None,
),
Picture3DContext::Out => (
Picture3DContext::Out,
if stacking_context.blit_reason.is_empty() {
// By default, this picture will be collapsed into
// the owning target.
None
} else {
// Add a dummy composite filter if the SC has to be isolated.
Some(PictureCompositeMode::Blit(stacking_context.blit_reason))
},
stacking_context.frame_output_pipeline_id
),
Picture3DContext::In { ancestor_index, .. } => {
assert!(!leaf_composite_mode.is_none());
Picture3DContext::In { root_data: None, ancestor_index }
}
Picture3DContext::Out => Picture3DContext::Out,
};
let leaf_prim_list = PrimitiveList::new(
stacking_context.primitives,
&self.interners,
);
// Add picture for this actual stacking context contents to render into.
let leaf_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
@ -1485,13 +1506,10 @@ impl<'a> DisplayListFlattener<'a> {
leaf_composite_mode,
leaf_context_3d,
stacking_context.pipeline_id,
leaf_output_pipeline_id,
stacking_context.frame_output_pipeline_id,
true,
stacking_context.requested_raster_space,
PrimitiveList::new(
stacking_context.primitives,
&self.interners,
),
leaf_prim_list,
stacking_context.spatial_node_index,
max_clip,
None,
@ -1632,8 +1650,7 @@ impl<'a> DisplayListFlattener<'a> {
self.prim_store.optimize_picture_if_possible(current_pic_index);
}
// Same for mix-blend-mode, except we can skip if this primitive is the first in the parent
// stacking context.
// Same for mix-blend-mode, except we can skip if the backdrop doesn't have any primitives.
// From https://drafts.fxtf.org/compositing-1/#generalformula, the formula for blending is:
// Cs = (1 - ab) x Cs + ab x Blend(Cb, Cs)
// where
@ -1644,8 +1661,15 @@ impl<'a> DisplayListFlattener<'a> {
// If we're the first primitive within a stacking context, then we can guarantee that the
// backdrop alpha will be 0, and then the blend equation collapses to just
// Cs = Cs, and the blend mode isn't taken into account at all.
let has_mix_blend = if let (Some(mix_blend_mode), false) = (stacking_context.composite_ops.mix_blend_mode, parent_is_empty) {
let composite_mode = Some(PictureCompositeMode::MixBlend(mix_blend_mode));
if let (Some(mode), Some((backdrop, backdrop_instance))) = (stacking_context.composite_ops.mix_blend_mode, stacking_context.backdrop_picture.take()) {
let composite_mode = Some(PictureCompositeMode::MixBlend { mode, backdrop });
// We need to make the backdrop picture to be at the same level as the content,
// to be available as a source for composition...
if let Some(parent_sc) = self.sc_stack.last_mut() {
// Not actually rendered, due to `PictureCompositeMode::Puppet`, unless the blend picture is culled.
parent_sc.primitives.push(backdrop_instance);
}
let blend_pic_index = PictureIndex(self.prim_store.pictures
.alloc()
@ -1667,9 +1691,14 @@ impl<'a> DisplayListFlattener<'a> {
))
);
// Assoiate the backdrop picture with the blend.
self.prim_store.pictures[backdrop.0].requested_composite_mode = Some(PictureCompositeMode::Puppet {
master: Some(blend_pic_index),
});
current_pic_index = blend_pic_index;
cur_instance = create_prim_instance(
blend_pic_index,
current_pic_index,
composite_mode.into(),
stacking_context.is_backface_visible,
ClipChainId::NONE,
@ -1678,12 +1707,9 @@ impl<'a> DisplayListFlattener<'a> {
);
if cur_instance.is_chased() {
println!("\tis a mix-blend picture for a stacking context with {:?}", mix_blend_mode);
println!("\tis a mix-blend picture for a stacking context with {:?}", mode);
}
true
} else {
false
};
}
// Set the stacking context clip on the outermost picture in the chain,
// unless we already set it on the leaf picture.
@ -1698,13 +1724,6 @@ impl<'a> DisplayListFlattener<'a> {
}
// Regular parenting path
Some(ref mut parent_sc) => {
// If we have a mix-blend-mode, the stacking context needs to be isolated
// to blend correctly as per the CSS spec.
// If not already isolated for some other reason,
// make this picture as isolated.
if has_mix_blend {
parent_sc.blit_reason |= BlitReason::ISOLATE;
}
parent_sc.primitives.push(cur_instance);
None
}
@ -2694,6 +2713,9 @@ struct FlattenedStackingContext {
/// stacking context.
composite_ops: CompositeOps,
/// For a mix-blend stacking context, specify the picture index for backdrop.
backdrop_picture: Option<(PictureIndex, PrimitiveInstance)>,
/// Bitfield of reasons this stacking context needs to
/// be an offscreen surface.
blit_reason: BlitReason,
@ -2736,7 +2758,8 @@ impl FlattenedStackingContext {
// We can skip mix-blend modes if they are the first primitive in a stacking context,
// see pop_stacking_context for a full explanation.
if !self.composite_ops.mix_blend_mode.is_none() &&
!parent.primitives.is_empty() {
!self.backdrop_picture.is_none()
{
return false;
}
@ -2774,29 +2797,24 @@ impl FlattenedStackingContext {
true
}
/// For a Preserve3D context, cut the sequence of the immediate flat children
/// Cut the sequence of the immediate children of a stacking context
/// recorded so far and generate a picture from them.
pub fn cut_flat_item_sequence(
fn cut_item_sequence(
&mut self,
prim_store: &mut PrimitiveStore,
interners: &mut Interners,
) -> Option<PrimitiveInstance> {
if !self.is_3d() || self.primitives.is_empty() {
composite_mode: PictureCompositeMode,
context_3d: Picture3DContext<OrderedPictureChild>,
) -> Option<(PictureIndex, PrimitiveInstance)> {
if self.primitives.is_empty() {
return None
}
let flat_items_context_3d = match self.context_3d {
Picture3DContext::In { ancestor_index, .. } => Picture3DContext::In {
root_data: None,
ancestor_index,
},
Picture3DContext::Out => panic!("Unexpected out of 3D context"),
};
let pic_index = PictureIndex(prim_store.pictures
.alloc()
.init(PicturePrimitive::new_image(
Some(PictureCompositeMode::Blit(BlitReason::PRESERVE3D)),
flat_items_context_3d,
Some(composite_mode),
context_3d,
self.pipeline_id,
None,
true,
@ -2821,7 +2839,7 @@ impl FlattenedStackingContext {
interners,
);
Some(prim_instance)
Some((pic_index, prim_instance))
}
}

Просмотреть файл

@ -1873,12 +1873,10 @@ bitflags! {
/// A set of flags describing why a picture may need a backing surface.
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct BlitReason: u32 {
/// Mix-blend-mode on a child that requires isolation.
const ISOLATE = 1;
/// Clip node that _might_ require a surface.
const CLIP = 2;
const CLIP = 1;
/// Preserve-3D requires a surface for plane-splitting.
const PRESERVE3D = 4;
const PRESERVE3D = 2;
}
}
@ -1888,8 +1886,20 @@ bitflags! {
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub enum PictureCompositeMode {
/// Don't composite this picture in a standard way,
/// can be used for pictures that need to be isolated but used
/// manually, e.g. for the backdrop of mix-blend pictures.
Puppet {
/// The master picture that actually handles compositing
/// of this one. If that picture turns out to be invisible,
/// the puppet mode becomes a regular blit.
master: Option<PictureIndex>,
},
/// Apply CSS mix-blend-mode effect.
MixBlend(MixBlendMode),
MixBlend {
mode: MixBlendMode,
backdrop: PictureIndex,
},
/// Apply a CSS filter (except component transfer).
Filter(FilterOp),
/// Apply a component transfer filter.
@ -3071,37 +3081,6 @@ impl PicturePrimitive {
PictureSurface::RenderTask(render_task_id)
}
PictureCompositeMode::MixBlend(..) => {
let uv_rect_kind = calculate_uv_rect_kind(
&pic_rect,
&transform,
&clipped,
device_pixel_scale,
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
child_tasks,
uv_rect_kind,
pic_context.raster_spatial_node_index,
device_pixel_scale,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
surfaces[surface_index.0].tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
surfaces[surface_index.0].tasks.push(render_task_id);
PictureSurface::RenderTask(render_task_id)
}
PictureCompositeMode::Filter(filter) => {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
@ -3161,11 +3140,13 @@ impl PicturePrimitive {
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
PictureSurface::RenderTask(render_task_id)
}
PictureCompositeMode::Puppet { .. } |
PictureCompositeMode::MixBlend { .. } |
PictureCompositeMode::Blit(_) => {
// The SplitComposite shader used for 3d contexts doesn't snap
// to pixels, so we shouldn't snap our uv coordinates either.
let supports_snapping = match self.context_3d {
Picture3DContext::In{ .. } => false,
Picture3DContext::In { .. } => false,
_ => true,
};

Просмотреть файл

@ -64,7 +64,7 @@ pub enum PictureCompositeKey {
impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
fn from(mode: Option<PictureCompositeMode>) -> Self {
match mode {
Some(PictureCompositeMode::MixBlend(mode)) => {
Some(PictureCompositeMode::MixBlend { mode, .. }) => {
match mode {
MixBlendMode::Normal => PictureCompositeKey::Identity,
MixBlendMode::Multiply => PictureCompositeKey::Multiply,
@ -123,6 +123,7 @@ impl From<Option<PictureCompositeMode>> for PictureCompositeKey {
Some(PictureCompositeMode::ComponentTransferFilter(handle)) => {
PictureCompositeKey::ComponentTransfer(handle.uid())
}
Some(PictureCompositeMode::Puppet { .. }) |
Some(PictureCompositeMode::Blit(_)) |
Some(PictureCompositeMode::TileCache { .. }) |
None => {

Просмотреть файл

@ -407,7 +407,6 @@ pub enum RenderTaskKind {
HorizontalBlur(BlurTask),
#[allow(dead_code)]
Glyph(GlyphTask),
Readback(DeviceIntRect),
Scaling(ScalingTask),
Blit(BlitTask),
Border(BorderTask),
@ -496,15 +495,6 @@ impl RenderTask {
}
}
pub fn new_readback(screen_rect: DeviceIntRect) -> Self {
RenderTask::with_dynamic_location(
screen_rect.size,
Vec::new(),
RenderTaskKind::Readback(screen_rect),
ClearMode::Transparent,
)
}
pub fn new_blit(
size: DeviceIntSize,
source: BlitSource,
@ -855,8 +845,7 @@ impl RenderTask {
fn uv_rect_kind(&self) -> UvRectKind {
match self.kind {
RenderTaskKind::CacheMask(..) |
RenderTaskKind::Readback(..) => {
RenderTaskKind::CacheMask(..) => {
unreachable!("bug: unexpected render task");
}
@ -929,7 +918,6 @@ impl RenderTask {
RenderTaskKind::Glyph(_) => {
[0.0, 1.0, 0.0]
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Border(..) |
RenderTaskKind::LineDecoration(..) |
@ -970,7 +958,6 @@ impl RenderTask {
gpu_cache.get_address(&info.uv_rect_handle)
}
RenderTaskKind::ClipRegion(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) |
RenderTaskKind::Border(..) |
@ -1023,8 +1010,6 @@ impl RenderTask {
pub fn target_kind(&self) -> RenderTargetKind {
match self.kind {
RenderTaskKind::Readback(..) => RenderTargetKind::Color,
RenderTaskKind::LineDecoration(..) => RenderTargetKind::Color,
RenderTaskKind::ClipRegion(..) |
@ -1077,7 +1062,6 @@ impl RenderTask {
RenderTaskKind::Picture(ref mut info) => {
(&mut info.uv_rect_handle, info.uv_rect_kind)
}
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) |
RenderTaskKind::Blit(..) |
RenderTaskKind::ClipRegion(..) |
@ -1128,10 +1112,6 @@ impl RenderTask {
pt.new_level("HorizontalBlur".to_owned());
task.print_with(pt);
}
RenderTaskKind::Readback(ref rect) => {
pt.new_level("Readback".to_owned());
pt.add_item(format!("rect: {:?}", rect));
}
RenderTaskKind::Scaling(ref kind) => {
pt.new_level("Scaling".to_owned());
pt.add_item(format!("kind: {:?}", kind));

Просмотреть файл

@ -82,7 +82,7 @@ use render_backend::{FrameId, RenderBackend};
use scene_builder::{SceneBuilder, LowPrioritySceneBuilder};
use shade::{Shaders, WrShaders};
use smallvec::SmallVec;
use render_task::{RenderTask, RenderTaskKind, RenderTaskTree};
use render_task::RenderTaskTree;
use resource_cache::ResourceCache;
use util::drain_filter;
@ -2339,11 +2339,6 @@ impl Renderer {
"Scalings",
target.scalings.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Readbacks",
target.readbacks.len(),
);
debug_target.add(
debug_server::BatchKind::Cache,
"Vertical Blur",
@ -3085,74 +3080,6 @@ impl Renderer {
self.profile_counters.vertices.add(6 * data.len());
}
fn handle_readback_composite(
&mut self,
draw_target: DrawTarget,
uses_scissor: bool,
source: &RenderTask,
backdrop: &RenderTask,
readback: &RenderTask,
) {
if uses_scissor {
self.device.disable_scissor();
}
let cache_texture = self.texture_resolver
.resolve(&TextureSource::PrevPassColor)
.unwrap();
// Before submitting the composite batch, do the
// framebuffer readbacks that are needed for each
// composite operation in this batch.
let (readback_rect, readback_layer) = readback.get_target_rect();
let (backdrop_rect, _) = backdrop.get_target_rect();
let backdrop_screen_origin = match backdrop.kind {
RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
_ => panic!("bug: composite on non-picture?"),
};
let source_screen_origin = match source.kind {
RenderTaskKind::Picture(ref task_info) => task_info.content_origin,
_ => panic!("bug: composite on non-picture?"),
};
// Bind the FBO to blit the backdrop to.
// Called per-instance in case the layer (and therefore FBO)
// changes. The device will skip the GL call if the requested
// target is already bound.
let cache_draw_target = DrawTarget::Texture {
texture: cache_texture,
layer: readback_layer.0 as usize,
with_depth: false,
};
self.device.bind_draw_target(cache_draw_target);
let mut src = DeviceIntRect::new(
source_screen_origin + (backdrop_rect.origin - backdrop_screen_origin),
readback_rect.size,
);
let mut dest = readback_rect.to_i32();
// Need to invert the y coordinates and flip the image vertically when
// reading back from the framebuffer.
if draw_target.is_default() {
src.origin.y = draw_target.dimensions().height as i32 - src.size.height - src.origin.y;
dest.origin.y += dest.size.height;
dest.size.height = -dest.size.height;
}
self.device.bind_read_target(draw_target.into());
self.device.blit_render_target(src, dest, TextureFilter::Linear);
// Restore draw target to current pass render target + layer, and reset
// the read target.
self.device.bind_draw_target(draw_target);
self.device.reset_read_target();
if uses_scissor {
self.device.enable_scissor();
}
}
//TODO: make this nicer. Currently we can't accept `&mut self` because the `DrawTarget` parameter
// needs to borrow self.texture_resolver
fn handle_blits(
@ -3484,20 +3411,6 @@ impl Renderer {
prev_blend_mode = batch.key.blend_mode;
}
// Handle special case readback for composites.
if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = batch.key.kind {
// composites can't be grouped together because
// they may overlap and affect each other.
debug_assert_eq!(batch.instances.len(), 1);
self.handle_readback_composite(
draw_target,
uses_scissor,
&render_tasks[source_id],
&render_tasks[task_id],
&render_tasks[backdrop_id],
);
}
let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
iterate_regions(

Просмотреть файл

@ -20,7 +20,7 @@ use internal_types::{CacheTextureId, FastHashMap, SavedTargetIndex, TextureSourc
#[cfg(feature = "pathfinder")]
use pathfinder_partitioner::mesh::Mesh;
use picture::{RecordedDirtyRegion, SurfaceInfo};
use prim_store::{PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer};
use prim_store::{PictureIndex, PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer};
use profiler::FrameProfileCounters;
use render_backend::{DataStores, FrameId};
use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
@ -62,6 +62,18 @@ pub struct RenderTargetContext<'a, 'rc> {
pub globals: &'a FrameGlobalResources,
}
impl<'a, 'rc> RenderTargetContext<'a, 'rc> {
/// Returns true if a picture has a surface that is visible.
pub fn is_picture_surface_visible(&self, index: PictureIndex) -> bool {
match self.prim_store.pictures[index.0].raster_config {
Some(ref raster_config) => {
self.surfaces[raster_config.surface_index.0].surface.is_some()
}
None => false,
}
}
}
/// Represents a number of rendering operations on a surface.
///
/// In graphics parlance, a "render target" usually means "a surface (texture or
@ -348,7 +360,6 @@ pub struct ColorRenderTarget {
// List of blur operations to apply for this render target.
pub vertical_blurs: Vec<BlurInstance>,
pub horizontal_blurs: Vec<BlurInstance>,
pub readbacks: Vec<DeviceIntRect>,
pub scalings: Vec<ScalingInstance>,
pub blits: Vec<BlitJob>,
// List of frame buffer outputs for this render target.
@ -370,7 +381,6 @@ impl RenderTarget for ColorRenderTarget {
alpha_batch_containers: Vec::new(),
vertical_blurs: Vec::new(),
horizontal_blurs: Vec::new(),
readbacks: Vec::new(),
scalings: Vec::new(),
blits: Vec::new(),
outputs: Vec::new(),
@ -502,9 +512,6 @@ impl RenderTarget for ColorRenderTarget {
// FIXME(pcwalton): Support color glyphs.
panic!("Glyphs should not be added to color target!");
}
RenderTaskKind::Readback(device_rect) => {
self.readbacks.push(device_rect);
}
RenderTaskKind::Scaling(..) => {
self.scalings.push(ScalingInstance {
task_address: render_tasks.get_task_address(task_id),
@ -637,7 +644,6 @@ impl RenderTarget for AlphaRenderTarget {
}
match task.kind {
RenderTaskKind::Readback(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::Blit(..) |
RenderTaskKind::Border(..) |
@ -819,7 +825,6 @@ impl TextureCacheRenderTarget {
RenderTaskKind::Picture(..) |
RenderTaskKind::ClipRegion(..) |
RenderTaskKind::CacheMask(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) => {
panic!("BUG: unexpected task kind for texture cache target");
}

Просмотреть файл

@ -1,13 +1,14 @@
# test that we handle the backdrop size to be smaller than the source
---
root:
items:
- type: rect
bounds: [0, 0, 100, 100]
color: [0, 255, 0]
bounds: [25, 25, 50, 50]
color: green
- type: stacking-context
bounds: [0, 0, 100, 100]
mix-blend-mode: multiply
items:
- type: rect
bounds: [0, 0, 100, 100]
color: [255, 128, 0]
color: green

Просмотреть файл

@ -8,10 +8,6 @@ root:
bounds: [0, 0, 100, 100]
mix-blend-mode: multiply
items:
- type: stacking-context
- type: rect
bounds: [0, 0, 100, 100]
mix-blend-mode: multiply
items:
- type: rect
bounds: [0, 0, 100, 100]
color: [255, 128, 0]
color: [255, 128, 0]

Просмотреть файл

@ -0,0 +1,17 @@
---
root:
items:
- type: rect
bounds: [0, 0, 100, 100]
color: [0, 255, 0]
- type: stacking-context
bounds: [0, 0, 100, 100]
mix-blend-mode: multiply
items:
- type: stacking-context
bounds: [0, 0, 100, 100]
mix-blend-mode: multiply
items:
- type: rect
bounds: [0, 0, 100, 100]
color: [255, 128, 0]

Просмотреть файл

@ -1,6 +1,7 @@
== multiply.yaml multiply-ref.yaml
== multiply-2.yaml multiply-2-ref.yaml
== color_targets(3) alpha_targets(0) multiply-3.yaml multiply-2-ref.yaml
== multiply-2.yaml multiply-ref.yaml
== multiply-3.yaml multiply-3-ref.yaml
== color_targets(2) alpha_targets(0) multiply-4.yaml multiply-3-ref.yaml
== difference.yaml difference-ref.yaml
fuzzy(1,10000) == difference-transparent.yaml difference-transparent-ref.yaml
== darken.yaml darken-ref.yaml
@ -22,3 +23,4 @@ fuzzy(1,2502) == transparent-composite-1.yaml transparent-composite-1-ref.yaml
fuzzy(1,2502) == transparent-composite-2.yaml transparent-composite-2-ref.yaml
== multi-mix-blend-mode.yaml multi-mix-blend-mode-ref.yaml
fuzzy(50,8) == transform-source.yaml transform-source-ref.yaml

Просмотреть файл

@ -0,0 +1,13 @@
---
root:
items:
- type: stacking-context
bounds: [0, 0, 0, 0]
transform: rotate-z(60)
items:
- type: rect
bounds: [25, -100, 150, 150]
color: blue
- type: rect
bounds: [25, 25, 100, 100]
color: black

Просмотреть файл

@ -0,0 +1,15 @@
# test that we handle the source stacking context being transformed
---
root:
items:
- type: rect
bounds: [25, 25, 100, 100]
color: green
- type: stacking-context
bounds: [0, 0, 0, 0]
mix-blend-mode: multiply
transform: rotate-z(60)
items:
- type: rect
bounds: [25, -100, 150, 150]
color: blue

Просмотреть файл

@ -549,9 +549,10 @@ fn render<'a>(
subargs: &clap::ArgMatches<'a>,
) {
let input_path = subargs.value_of("INPUT").map(PathBuf::from).unwrap();
let mut show_stats = false;
// If the input is a directory, we are looking at a capture.
let mut thing = if input_path.as_path().is_dir() {
let mut thing = if input_path.is_dir() {
let mut documents = wrench.api.load_capture(input_path);
println!("loaded {:?}", documents.iter().map(|cd| cd.document_id).collect::<Vec<_>>());
let captured = documents.swap_remove(0);
@ -566,6 +567,7 @@ fn render<'a>(
.expect("Tried to render with an unknown file type.")
.to_str()
.expect("Tried to render with an unknown file type.");
show_stats = true; // show when invoked on single files
match extension {
"yaml" => Box::new(YamlFrameReader::new_from_args(subargs)) as Box<WrenchThing>,
@ -772,9 +774,14 @@ fn render<'a>(
wrench.show_onscreen_help();
}
wrench.render();
let results = wrench.render();
window.swap_buffers();
if show_stats {
show_stats = false;
println!("{:#?}", results.stats);
}
if do_loop {
thing.next_frame();
}

Просмотреть файл

@ -1,11 +1,11 @@
== blend-canvas.html blend-canvas-ref.html
== blend-constant-background-color.html blend-constant-background-color-ref.html
fuzzy-if(webrender,1-3,1313-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
fuzzy-if(webrender,1-3,1291-7888) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
== blend-image.html blend-image-ref.html
== blend-difference-stacking.html blend-difference-stacking-ref.html
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-10000) fuzzy-if(skiaContent,0-1,0-30000) == background-blending-alpha.html background-blending-alpha-ref.html
fuzzy-if(webrender,1-3,1313-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
fuzzy-if(webrender,1-3,1291-7888) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
fuzzy-if(azureSkiaGL,0-3,0-7597) fuzzy-if(cocoaWidget,0-3,0-7597) fuzzy-if(d2d,0-1,0-3800) fuzzy-if(d3d11,0-1,0-4200) fuzzy-if(skiaContent,0-2,0-9450) fuzzy-if(webrender,1-5,3938-23925) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html
fuzzy-if(azureSkiaGL,0-2,0-7174) fuzzy-if(webrender,1-3,1288-7888) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
fuzzy-if(azureSkia||d2d||gtkWidget,0-1,0-10000) == background-blending-image-color-jpg.html background-blending-image-color-ref.html