diff --git a/webrender/examples/common/boilerplate.rs b/webrender/examples/common/boilerplate.rs index 732b5ab88d..5894fdec1e 100644 --- a/webrender/examples/common/boilerplate.rs +++ b/webrender/examples/common/boilerplate.rs @@ -223,13 +223,6 @@ pub fn main_wrapper( ) => { renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG); } - glutin::Event::KeyboardInput( - glutin::ElementState::Pressed, - _, - Some(glutin::VirtualKeyCode::B), - ) => { - renderer.toggle_debug_flags(webrender::DebugFlags::ALPHA_PRIM_DBG); - } glutin::Event::KeyboardInput( glutin::ElementState::Pressed, _, diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 80e7eae7d4..b8478f217e 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -4,7 +4,7 @@ use api::{AlphaType, DeviceIntRect, DeviceIntSize, LayerToWorldScale}; use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, FilterOp, ImageRendering, LayerRect}; -use api::{SubpixelDirection, YuvColorSpace, YuvFormat}; +use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat}; use api::{LayerToWorldTransform, WorldPixel}; use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind}; use clip::{ClipSource, ClipStore}; @@ -13,16 +13,16 @@ use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; use gpu_cache::{GpuCache, GpuCacheAddress}; use gpu_types::{BrushImageKind, BrushInstance, ClipChainRectIndex}; -use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, PictureType}; +use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex}; use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance}; use internal_types::{FastHashMap, SourceTexture}; -use picture::{PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; +use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; use plane_split::{BspSplitter, Polygon, Splitter}; use prim_store::{ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun}; use render_task::{ClipWorkItem}; -use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind}; -use render_task::{RenderTaskTree}; +use render_task::{RenderTaskAddress, RenderTaskId}; +use render_task::{RenderTaskKind, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind}; use renderer::BLOCKS_PER_UV_RECT; use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache}; @@ -124,42 +124,6 @@ impl BatchTextures { } } -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct AlphaPrimitiveBatch { - pub key: BatchKey, - pub instances: Vec, - pub item_rects: Vec, -} - -impl AlphaPrimitiveBatch { - pub fn new(key: BatchKey) -> AlphaPrimitiveBatch { - AlphaPrimitiveBatch { - key, - instances: Vec::new(), - item_rects: Vec::new(), - } - } -} - -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct OpaquePrimitiveBatch { - pub key: BatchKey, - pub instances: Vec, -} - -impl OpaquePrimitiveBatch { - pub fn new(key: BatchKey) -> OpaquePrimitiveBatch { - OpaquePrimitiveBatch { - key, - instances: Vec::new(), - } - } -} - #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -191,23 +155,23 @@ fn textures_compatible(t1: SourceTexture, t2: SourceTexture) -> bool { t1 == SourceTexture::Invalid || t2 == SourceTexture::Invalid || t1 == t2 } -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] pub struct AlphaBatchList { - pub batches: Vec, + pub batches: Vec, + pub item_rects: Vec>, } impl AlphaBatchList { fn new() -> Self { AlphaBatchList { batches: Vec::new(), + item_rects: Vec::new(), } } pub fn get_suitable_batch( &mut self, key: BatchKey, - item_bounding_rect: &DeviceIntRect, + task_relative_bounding_rect: &DeviceIntRect, ) -> &mut Vec { let mut selected_batch_index = None; @@ -224,8 +188,8 @@ impl AlphaBatchList { // Subpixel text is drawn in two passes. Because of this, we need // to check for overlaps with every batch (which is a bit different // than the normal batching below). - for item_rect in &batch.item_rects { - if item_rect.intersects(item_bounding_rect) { + for item_rect in &self.item_rects[batch_index] { + if item_rect.intersects(task_relative_bounding_rect) { break 'outer_text; } } @@ -248,8 +212,8 @@ impl AlphaBatchList { } // check for intersections - for item_rect in &batch.item_rects { - if item_rect.intersects(item_bounding_rect) { + for item_rect in &self.item_rects[batch_index] { + if item_rect.intersects(task_relative_bounding_rect) { break 'outer_default; } } @@ -258,27 +222,25 @@ impl AlphaBatchList { } if selected_batch_index.is_none() { - let new_batch = AlphaPrimitiveBatch::new(key); + let new_batch = PrimitiveBatch::new(key); selected_batch_index = Some(self.batches.len()); self.batches.push(new_batch); + self.item_rects.push(Vec::new()); } - let batch = &mut self.batches[selected_batch_index.unwrap()]; - batch.item_rects.push(*item_bounding_rect); - - &mut batch.instances + let selected_batch_index = selected_batch_index.unwrap(); + self.item_rects[selected_batch_index].push(*task_relative_bounding_rect); + &mut self.batches[selected_batch_index].instances } } -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] pub struct OpaqueBatchList { - pub pixel_area_threshold_for_new_batch: i32, - pub batches: Vec, + pub pixel_area_threshold_for_new_batch: f32, + pub batches: Vec, } impl OpaqueBatchList { - fn new(pixel_area_threshold_for_new_batch: i32) -> Self { + fn new(pixel_area_threshold_for_new_batch: f32) -> Self { OpaqueBatchList { batches: Vec::new(), pixel_area_threshold_for_new_batch, @@ -288,10 +250,10 @@ impl OpaqueBatchList { pub fn get_suitable_batch( &mut self, key: BatchKey, - item_bounding_rect: &DeviceIntRect + task_relative_bounding_rect: &DeviceIntRect ) -> &mut Vec { let mut selected_batch_index = None; - let item_area = item_bounding_rect.size.area(); + let item_area = task_relative_bounding_rect.size.to_f32().area(); // If the area of this primitive is larger than the given threshold, // then it is large enough to warrant breaking a batch for. In this @@ -314,7 +276,7 @@ impl OpaqueBatchList { } if selected_batch_index.is_none() { - let new_batch = OpaquePrimitiveBatch::new(key); + let new_batch = PrimitiveBatch::new(key); selected_batch_index = Some(self.batches.len()); self.batches.push(new_batch); } @@ -337,34 +299,36 @@ impl OpaqueBatchList { } } -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BatchList { pub alpha_batch_list: AlphaBatchList, pub opaque_batch_list: OpaqueBatchList, + pub combined_bounding_rect: DeviceIntRect, } impl BatchList { pub fn new(screen_size: DeviceIntSize) -> Self { // The threshold for creating a new batch is // one quarter the screen size. - let batch_area_threshold = screen_size.width * screen_size.height / 4; + let batch_area_threshold = (screen_size.width * screen_size.height) as f32 / 4.0; BatchList { alpha_batch_list: AlphaBatchList::new(), opaque_batch_list: OpaqueBatchList::new(batch_area_threshold), + combined_bounding_rect: DeviceIntRect::zero(), } } pub fn get_suitable_batch( &mut self, key: BatchKey, - item_bounding_rect: &DeviceIntRect, + task_relative_bounding_rect: &DeviceIntRect, ) -> &mut Vec { + self.combined_bounding_rect = self.combined_bounding_rect.union(task_relative_bounding_rect); + match key.blend_mode { BlendMode::None => { self.opaque_batch_list - .get_suitable_batch(key, item_bounding_rect) + .get_suitable_batch(key, task_relative_bounding_rect) } BlendMode::Alpha | BlendMode::PremultipliedAlpha | @@ -374,7 +338,7 @@ impl BatchList { BlendMode::SubpixelWithBgColor | BlendMode::SubpixelDualSource => { self.alpha_batch_list - .get_suitable_batch(key, item_bounding_rect) + .get_suitable_batch(key, task_relative_bounding_rect) } } } @@ -384,61 +348,126 @@ impl BatchList { } } -/// Encapsulates the logic of building batches for items that are blended. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct AlphaBatcher { - pub batch_list: BatchList, +pub struct PrimitiveBatch { + pub key: BatchKey, + pub instances: Vec, +} + +impl PrimitiveBatch { + fn new(key: BatchKey) -> PrimitiveBatch { + PrimitiveBatch { + key, + instances: Vec::new(), + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct AlphaBatchContainer { pub text_run_cache_prims: FastHashMap>, - glyph_fetch_buffer: Vec, + pub opaque_batches: Vec, + pub alpha_batches: Vec, + pub target_rect: Option, } -impl AlphaBatcher { - pub fn new(screen_size: DeviceIntSize) -> Self { - AlphaBatcher { - batch_list: BatchList::new(screen_size), - glyph_fetch_buffer: Vec::new(), +impl AlphaBatchContainer { + pub fn new(target_rect: Option) -> AlphaBatchContainer { + AlphaBatchContainer { text_run_cache_prims: FastHashMap::default(), + opaque_batches: Vec::new(), + alpha_batches: Vec::new(), + target_rect, } } - pub fn build( - &mut self, - tasks: &[RenderTaskId], - ctx: &RenderTargetContext, - gpu_cache: &mut GpuCache, - render_tasks: &RenderTaskTree, - deferred_resolves: &mut Vec, - ) { - for &task_id in tasks { - match render_tasks[task_id].kind { - RenderTaskKind::Picture(ref pic_task) => { - let pic_index = ctx.prim_store.cpu_metadata[pic_task.prim_index.0].cpu_prim_index; - let pic = &ctx.prim_store.cpu_pictures[pic_index.0]; - self.add_pic_to_batch( - pic, - task_id, - ctx, - gpu_cache, - render_tasks, - deferred_resolves, - ); + fn merge(&mut self, builder: AlphaBatchBuilder) { + self.text_run_cache_prims.extend(builder.text_run_cache_prims); + + for other_batch in builder.batch_list.opaque_batch_list.batches { + let batch_index = self.opaque_batches.iter().position(|batch| { + batch.key.is_compatible_with(&other_batch.key) + }); + + match batch_index { + Some(batch_index) => { + self.opaque_batches[batch_index].instances.extend(other_batch.instances); } - _ => { - unreachable!(); + None => { + self.opaque_batches.push(other_batch); } } } - self.batch_list.finalize(); + let mut min_batch_index = 0; + + for other_batch in builder.batch_list.alpha_batch_list.batches { + let batch_index = self.alpha_batches.iter().skip(min_batch_index).position(|batch| { + batch.key.is_compatible_with(&other_batch.key) + }); + + match batch_index { + Some(batch_index) => { + let batch_index = batch_index + min_batch_index; + self.alpha_batches[batch_index].instances.extend(other_batch.instances); + min_batch_index = batch_index; + } + None => { + self.alpha_batches.push(other_batch); + min_batch_index = self.alpha_batches.len(); + } + } + } } +} + +/// Encapsulates the logic of building batches for items that are blended. +pub struct AlphaBatchBuilder { + pub batch_list: BatchList, + pub text_run_cache_prims: FastHashMap>, + glyph_fetch_buffer: Vec, + target_rect: DeviceIntRect, +} - pub fn is_empty(&self) -> bool { - self.batch_list.opaque_batch_list.batches.is_empty() && - self.batch_list.alpha_batch_list.batches.is_empty() +impl AlphaBatchBuilder { + pub fn new( + screen_size: DeviceIntSize, + target_rect: DeviceIntRect, + ) -> Self { + AlphaBatchBuilder { + batch_list: BatchList::new(screen_size), + glyph_fetch_buffer: Vec::new(), + text_run_cache_prims: FastHashMap::default(), + target_rect, + } + } + + pub fn build(mut self, merged_batches: &mut AlphaBatchContainer) -> Option { + self.batch_list.finalize(); + + let task_relative_target_rect = DeviceIntRect::new( + DeviceIntPoint::zero(), + self.target_rect.size, + ); + + let can_merge = task_relative_target_rect.contains_rect(&self.batch_list.combined_bounding_rect); + + if can_merge { + merged_batches.merge(self); + None + } else { + Some(AlphaBatchContainer { + alpha_batches: self.batch_list.alpha_batch_list.batches, + opaque_batches: self.batch_list.opaque_batch_list.batches, + target_rect: Some(self.target_rect), + text_run_cache_prims: self.text_run_cache_prims, + }) + } } - fn add_pic_to_batch( + pub fn add_pic_to_batch( &mut self, pic: &PicturePrimitive, task_id: RenderTaskId, @@ -449,6 +478,16 @@ impl AlphaBatcher { ) { let task_address = render_tasks.get_task_address(task_id); + let task = &render_tasks[task_id]; + let content_origin = match task.kind { + RenderTaskKind::Picture(ref pic_task) => { + pic_task.content_origin + } + _ => { + panic!("todo: tidy this up"); + } + }; + // Even though most of the time a splitter isn't used or needed, // they are cheap to construct so we will always pass one down. let mut splitter = BspSplitter::new(); @@ -467,7 +506,8 @@ impl AlphaBatcher { task_address, deferred_resolves, &mut splitter, - pic.picture_type(), + pic, + content_origin, ); } @@ -490,7 +530,7 @@ impl AlphaBatcher { ); let pic_metadata = &ctx.prim_store.cpu_metadata[prim_index.0]; let pic = &ctx.prim_store.cpu_pictures[pic_metadata.cpu_prim_index.0]; - let batch = self.batch_list.get_suitable_batch(key, pic_metadata.screen_rect.as_ref().expect("bug")); + let batch = self.batch_list.get_suitable_batch(key, &pic_metadata.screen_rect.as_ref().expect("bug").clipped); let render_task_id = match pic.surface { Some(PictureSurface::RenderTask(render_task_id)) => render_task_id, @@ -528,7 +568,8 @@ impl AlphaBatcher { task_address: RenderTaskAddress, deferred_resolves: &mut Vec, splitter: &mut BspSplitter, - pic_type: PictureType, + pic: &PicturePrimitive, + content_origin: ContentOrigin, ) { for i in 0 .. run.count { let prim_index = PrimitiveIndex(run.base_prim_index.0 + i); @@ -541,7 +582,12 @@ impl AlphaBatcher { // We currently only support culling on normal (Image) // picture types. // TODO(gw): Support culling on shadow image types. - if pic_type != PictureType::Image || metadata.screen_rect.is_some() { + let is_image = match pic.kind { + PictureKind::Image { .. } => true, + PictureKind::BoxShadow { .. } | PictureKind::TextShadow { .. } => false, + }; + + if !is_image || metadata.screen_rect.is_some() { self.add_prim_to_batch( metadata.clip_chain_rect_index, scroll_id, @@ -553,7 +599,8 @@ impl AlphaBatcher { task_address, deferred_resolves, splitter, - pic_type, + content_origin, + pic, ); } } @@ -593,7 +640,8 @@ impl AlphaBatcher { task_address: RenderTaskAddress, deferred_resolves: &mut Vec, splitter: &mut BspSplitter, - pic_type: PictureType, + content_origin: ContentOrigin, + pic: &PicturePrimitive, ) { let z = prim_index.0 as i32; let prim_metadata = ctx.prim_store.get_metadata(prim_index); @@ -602,13 +650,32 @@ impl AlphaBatcher { // wasteful. We should probably cache this in // the scroll node... let transform_kind = scroll_node.transform.transform_kind(); - let item_bounding_rect = &match prim_metadata.screen_rect { - Some(screen_rect) => screen_rect, - None => { - debug_assert_ne!(pic_type, PictureType::Image); - DeviceIntRect::zero() + + let task_relative_bounding_rect = match content_origin { + ContentOrigin::Screen(point) => { + // translate by content-origin + let screen_rect = prim_metadata.screen_rect.expect("bug"); + DeviceIntRect::new( + DeviceIntPoint::new( + screen_rect.unclipped.origin.x - point.x, + screen_rect.unclipped.origin.y - point.y, + ), + screen_rect.unclipped.size, + ) + } + ContentOrigin::Local(point) => { + // scale local rect by device pixel ratio + let content_rect = LayerRect::new( + LayerPoint::new( + prim_metadata.local_rect.origin.x - point.x, + prim_metadata.local_rect.origin.y - point.y, + ), + prim_metadata.local_rect.size, + ); + (content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round().to_i32() } }; + let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location); let no_textures = BatchTextures::no_texture(); let clip_task_address = prim_metadata @@ -636,7 +703,7 @@ impl AlphaBatcher { batch_key, clip_chain_rect_index, clip_task_address, - item_bounding_rect, + &task_relative_bounding_rect, prim_cache_address, scroll_id, task_address, @@ -665,7 +732,7 @@ impl AlphaBatcher { // Work around borrow ck on borrowing batch_list twice. { let batch = - self.batch_list.get_suitable_batch(corner_key, item_bounding_rect); + self.batch_list.get_suitable_batch(corner_key, &task_relative_bounding_rect); for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() { let sub_index = i as i32; @@ -694,7 +761,7 @@ impl AlphaBatcher { } } - let batch = self.batch_list.get_suitable_batch(edge_key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(edge_key, &task_relative_bounding_rect); for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() { match *instance_kind { BorderEdgeKind::None => {}, @@ -723,7 +790,7 @@ impl AlphaBatcher { if cache_item.texture_id == SourceTexture::Invalid { warn!("Warnings: skip a PrimitiveKind::Image"); - debug!("at {:?}.", item_bounding_rect); + debug!("at {:?}.", task_relative_bounding_rect); return; } @@ -739,13 +806,16 @@ impl AlphaBatcher { ], }, ); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build(cache_item.uv_rect_handle.as_int(gpu_cache), 0, 0)); } PrimitiveKind::TextRun => { let text_cpu = &ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0]; - let is_shadow = pic_type == PictureType::TextShadow; + let is_shadow = match pic.kind { + PictureKind::TextShadow { .. } => true, + PictureKind::BoxShadow { .. } | PictureKind::Image { .. } => false, + }; // TODO(gw): It probably makes sense to base this decision on the content // origin field in the future (once that's configurable). @@ -819,7 +889,7 @@ impl AlphaBatcher { }; let key = BatchKey::new(kind, blend_mode, textures); - batch_list.get_suitable_batch(key, item_bounding_rect) + batch_list.get_suitable_batch(key, &task_relative_bounding_rect) }; for glyph in glyphs { @@ -861,7 +931,7 @@ impl AlphaBatcher { alpha_batch_key, clip_chain_rect_index, clip_task_address, - item_bounding_rect, + &task_relative_bounding_rect, prim_cache_address, scroll_id, task_address, @@ -885,7 +955,7 @@ impl AlphaBatcher { BrushImageSourceKind::from_render_target_kind(picture.target_kind())), ); let key = BatchKey::new(kind, blend_mode, textures); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let instance = BrushInstance { picture_address: task_address, @@ -949,7 +1019,8 @@ impl AlphaBatcher { BlendMode::PremultipliedAlpha, BatchTextures::render_target_cache(), ); - let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); + let item_bounding_rect = prim_metadata.screen_rect.expect("bug!!").clipped; let instance = CompositePrimitiveInstance::new( task_address, src_task_address, @@ -983,7 +1054,7 @@ impl AlphaBatcher { }; { - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(PrimitiveInstance::from(instance)); } @@ -1003,7 +1074,7 @@ impl AlphaBatcher { BlendMode::PremultipliedAlpha, secondary_textures, ); - let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect); + 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() @@ -1045,7 +1116,7 @@ impl AlphaBatcher { }; let amount = (amount * 65535.0).round() as i32; - let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let instance = CompositePrimitiveInstance::new( task_address, @@ -1074,7 +1145,7 @@ impl AlphaBatcher { BlendMode::PremultipliedAlpha, BatchTextures::no_texture(), ); - let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect); + 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); @@ -1098,7 +1169,8 @@ impl AlphaBatcher { BlendMode::PremultipliedAlpha, BatchTextures::render_target_cache(), ); - let batch = self.batch_list.get_suitable_batch(key, &item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); + let item_bounding_rect = prim_metadata.screen_rect.expect("bug!!").clipped; let instance = CompositePrimitiveInstance::new( task_address, src_task_address, @@ -1138,7 +1210,7 @@ impl AlphaBatcher { TransformBatchKind::AlignedGradient, ); let key = BatchKey::new(kind, blend_mode, no_textures); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); for part_index in 0 .. (gradient_cpu.stops_count - 1) { batch.push(base_instance.build(part_index as i32, 0, 0)); } @@ -1149,7 +1221,7 @@ impl AlphaBatcher { TransformBatchKind::AngleGradient, ); let key = BatchKey::new(kind, blend_mode, no_textures); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build(0, 0, 0)); } PrimitiveKind::RadialGradient => { @@ -1158,7 +1230,7 @@ impl AlphaBatcher { TransformBatchKind::RadialGradient, ); let key = BatchKey::new(kind, blend_mode, no_textures); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build(0, 0, 0)); } PrimitiveKind::YuvImage => { @@ -1186,7 +1258,7 @@ impl AlphaBatcher { if cache_item.texture_id == SourceTexture::Invalid { warn!("Warnings: skip a PrimitiveKind::YuvImage"); - debug!("at {:?}.", item_bounding_rect); + debug!("at {:?}.", task_relative_bounding_rect); return; } @@ -1211,7 +1283,7 @@ impl AlphaBatcher { ), ); let key = BatchKey::new(kind, blend_mode, textures); - let batch = self.batch_list.get_suitable_batch(key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build( uv_rect_addresses[0], @@ -1229,7 +1301,7 @@ impl AlphaBatcher { batch_key: BatchKey, clip_chain_rect_index: ClipChainRectIndex, clip_task_address: RenderTaskAddress, - item_bounding_rect: &DeviceIntRect, + task_relative_bounding_rect: &DeviceIntRect, prim_cache_address: GpuCacheAddress, scroll_id: ClipScrollNodeIndex, task_address: RenderTaskAddress, @@ -1261,7 +1333,7 @@ impl AlphaBatcher { let alpha_batch = self.batch_list.alpha_batch_list.get_suitable_batch( alpha_batch_key, - item_bounding_rect + task_relative_bounding_rect ); let opaque_batch_key = BatchKey { @@ -1271,7 +1343,7 @@ impl AlphaBatcher { let opaque_batch = self.batch_list.opaque_batch_list.get_suitable_batch( opaque_batch_key, - item_bounding_rect + task_relative_bounding_rect ); for (i, segment) in segment_desc.segments.iter().enumerate() { @@ -1299,7 +1371,7 @@ impl AlphaBatcher { } } None => { - let batch = self.batch_list.get_suitable_batch(batch_key, item_bounding_rect); + let batch = self.batch_list.get_suitable_batch(batch_key, task_relative_bounding_rect); batch.push(PrimitiveInstance::from(base_instance)); } } diff --git a/webrender/src/debug_server.rs b/webrender/src/debug_server.rs index d75226c31a..751394235f 100644 --- a/webrender/src/debug_server.rs +++ b/webrender/src/debug_server.rs @@ -53,8 +53,6 @@ impl ws::Handler for Server { "disable_texture_cache_debug" => DebugCommand::EnableTextureCacheDebug(false), "enable_render_target_debug" => DebugCommand::EnableRenderTargetDebug(true), "disable_render_target_debug" => DebugCommand::EnableRenderTargetDebug(false), - "enable_alpha_rects_debug" => DebugCommand::EnableAlphaRectsDebug(true), - "disable_alpha_rects_debug" => DebugCommand::EnableAlphaRectsDebug(false), "enable_gpu_time_queries" => DebugCommand::EnableGpuTimeQueries(true), "disable_gpu_time_queries" => DebugCommand::EnableGpuTimeQueries(false), "enable_gpu_sample_queries" => DebugCommand::EnableGpuSampleQueries(true), diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 302aa55068..6497ccc7fb 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1943,6 +1943,19 @@ impl Device { self.gl.disable(gl::STENCIL_TEST); } + pub fn set_scissor_rect(&self, rect: DeviceIntRect) { + self.gl.scissor( + rect.origin.x, + rect.origin.y, + rect.size.width, + rect.size.height, + ); + } + + pub fn enable_scissor(&self) { + self.gl.enable(gl::SCISSOR_TEST); + } + pub fn disable_scissor(&self) { self.gl.disable(gl::SCISSOR_TEST); } diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 02cbccb671..3298dbcfe4 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -30,7 +30,7 @@ use prim_store::{PrimitiveContainer, PrimitiveIndex}; use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu}; use prim_store::{BrushSegmentDescriptor, PrimitiveRun, TextRunPrimitiveCpu}; use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters}; -use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskTree}; +use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; use resource_cache::{ImageRequest, ResourceCache}; use scene::{ScenePipeline, SceneProperties}; use std::{mem, usize, f32}; @@ -1648,7 +1648,7 @@ impl FrameBuilder { pic.runs = pic_context.prim_runs; let root_render_task = RenderTask::new_picture( - None, + RenderTaskLocation::Fixed(frame_context.screen_rect), PrimitiveIndex(0), RenderTargetKind::Color, ContentOrigin::Screen(DeviceIntPoint::zero()), diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 5ebcb8755e..d48bdbf6eb 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -12,7 +12,7 @@ use gpu_cache::GpuDataRequest; use gpu_types::{BrushImageKind, PictureType}; use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect}; use render_task::{ClearMode, RenderTask, RenderTaskCacheKey}; -use render_task::{RenderTaskCacheKeyKind, RenderTaskId}; +use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation}; use resource_cache::CacheItem; use scene::{FilterOpHelpers, SceneProperties}; use tiling::RenderTargetKind; @@ -318,14 +318,6 @@ impl PicturePrimitive { } } - pub fn picture_type(&self) -> PictureType { - match self.kind { - PictureKind::Image { .. } => PictureType::Image, - PictureKind::BoxShadow { .. } => PictureType::BoxShadow, - PictureKind::TextShadow { .. } => PictureType::TextShadow, - } - } - pub fn prepare_for_render( &mut self, prim_index: PrimitiveIndex, @@ -348,7 +340,7 @@ impl PicturePrimitive { match composite_mode { Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => { let picture_task = RenderTask::new_picture( - Some(prim_screen_rect.size), + RenderTaskLocation::Dynamic(None, prim_screen_rect.size), prim_index, RenderTargetKind::Color, content_origin, @@ -377,7 +369,7 @@ impl PicturePrimitive { Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => { let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32(); let picture_task = RenderTask::new_picture( - Some(rect.size), + RenderTaskLocation::Dynamic(None, rect.size), prim_index, RenderTargetKind::Color, ContentOrigin::Screen(rect.origin), @@ -407,7 +399,7 @@ impl PicturePrimitive { } Some(PictureCompositeMode::MixBlend(..)) => { let picture_task = RenderTask::new_picture( - Some(prim_screen_rect.size), + RenderTaskLocation::Dynamic(None, prim_screen_rect.size), prim_index, RenderTargetKind::Color, content_origin, @@ -437,7 +429,7 @@ impl PicturePrimitive { self.surface = None; } else { let picture_task = RenderTask::new_picture( - Some(prim_screen_rect.size), + RenderTaskLocation::Dynamic(None, prim_screen_rect.size), prim_index, RenderTargetKind::Color, content_origin, @@ -454,7 +446,7 @@ impl PicturePrimitive { } Some(PictureCompositeMode::Blit) => { let picture_task = RenderTask::new_picture( - Some(prim_screen_rect.size), + RenderTaskLocation::Dynamic(None, prim_screen_rect.size), prim_index, RenderTargetKind::Color, content_origin, @@ -494,7 +486,7 @@ impl PicturePrimitive { let blur_std_deviation = device_radius * 0.5; let picture_task = RenderTask::new_picture( - Some(cache_size), + RenderTaskLocation::Dynamic(None, cache_size), prim_index, RenderTargetKind::Color, ContentOrigin::Local(content_rect.origin), @@ -554,7 +546,7 @@ impl PicturePrimitive { }; let picture_task = RenderTask::new_picture( - Some(cache_size), + RenderTaskLocation::Dynamic(None, cache_size), prim_index, RenderTargetKind::Alpha, ContentOrigin::Local(content_rect.origin), diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 5e5b7677f9..8934d77632 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -136,6 +136,12 @@ impl GpuCacheAddress { } } +#[derive(Debug, Copy, Clone)] +pub struct ScreenRect { + pub clipped: DeviceIntRect, + pub unclipped: DeviceIntRect, +} + // TODO(gw): Pack the fields here better! #[derive(Debug)] pub struct PrimitiveMetadata { @@ -153,7 +159,7 @@ pub struct PrimitiveMetadata { pub local_clip_rect: LayerRect, pub clip_chain_rect_index: ClipChainRectIndex, pub is_backface_visible: bool, - pub screen_rect: Option, + pub screen_rect: Option, /// A tag used to identify this primitive outside of WebRender. This is /// used for returning useful data during hit testing. @@ -1153,7 +1159,9 @@ impl PrimitiveStore { self.cpu_pictures[metadata.cpu_prim_index.0] .prepare_for_render( prim_index, - metadata.screen_rect.as_ref().expect("bug: trying to draw an off-screen picture!?"), + &metadata.screen_rect + .expect("bug: trying to draw an off-screen picture!?") + .clipped, &metadata.local_rect, pic_state_for_children, pic_state, @@ -1828,7 +1836,14 @@ impl PrimitiveStore { Some(ref node) => node.combined_outer_screen_rect, None => frame_context.screen_rect, }; - metadata.screen_rect = screen_bounding_rect.intersection(&clip_bounds); + metadata.screen_rect = screen_bounding_rect + .intersection(&clip_bounds) + .map(|clipped| { + ScreenRect { + clipped, + unclipped: screen_bounding_rect, + } + }); if metadata.screen_rect.is_none() && pic_context.perform_culling { return None; diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 635e4faefc..69356de646 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -167,7 +167,7 @@ impl RenderTaskTree { // Sanity check - can be relaxed if needed match task.location { - RenderTaskLocation::Fixed => { + RenderTaskLocation::Fixed(..) => { debug_assert!(pass_index == passes.len() - 1); } RenderTaskLocation::Dynamic(..) | @@ -218,7 +218,7 @@ impl ops::IndexMut for RenderTaskTree { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum RenderTaskLocation { - Fixed, + Fixed(DeviceIntRect), Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize), TextureCache(SourceTexture, i32, DeviceIntRect), } @@ -336,7 +336,7 @@ pub struct RenderTask { impl RenderTask { pub fn new_picture( - size: Option, + location: RenderTaskLocation, prim_index: PrimitiveIndex, target_kind: RenderTargetKind, content_origin: ContentOrigin, @@ -345,11 +345,6 @@ impl RenderTask { children: Vec, pic_type: PictureType, ) -> Self { - let location = match size { - Some(size) => RenderTaskLocation::Dynamic(None, size), - None => RenderTaskLocation::Fixed, - }; - RenderTask { children, location, @@ -601,7 +596,7 @@ impl RenderTask { pub fn get_dynamic_size(&self) -> DeviceIntSize { match self.location { - RenderTaskLocation::Fixed => DeviceIntSize::zero(), + RenderTaskLocation::Fixed(..) => DeviceIntSize::zero(), RenderTaskLocation::Dynamic(_, size) => size, RenderTaskLocation::TextureCache(_, _, rect) => rect.size, } @@ -609,8 +604,8 @@ impl RenderTask { pub fn get_target_rect(&self) -> (DeviceIntRect, RenderTargetIndex) { match self.location { - RenderTaskLocation::Fixed => { - (DeviceIntRect::zero(), RenderTargetIndex(0)) + RenderTaskLocation::Fixed(rect) => { + (rect, RenderTargetIndex(0)) } // Previously, we only added render tasks after the entire // primitive chain was determined visible. This meant that @@ -824,7 +819,7 @@ impl RenderTaskCache { // Find out what size to alloc in the texture cache. let size = match render_task.location { - RenderTaskLocation::Fixed | + RenderTaskLocation::Fixed(..) | RenderTaskLocation::TextureCache(..) => { panic!("BUG: dynamic task was expected"); } diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 9839eb912d..ecd2f8a13f 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -262,12 +262,11 @@ bitflags! { const PROFILER_DBG = 1 << 0; const RENDER_TARGET_DBG = 1 << 1; const TEXTURE_CACHE_DBG = 1 << 2; - const ALPHA_PRIM_DBG = 1 << 3; - const GPU_TIME_QUERIES = 1 << 4; - const GPU_SAMPLE_QUERIES= 1 << 5; - const DISABLE_BATCHING = 1 << 6; - const EPOCHS = 1 << 7; - const COMPACT_PROFILER = 1 << 8; + const GPU_TIME_QUERIES = 1 << 3; + const GPU_SAMPLE_QUERIES= 1 << 4; + const DISABLE_BATCHING = 1 << 5; + const EPOCHS = 1 << 6; + const COMPACT_PROFILER = 1 << 7; } } @@ -2566,35 +2565,35 @@ impl Renderer { "Horizontal Blur", target.horizontal_blurs.len(), ); - for (_, batch) in &target.alpha_batcher.text_run_cache_prims { - debug_target.add( - debug_server::BatchKind::Cache, - "Text Shadow", - batch.len(), - ); - } - for batch in target - .alpha_batcher - .batch_list - .opaque_batch_list - .batches - .iter() - .rev() - { - debug_target.add( - debug_server::BatchKind::Opaque, - batch.key.kind.debug_name(), - batch.instances.len(), - ); - } + for alpha_batch_container in &target.alpha_batch_containers { + for (_, batch) in &alpha_batch_container.text_run_cache_prims { + debug_target.add( + debug_server::BatchKind::Cache, + "Text Shadow", + batch.len(), + ); + } - for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches { - debug_target.add( - debug_server::BatchKind::Alpha, - batch.key.kind.debug_name(), - batch.instances.len(), - ); + for batch in alpha_batch_container + .opaque_batches + .iter() + .rev() { + debug_target.add( + debug_server::BatchKind::Opaque, + batch.key.kind.debug_name(), + batch.instances.len(), + ); + } + + for batch in &alpha_batch_container + .alpha_batches { + debug_target.add( + debug_server::BatchKind::Alpha, + batch.key.kind.debug_name(), + batch.instances.len(), + ); + } } debug_target @@ -2674,9 +2673,6 @@ impl Renderer { DebugCommand::EnableRenderTargetDebug(enable) => { self.set_debug_flag(DebugFlags::RENDER_TARGET_DBG, enable); } - DebugCommand::EnableAlphaRectsDebug(enable) => { - self.set_debug_flag(DebugFlags::ALPHA_PRIM_DBG, enable); - } DebugCommand::EnableGpuTimeQueries(enable) => { self.set_debug_flag(DebugFlags::GPU_TIME_QUERIES, enable); } @@ -3166,6 +3162,7 @@ impl Renderer { render_target: Option<(&Texture, i32)>, framebuffer_size: DeviceUintSize, stats: &mut RendererStats, + scissor_rect: Option, ) { match key.kind { BatchKind::Composite { .. } => { @@ -3302,6 +3299,10 @@ impl Renderer { // Handle special case readback for composites. if let BatchKind::Composite { task_id, source_id, backdrop_id } = key.kind { + if scissor_rect.is_some() { + self.device.disable_scissor(); + } + // composites can't be grouped together because // they may overlap and affect each other. debug_assert_eq!(instances.len(), 1); @@ -3360,6 +3361,10 @@ impl Renderer { // Restore draw target to current pass render target + layer. // Note: leaving the viewport unchanged, it's not a part of FBO state self.device.bind_draw_target(render_target, None); + + if scissor_rect.is_some() { + self.device.enable_scissor(); + } } let _timer = self.gpu_profile.start_timer(key.kind.gpu_sampler_tag()); @@ -3547,45 +3552,46 @@ impl Renderer { // considering using this for (some) other text runs, since // it removes the overhead of submitting many small glyphs // to multiple tiles in the normal text run case. - if !target.alpha_batcher.text_run_cache_prims.is_empty() { - self.device.set_blend(true); - self.device.set_blend_mode_premultiplied_alpha(); + for alpha_batch_container in &target.alpha_batch_containers { + if !alpha_batch_container.text_run_cache_prims.is_empty() { + self.device.set_blend(true); + self.device.set_blend_mode_premultiplied_alpha(); - let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_TEXT_RUN); - self.cs_text_run - .bind(&mut self.device, projection, 0, &mut self.renderer_errors); - for (texture_id, instances) in &target.alpha_batcher.text_run_cache_prims { - self.draw_instanced_batch( - instances, - VertexArrayKind::Primitive, - &BatchTextures::color(*texture_id), - stats, - ); + let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_TEXT_RUN); + self.cs_text_run + .bind(&mut self.device, projection, 0, &mut self.renderer_errors); + for (texture_id, instances) in &alpha_batch_container.text_run_cache_prims { + self.draw_instanced_batch( + instances, + VertexArrayKind::Primitive, + &BatchTextures::color(*texture_id), + stats, + ); + } } } //TODO: record the pixel count for cached primitives - if !target.alpha_batcher.is_empty() { - let _gl = self.gpu_profile.start_marker("alpha batches"); + if target.needs_depth() { + let _gl = self.gpu_profile.start_marker("opaque batches"); + let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE); self.device.set_blend(false); - let mut prev_blend_mode = BlendMode::None; - - if target.needs_depth() { - let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE); - - //Note: depth equality is needed for split planes - self.device.set_depth_func(DepthFunction::LessEqual); - self.device.enable_depth(); - self.device.enable_depth_write(); + //Note: depth equality is needed for split planes + self.device.set_depth_func(DepthFunction::LessEqual); + self.device.enable_depth(); + self.device.enable_depth_write(); + + for alpha_batch_container in &target.alpha_batch_containers { + if let Some(target_rect) = alpha_batch_container.target_rect { + self.device.enable_scissor(); + self.device.set_scissor_rect(target_rect); + } // Draw opaque batches front-to-back for maximum // z-buffer efficiency! - for batch in target - .alpha_batcher - .batch_list - .opaque_batch_list - .batches + for batch in alpha_batch_container + .opaque_batches .iter() .rev() { @@ -3597,32 +3603,31 @@ impl Renderer { render_target, target_size, stats, + alpha_batch_container.target_rect, ); } - self.device.disable_depth_write(); - self.gpu_profile.finish_sampler(opaque_sampler); + if alpha_batch_container.target_rect.is_some() { + self.device.disable_scissor(); + } } - let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT); - - for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches { - if self.debug_flags.contains(DebugFlags::ALPHA_PRIM_DBG) { - let color = match batch.key.blend_mode { - BlendMode::None => debug_colors::BLACK, - BlendMode::Alpha | - BlendMode::PremultipliedAlpha => debug_colors::GREY, - BlendMode::PremultipliedDestOut => debug_colors::SALMON, - BlendMode::SubpixelConstantTextColor(..) => debug_colors::GREEN, - BlendMode::SubpixelVariableTextColor => debug_colors::RED, - BlendMode::SubpixelWithBgColor => debug_colors::BLUE, - BlendMode::SubpixelDualSource => debug_colors::YELLOW, - }.into(); - for item_rect in &batch.item_rects { - self.debug.add_rect(item_rect, color); - } - } + self.device.disable_depth_write(); + self.gpu_profile.finish_sampler(opaque_sampler); + } + + let _gl = self.gpu_profile.start_marker("alpha batches"); + let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT); + self.device.set_blend(false); + let mut prev_blend_mode = BlendMode::None; + + for alpha_batch_container in &target.alpha_batch_containers { + if let Some(target_rect) = alpha_batch_container.target_rect { + self.device.enable_scissor(); + self.device.set_scissor_rect(target_rect); + } + for batch in &alpha_batch_container.alpha_batches { match batch.key.kind { BatchKind::Transformable(transform_kind, TransformBatchKind::TextRun(glyph_format)) => { // Text run batches are handled by this special case branch. @@ -3836,16 +3841,21 @@ impl Renderer { render_target, target_size, stats, + alpha_batch_container.target_rect, ); } } } - self.device.disable_depth(); - self.device.set_blend(false); - self.gpu_profile.finish_sampler(transparent_sampler); + if alpha_batch_container.target_rect.is_some() { + self.device.disable_scissor(); + } } + self.device.disable_depth(); + self.device.set_blend(false); + self.gpu_profile.finish_sampler(transparent_sampler); + // For any registered image outputs on this render target, // get the texture from caller and blit it. for output in &target.outputs { diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 977fd43b24..2a4f4c8b14 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -6,7 +6,7 @@ use api::{ClipId, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::{DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize}; use api::{DocumentLayer, FilterOp, ImageFormat}; use api::{LayerRect, MixBlendMode, PipelineId}; -use batch::{AlphaBatcher, ClipBatcher, resolve_image}; +use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image}; use clip::{ClipStore}; use clip_scroll_tree::{ClipScrollTree}; use device::{FrameId, Texture}; @@ -269,7 +269,7 @@ pub struct BlitJob { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ColorRenderTarget { - pub alpha_batcher: AlphaBatcher, + pub alpha_batch_containers: Vec, // List of blur operations to apply for this render target. pub vertical_blurs: Vec, pub horizontal_blurs: Vec, @@ -280,6 +280,7 @@ pub struct ColorRenderTarget { pub outputs: Vec, allocator: Option, alpha_tasks: Vec, + screen_size: DeviceIntSize, } impl RenderTarget for ColorRenderTarget { @@ -295,7 +296,7 @@ impl RenderTarget for ColorRenderTarget { screen_size: DeviceIntSize, ) -> Self { ColorRenderTarget { - alpha_batcher: AlphaBatcher::new(screen_size), + alpha_batch_containers: Vec::new(), vertical_blurs: Vec::new(), horizontal_blurs: Vec::new(), readbacks: Vec::new(), @@ -304,6 +305,7 @@ impl RenderTarget for ColorRenderTarget { allocator: size.map(TextureAllocator::new), outputs: Vec::new(), alpha_tasks: Vec::new(), + screen_size, } } @@ -314,13 +316,39 @@ impl RenderTarget for ColorRenderTarget { render_tasks: &mut RenderTaskTree, deferred_resolves: &mut Vec, ) { - self.alpha_batcher.build( - &self.alpha_tasks, - ctx, - gpu_cache, - render_tasks, - deferred_resolves, - ); + let mut merged_batches = AlphaBatchContainer::new(None); + + for task_id in &self.alpha_tasks { + let task = &render_tasks[*task_id]; + + match task.kind { + RenderTaskKind::Picture(ref pic_task) => { + let pic_index = ctx.prim_store.cpu_metadata[pic_task.prim_index.0].cpu_prim_index; + let pic = &ctx.prim_store.cpu_pictures[pic_index.0]; + let (target_rect, _) = task.get_target_rect(); + + let mut batch_builder = AlphaBatchBuilder::new(self.screen_size, target_rect); + + batch_builder.add_pic_to_batch( + pic, + *task_id, + ctx, + gpu_cache, + render_tasks, + deferred_resolves, + ); + + if let Some(batch_container) = batch_builder.build(&mut merged_batches) { + self.alpha_batch_containers.push(batch_container); + } + } + _ => { + unreachable!(); + } + } + } + + self.alpha_batch_containers.push(merged_batches); } fn add_task( @@ -444,7 +472,9 @@ impl RenderTarget for ColorRenderTarget { } fn needs_depth(&self) -> bool { - !self.alpha_batcher.batch_list.opaque_batch_list.batches.is_empty() + self.alpha_batch_containers.iter().any(|ab| { + !ab.opaque_batches.is_empty() + }) } } @@ -791,7 +821,7 @@ impl RenderPass { // correct target kind. (RenderTargetKind::Alpha, Some((texture_id, layer))) } - RenderTaskLocation::Fixed => { + RenderTaskLocation::Fixed(..) => { (RenderTargetKind::Color, None) } RenderTaskLocation::Dynamic(ref mut origin, size) => { diff --git a/webrender/src/util.rs b/webrender/src/util.rs index ab8135b6db..34ced28237 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -111,17 +111,11 @@ pub trait RectHelpers where Self: Sized, { - fn contains_rect(&self, other: &Self) -> bool; fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self; fn is_well_formed_and_nonempty(&self) -> bool; } impl RectHelpers for TypedRect { - fn contains_rect(&self, other: &Self) -> bool { - self.origin.x <= other.origin.x && self.origin.y <= other.origin.y && - self.max_x() >= other.max_x() && self.max_y() >= other.max_y() - } - fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Self { TypedRect::new( TypedPoint2D::new(x0, y0), diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs index 5a201ff219..58bfbe45a4 100644 --- a/webrender_api/src/api.rs +++ b/webrender_api/src/api.rs @@ -477,8 +477,6 @@ pub enum DebugCommand { EnableTextureCacheDebug(bool), /// Display intermediate render targets on screen. EnableRenderTargetDebug(bool), - /// Display alpha primitive rects. - EnableAlphaRectsDebug(bool), /// Display GPU timing results. EnableGpuTimeQueries(bool), /// Display GPU overdraw results diff --git a/wrench/src/main.rs b/wrench/src/main.rs index 1126b4b24c..4bbaf7d602 100644 --- a/wrench/src/main.rs +++ b/wrench/src/main.rs @@ -496,10 +496,6 @@ fn main() { wrench.renderer.toggle_debug_flags(DebugFlags::TEXTURE_CACHE_DBG); do_render = true; } - VirtualKeyCode::B => { - wrench.renderer.toggle_debug_flags(DebugFlags::ALPHA_PRIM_DBG); - do_render = true; - } VirtualKeyCode::S => { wrench.renderer.toggle_debug_flags(DebugFlags::COMPACT_PROFILER); do_render = true;