diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 21d9d5e86f..296f78a2b9 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1294,7 +1294,8 @@ impl AlphaBatchBuilder { for (segment_index, (segment, segment_data)) in segment_desc.segments .iter() .zip(segment_data.iter()) - .enumerate() { + .enumerate() + { self.add_segment_to_batch( segment, segment_data, @@ -1315,7 +1316,8 @@ impl AlphaBatchBuilder { // between all segments. for (segment_index, segment) in segment_desc.segments .iter() - .enumerate() { + .enumerate() + { self.add_segment_to_batch( segment, segment_data, @@ -1333,6 +1335,7 @@ impl AlphaBatchBuilder { } (None, SegmentDataKind::Shared(ref segment_data)) => { // No segments, and thus no per-segment instance data. + // Note: the blend mode already takes opacity into account let batch_key = BatchKey { blend_mode: non_segmented_blend_mode, kind: BatchKind::Brush(params.batch_kind), diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index d55a01f10e..ddad312e2e 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -1907,7 +1907,8 @@ impl PrimitiveStore { prim_instance.clipped_world_rect = Some(pic_state.map_pic_to_world.bounds); } else { if prim.local_rect.size.width <= 0.0 || - prim.local_rect.size.height <= 0.0 { + prim.local_rect.size.height <= 0.0 + { if cfg!(debug_assertions) && is_chased { println!("\tculled for zero local rectangle"); } @@ -1954,6 +1955,9 @@ impl PrimitiveStore { let clip_chain = match clip_chain { Some(clip_chain) => clip_chain, None => { + if cfg!(debug_assertions) && is_chased { + println!("\tunable to build the clip chain, skipping"); + } prim_instance.clipped_world_rect = None; return false; } @@ -2060,8 +2064,8 @@ impl PrimitiveStore { let prim_index = prim_instance.prim_index; let is_chased = Some(prim_index) == self.chase_id; - if is_chased { - println!("\tpreparing prim {:?} in pipeline {:?}", + if cfg!(debug_assertions) && is_chased { + println!("\tpreparing {:?} in {:?}", prim_instance.prim_index, pic_context.pipeline_id); } @@ -2554,7 +2558,7 @@ impl PrimitiveInstance { self.prepared_frame_id = frame_state.render_tasks.frame_id(); } - match *prim_details { + self.opacity = match *prim_details { PrimitiveDetails::TextRun(ref mut text) => { // The transform only makes sense for screen space rasterization let transform = prim_context.spatial_node.world_content_transform.to_transform(); @@ -2566,6 +2570,7 @@ impl PrimitiveInstance { display_list, frame_state, ); + PrimitiveOpacity::translucent() } PrimitiveDetails::Brush(ref mut brush) => { match brush.kind { @@ -2595,13 +2600,6 @@ impl PrimitiveInstance { frame_state.gpu_cache.invalidate(&mut self.gpu_location); } - // Update opacity for this primitive to ensure the correct - // batching parameters are used. - self.opacity.is_opaque = - image_properties.descriptor.is_opaque && - opacity_binding.current == 1.0 && - color.a == 1.0; - if *tile_spacing != LayoutSize::zero() && !is_tiled { *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. @@ -2623,6 +2621,7 @@ impl PrimitiveInstance { } let mut request_source_image = false; + let mut is_opaque = image_properties.descriptor.is_opaque; // Every frame, for cached items, we need to request the render // task cache item. The closure will be invoked on the first @@ -2641,9 +2640,7 @@ impl PrimitiveInstance { size.width += padding.horizontal(); size.height += padding.vertical(); - if padding != DeviceIntSideOffsets::zero() { - self.opacity.is_opaque = false; - } + is_opaque &= padding == DeviceIntSideOffsets::zero(); let image_cache_key = ImageCacheKey { request, @@ -2782,11 +2779,18 @@ impl PrimitiveInstance { frame_state.gpu_cache, ); } + + if is_opaque { + PrimitiveOpacity::from_alpha(opacity_binding.current * color.a) + } else { + PrimitiveOpacity::translucent() + } + } else { + PrimitiveOpacity::opaque() } } - BrushKind::LineDecoration { ref mut handle, style, orientation, wavy_line_thickness, .. } => { + BrushKind::LineDecoration { color, ref mut handle, style, orientation, wavy_line_thickness } => { // Work out the device pixel size to be used to cache this line decoration. - let size = get_line_decoration_sizes( &prim_local_rect.size, orientation, @@ -2794,6 +2798,10 @@ impl PrimitiveInstance { wavy_line_thickness, ); + if cfg!(debug_assertions) && is_chased { + println!("\tline decoration opaque={}, sizes={:?}", self.opacity.is_opaque, size); + } + if let Some((inline_size, block_size)) = size { let size = match orientation { LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size), @@ -2862,10 +2870,15 @@ impl PrimitiveInstance { } )); } + + match style { + LineStyle::Solid => PrimitiveOpacity::from_alpha(color.a), + LineStyle::Dotted | + LineStyle::Dashed | + LineStyle::Wavy => PrimitiveOpacity::translucent(), + } } BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => { - self.opacity = PrimitiveOpacity::opaque(); - let channel_num = format.get_plane_num(); debug_assert!(channel_num <= 3); for channel in 0 .. channel_num { @@ -2878,6 +2891,8 @@ impl PrimitiveInstance { frame_state.gpu_cache, ); } + + PrimitiveOpacity::opaque() } BrushKind::Border { ref mut source, .. } => { match *source { @@ -2887,15 +2902,15 @@ impl PrimitiveInstance { .get_image_properties(request.key); if let Some(image_properties) = image_properties { - // Update opacity for this primitive to ensure the correct - // batching parameters are used. - self.opacity.is_opaque = - image_properties.descriptor.is_opaque; - frame_state.resource_cache.request_image( request, frame_state.gpu_cache, ); + PrimitiveOpacity { + is_opaque: image_properties.descriptor.is_opaque, + } + } else { + PrimitiveOpacity::opaque() } } BorderSource::Border { ref border, ref widths, ref mut segments, .. } => { @@ -2938,6 +2953,9 @@ impl PrimitiveInstance { } )); } + + // Shouldn't matter, since the segment opacity is used instead + PrimitiveOpacity::translucent() } } } @@ -2990,6 +3008,9 @@ impl PrimitiveInstance { }, ); } + + //TODO: can we make it opaque in some cases? + PrimitiveOpacity::translucent() } BrushKind::LinearGradient { stops_range, @@ -3004,19 +3025,6 @@ impl PrimitiveInstance { ref mut visible_tiles, .. } => { - // If the coverage of the gradient extends to or beyond - // the primitive rect, then the opacity can be determined - // by the colors of the stops. If we have tiling / spacing - // then we just assume the gradient is translucent for now. - // (In the future we could consider segmenting in some cases). - let stride = stretch_size + tile_spacing; - self.opacity = if stride.width >= prim_local_rect.size.width && - stride.height >= prim_local_rect.size.height { - stops_opacity - } else { - PrimitiveOpacity::translucent() - }; - build_gradient_stops_request( stops_handle, stops_range, @@ -3053,6 +3061,19 @@ impl PrimitiveInstance { } ); } + + // If the coverage of the gradient extends to or beyond + // the primitive rect, then the opacity can be determined + // by the colors of the stops. If we have tiling / spacing + // then we just assume the gradient is translucent for now. + // (In the future we could consider segmenting in some cases). + let stride = stretch_size + tile_spacing; + if stride.width >= prim_local_rect.size.width && + stride.height >= prim_local_rect.size.height { + stops_opacity + } else { + PrimitiveOpacity::translucent() + } } BrushKind::Picture { pic_index, .. } => { let pic = &mut pictures[pic_index.0]; @@ -3076,6 +3097,8 @@ impl PrimitiveInstance { } else { self.clipped_world_rect = None; } + + PrimitiveOpacity::translucent() } BrushKind::Solid { ref color, ref mut opacity_binding, .. } => { // If the opacity changed, invalidate the GPU cache so that @@ -3085,12 +3108,12 @@ impl PrimitiveInstance { if opacity_binding.update(frame_context.scene_properties) { frame_state.gpu_cache.invalidate(&mut self.gpu_location); } - self.opacity = PrimitiveOpacity::from_alpha(opacity_binding.current * color.a); + PrimitiveOpacity::from_alpha(opacity_binding.current * color.a) } - BrushKind::Clear => {} + BrushKind::Clear => PrimitiveOpacity::opaque(), } } - } + }; if is_tiled { // we already requested each tile's gpu data. diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index f514c4dc61..6903580cc8 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -52,7 +52,7 @@ fn render_task_sanity_check(size: &DeviceIntSize) { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskId(pub u32, FrameId); // TODO(gw): Make private when using GPU cache! -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq)] #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))]