diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs index c4d3680747d0..61a34e0a047e 100644 --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -542,6 +542,116 @@ impl AlphaBatchBuilder { .map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id)); match prim_instance.kind { + PrimitiveInstanceKind::TextRun { ref run, .. } => { + let subpx_dir = run.used_font.get_subpx_dir(); + + // The GPU cache data is stored in the template and reused across + // frames and display lists. + let prim_data = &ctx + .resources + .prim_data_store[prim_instance.prim_data_handle]; + + let glyph_fetch_buffer = &mut self.glyph_fetch_buffer; + let alpha_batch_list = &mut self.batch_list.alpha_batch_list; + let prim_cache_address = gpu_cache.get_address(&prim_data.gpu_cache_handle); + + let prim_header = PrimitiveHeader { + local_rect: prim_data.prim_rect, + local_clip_rect: prim_instance.combined_local_clip_rect, + task_address, + specific_prim_address: prim_cache_address, + clip_task_address, + transform_id, + }; + + ctx.resource_cache.fetch_glyphs( + run.used_font.clone(), + &run.glyph_keys, + glyph_fetch_buffer, + gpu_cache, + |texture_id, mut glyph_format, glyphs| { + debug_assert_ne!(texture_id, TextureSource::Invalid); + + // Ignore color and only sample alpha when shadowing. + if run.shadow { + glyph_format = glyph_format.ignore_color(); + } + + let subpx_dir = subpx_dir.limit_by(glyph_format); + + let textures = BatchTextures { + colors: [ + texture_id, + TextureSource::Invalid, + TextureSource::Invalid, + ], + }; + + let kind = BatchKind::TextRun(glyph_format); + + let (blend_mode, color_mode) = match glyph_format { + GlyphFormat::Subpixel | + GlyphFormat::TransformedSubpixel => { + if run.used_font.bg_color.a != 0 { + ( + BlendMode::SubpixelWithBgColor, + ShaderColorMode::FromRenderPassMode, + ) + } else if ctx.use_dual_source_blending { + ( + BlendMode::SubpixelDualSource, + ShaderColorMode::SubpixelDualSource, + ) + } else { + ( + BlendMode::SubpixelConstantTextColor(run.used_font.color.into()), + ShaderColorMode::SubpixelConstantTextColor, + ) + } + } + GlyphFormat::Alpha | + GlyphFormat::TransformedAlpha => { + ( + BlendMode::PremultipliedAlpha, + ShaderColorMode::Alpha, + ) + } + GlyphFormat::Bitmap => { + ( + BlendMode::PremultipliedAlpha, + ShaderColorMode::Bitmap, + ) + } + GlyphFormat::ColorBitmap => { + ( + BlendMode::PremultipliedAlpha, + ShaderColorMode::ColorBitmap, + ) + } + }; + + let prim_header_index = prim_headers.push(&prim_header, z_id, [0; 3]); + let key = BatchKey::new(kind, blend_mode, textures); + let base_instance = GlyphInstance::new( + prim_header_index, + ); + let batch = alpha_batch_list.set_params_and_get_batch( + key, + bounding_rect, + z_id, + ); + + for glyph in glyphs { + batch.push(base_instance.build( + glyph.index_in_text_run, + glyph.uv_rect_address.as_int(), + (subpx_dir as u32 as i32) << 16 | + (color_mode as u32 as i32), + )); + } + }, + ); + } PrimitiveInstanceKind::LineDecoration { ref cache_handle, .. } => { // The GPU cache data is stored in the template and reused across // frames and display lists. @@ -654,6 +764,7 @@ impl AlphaBatchBuilder { let pic_index = match prim_instance.kind { PrimitiveInstanceKind::Picture { pic_index } => pic_index, PrimitiveInstanceKind::LineDecoration { .. } | + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LegacyPrimitive { .. } => { unreachable!(); } @@ -1055,7 +1166,6 @@ impl AlphaBatchBuilder { _ => false, } } - _ => false, }; let prim_cache_address = if is_multiple_primitives { @@ -1185,102 +1295,7 @@ impl AlphaBatchBuilder { } } } - PrimitiveDetails::TextRun(ref text_cpu) => { - let subpx_dir = text_cpu.used_font.get_subpx_dir(); - - let glyph_fetch_buffer = &mut self.glyph_fetch_buffer; - let alpha_batch_list = &mut self.batch_list.alpha_batch_list; - - ctx.resource_cache.fetch_glyphs( - text_cpu.used_font.clone(), - &text_cpu.glyph_keys, - glyph_fetch_buffer, - gpu_cache, - |texture_id, mut glyph_format, glyphs| { - debug_assert_ne!(texture_id, TextureSource::Invalid); - - // Ignore color and only sample alpha when shadowing. - if text_cpu.shadow { - glyph_format = glyph_format.ignore_color(); - } - - let subpx_dir = subpx_dir.limit_by(glyph_format); - - let textures = BatchTextures { - colors: [ - texture_id, - TextureSource::Invalid, - TextureSource::Invalid, - ], - }; - - let kind = BatchKind::TextRun(glyph_format); - - let (blend_mode, color_mode) = match glyph_format { - GlyphFormat::Subpixel | - GlyphFormat::TransformedSubpixel => { - if text_cpu.used_font.bg_color.a != 0 { - ( - BlendMode::SubpixelWithBgColor, - ShaderColorMode::FromRenderPassMode, - ) - } else if ctx.use_dual_source_blending { - ( - BlendMode::SubpixelDualSource, - ShaderColorMode::SubpixelDualSource, - ) - } else { - ( - BlendMode::SubpixelConstantTextColor(text_cpu.used_font.color.into()), - ShaderColorMode::SubpixelConstantTextColor, - ) - } - } - GlyphFormat::Alpha | - GlyphFormat::TransformedAlpha => { - ( - BlendMode::PremultipliedAlpha, - ShaderColorMode::Alpha, - ) - } - GlyphFormat::Bitmap => { - ( - BlendMode::PremultipliedAlpha, - ShaderColorMode::Bitmap, - ) - } - GlyphFormat::ColorBitmap => { - ( - BlendMode::PremultipliedAlpha, - ShaderColorMode::ColorBitmap, - ) - } - }; - - let prim_header_index = prim_headers.push(&prim_header, z_id, [0; 3]); - let key = BatchKey::new(kind, blend_mode, textures); - let base_instance = GlyphInstance::new( - prim_header_index, - ); - let batch = alpha_batch_list.set_params_and_get_batch( - key, - bounding_rect, - z_id, - ); - - for glyph in glyphs { - batch.push(base_instance.build( - glyph.index_in_text_run, - glyph.uv_rect_address.as_int(), - (subpx_dir as u32 as i32) << 16 | - (color_mode as u32 as i32), - )); - } - }, - ); - } } - } } } @@ -1807,11 +1822,6 @@ impl PrimitiveInstance { details: &PrimitiveDetails, ) -> BlendMode { match *details { - // Can only resolve the TextRun's blend mode once glyphs are fetched. - PrimitiveDetails::TextRun(..) => { - BlendMode::PremultipliedAlpha - } - PrimitiveDetails::Brush(ref brush) => { match brush.kind { BrushKind::Clear => { @@ -1847,8 +1857,7 @@ impl PrimitiveInstance { PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::YuvImage{ yuv_key, .. }, .. }) => { yuv_key[0] } - PrimitiveDetails::Brush(_) | - PrimitiveDetails::TextRun(..) => { + PrimitiveDetails::Brush(_) => { return true } }; diff --git a/gfx/webrender/src/display_list_flattener.rs b/gfx/webrender/src/display_list_flattener.rs index b6dd6fb23779..caa3413584dd 100644 --- a/gfx/webrender/src/display_list_flattener.rs +++ b/gfx/webrender/src/display_list_flattener.rs @@ -27,7 +27,7 @@ use picture::{Picture3DContext, PictureCompositeMode, PictureIdGenerator, Pictur use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind}; use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveOpacity, PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind}; use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveDataHandle, PrimitiveStore}; -use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive, PictureIndex, register_prim_chase_id}; +use prim_store::{OpacityBinding, ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id}; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; use scene::{Scene, ScenePipeline, StackingContextHelpers}; @@ -553,6 +553,7 @@ impl<'a> DisplayListFlattener<'a> { &text_info.color, item.glyphs(), text_info.glyph_options, + pipeline_id, ); } SpecificDisplayItem::Rectangle(ref info) => { @@ -2062,14 +2063,15 @@ impl<'a> DisplayListFlattener<'a> { pub fn add_text( &mut self, clip_and_scroll: ScrollNodeAndClipChain, - run_offset: LayoutVector2D, + offset: LayoutVector2D, prim_info: &LayoutPrimitiveInfo, font_instance_key: &FontInstanceKey, text_color: &ColorF, glyph_range: ItemRange, glyph_options: Option, + pipeline_id: PipelineId, ) { - let prim = { + let container = { let instance_map = self.font_instances.read().unwrap(); let font_instance = match instance_map.get(font_instance_key) { Some(instance) => instance, @@ -2097,7 +2099,7 @@ impl<'a> DisplayListFlattener<'a> { flags |= options.flags; } - let prim_font = FontInstance::new( + let font = FontInstance::new( font_instance.font_key, font_instance.size, *text_color, @@ -2108,20 +2110,29 @@ impl<'a> DisplayListFlattener<'a> { font_instance.platform_options, font_instance.variations.clone(), ); - TextRunPrimitive::new( - prim_font, - run_offset, - glyph_range, - Vec::new(), - false, - ) + + // TODO(gw): We can do better than a hash lookup here... + let display_list = self.scene.get_display_list_for_pipeline(pipeline_id); + + // TODO(gw): It'd be nice not to have to allocate here for creating + // the primitive key, when the common case is that the + // hash will match and we won't end up creating a new + // primitive template. + let glyphs = display_list.get(glyph_range).collect(); + + PrimitiveContainer::TextRun { + glyphs, + font, + offset, + shadow: false, + } }; self.add_primitive( clip_and_scroll, prim_info, Vec::new(), - PrimitiveContainer::TextRun(prim), + container, ); } diff --git a/gfx/webrender/src/gpu_cache.rs b/gfx/webrender/src/gpu_cache.rs index ee2405c2beb7..4ba82e1bd51a 100644 --- a/gfx/webrender/src/gpu_cache.rs +++ b/gfx/webrender/src/gpu_cache.rs @@ -512,10 +512,6 @@ impl<'a> GpuDataRequest<'a> { self.texture.pending_blocks.push(block.into()); } - pub fn extend_from_slice(&mut self, blocks: &[GpuBlockData]) { - self.texture.pending_blocks.extend_from_slice(blocks); - } - pub fn current_used_block_num(&self) -> usize { self.texture.pending_blocks.len() - self.start_index } diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index 318c38b91ba9..5b03ef969b57 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -8,7 +8,7 @@ use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemR use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, LayoutToWorldTransform}; use api::{LayoutVector2D, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat, LayoutRectAu}; use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale}; -use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers}; +use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers, LayoutVector2DAu}; use app_units::Au; use border::{get_max_scale_for_border, build_border_instances, create_normal_border_prim}; use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, SpatialNodeIndex}; @@ -17,8 +17,7 @@ use euclid::{TypedTransform3D, TypedRect, TypedScale}; use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState}; use frame_builder::PrimitiveContext; use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT}; -use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, - ToGpuBlocks}; +use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_types::BrushFlags; use image::{self, Repetition}; use intern; @@ -26,7 +25,7 @@ use picture::{ClusterRange, PictureCompositeMode, PicturePrimitive, PictureUpdat use picture::{PrimitiveList, SurfaceInfo}; #[cfg(debug_assertions)] use render_backend::FrameId; -use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, to_cache_size}; +use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskTree, to_cache_size}; use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle}; use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use resource_cache::{ImageProperties, ImageRequest, ResourceCache}; @@ -34,6 +33,7 @@ use scene::SceneProperties; use std::{cmp, fmt, mem, ops, usize}; #[cfg(debug_assertions)] use std::sync::atomic::{AtomicUsize, Ordering}; +use tiling::SpecialRenderPasses; use util::{ScaleOffset, MatrixHelpers, MaxRect}; use util::{pack_as_float, project_rect, raster_rect_to_device_pixels}; use smallvec::SmallVec; @@ -314,6 +314,13 @@ pub enum PrimitiveKeyKind { /// to instead have Option. It should become /// clearer as we port more primitives to be interned. Unused, + /// A run of glyphs, with associated font information. + TextRun { + font: FontInstance, + offset: LayoutVector2DAu, + glyphs: Vec, + shadow: bool, + }, /// Identifying key for a line decoration. LineDecoration { // If the cache_key is Some(..) it is a line decoration @@ -359,6 +366,15 @@ impl PrimitiveKey { cache_handle: None, } } + PrimitiveKeyKind::TextRun { ref font, shadow, .. } => { + PrimitiveInstanceKind::TextRun { + run: TextRunPrimitive { + used_font: font.clone(), + glyph_keys: Vec::new(), + shadow, + } + } + } PrimitiveKeyKind::Unused => { // Should never be hit as this method should not be // called for old style primitives. @@ -377,6 +393,11 @@ pub enum PrimitiveTemplateKind { cache_key: Option, color: ColorF, }, + TextRun { + font: FontInstance, + offset: LayoutVector2DAu, + glyphs: Vec, + }, Unused, } @@ -387,6 +408,13 @@ impl From for PrimitiveTemplateKind { fn from(item: PrimitiveKeyKind) -> Self { match item { PrimitiveKeyKind::Unused => PrimitiveTemplateKind::Unused, + PrimitiveKeyKind::TextRun { glyphs, font, offset, .. } => { + PrimitiveTemplateKind::TextRun { + font, + offset, + glyphs, + } + } PrimitiveKeyKind::LineDecoration { cache_key, color } => { PrimitiveTemplateKind::LineDecoration { cache_key, @@ -460,6 +488,42 @@ impl PrimitiveTemplate { ); } } + PrimitiveTemplateKind::TextRun { ref glyphs, ref font, ref offset, .. } => { + if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) { + request.push(ColorF::from(font.color).premultiplied()); + // this is the only case where we need to provide plain color to GPU + let bg_color = ColorF::from(font.bg_color); + request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]); + request.push([ + offset.x.to_f32_px(), + offset.y.to_f32_px(), + 0.0, + 0.0, + ]); + + let mut gpu_block = [0.0; 4]; + for (i, src) in glyphs.iter().enumerate() { + // Two glyphs are packed per GPU block. + + if (i & 1) == 0 { + gpu_block[0] = src.point.x; + gpu_block[1] = src.point.y; + } else { + gpu_block[2] = src.point.x; + gpu_block[3] = src.point.y; + request.push(gpu_block); + } + } + + // Ensure the last block is added in the case + // of an odd number of glyphs. + if (glyphs.len() & 1) != 0 { + request.push(gpu_block); + } + + assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH); + } + } PrimitiveTemplateKind::Unused => {} } } @@ -1129,43 +1193,22 @@ impl<'a> GradientGpuBlockBuilder<'a> { #[derive(Debug, Clone)] pub struct TextRunPrimitive { - pub specified_font: FontInstance, pub used_font: FontInstance, - pub offset: LayoutVector2D, - pub glyph_range: ItemRange, pub glyph_keys: Vec, - pub glyph_gpu_blocks: Vec, pub shadow: bool, } impl TextRunPrimitive { - pub fn new( - font: FontInstance, - offset: LayoutVector2D, - glyph_range: ItemRange, - glyph_keys: Vec, - shadow: bool, - ) -> Self { - TextRunPrimitive { - specified_font: font.clone(), - used_font: font, - offset, - glyph_range, - glyph_keys, - glyph_gpu_blocks: Vec::new(), - shadow, - } - } - pub fn update_font_instance( &mut self, + specified_font: &FontInstance, device_pixel_scale: DevicePixelScale, transform: &LayoutToWorldTransform, allow_subpixel_aa: bool, raster_space: RasterSpace, ) -> bool { // Get the current font size in device pixels - let device_font_size = self.specified_font.size.scale_by(device_pixel_scale.0); + let device_font_size = specified_font.size.scale_by(device_pixel_scale.0); // Determine if rasterizing glyphs in local or screen space. // Only support transforms that can be coerced to simple 2D transforms. @@ -1198,13 +1241,13 @@ impl TextRunPrimitive { self.used_font = FontInstance { transform: font_transform, size: device_font_size, - ..self.specified_font.clone() + ..specified_font.clone() }; // If subpixel AA is disabled due to the backing surface the glyphs // are being drawn onto, disable it (unless we are using the // specifial subpixel mode that estimates background color). - if !allow_subpixel_aa && self.specified_font.bg_color.a == 0 { + if !allow_subpixel_aa && self.used_font.bg_color.a == 0 { self.used_font.disable_subpixel_aa(); } @@ -1220,79 +1263,43 @@ impl TextRunPrimitive { fn prepare_for_render( &mut self, + specified_font: &FontInstance, + glyphs: &[GlyphInstance], device_pixel_scale: DevicePixelScale, transform: &LayoutToWorldTransform, allow_subpixel_aa: bool, raster_space: RasterSpace, - display_list: &BuiltDisplayList, - frame_building_state: &mut FrameBuildingState, + resource_cache: &mut ResourceCache, + gpu_cache: &mut GpuCache, + render_tasks: &mut RenderTaskTree, + special_render_passes: &mut SpecialRenderPasses, ) { let cache_dirty = self.update_font_instance( + specified_font, device_pixel_scale, transform, allow_subpixel_aa, raster_space, ); - // Cache the glyph positions, if not in the cache already. - // TODO(gw): In the future, remove `glyph_instances` - // completely, and just reference the glyphs - // directly from the display list. if self.glyph_keys.is_empty() || cache_dirty { let subpx_dir = self.used_font.get_subpx_dir(); - let src_glyphs = display_list.get(self.glyph_range); - // TODO(gw): If we support chunks() on AuxIter - // in the future, this code below could - // be much simpler... - let mut gpu_block = [0.0; 4]; - for (i, src) in src_glyphs.enumerate() { + for src in glyphs { let world_offset = self.used_font.transform.transform(&src.point); let device_offset = device_pixel_scale.transform_point(&world_offset); let key = GlyphKey::new(src.index, device_offset, subpx_dir); self.glyph_keys.push(key); - - // Two glyphs are packed per GPU block. - - if (i & 1) == 0 { - gpu_block[0] = src.point.x; - gpu_block[1] = src.point.y; - } else { - gpu_block[2] = src.point.x; - gpu_block[3] = src.point.y; - self.glyph_gpu_blocks.push(gpu_block.into()); - } - } - - // Ensure the last block is added in the case - // of an odd number of glyphs. - if (self.glyph_keys.len() & 1) != 0 { - self.glyph_gpu_blocks.push(gpu_block.into()); } } - frame_building_state.resource_cache - .request_glyphs(self.used_font.clone(), - &self.glyph_keys, - frame_building_state.gpu_cache, - frame_building_state.render_tasks, - frame_building_state.special_render_passes); - } - - fn write_gpu_blocks(&self, request: &mut GpuDataRequest) { - request.push(ColorF::from(self.used_font.color).premultiplied()); - // this is the only case where we need to provide plain color to GPU - let bg_color = ColorF::from(self.used_font.bg_color); - request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]); - request.push([ - self.offset.x, - self.offset.y, - 0.0, - 0.0, - ]); - request.extend_from_slice(&self.glyph_gpu_blocks); - - assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH); + resource_cache.request_glyphs( + self.used_font.clone(), + &self.glyph_keys, + gpu_cache, + render_tasks, + special_render_passes, + ); } } @@ -1484,7 +1491,12 @@ impl ClipData { } pub enum PrimitiveContainer { - TextRun(TextRunPrimitive), + TextRun { + font: FontInstance, + offset: LayoutVector2D, + glyphs: Vec, + shadow: bool, + }, Brush(BrushPrimitive), LineDecoration { color: ColorF, @@ -1504,8 +1516,8 @@ impl PrimitiveContainer { // primitive types to use this. pub fn is_visible(&self) -> bool { match *self { - PrimitiveContainer::TextRun(ref info) => { - info.specified_font.color.a > 0 + PrimitiveContainer::TextRun { ref font, .. } => { + font.color.a > 0 } PrimitiveContainer::Brush(ref brush) => { match brush.kind { @@ -1535,8 +1547,15 @@ impl PrimitiveContainer { info: &mut LayoutPrimitiveInfo, ) -> (PrimitiveKeyKind, Option) { match self { - PrimitiveContainer::TextRun(prim) => { - (PrimitiveKeyKind::Unused, Some(PrimitiveDetails::TextRun(prim))) + PrimitiveContainer::TextRun { font, offset, glyphs, shadow, .. } => { + let key = PrimitiveKeyKind::TextRun { + font, + offset: offset.to_au(), + glyphs, + shadow, + }; + + (key, None) } PrimitiveContainer::LineDecoration { color, style, orientation, wavy_line_thickness } => { // For line decorations, we can construct the render task cache key @@ -1612,22 +1631,21 @@ impl PrimitiveContainer { prim_rect: &LayoutRect, ) -> PrimitiveContainer { match *self { - PrimitiveContainer::TextRun(ref info) => { + PrimitiveContainer::TextRun { ref font, offset, ref glyphs, .. } => { let mut font = FontInstance { color: shadow.color.into(), - ..info.specified_font.clone() + ..font.clone() }; if shadow.blur_radius > 0.0 { font.disable_subpixel_aa(); } - PrimitiveContainer::TextRun(TextRunPrimitive::new( + PrimitiveContainer::TextRun { font, - info.offset + shadow.offset, - info.glyph_range, - info.glyph_keys.clone(), - true, - )) + glyphs: glyphs.clone(), + offset: offset + shadow.offset, + shadow: true, + } } PrimitiveContainer::LineDecoration { style, orientation, wavy_line_thickness, .. } => { PrimitiveContainer::LineDecoration { @@ -1688,7 +1706,6 @@ impl PrimitiveContainer { pub enum PrimitiveDetails { Brush(BrushPrimitive), - TextRun(TextRunPrimitive), } pub struct Primitive { @@ -1713,6 +1730,10 @@ pub enum PrimitiveInstanceKind { LegacyPrimitive { prim_index: PrimitiveIndex, }, + /// A run of glyphs, with associated font parameters. + TextRun { + run: TextRunPrimitive, + }, /// A line decoration. cache_handle refers to a cached render /// task handle, if this line decoration is not a simple solid. LineDecoration { @@ -1912,6 +1933,7 @@ impl PrimitiveStore { // handled by this optimization. In the future, we can easily extend // this to other primitives, such as text runs and gradients. match prim_instance.kind { + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { // TODO: Once rectangles and/or images are ported // to use interned primitives, we will need @@ -1944,7 +1966,6 @@ impl PrimitiveStore { BrushKind::Clear => {} } } - PrimitiveDetails::TextRun(..) => {} } } } @@ -1993,9 +2014,6 @@ impl PrimitiveStore { } } } - PrimitiveDetails::TextRun(..) => { - unreachable!("bug: invalid prim type for opacity collapse"); - } } } None => { @@ -2054,6 +2072,7 @@ impl PrimitiveStore { } } } + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::LegacyPrimitive { .. } => { None @@ -2107,6 +2126,7 @@ impl PrimitiveStore { let pic = &self.pictures[pic_index.0]; (pic.local_rect, LayoutRect::max_rect()) } + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { let prim_data = &frame_state .resources @@ -2277,8 +2297,11 @@ impl PrimitiveStore { ); } } + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { prim_instance.prepare_interned_prim_for_render( + prim_context, + pic_context, pic_state, frame_context, frame_state, @@ -2291,7 +2314,6 @@ impl PrimitiveStore { prim_local_rect, prim_details, prim_context, - pic_context, pic_state, frame_context, frame_state, @@ -2705,6 +2727,7 @@ impl PrimitiveInstance { ) -> bool { let brush = match self.kind { PrimitiveInstanceKind::Picture { .. } | + PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { return false; } @@ -2712,7 +2735,6 @@ impl PrimitiveInstance { let prim = &mut primitives[prim_index.0]; match prim.details { PrimitiveDetails::Brush(ref mut brush) => brush, - PrimitiveDetails::TextRun(..) => return false, } } }; @@ -2791,6 +2813,8 @@ impl PrimitiveInstance { /// prepare_prim_for_render_inner call for old style primitives. fn prepare_interned_prim_for_render( &mut self, + prim_context: &PrimitiveContext, + pic_context: &PictureContext, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, @@ -2805,10 +2829,15 @@ impl PrimitiveInstance { frame_state.gpu_cache, ); - self.opacity = match prim_data.kind { - PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } => { + let is_chased = self.is_chased(); + + self.opacity = match (&mut self.kind, &mut prim_data.kind) { + ( + PrimitiveInstanceKind::LineDecoration { ref mut cache_handle, .. }, + PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } + ) => { // Work out the device pixel size to be used to cache this line decoration. - if self.is_chased() { + if is_chased { println!("\tline decoration opaque={}, key={:?}", self.opacity.is_opaque, cache_key); } @@ -2826,36 +2855,28 @@ impl PrimitiveInstance { // once the prepare_prims and batching are unified. When that // happens, we can use the cache handle immediately, and not need // to temporarily store it in the primitive instance. - match self.kind { - PrimitiveInstanceKind::LineDecoration { ref mut cache_handle, .. } => { - *cache_handle = Some(frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size: task_size, - kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()), - }, - frame_state.gpu_cache, - frame_state.render_tasks, - None, - false, - |render_tasks| { - let task = RenderTask::new_line_decoration( - task_size, - cache_key.style, - cache_key.orientation, - cache_key.wavy_line_thickness.to_f32_px(), - LayoutSize::from_au(cache_key.size), - ); - let task_id = render_tasks.add(task); - pic_state.tasks.push(task_id); - task_id - } - )); + *cache_handle = Some(frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size: task_size, + kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()), + }, + frame_state.gpu_cache, + frame_state.render_tasks, + None, + false, + |render_tasks| { + let task = RenderTask::new_line_decoration( + task_size, + cache_key.style, + cache_key.orientation, + cache_key.wavy_line_thickness.to_f32_px(), + LayoutSize::from_au(cache_key.size), + ); + let task_id = render_tasks.add(task); + pic_state.tasks.push(task_id); + task_id } - PrimitiveInstanceKind::LegacyPrimitive { .. } | - PrimitiveInstanceKind::Picture { .. } => { - unreachable!(); - } - } + )); PrimitiveOpacity::translucent() } @@ -2864,7 +2885,33 @@ impl PrimitiveInstance { } } } - PrimitiveTemplateKind::Unused => { + ( + PrimitiveInstanceKind::TextRun { ref mut run, .. }, + PrimitiveTemplateKind::TextRun { ref font, ref glyphs, .. } + ) => { + // The transform only makes sense for screen space rasterization + let transform = prim_context.spatial_node.world_content_transform.to_transform(); + + // TODO(gw): This match is a bit untidy, but it should disappear completely + // once the prepare_prims and batching are unified. When that + // happens, we can use the cache handle immediately, and not need + // to temporarily store it in the primitive instance. + run.prepare_for_render( + font, + glyphs, + frame_context.device_pixel_scale, + &transform, + pic_context.allow_subpixel_aa, + pic_context.raster_space, + frame_state.resource_cache, + frame_state.gpu_cache, + frame_state.render_tasks, + frame_state.special_render_passes, + ); + + PrimitiveOpacity::translucent() + } + _ => { unreachable!(); } }; @@ -2875,7 +2922,6 @@ impl PrimitiveInstance { prim_local_rect: LayoutRect, prim_details: &mut PrimitiveDetails, prim_context: &PrimitiveContext, - pic_context: &PictureContext, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, @@ -2889,19 +2935,6 @@ impl PrimitiveInstance { ); 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(); - text.prepare_for_render( - frame_context.device_pixel_scale, - &transform, - pic_context.allow_subpixel_aa, - pic_context.raster_space, - display_list, - frame_state, - ); - PrimitiveOpacity::translucent() - } PrimitiveDetails::Brush(ref mut brush) => { match brush.kind { BrushKind::Image { @@ -3329,9 +3362,6 @@ impl PrimitiveInstance { let is_chased = self.is_chased(); if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_location) { match *prim_details { - PrimitiveDetails::TextRun(ref mut text) => { - text.write_gpu_blocks(&mut request); - } PrimitiveDetails::Brush(ref mut brush) => { brush.write_gpu_blocks(&mut request, prim_local_rect); diff --git a/gfx/webrender_api/src/font.rs b/gfx/webrender_api/src/font.rs index de502d28462c..ed37cc779093 100644 --- a/gfx/webrender_api/src/font.rs +++ b/gfx/webrender_api/src/font.rs @@ -376,3 +376,13 @@ pub struct GlyphInstance { pub point: LayoutPoint, } +impl Eq for GlyphInstance {} + +impl Hash for GlyphInstance { + fn hash(&self, state: &mut H) { + // Note: this is inconsistent with the Eq impl for -0.0 (don't care). + self.index.hash(state); + self.point.x.to_bits().hash(state); + self.point.y.to_bits().hash(state); + } +} diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index b4181f9a91e8..d38cc7a5d81c 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -347e66c2aa117724ac6b0f391b346f9c6898ad11 +d30fda15ac69d3d421c7307f77f2b5b9c0a1b4ce