tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }