Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/wr/webrender/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 10 kB image not shown  

Quelle  transform.rs

  Sprache: Rust
 

use api::units::{LayoutToPictureTransform, PicturePixel, PictureToLayoutTransform};
use crate::{FastHashMap, frame_allocator::FrameMemory, gpu_types::VECS_PER_TRANSFORM};
use crate::internal_types::FrameVec;
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree};
use crate::util::{TransformedRectKind, MatrixHelpers};

/* This Source Code Form is subject to the terms of the Mozilla Public
 * 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/. */


/// 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.
#[derive(Copy, Clone, PartialEq, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct GpuTransformId(pub u32);

impl GpuTransformId {
    /// Identity transform ID.
    pub const IDENTITY: Self = GpuTransformId(0);
    const INDEX_MASK: u32 = 0x003fffff;

    // Note: we use unset bits instead of set bits to denote certain
    // properties of the transform so that the identity transform id
    // remains zero.

    /// if *not* set, the transform is axis-aligned.
    const AXIS_ALIGNED_2D_BIT: u32 = 1 << 23;
    /// If *not* set, the transform can be represented as a 2d scale + offset.
    const SCALE_OFFSET_2D_BIT: u32 = 1 << 22;

    /// Extract the transform kind from the id.
    pub fn transform_kind(&self) -> TransformedRectKind {
        if (self.0 & Self::AXIS_ALIGNED_2D_BIT) == 0 {
            TransformedRectKind::AxisAligned
        } else {
            TransformedRectKind::Complex
        }
    }

    /// Note: There are transformations that preserve axis-alignment without
    /// being scale + offsets.
    pub fn is_2d_axis_aligned(&self) -> bool {
        self.0 & Self::AXIS_ALIGNED_2D_BIT == 0
    }

    /// Returns true if the transform can be represented by a 2d scale + offset.
    pub fn is_2d_scale_offset(&self) -> bool {
        self.0 & Self::SCALE_OFFSET_2D_BIT == 0
    }

    pub fn metadata(&self) -> TransformMetadata {
        TransformMetadata {
            is_2d_axis_aligned: self.is_2d_axis_aligned(),
            is_2d_scale_offset: self.is_2d_scale_offset(),
        }
    }

    /// Override the kind of transform stored in this id. This can be useful in
    /// cases where we don't want shaders to consider certain transforms axis-
    /// aligned (i.e. perspective warp) even though we may still want to for the
    /// general case.
    pub fn override_transform_kind(&self, kind: TransformedRectKind) -> Self {
        GpuTransformId((self.0 & (1 << 23)) | ((kind as u32) << 23))
    }
}

impl std::fmt::Debug for GpuTransformId {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        if *self == Self::IDENTITY {
            write!(f, "<identity>")
        } else {
            let index = self.0 & Self::INDEX_MASK;
            write!(f, "#{index}")?;
            let flag_bits = Self::AXIS_ALIGNED_2D_BIT | Self::SCALE_OFFSET_2D_BIT;
            if self.0 & flag_bits != flag_bits {
                let axis_aligned = if self.is_2d_axis_aligned() { "axis-aligned" } else { "" };
                let scale_offset = if self.is_2d_scale_offset() { "scale-offset" } else { "" };
                write!(f, "({axis_aligned} {scale_offset})")?;
            }
            Ok(())
        }
    }
}


/// The GPU data payload for a transform palette entry.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)]
pub struct TransformData {
    transform: LayoutToPictureTransform,
    inv_transform: PictureToLayoutTransform,
}

impl TransformData {
    fn invalid() -> Self {
        TransformData {
            transform: LayoutToPictureTransform::identity(),
            inv_transform: PictureToLayoutTransform::identity(),
        }
    }
}

// Extra data stored about each transform palette entry.
#[derive(Copy, Clone)]
pub struct TransformMetadata {
    pub is_2d_axis_aligned: bool,
    pub is_2d_scale_offset: bool,
}

impl TransformMetadata {
    pub fn invalid() -> Self {
        TransformMetadata {
            is_2d_axis_aligned: true,
            is_2d_scale_offset: true,
        }
    }

    pub fn flags(&self) -> u32 {
        let mut flags = 0;
        if !self.is_2d_axis_aligned {
            flags |= GpuTransformId::AXIS_ALIGNED_2D_BIT
        };
        if !self.is_2d_scale_offset {
            flags |= GpuTransformId::SCALE_OFFSET_2D_BIT
        };

        flags
    }
}

#[derive(Debug, Hash, Eq, PartialEq)]
struct RelativeTransformKey {
    from_index: SpatialNodeIndex,
    to_index: SpatialNodeIndex,
    scale: u32,
    pre_scale: bool,
}

pub struct TransformPalette {
    pub gpu: GpuTransforms,
}

impl TransformPalette {
    pub fn new(
        count: usize,
        memory: &FrameMemory,
    ) -> Self {
        TransformPalette {
            gpu: GpuTransforms::new(count, memory),
        }
    }

    pub fn finish(self) -> FrameVec<TransformData> {
        self.gpu.finish()
    }
}

