diff --git a/webrender/res/brush.glsl b/webrender/res/brush.glsl index 034fe61609..410b690ecb 100644 --- a/webrender/res/brush.glsl +++ b/webrender/res/brush.glsl @@ -164,8 +164,12 @@ void main(void) { // Write the normal vertex information out. if (transform.is_axis_aligned) { + + // Select the corner of the local rect that we are processing. + vec2 local_pos = segment_rect.p0 + segment_rect.size * aPosition.xy; + vi = write_vertex( - segment_rect, + local_pos, ph.local_clip_rect, ph.z, transform, @@ -245,13 +249,6 @@ void main(void) { #ifdef WR_FRAGMENT_SHADER -struct Fragment { - vec4 color; -#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING - vec4 blend; -#endif -}; - // Foward-declare all brush entry-points. Fragment image_brush_fs(); Fragment solid_brush_fs(); @@ -262,6 +259,7 @@ Fragment radial_gradient_brush_fs(); Fragment conic_gradient_brush_fs(); Fragment yuv_brush_fs(); Fragment opacity_brush_fs(); +Fragment text_brush_fs(); Fragment multi_brush_fs(int brush_kind); void main(void) { diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 60c0fe7e5b..d4a06b2a2d 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -109,15 +109,11 @@ struct VertexInfo { vec4 world_pos; }; -VertexInfo write_vertex(RectWithSize instance_rect, +VertexInfo write_vertex(vec2 local_pos, RectWithSize local_clip_rect, float z, Transform transform, PictureTask task) { - - // Select the corner of the local rect that we are processing. - vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy; - // Clamp to the two local clip rects. vec2 clamped_local_pos = clamp_rect(local_pos, local_clip_rect); @@ -245,6 +241,14 @@ vec2 get_image_quad_uv(int address, vec2 f) { #ifdef WR_FRAGMENT_SHADER +struct Fragment { + vec4 color; +#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + vec4 blend; +#endif +}; + + float do_clip() { // check for the dummy bounds, which are given to the opaque objects if (vClipMaskUvBounds.xy == vClipMaskUvBounds.zw) { diff --git a/webrender/res/ps_text_run.glsl b/webrender/res/ps_text_run.glsl index 0fd1943ed7..661e55ba28 100644 --- a/webrender/res/ps_text_run.glsl +++ b/webrender/res/ps_text_run.glsl @@ -90,6 +90,28 @@ TextRun fetch_text_run(int address) { return TextRun(data[0], data[1]); } +vec2 get_snap_bias(int subpx_dir) { + // In subpixel mode, the subpixel offset has already been + // accounted for while rasterizing the glyph. However, we + // must still round with a subpixel bias rather than rounding + // to the nearest whole pixel, depending on subpixel direciton. + switch (subpx_dir) { + case SUBPX_DIR_NONE: + default: + return vec2(0.5); + case SUBPX_DIR_HORIZONTAL: + // Glyphs positioned [-0.125, 0.125] get a + // subpx position of zero. So include that + // offset in the glyph position to ensure + // we round to the correct whole position. + return vec2(0.125, 0.5); + case SUBPX_DIR_VERTICAL: + return vec2(0.5, 0.125); + case SUBPX_DIR_MIXED: + return vec2(0.125); + } +} + void main(void) { Instance instance = decode_instance_attributes(); @@ -118,30 +140,7 @@ void main(void) { GlyphResource res = fetch_glyph_resource(instance.resource_address); - vec2 snap_bias; - // In subpixel mode, the subpixel offset has already been - // accounted for while rasterizing the glyph. However, we - // must still round with a subpixel bias rather than rounding - // to the nearest whole pixel, depending on subpixel direciton. - switch (subpx_dir) { - case SUBPX_DIR_NONE: - default: - snap_bias = vec2(0.5); - break; - case SUBPX_DIR_HORIZONTAL: - // Glyphs positioned [-0.125, 0.125] get a - // subpx position of zero. So include that - // offset in the glyph position to ensure - // we round to the correct whole position. - snap_bias = vec2(0.125, 0.5); - break; - case SUBPX_DIR_VERTICAL: - snap_bias = vec2(0.5, 0.125); - break; - case SUBPX_DIR_MIXED: - snap_bias = vec2(0.125); - break; - } + vec2 snap_bias = get_snap_bias(subpx_dir); // Glyph space refers to the pixel space used by glyph rasterization during frame // building. If a non-identity transform was used, WR_FEATURE_GLYPH_TRANSFORM will @@ -220,26 +219,22 @@ void main(void) { vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy; #endif - // Clamp to the local clip rect. - local_pos = clamp_rect(local_pos, ph.local_clip_rect); - - // Map the clamped local space corner into device space. - vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0); - vec2 device_pos = world_pos.xy * task.device_pixel_scale; - - // Apply offsets for the render task to get correct screen location. - vec2 final_offset = -task.content_origin + task.common_data.task_rect.p0; - - gl_Position = uTransform * vec4(device_pos + final_offset * world_pos.w, ph.z * world_pos.w, world_pos.w); + VertexInfo vi = write_vertex( + local_pos, + ph.local_clip_rect, + ph.z, + transform, + task + ); #ifdef WR_FEATURE_GLYPH_TRANSFORM - vec2 f = (glyph_transform * local_pos - glyph_rect.p0) / glyph_rect.size; + vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size; V_UV_CLIP = vec4(f, 1.0 - f); #else - vec2 f = (local_pos - glyph_rect.p0) / glyph_rect.size; + vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size; #endif - write_clip(world_pos, clip_area); + write_clip(vi.world_pos, clip_area); switch (color_mode) { case COLOR_MODE_ALPHA: @@ -278,24 +273,41 @@ void main(void) { #endif #ifdef WR_FRAGMENT_SHADER -void main(void) { + +Fragment text_brush_fs(void) { + Fragment frag; + vec3 tc = vec3(clamp(V_UV, V_UV_BOUNDS.xy, V_UV_BOUNDS.zw), V_LAYER); vec4 mask = texture(sColor0, tc); mask.rgb = mask.rgb * V_MASK_SWIZZLE.x + mask.aaa * V_MASK_SWIZZLE.y; - float alpha = do_clip(); -#ifdef WR_FEATURE_GLYPH_TRANSFORM - alpha *= float(all(greaterThanEqual(V_UV_CLIP, vec4(0.0)))); -#endif + #ifdef WR_FEATURE_GLYPH_TRANSFORM + mask *= float(all(greaterThanEqual(V_UV_CLIP, vec4(0.0)))); + #endif -#if defined(WR_FEATURE_DEBUG_OVERDRAW) - oFragColor = WR_DEBUG_OVERDRAW_COLOR; -#elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING) - vec4 alpha_mask = mask * alpha; - oFragColor = V_COLOR * alpha_mask; - oFragBlend = alpha_mask * V_COLOR.a; -#else - write_output(V_COLOR * mask * alpha); -#endif + frag.color = V_COLOR * mask; + + #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + frag.blend = V_COLOR.a * mask; + #endif + + return frag; } -#endif + +void main(void) { + Fragment frag = text_brush_fs(); + + float clip_mask = do_clip(); + frag.color *= clip_mask; + + #if defined(WR_FEATURE_DEBUG_OVERDRAW) + oFragColor = WR_DEBUG_OVERDRAW_COLOR; + #elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING) + oFragColor = frag.color; + oFragBlend = frag.blend * clip_mask; + #else + write_output(frag.color); + #endif +} + +#endif // WR_FRAGMENT_SHADER diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 9032f69875..04d3b861c1 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -14,6 +14,7 @@ use crate::gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, Z use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance, BrushShaderKind}; use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; +use crate::gpu_types::{ImageBrushData, get_shader_opacity}; use crate::internal_types::{FastHashMap, SavedTargetIndex, Swizzle, TextureSource, Filter}; use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive}; use crate::prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex, PrimitiveVisibilityMask}; @@ -849,12 +850,12 @@ impl BatchBuilder { let batch_params = BrushBatchParameters::instanced( BrushBatchKind::Image(ImageBufferKind::Texture2DArray), - [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(1.0), - 0, - ], + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(), segment_data, ); @@ -1004,12 +1005,12 @@ impl BatchBuilder { for glyph in glyphs { batch.push(base_instance.build( - ((render_task_address.0 as i32) << 16) - | clip_task_address.unwrap().0 as i32, - (subpx_dir as u32 as i32) << 24 - | (color_mode as u32 as i32) << 16 - | glyph.index_in_text_run, - glyph.uv_rect_address.as_int(), + render_task_address, + clip_task_address.unwrap(), + subpx_dir, + glyph.index_in_text_run, + glyph.uv_rect_address, + color_mode, )); } } @@ -1035,12 +1036,12 @@ impl BatchBuilder { ( BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, - [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(1.0), - 0, - ], + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(), cache_item.uv_rect_handle.as_int(gpu_cache), ) } @@ -1248,12 +1249,16 @@ impl BatchBuilder { non_segmented_blend_mode, textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), + ); self.add_brush_instance_to_batches( key, @@ -1323,12 +1328,16 @@ impl BatchBuilder { ..prim_header }; - let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id, [ - ShaderColorMode::Alpha as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ]); + let shadow_prim_header_index = prim_headers.push( + &shadow_prim_header, + z_id, + ImageBrushData { + color_mode: ShaderColorMode::Alpha, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), + ); self.add_brush_instance_to_batches( shadow_key, @@ -1346,12 +1355,16 @@ impl BatchBuilder { } let z_id_content = z_generator.next(); - let content_prim_header_index = prim_headers.push(&prim_header, z_id_content, [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ]); + let content_prim_header_index = prim_headers.push( + &prim_header, + z_id_content, + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), + ); self.add_brush_instance_to_batches( content_key, @@ -1525,12 +1538,16 @@ impl BatchBuilder { BlendMode::Advanced(mode), textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(1.0), - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(), + ); self.add_brush_instance_to_batches( key, @@ -1607,12 +1624,12 @@ impl BatchBuilder { let batch_params = BrushBatchParameters::shared( BrushBatchKind::Image(ImageBufferKind::Texture2DArray), textures, - [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ], + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), uv_rect_address, ); @@ -1680,12 +1697,16 @@ impl BatchBuilder { non_segmented_blend_mode, textures, ); - let prim_header_index = prim_headers.push(&prim_header, z_id, [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0, - ]); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), + ); self.add_brush_instance_to_batches( key, @@ -1759,12 +1780,12 @@ impl BatchBuilder { let batch_params = BrushBatchParameters::shared( BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, - [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(1.0), - 0, - ], + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(), cache_item.uv_rect_handle.as_int(gpu_cache), ); @@ -1976,12 +1997,12 @@ impl BatchBuilder { rendering: image_data.image_rendering, tile: None, }; - let prim_user_data = [ - ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(opacity_binding), - 0, - ]; + let prim_user_data = ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: image_data.alpha_type, + raster_space: RasterizationSpace::Local, + opacity: opacity_binding, + }.encode(); if image_instance.visible_tiles.is_empty() { let cache_item = match image_data.source { @@ -2156,12 +2177,13 @@ impl BatchBuilder { let textures = BatchTextures::color(cache_item.texture_id); let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)); - let prim_user_data = [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Local as i32, - get_shader_opacity(1.0), - 0, - ]; + let prim_user_data = ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(); + let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache); prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle); @@ -2451,12 +2473,12 @@ impl BatchBuilder { let prim_header_index = prim_headers.push( &prim_header, z_id, - [ - ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16), - RasterizationSpace::Screen as i32, - get_shader_opacity(1.0), - 0 - ], + ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Screen, + opacity: 1.0, + }.encode(), ); self.add_brush_instance_to_batches( @@ -3219,10 +3241,6 @@ fn get_buffer_kind(texture: TextureSource) -> ImageBufferKind { } } -fn get_shader_opacity(opacity: f32) -> i32 { - (opacity * 65535.0).round() as i32 -} - impl<'a, 'rc> RenderTargetContext<'a, 'rc> { /// Retrieve the GPU task address for a given clip task instance. /// Returns None if the segment was completely clipped out. diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index a51f801bbb..af06840f37 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -262,7 +262,6 @@ impl FrameBuilder { texture_cache_profile: &mut TextureCacheProfileCounters, composite_state: &mut CompositeState, tile_cache_logger: &mut TileCacheLogger, - config: FrameBuilderConfig, ) -> Option { profile_scope!("cull"); @@ -349,7 +348,7 @@ impl FrameBuilder { surfaces, debug_flags, scene_properties, - config, + config: scene.config, }; let mut visibility_state = FrameVisibilityState { @@ -376,6 +375,12 @@ impl FrameBuilder { &mut visibility_state, ); + // When there are tiles that are left remaining in the `retained_tiles`, + // dirty rects are not valid. + if !visibility_state.retained_tiles.caches.is_empty() { + visibility_state.composite_state.dirty_rects_are_valid = false; + } + // When a new display list is processed by WR, the existing tiles from // any picture cache are stored in the `retained_tiles` field above. This // allows the first frame of a new display list to reuse any existing tiles @@ -498,7 +503,6 @@ impl FrameBuilder { render_task_counters: &mut RenderTaskGraphCounters, debug_flags: DebugFlags, tile_cache_logger: &mut TileCacheLogger, - config: FrameBuilderConfig, ) -> Frame { profile_scope!("build"); profile_marker!("BuildFrame"); @@ -569,7 +573,6 @@ impl FrameBuilder { &mut resource_profile.texture_cache, &mut composite_state, tile_cache_logger, - config, ); let mut passes; diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 3dffb0a40b..b08814f726 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -2,15 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{DocumentLayer, PremultipliedColorF}; +use api::{DocumentLayer, PremultipliedColorF, AlphaType}; use api::units::*; use crate::spatial_tree::{SpatialTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex}; use crate::gpu_cache::{GpuCacheAddress, GpuDataRequest}; use crate::internal_types::FastHashMap; use crate::prim_store::EdgeAaSegmentMask; use crate::render_task::RenderTaskAddress; +use crate::renderer::ShaderColorMode; use std::i32; use crate::util::{TransformedRectKind, MatrixHelpers}; +use crate::glyph_rasterizer::SubpixelDirection; // Contains type that must exactly match the same structures declared in GLSL. @@ -364,13 +366,24 @@ impl GlyphInstance { // TODO(gw): Some of these fields can be moved to the primitive // header since they are constant, and some can be // compressed to a smaller size. - pub fn build(&self, data0: i32, data1: i32, resource_address: i32) -> PrimitiveInstanceData { + pub fn build(&self, + render_task: RenderTaskAddress, + clip_task: RenderTaskAddress, + subpx_dir: SubpixelDirection, + glyph_index_in_text_run: i32, + glyph_uv_rect: GpuCacheAddress, + color_mode: ShaderColorMode, + ) -> PrimitiveInstanceData { PrimitiveInstanceData { data: [ self.prim_header_index.0 as i32, - data0, - data1, - resource_address | ((BrushShaderKind::Text as i32) << 24), + ((render_task.0 as i32) << 16) + | clip_task.0 as i32, + (subpx_dir as u32 as i32) << 24 + | (color_mode as u32 as i32) << 16 + | glyph_index_in_text_run, + glyph_uv_rect.as_int() + | ((BrushShaderKind::Text as i32) << 24), ], } } @@ -452,6 +465,27 @@ impl From for PrimitiveInstanceData { } } +/// Convenience structure to encode into the image brush's user data. +#[derive(Copy, Clone, Debug)] +pub struct ImageBrushData { + pub color_mode: ShaderColorMode, + pub alpha_type: AlphaType, + pub raster_space: RasterizationSpace, + pub opacity: f32, +} + +impl ImageBrushData { + #[inline] + pub fn encode(&self) -> [i32; 4] { + [ + self.color_mode as i32 | ((self.alpha_type as i32) << 16), + self.raster_space as i32, + get_shader_opacity(self.opacity), + 0, + ] + } +} + // Represents the information about a transform palette // entry that is passed to shaders. It includes an index // into the transform palette, and a set of flags. The @@ -720,3 +754,7 @@ fn register_transform( index } } + +pub fn get_shader_opacity(opacity: f32) -> i32 { + (opacity * 65535.0).round() as i32 +} diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index f3d17b4668..333712c76d 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -545,7 +545,6 @@ impl Document { resource_profile: &mut ResourceProfileCounters, debug_flags: DebugFlags, tile_cache_logger: &mut TileCacheLogger, - config: FrameBuilderConfig, ) -> RenderedDocument { let accumulated_scale_factor = self.view.accumulated_scale_factor(); let pan = self.view.pan.to_f32() / accumulated_scale_factor; @@ -573,7 +572,6 @@ impl Document { &mut self.render_task_counters, debug_flags, tile_cache_logger, - config, ); self.hit_tester = Some(self.scene.create_hit_tester(&self.data_stores.clip)); frame @@ -1142,16 +1140,14 @@ impl RenderBackend { // that are created. self.frame_config .dual_source_blending_is_enabled = enable; - - self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( - self.frame_config.clone() - )).unwrap(); + self.update_frame_builder_config(); // We don't want to forward this message to the renderer. return RenderBackendStatus::Continue; } DebugCommand::SetPictureTileSize(tile_size) => { self.frame_config.tile_size_override = tile_size; + self.update_frame_builder_config(); return RenderBackendStatus::Continue; } @@ -1249,11 +1245,7 @@ impl RenderBackend { } self.frame_config.compositor_kind = compositor_kind; - - // Update config in SceneBuilder - self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( - self.frame_config.clone() - )).unwrap(); + self.update_frame_builder_config(); // We don't want to forward this message to the renderer. return RenderBackendStatus::Continue; @@ -1262,6 +1254,12 @@ impl RenderBackend { self.resource_cache.enable_multithreading(enable); return RenderBackendStatus::Continue; } + DebugCommand::SetBatchingLookback(count) => { + self.frame_config.batch_lookback_count = count as usize; + self.update_frame_builder_config(); + + return RenderBackendStatus::Continue; + } DebugCommand::SimulateLongSceneBuild(time_ms) => { self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)).unwrap(); return RenderBackendStatus::Continue; @@ -1315,6 +1313,12 @@ impl RenderBackend { RenderBackendStatus::Continue } + fn update_frame_builder_config(&self) { + self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( + self.frame_config.clone() + )).unwrap(); + } + fn prepare_for_frames(&mut self) { self.resource_cache.prepare_for_frames(SystemTime::now()); self.gpu_cache.prepare_for_frames(); @@ -1584,7 +1588,6 @@ impl RenderBackend { &mut profile_counters.resources, self.debug_flags, &mut self.tile_cache_logger, - self.frame_config, ); debug!("generated frame for document {:?} with {} passes", @@ -1763,7 +1766,6 @@ impl RenderBackend { &mut profile_counters.resources, self.debug_flags, &mut self.tile_cache_logger, - self.frame_config, ); // After we rendered the frames, there are pending updates to both // GPU cache and resources. Instead of serializing them, we are going to make sure diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 4f5671ccba..5fec66cdf5 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -1969,6 +1969,10 @@ impl Renderer { shaders: Option<&mut WrShaders>, start_size: DeviceIntSize, ) -> Result<(Self, RenderApiSender), RendererError> { + if !wr_has_been_initialized() { + register_thread_with_profiler("Compositor".to_owned()); + } + HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst); let (api_tx, api_rx) = channel::msg_channel()?; @@ -2028,8 +2032,6 @@ impl Renderer { let max_texture_size = device.max_texture_size(); let max_texture_layers = device.max_texture_layers(); - register_thread_with_profiler("Compositor".to_owned()); - device.begin_frame(); let shaders = match shaders { @@ -2884,6 +2886,7 @@ impl Renderer { | DebugCommand::SimulateLongSceneBuild(_) | DebugCommand::SimulateLongLowPrioritySceneBuild(_) | DebugCommand::EnableNativeCompositor(_) + | DebugCommand::SetBatchingLookback(_) | DebugCommand::EnableMultithreading(_) => {} DebugCommand::InvalidateGpuCache => { match self.gpu_cache_texture.bus { diff --git a/webrender/src/scene.rs b/webrender/src/scene.rs index a5a683f5e8..f00cf5b7ca 100644 --- a/webrender/src/scene.rs +++ b/webrender/src/scene.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BuiltDisplayList, DisplayItemCache, ColorF, DynamicProperties, Epoch, FontRenderMode}; +use api::{BuiltDisplayList, DisplayListWithCache, ColorF, DynamicProperties, Epoch, FontRenderMode}; use api::{PipelineId, PropertyBinding, PropertyBindingId, PropertyValue, MixBlendMode, StackingContext}; use api::units::*; use crate::composite::CompositorKind; @@ -132,8 +132,7 @@ pub struct ScenePipeline { pub viewport_size: LayoutSize, pub content_size: LayoutSize, pub background_color: Option, - pub display_list: BuiltDisplayList, - pub display_list_cache: DisplayItemCache, + pub display_list: DisplayListWithCache, } /// A complete representation of the layout bundling visible pipelines together. @@ -168,12 +167,15 @@ impl Scene { viewport_size: LayoutSize, content_size: LayoutSize, ) { - let pipeline = self.pipelines.remove(&pipeline_id); - let mut display_list_cache = pipeline.map_or(Default::default(), |p| { - p.display_list_cache - }); - - display_list_cache.update(&display_list); + // Adds a cache to the given display list. If this pipeline already had + // a display list before, that display list is updated and used instead. + let display_list = match self.pipelines.remove(&pipeline_id) { + Some(mut pipeline) => { + pipeline.display_list.update(display_list); + pipeline.display_list + } + None => DisplayListWithCache::new_from_list(display_list) + }; let new_pipeline = ScenePipeline { pipeline_id, @@ -181,7 +183,6 @@ impl Scene { content_size, background_color, display_list, - display_list_cache, }; self.pipelines.insert(pipeline_id, new_pipeline); diff --git a/webrender/src/scene_building.rs b/webrender/src/scene_building.rs index 540b9974a1..2991c757ea 100644 --- a/webrender/src/scene_building.rs +++ b/webrender/src/scene_building.rs @@ -459,9 +459,8 @@ impl<'a> SceneBuilder<'a> { device_pixel_scale, ); - let cache = &root_pipeline.display_list_cache; builder.build_items( - &mut root_pipeline.display_list.iter_with_cache(cache), + &mut root_pipeline.display_list.iter(), root_pipeline.pipeline_id, true, ); @@ -1001,9 +1000,8 @@ impl<'a> SceneBuilder<'a> { self.rf_mapper.push_scope(); self.iframe_depth += 1; - let cache = &pipeline.display_list_cache; self.build_items( - &mut pipeline.display_list.iter_with_cache(cache), + &mut pipeline.display_list.iter(), pipeline.pipeline_id, true, ); diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs index 3b91058480..302ab3d2e9 100644 --- a/webrender_api/src/api.rs +++ b/webrender_api/src/api.rs @@ -974,6 +974,8 @@ pub enum DebugCommand { EnableNativeCompositor(bool), /// Enable/disable parallel job execution with rayon. EnableMultithreading(bool), + /// Sets the maximum amount of existing batches to visit before creating a new one. + SetBatchingLookback(u32), /// Invalidate GPU cache, forcing the update from the CPU mirror. InvalidateGpuCache, /// Causes the scene builder to pause for a given amount of milliseconds each time it diff --git a/webrender_api/src/display_item_cache.rs b/webrender_api/src/display_item_cache.rs index 79d4aecf43..604325c295 100644 --- a/webrender_api/src/display_item_cache.rs +++ b/webrender_api/src/display_item_cache.rs @@ -40,7 +40,7 @@ impl From> for CachedDisplayItem { } } -#[derive(Clone, Default, Deserialize, Serialize)] +#[derive(Clone, Deserialize, Serialize)] pub struct DisplayItemCache { items: Vec> } @@ -57,7 +57,7 @@ impl DisplayItemCache { } } - pub fn add_item( + fn add_item( &mut self, key: Option, item: DisplayItemRef @@ -73,6 +73,12 @@ impl DisplayItemCache { self.items[key as usize].as_ref() } + pub fn new() -> Self { + Self { + items: Vec::new() + } + } + pub fn update( &mut self, display_list: &BuiltDisplayList diff --git a/webrender_api/src/display_list.rs b/webrender_api/src/display_list.rs index c2e5968844..773378a5cb 100644 --- a/webrender_api/src/display_list.rs +++ b/webrender_api/src/display_list.rs @@ -137,6 +137,67 @@ pub struct BuiltDisplayListDescriptor { extra_data_offset: usize, } +#[derive(Clone)] +pub struct DisplayListWithCache { + display_list: BuiltDisplayList, + cache: DisplayItemCache, +} + +impl DisplayListWithCache { + pub fn iter(&self) -> BuiltDisplayListIter { + self.display_list.iter_with_cache(&self.cache) + } + + pub fn new_from_list(display_list: BuiltDisplayList) -> Self { + let mut cache = DisplayItemCache::new(); + cache.update(&display_list); + + DisplayListWithCache { + display_list, + cache + } + } + + pub fn update(&mut self, display_list: BuiltDisplayList) { + self.cache.update(&display_list); + self.display_list = display_list; + } + + pub fn descriptor(&self) -> &BuiltDisplayListDescriptor { + self.display_list.descriptor() + } + + pub fn data(&self) -> &[u8] { + self.display_list.data() + } +} + +#[cfg(feature = "serialize")] +impl Serialize for DisplayListWithCache { + fn serialize( + &self, + serializer: S + ) -> Result { + BuiltDisplayList::serialize_with_iterator(serializer, self.iter()) + } +} + +#[cfg(feature = "deserialize")] +impl<'de> Deserialize<'de> for DisplayListWithCache { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let display_list = BuiltDisplayList::deserialize(deserializer)?; + let cache = DisplayItemCache::new(); + + Ok(DisplayListWithCache { + display_list, + cache, + }) + } +} + impl BuiltDisplayListDescriptor {} pub struct BuiltDisplayListIter<'a> { @@ -352,6 +413,92 @@ impl BuiltDisplayList { pub fn cache_size(&self) -> usize { self.descriptor.cache_size } + + #[cfg(feature = "serialize")] + pub fn serialize_with_iterator( + serializer: S, + mut iterator: BuiltDisplayListIter, + ) -> Result { + use crate::display_item::DisplayItem as Real; + use crate::display_item::DebugDisplayItem as Debug; + + let mut seq = serializer.serialize_seq(None)?; + + while let Some(item) = iterator.next_raw() { + let serial_di = match *item.item() { + Real::Clip(v) => Debug::Clip( + v, + item.iter.cur_complex_clip.iter().collect() + ), + Real::ClipChain(v) => Debug::ClipChain( + v, + item.iter.cur_clip_chain_items.iter().collect() + ), + Real::ScrollFrame(v) => Debug::ScrollFrame( + v, + item.iter.cur_complex_clip.iter().collect() + ), + Real::Text(v) => Debug::Text( + v, + item.iter.cur_glyphs.iter().collect() + ), + Real::SetFilterOps => Debug::SetFilterOps( + item.iter.cur_filters.iter().collect() + ), + Real::SetFilterData => { + debug_assert!(!item.iter.cur_filter_data.is_empty(), + "next_raw should have populated cur_filter_data"); + let temp_filter_data = &item.iter.cur_filter_data[item.iter.cur_filter_data.len()-1]; + + let func_types: Vec = + temp_filter_data.func_types.iter().collect(); + debug_assert!(func_types.len() == 4, + "someone changed the number of filter funcs without updating this code"); + Debug::SetFilterData(di::FilterData { + func_r_type: func_types[0], + r_values: temp_filter_data.r_values.iter().collect(), + func_g_type: func_types[1], + g_values: temp_filter_data.g_values.iter().collect(), + func_b_type: func_types[2], + b_values: temp_filter_data.b_values.iter().collect(), + func_a_type: func_types[3], + a_values: temp_filter_data.a_values.iter().collect(), + }) + }, + Real::SetFilterPrimitives => Debug::SetFilterPrimitives( + item.iter.cur_filter_primitives.iter().collect() + ), + Real::SetGradientStops => Debug::SetGradientStops( + item.iter.cur_stops.iter().collect() + ), + Real::StickyFrame(v) => Debug::StickyFrame(v), + Real::Rectangle(v) => Debug::Rectangle(v), + Real::ClearRectangle(v) => Debug::ClearRectangle(v), + Real::HitTest(v) => Debug::HitTest(v), + Real::Line(v) => Debug::Line(v), + Real::Image(v) => Debug::Image(v), + Real::RepeatingImage(v) => Debug::RepeatingImage(v), + Real::YuvImage(v) => Debug::YuvImage(v), + Real::Border(v) => Debug::Border(v), + Real::BoxShadow(v) => Debug::BoxShadow(v), + Real::Gradient(v) => Debug::Gradient(v), + Real::RadialGradient(v) => Debug::RadialGradient(v), + Real::ConicGradient(v) => Debug::ConicGradient(v), + Real::Iframe(v) => Debug::Iframe(v), + Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v), + Real::PushStackingContext(v) => Debug::PushStackingContext(v), + Real::PushShadow(v) => Debug::PushShadow(v), + Real::BackdropFilter(v) => Debug::BackdropFilter(v), + + Real::PopReferenceFrame => Debug::PopReferenceFrame, + Real::PopStackingContext => Debug::PopStackingContext, + Real::PopAllShadows => Debug::PopAllShadows, + Real::ReuseItem(_) => unreachable!("Unexpected item"), + }; + seq.serialize_element(&serial_di)? + } + seq.end() + } } /// Returns the byte-range the slice occupied. @@ -616,89 +763,13 @@ impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> { impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {} - #[cfg(feature = "serialize")] impl Serialize for BuiltDisplayList { - fn serialize(&self, serializer: S) -> Result { - use crate::display_item::DisplayItem as Real; - use crate::display_item::DebugDisplayItem as Debug; - - let mut seq = serializer.serialize_seq(None)?; - let mut traversal = self.iter(); - while let Some(item) = traversal.next_raw() { - let serial_di = match *item.item() { - Real::Clip(v) => Debug::Clip( - v, - item.iter.cur_complex_clip.iter().collect() - ), - Real::ClipChain(v) => Debug::ClipChain( - v, - item.iter.cur_clip_chain_items.iter().collect() - ), - Real::ScrollFrame(v) => Debug::ScrollFrame( - v, - item.iter.cur_complex_clip.iter().collect() - ), - Real::Text(v) => Debug::Text( - v, - item.iter.cur_glyphs.iter().collect() - ), - Real::SetFilterOps => Debug::SetFilterOps( - item.iter.cur_filters.iter().collect() - ), - Real::SetFilterData => { - debug_assert!(!item.iter.cur_filter_data.is_empty(), - "next_raw should have populated cur_filter_data"); - let temp_filter_data = &item.iter.cur_filter_data[item.iter.cur_filter_data.len()-1]; - - let func_types: Vec = - temp_filter_data.func_types.iter().collect(); - debug_assert!(func_types.len() == 4, - "someone changed the number of filter funcs without updating this code"); - Debug::SetFilterData(di::FilterData { - func_r_type: func_types[0], - r_values: temp_filter_data.r_values.iter().collect(), - func_g_type: func_types[1], - g_values: temp_filter_data.g_values.iter().collect(), - func_b_type: func_types[2], - b_values: temp_filter_data.b_values.iter().collect(), - func_a_type: func_types[3], - a_values: temp_filter_data.a_values.iter().collect(), - }) - }, - Real::SetFilterPrimitives => Debug::SetFilterPrimitives( - item.iter.cur_filter_primitives.iter().collect() - ), - Real::SetGradientStops => Debug::SetGradientStops( - item.iter.cur_stops.iter().collect() - ), - Real::StickyFrame(v) => Debug::StickyFrame(v), - Real::Rectangle(v) => Debug::Rectangle(v), - Real::ClearRectangle(v) => Debug::ClearRectangle(v), - Real::HitTest(v) => Debug::HitTest(v), - Real::Line(v) => Debug::Line(v), - Real::Image(v) => Debug::Image(v), - Real::RepeatingImage(v) => Debug::RepeatingImage(v), - Real::YuvImage(v) => Debug::YuvImage(v), - Real::Border(v) => Debug::Border(v), - Real::BoxShadow(v) => Debug::BoxShadow(v), - Real::Gradient(v) => Debug::Gradient(v), - Real::RadialGradient(v) => Debug::RadialGradient(v), - Real::ConicGradient(v) => Debug::ConicGradient(v), - Real::Iframe(v) => Debug::Iframe(v), - Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v), - Real::PushStackingContext(v) => Debug::PushStackingContext(v), - Real::PushShadow(v) => Debug::PushShadow(v), - Real::BackdropFilter(v) => Debug::BackdropFilter(v), - - Real::PopReferenceFrame => Debug::PopReferenceFrame, - Real::PopStackingContext => Debug::PopStackingContext, - Real::PopAllShadows => Debug::PopAllShadows, - Real::ReuseItem(k) => Debug::ReuseItem(k), - }; - seq.serialize_element(&serial_di)? - } - seq.end() + fn serialize( + &self, + serializer: S + ) -> Result { + Self::serialize_with_iterator(serializer, self.iter()) } } @@ -708,10 +779,9 @@ impl Serialize for BuiltDisplayList { #[cfg(feature = "deserialize")] impl<'de> Deserialize<'de> for BuiltDisplayList { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { + fn deserialize>( + deserializer: D + ) -> Result { use crate::display_item::DisplayItem as Real; use crate::display_item::DebugDisplayItem as Debug; @@ -799,7 +869,7 @@ impl<'de> Deserialize<'de> for BuiltDisplayList { Debug::PopStackingContext => Real::PopStackingContext, Debug::PopReferenceFrame => Real::PopReferenceFrame, Debug::PopAllShadows => Real::PopAllShadows, - Debug::ReuseItem(k) => Real::ReuseItem(k), + Debug::ReuseItem(_) => unreachable!("Unexpected item"), }; poke_into_vec(&item, &mut data); // the aux data is serialized after the item, hence the temporary