borders.rs (11674B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use api::{NormalBorder, PremultipliedColorF, Shadow, RasterSpace}; 6 use api::units::*; 7 use crate::border::create_border_segments; 8 use crate::border::NormalBorderAu; 9 use crate::gpu_types::ImageBrushPrimitiveData; 10 use crate::renderer::GpuBufferWriterF; 11 use crate::scene_building::{CreateShadow, IsVisible}; 12 use crate::frame_builder::FrameBuildingState; 13 use crate::intern; 14 use crate::internal_types::{LayoutPrimitiveInfo, FrameId}; 15 use crate::prim_store::{ 16 BorderSegmentInfo, BrushSegment, InternablePrimitive, NinePatchDescriptor, PrimKey, PrimTemplate, PrimTemplateCommonData, PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveStore, VECS_PER_SEGMENT 17 }; 18 use crate::resource_cache::ImageRequest; 19 use crate::render_task::RenderTask; 20 use crate::render_task_graph::RenderTaskId; 21 22 use super::storage; 23 24 #[cfg_attr(feature = "capture", derive(Serialize))] 25 #[cfg_attr(feature = "replay", derive(Deserialize))] 26 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] 27 pub struct NormalBorderPrim { 28 pub border: NormalBorderAu, 29 pub widths: LayoutSideOffsetsAu, 30 } 31 32 pub type NormalBorderKey = PrimKey<NormalBorderPrim>; 33 34 impl NormalBorderKey { 35 pub fn new( 36 info: &LayoutPrimitiveInfo, 37 normal_border: NormalBorderPrim, 38 ) -> Self { 39 NormalBorderKey { 40 common: info.into(), 41 kind: normal_border, 42 } 43 } 44 } 45 46 impl intern::InternDebug for NormalBorderKey {} 47 48 #[cfg_attr(feature = "capture", derive(Serialize))] 49 #[cfg_attr(feature = "replay", derive(Deserialize))] 50 #[derive(MallocSizeOf)] 51 pub struct NormalBorderData { 52 pub brush_segments: Vec<BrushSegment>, 53 pub border_segments: Vec<BorderSegmentInfo>, 54 pub border: NormalBorder, 55 pub widths: LayoutSideOffsets, 56 } 57 58 impl NormalBorderData { 59 /// Update the GPU cache for a given primitive template. This may be called multiple 60 /// times per frame, by each primitive reference that refers to this interned 61 /// template. The initial request call to the GPU cache ensures that work is only 62 /// done if the cache entry is invalid (due to first use or eviction). 63 pub fn update( 64 &mut self, 65 common: &mut PrimTemplateCommonData, 66 frame_state: &mut FrameBuildingState, 67 ) { 68 let mut writer = frame_state.frame_gpu_data.f32.write_blocks(3 + self.brush_segments.len() * VECS_PER_SEGMENT); 69 self.write_prim_gpu_blocks(&mut writer, common.prim_rect.size()); 70 self.write_segment_gpu_blocks(&mut writer); 71 common.gpu_buffer_address = writer.finish(); 72 common.opacity = PrimitiveOpacity::translucent(); 73 } 74 75 fn write_prim_gpu_blocks( 76 &self, 77 writer: &mut GpuBufferWriterF, 78 prim_size: LayoutSize 79 ) { 80 // Border primitives currently used for 81 // image borders, and run through the 82 // normal brush_image shader. 83 writer.push(&ImageBrushPrimitiveData { 84 color: PremultipliedColorF::WHITE, 85 background_color: PremultipliedColorF::WHITE, 86 stretch_size: prim_size, 87 }); 88 } 89 90 fn write_segment_gpu_blocks( 91 &self, 92 writer: &mut GpuBufferWriterF, 93 ) { 94 for segment in &self.brush_segments { 95 segment.write_gpu_blocks(writer); 96 } 97 } 98 } 99 100 pub type NormalBorderTemplate = PrimTemplate<NormalBorderData>; 101 102 impl From<NormalBorderKey> for NormalBorderTemplate { 103 fn from(key: NormalBorderKey) -> Self { 104 let common = PrimTemplateCommonData::with_key_common(key.common); 105 106 let mut border: NormalBorder = key.kind.border.into(); 107 let widths = LayoutSideOffsets::from_au(key.kind.widths); 108 109 // FIXME(emilio): Is this the best place to do this? 110 border.normalize(&widths); 111 112 let mut brush_segments = Vec::new(); 113 let mut border_segments = Vec::new(); 114 115 create_border_segments( 116 common.prim_rect.size(), 117 &border, 118 &widths, 119 &mut border_segments, 120 &mut brush_segments, 121 ); 122 123 NormalBorderTemplate { 124 common, 125 kind: NormalBorderData { 126 brush_segments, 127 border_segments, 128 border, 129 widths, 130 } 131 } 132 } 133 } 134 135 pub type NormalBorderDataHandle = intern::Handle<NormalBorderPrim>; 136 137 impl intern::Internable for NormalBorderPrim { 138 type Key = NormalBorderKey; 139 type StoreData = NormalBorderTemplate; 140 type InternData = (); 141 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_NORMAL_BORDERS; 142 } 143 144 impl InternablePrimitive for NormalBorderPrim { 145 fn into_key( 146 self, 147 info: &LayoutPrimitiveInfo, 148 ) -> NormalBorderKey { 149 NormalBorderKey::new( 150 info, 151 self, 152 ) 153 } 154 155 fn make_instance_kind( 156 _key: NormalBorderKey, 157 data_handle: NormalBorderDataHandle, 158 _: &mut PrimitiveStore, 159 ) -> PrimitiveInstanceKind { 160 PrimitiveInstanceKind::NormalBorder { 161 data_handle, 162 render_task_ids: storage::Range::empty(), 163 } 164 } 165 } 166 167 impl CreateShadow for NormalBorderPrim { 168 fn create_shadow( 169 &self, 170 shadow: &Shadow, 171 _: bool, 172 _: RasterSpace, 173 ) -> Self { 174 let border = self.border.with_color(shadow.color.into()); 175 NormalBorderPrim { 176 border, 177 widths: self.widths, 178 } 179 } 180 } 181 182 impl IsVisible for NormalBorderPrim { 183 fn is_visible(&self) -> bool { 184 true 185 } 186 } 187 188 //////////////////////////////////////////////////////////////////////////////// 189 190 #[cfg_attr(feature = "capture", derive(Serialize))] 191 #[cfg_attr(feature = "replay", derive(Deserialize))] 192 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)] 193 pub struct ImageBorder { 194 #[ignore_malloc_size_of = "Arc"] 195 pub request: ImageRequest, 196 pub nine_patch: NinePatchDescriptor, 197 } 198 199 pub type ImageBorderKey = PrimKey<ImageBorder>; 200 201 impl ImageBorderKey { 202 pub fn new( 203 info: &LayoutPrimitiveInfo, 204 image_border: ImageBorder, 205 ) -> Self { 206 ImageBorderKey { 207 common: info.into(), 208 kind: image_border, 209 } 210 } 211 } 212 213 impl intern::InternDebug for ImageBorderKey {} 214 215 216 #[cfg_attr(feature = "capture", derive(Serialize))] 217 #[cfg_attr(feature = "replay", derive(Deserialize))] 218 #[derive(MallocSizeOf)] 219 pub struct ImageBorderData { 220 #[ignore_malloc_size_of = "Arc"] 221 pub request: ImageRequest, 222 pub brush_segments: Vec<BrushSegment>, 223 pub src_color: Option<RenderTaskId>, 224 pub frame_id: FrameId, 225 pub is_opaque: bool, 226 } 227 228 impl ImageBorderData { 229 /// Update the GPU cache for a given primitive template. This may be called multiple 230 /// times per frame, by each primitive reference that refers to this interned 231 /// template. The initial request call to the GPU cache ensures that work is only 232 /// done if the cache entry is invalid (due to first use or eviction). 233 pub fn update( 234 &mut self, 235 common: &mut PrimTemplateCommonData, 236 frame_state: &mut FrameBuildingState, 237 ) { 238 let mut writer = frame_state.frame_gpu_data.f32.write_blocks(3 + self.brush_segments.len() * VECS_PER_SEGMENT); 239 self.write_prim_gpu_blocks(&mut writer, &common.prim_rect.size()); 240 self.write_segment_gpu_blocks(&mut writer); 241 common.gpu_buffer_address = writer.finish(); 242 243 let frame_id = frame_state.rg_builder.frame_id(); 244 if self.frame_id != frame_id { 245 self.frame_id = frame_id; 246 247 let size = frame_state.resource_cache.request_image( 248 self.request, 249 &mut frame_state.frame_gpu_data.f32, 250 ); 251 252 let task_id = frame_state.rg_builder.add().init( 253 RenderTask::new_image(size, self.request, false) 254 ); 255 256 self.src_color = Some(task_id); 257 258 let image_properties = frame_state 259 .resource_cache 260 .get_image_properties(self.request.key); 261 262 self.is_opaque = image_properties 263 .map(|properties| properties.descriptor.is_opaque()) 264 .unwrap_or(true); 265 } 266 267 common.opacity = PrimitiveOpacity { is_opaque: self.is_opaque }; 268 } 269 270 fn write_prim_gpu_blocks( 271 &self, 272 writer: &mut GpuBufferWriterF, 273 prim_size: &LayoutSize, 274 ) { 275 // Border primitives currently used for 276 // image borders, and run through the 277 // normal brush_image shader. 278 writer.push(&ImageBrushPrimitiveData { 279 color: PremultipliedColorF::WHITE, 280 background_color: PremultipliedColorF::WHITE, 281 stretch_size: *prim_size, 282 }); 283 } 284 285 fn write_segment_gpu_blocks( 286 &self, 287 writer: &mut GpuBufferWriterF, 288 ) { 289 for segment in &self.brush_segments { 290 segment.write_gpu_blocks(writer); 291 } 292 } 293 } 294 295 pub type ImageBorderTemplate = PrimTemplate<ImageBorderData>; 296 297 impl From<ImageBorderKey> for ImageBorderTemplate { 298 fn from(key: ImageBorderKey) -> Self { 299 let common = PrimTemplateCommonData::with_key_common(key.common); 300 301 let brush_segments = key.kind.nine_patch.create_segments(common.prim_rect.size()); 302 ImageBorderTemplate { 303 common, 304 kind: ImageBorderData { 305 request: key.kind.request, 306 brush_segments, 307 src_color: None, 308 frame_id: FrameId::INVALID, 309 is_opaque: false, 310 } 311 } 312 } 313 } 314 315 pub type ImageBorderDataHandle = intern::Handle<ImageBorder>; 316 317 impl intern::Internable for ImageBorder { 318 type Key = ImageBorderKey; 319 type StoreData = ImageBorderTemplate; 320 type InternData = (); 321 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_IMAGE_BORDERS; 322 } 323 324 impl InternablePrimitive for ImageBorder { 325 fn into_key( 326 self, 327 info: &LayoutPrimitiveInfo, 328 ) -> ImageBorderKey { 329 ImageBorderKey::new( 330 info, 331 self, 332 ) 333 } 334 335 fn make_instance_kind( 336 _key: ImageBorderKey, 337 data_handle: ImageBorderDataHandle, 338 _: &mut PrimitiveStore, 339 ) -> PrimitiveInstanceKind { 340 PrimitiveInstanceKind::ImageBorder { 341 data_handle 342 } 343 } 344 } 345 346 impl IsVisible for ImageBorder { 347 fn is_visible(&self) -> bool { 348 true 349 } 350 } 351 352 #[test] 353 #[cfg(target_pointer_width = "64")] 354 fn test_struct_sizes() { 355 use std::mem; 356 // The sizes of these structures are critical for performance on a number of 357 // talos stress tests. If you get a failure here on CI, there's two possibilities: 358 // (a) You made a structure smaller than it currently is. Great work! Update the 359 // test expectations and move on. 360 // (b) You made a structure larger. This is not necessarily a problem, but should only 361 // be done with care, and after checking if talos performance regresses badly. 362 assert_eq!(mem::size_of::<NormalBorderPrim>(), 84, "NormalBorderPrim size changed"); 363 assert_eq!(mem::size_of::<NormalBorderTemplate>(), 208, "NormalBorderTemplate size changed"); 364 assert_eq!(mem::size_of::<NormalBorderKey>(), 104, "NormalBorderKey size changed"); 365 assert_eq!(mem::size_of::<ImageBorder>(), 68, "ImageBorder size changed"); 366 assert_eq!(mem::size_of::<ImageBorderTemplate>(), 96, "ImageBorderTemplate size changed"); 367 assert_eq!(mem::size_of::<ImageBorderKey>(), 88, "ImageBorderKey size changed"); 368 }