// Stores a contiguous list of TransformData structs, that
// are ready for upload to the GPU.
// TODO(gw): For now, this only stores the complete local
//           to world transform for each spatial node. In
//           the future, the transform palette will support
//           specifying a coordinate system that the transform
//           should be relative to.
pub struct GpuTransforms {
    transforms: FrameVec<TransformData>,
    metadata: Vec<TransformMetadata>,
    map: FastHashMap<RelativeTransformKey, usize>,
}

impl GpuTransforms {
    fn new(
        count: usize,
        memory: &FrameMemory,
    ) -> Self {
        let _ = VECS_PER_TRANSFORM;

        let mut transforms = memory.new_vec_with_capacity(count);
        let mut metadata = Vec::with_capacity(count);

        transforms.push(TransformData::invalid());
        metadata.push(TransformMetadata::invalid());

        GpuTransforms {
            transforms,
            metadata,
            map: FastHashMap::default(),
        }
    }

    fn finish(self) -> FrameVec<TransformData> {
        self.transforms
    }

    fn get_index(
        &mut self,
        child_index: SpatialNodeIndex,
        parent_index: SpatialNodeIndex,
        mut scale: Option<f32>,
        pre_scale: bool,
        spatial_tree: &SpatialTree,
    ) -> usize {
        if scale == Some(1.0) {
            scale = None;
        }

        // Deduplicate the common case of identity transforms.
        if child_index == parent_index && scale.is_none() {
            return 0;
        }

        let scale_key = scale.map(|s| s.to_bits()).unwrap_or(0);

        let key = RelativeTransformKey {
            from_index: child_index,
            to_index: parent_index,
            scale: scale_key,
            pre_scale,
        };

        let metadata = &mut self.metadata;
        let transforms = &mut self.transforms;

        *self.map.entry(key).or_insert_with(|| {
            let transform = spatial_tree.get_relative_transform(
                child_index,
                parent_index,
            );

            let is_2d_axis_aligned = transform.is_2d_axis_aligned();
            let is_2d_scale_offset  = transform.is_2d_scale_translation();

            let transform = transform
                .into_transform()
                .with_destination::<PicturePixel>();

            register_gpu_transform(
                metadata,
                transforms,
                transform,
                scale,
                pre_scale,
                TransformMetadata {
                    is_2d_axis_aligned,
                    is_2d_scale_offset,
                }
            )
        })
    }

    // Get a transform palette id for the given spatial node.
    // TODO(gw): In the future, it will be possible to specify
    //           a coordinate system id here, to allow retrieving
    //           transforms in the local space of a given spatial node.
    pub fn get_id(
        &mut self,
        from_index: SpatialNodeIndex,
        to_index: SpatialNodeIndex,
        spatial_tree: &SpatialTree,
    ) -> GpuTransformId {
        let index = self.get_index(
            from_index,
            to_index,
            None,
            false,
            spatial_tree,
        );

        let flags = self.metadata[index].flags();

        GpuTransformId((index as u32) | flags)
    }

    pub fn get_id_with_post_scale(
        &mut self,
        from_index: SpatialNodeIndex,
        to_index: SpatialNodeIndex,
        scale: f32,
        spatial_tree: &SpatialTree,
    ) -> GpuTransformId {
        let index = self.get_index(
            from_index,
            to_index,
            Some(scale),
            false,
            spatial_tree,
        );

        let flags = self.metadata[index].flags();

        GpuTransformId((index as u32) | flags)
    }

    pub fn get_id_with_pre_scale(
        &mut self,
        scale: f32,
        from_index: SpatialNodeIndex,
        to_index: SpatialNodeIndex,
        spatial_tree: &SpatialTree,
    ) -> GpuTransformId {
        let index = self.get_index(
            from_index,
            to_index,
            Some(scale),
            true,
            spatial_tree,
        );

        let flags = self.metadata[index].flags();

        GpuTransformId((index as u32) | flags)
    }

    pub fn get_custom(
        &mut self,
        transform: LayoutToPictureTransform,
    ) -> GpuTransformId {
        let is_2d_scale_offset = transform.is_2d_scale_translation();
        let is_axis_aligned = transform.preserves_2d_axis_alignment();
        let metadata = TransformMetadata {
            is_2d_scale_offset,
            is_2d_axis_aligned: is_axis_aligned,
        };
        let index = register_gpu_transform(
            &mut self.metadata,
            &mut self.transforms,
            transform,
            None,
            false,
            metadata,
        );

        GpuTransformId((index as u32) | metadata.flags())
    }
}

// Set the local -> world transform for a given spatial
// node in the transform palette.
fn register_gpu_transform(
    metadatas: &mut Vec<TransformMetadata>,
    transforms: &mut FrameVec<TransformData>,
    mut transform: LayoutToPictureTransform,
    scale: Option<f32>,
    pre_scale: bool,
    metadata: TransformMetadata,
) -> usize {
    if let Some(scale) = scale {
        if pre_scale {
            transform = transform.pre_scale(scale, scale, 1.0);
        } else {
            transform = transform.then_scale(scale, scale, 1.0);
        }
    }
    // TODO: refactor the calling code to not even try
    // registering a non-invertible transform.
    let inv_transform = transform
        .inverse()
        .unwrap_or_else(PictureToLayoutTransform::identity);

    let data = TransformData {
        transform,
        inv_transform,
    };

    let index = transforms.len();
    metadatas.push(metadata);
    transforms.push(data);

    index
}

Messung V0.5 in Prozent
C=85 H=100 G=92

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.