summaryrefslogtreecommitdiffstats
path: root/gfx/wr/webrender/src/gpu_types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/wr/webrender/src/gpu_types.rs')
-rw-r--r--gfx/wr/webrender/src/gpu_types.rs955
1 files changed, 955 insertions, 0 deletions
diff --git a/gfx/wr/webrender/src/gpu_types.rs b/gfx/wr/webrender/src/gpu_types.rs
new file mode 100644
index 0000000000..cc7d46e602
--- /dev/null
+++ b/gfx/wr/webrender/src/gpu_types.rs
@@ -0,0 +1,955 @@
+/* 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/. */
+
+use api::{AlphaType, PremultipliedColorF, YuvFormat, YuvRangedColorSpace};
+use api::units::*;
+use crate::composite::CompositeFeatures;
+use crate::segment::EdgeAaSegmentMask;
+use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
+use crate::gpu_cache::{GpuCacheAddress, GpuDataRequest};
+use crate::internal_types::FastHashMap;
+use crate::prim_store::ClipData;
+use crate::render_task::RenderTaskAddress;
+use crate::render_task_graph::RenderTaskId;
+use crate::renderer::{ShaderColorMode, GpuBufferAddress};
+use std::i32;
+use crate::util::{TransformedRectKind, MatrixHelpers};
+use glyph_rasterizer::SubpixelDirection;
+use crate::util::{ScaleOffset, pack_as_float};
+
+// Contains type that must exactly match the same structures declared in GLSL.
+
+pub const VECS_PER_TRANSFORM: usize = 8;
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct ZBufferId(pub i32);
+
+impl ZBufferId {
+ pub fn invalid() -> Self {
+ ZBufferId(i32::MAX)
+ }
+}
+
+#[derive(Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct ZBufferIdGenerator {
+ next: i32,
+ max_depth_ids: i32,
+}
+
+impl ZBufferIdGenerator {
+ pub fn new(max_depth_ids: i32) -> Self {
+ ZBufferIdGenerator {
+ next: 0,
+ max_depth_ids,
+ }
+ }
+
+ pub fn next(&mut self) -> ZBufferId {
+ debug_assert!(self.next < self.max_depth_ids);
+ let id = ZBufferId(self.next);
+ self.next += 1;
+ id
+ }
+}
+
+#[derive(Clone, Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct CopyInstance {
+ pub src_rect: DeviceRect,
+ pub dst_rect: DeviceRect,
+ pub dst_texture_size: DeviceSize,
+}
+
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub enum RasterizationSpace {
+ Local = 0,
+ Screen = 1,
+}
+
+#[derive(Debug, Copy, Clone, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub enum BoxShadowStretchMode {
+ Stretch = 0,
+ Simple = 1,
+}
+
+#[repr(i32)]
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub enum BlurDirection {
+ Horizontal = 0,
+ Vertical,
+}
+
+#[derive(Clone, Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct BlurInstance {
+ pub task_address: RenderTaskAddress,
+ pub src_task_address: RenderTaskAddress,
+ pub blur_direction: BlurDirection,
+}
+
+#[derive(Clone, Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct ScalingInstance {
+ pub target_rect: DeviceRect,
+ pub source_rect: DeviceRect,
+}
+
+#[derive(Clone, Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct SvgFilterInstance {
+ pub task_address: RenderTaskAddress,
+ pub input_1_task_address: RenderTaskAddress,
+ pub input_2_task_address: RenderTaskAddress,
+ pub kind: u16,
+ pub input_count: u16,
+ pub generic_int: u16,
+ pub extra_data_address: GpuCacheAddress,
+}
+
+#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub enum BorderSegment {
+ TopLeft,
+ TopRight,
+ BottomRight,
+ BottomLeft,
+ Left,
+ Top,
+ Right,
+ Bottom,
+}
+
+#[derive(Debug, Clone)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct BorderInstance {
+ pub task_origin: DevicePoint,
+ pub local_rect: DeviceRect,
+ pub color0: PremultipliedColorF,
+ pub color1: PremultipliedColorF,
+ pub flags: i32,
+ pub widths: DeviceSize,
+ pub radius: DeviceSize,
+ pub clip_params: [f32; 8],
+}
+
+#[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskInstanceCommon {
+ pub sub_rect: DeviceRect,
+ pub task_origin: DevicePoint,
+ pub screen_origin: DevicePoint,
+ pub device_pixel_scale: f32,
+ pub clip_transform_id: TransformPaletteId,
+ pub prim_transform_id: TransformPaletteId,
+}
+
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskInstanceImage {
+ pub common: ClipMaskInstanceCommon,
+ pub tile_rect: LayoutRect,
+ pub resource_address: GpuCacheAddress,
+ pub local_rect: LayoutRect,
+}
+
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskInstanceRect {
+ pub common: ClipMaskInstanceCommon,
+ pub local_pos: LayoutPoint,
+ pub clip_data: ClipData,
+}
+
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct BoxShadowData {
+ pub src_rect_size: LayoutSize,
+ pub clip_mode: i32,
+ pub stretch_mode_x: i32,
+ pub stretch_mode_y: i32,
+ pub dest_rect: LayoutRect,
+}
+
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskInstanceBoxShadow {
+ pub common: ClipMaskInstanceCommon,
+ pub resource_address: GpuCacheAddress,
+ pub shadow_data: BoxShadowData,
+}
+
+/// A clipping primitive drawn into the clipping mask.
+/// Could be an image or a rectangle, which defines the
+/// way `address` is treated.
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskInstance {
+ pub clip_transform_id: TransformPaletteId,
+ pub prim_transform_id: TransformPaletteId,
+ pub clip_data_address: GpuCacheAddress,
+ pub resource_address: GpuCacheAddress,
+ pub local_pos: LayoutPoint,
+ pub tile_rect: LayoutRect,
+ pub sub_rect: DeviceRect,
+ pub task_origin: DevicePoint,
+ pub screen_origin: DevicePoint,
+ pub device_pixel_scale: f32,
+}
+
+// 16 bytes per instance should be enough for anyone!
+#[repr(C)]
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveInstanceData {
+ data: [i32; 4],
+}
+
+/// Specifies that an RGB CompositeInstance's UV coordinates are normalized.
+const UV_TYPE_NORMALIZED: u32 = 0;
+/// Specifies that an RGB CompositeInstance's UV coordinates are not normalized.
+const UV_TYPE_UNNORMALIZED: u32 = 1;
+
+/// A GPU-friendly representation of the `ScaleOffset` type
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub struct CompositorTransform {
+ pub sx: f32,
+ pub sy: f32,
+ pub tx: f32,
+ pub ty: f32,
+}
+
+impl CompositorTransform {
+ pub fn identity() -> Self {
+ CompositorTransform {
+ sx: 1.0,
+ sy: 1.0,
+ tx: 0.0,
+ ty: 0.0,
+ }
+ }
+}
+
+impl From<ScaleOffset> for CompositorTransform {
+ fn from(scale_offset: ScaleOffset) -> Self {
+ CompositorTransform {
+ sx: scale_offset.scale.x,
+ sy: scale_offset.scale.y,
+ tx: scale_offset.offset.x,
+ ty: scale_offset.offset.y,
+ }
+ }
+}
+
+/// Vertex format for picture cache composite shader.
+/// When editing the members, update desc::COMPOSITE
+/// so its list of instance_attributes matches:
+#[derive(Clone, Debug)]
+#[repr(C)]
+pub struct CompositeInstance {
+ // Picture space destination rectangle of surface
+ rect: PictureRect,
+ // Device space destination clip rect for this surface
+ clip_rect: DeviceRect,
+ // Color for solid color tiles, white otherwise
+ color: PremultipliedColorF,
+
+ // Packed into a single vec4 (aParams)
+ _padding: f32,
+ color_space_or_uv_type: f32, // YuvColorSpace for YUV;
+ // UV coordinate space for RGB
+ yuv_format: f32, // YuvFormat
+ yuv_channel_bit_depth: f32,
+
+ // UV rectangles (pixel space) for color / yuv texture planes
+ uv_rects: [TexelRect; 3],
+
+ // A 2d scale + offset transform for the rect
+ transform: CompositorTransform,
+}
+
+impl CompositeInstance {
+ pub fn new(
+ rect: PictureRect,
+ clip_rect: DeviceRect,
+ color: PremultipliedColorF,
+ transform: CompositorTransform,
+ ) -> Self {
+ let uv = TexelRect::new(0.0, 0.0, 1.0, 1.0);
+ CompositeInstance {
+ rect,
+ clip_rect,
+ color,
+ _padding: 0.0,
+ color_space_or_uv_type: pack_as_float(UV_TYPE_NORMALIZED),
+ yuv_format: 0.0,
+ yuv_channel_bit_depth: 0.0,
+ uv_rects: [uv, uv, uv],
+ transform,
+ }
+ }
+
+ pub fn new_rgb(
+ rect: PictureRect,
+ clip_rect: DeviceRect,
+ color: PremultipliedColorF,
+ uv_rect: TexelRect,
+ transform: CompositorTransform,
+ ) -> Self {
+ CompositeInstance {
+ rect,
+ clip_rect,
+ color,
+ _padding: 0.0,
+ color_space_or_uv_type: pack_as_float(UV_TYPE_UNNORMALIZED),
+ yuv_format: 0.0,
+ yuv_channel_bit_depth: 0.0,
+ uv_rects: [uv_rect, uv_rect, uv_rect],
+ transform,
+ }
+ }
+
+ pub fn new_yuv(
+ rect: PictureRect,
+ clip_rect: DeviceRect,
+ yuv_color_space: YuvRangedColorSpace,
+ yuv_format: YuvFormat,
+ yuv_channel_bit_depth: u32,
+ uv_rects: [TexelRect; 3],
+ transform: CompositorTransform,
+ ) -> Self {
+ CompositeInstance {
+ rect,
+ clip_rect,
+ color: PremultipliedColorF::WHITE,
+ _padding: 0.0,
+ color_space_or_uv_type: pack_as_float(yuv_color_space as u32),
+ yuv_format: pack_as_float(yuv_format as u32),
+ yuv_channel_bit_depth: pack_as_float(yuv_channel_bit_depth),
+ uv_rects,
+ transform,
+ }
+ }
+
+ // Returns the CompositeFeatures that can be used to composite
+ // this RGB instance.
+ pub fn get_rgb_features(&self) -> CompositeFeatures {
+ let mut features = CompositeFeatures::empty();
+
+ // If the UV rect covers the entire texture then we can avoid UV clamping.
+ // We should try harder to determine this for unnormalized UVs too.
+ if self.color_space_or_uv_type == pack_as_float(UV_TYPE_NORMALIZED)
+ && self.uv_rects[0] == TexelRect::new(0.0, 0.0, 1.0, 1.0)
+ {
+ features |= CompositeFeatures::NO_UV_CLAMP;
+ }
+
+ if self.color == PremultipliedColorF::WHITE {
+ features |= CompositeFeatures::NO_COLOR_MODULATION
+ }
+
+ features
+ }
+}
+
+/// Vertex format for issuing colored quads.
+#[derive(Debug, Clone)]
+#[repr(C)]
+pub struct ClearInstance {
+ pub rect: [f32; 4],
+ pub color: [f32; 4],
+}
+
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveHeaderIndex(pub i32);
+
+#[derive(Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveHeaders {
+ // The integer-type headers for a primitive.
+ pub headers_int: Vec<PrimitiveHeaderI>,
+ // The float-type headers for a primitive.
+ pub headers_float: Vec<PrimitiveHeaderF>,
+}
+
+impl PrimitiveHeaders {
+ pub fn new() -> PrimitiveHeaders {
+ PrimitiveHeaders {
+ headers_int: Vec::new(),
+ headers_float: Vec::new(),
+ }
+ }
+
+ // Add a new primitive header.
+ pub fn push(
+ &mut self,
+ prim_header: &PrimitiveHeader,
+ z: ZBufferId,
+ user_data: [i32; 4],
+ ) -> PrimitiveHeaderIndex {
+ debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
+ let id = self.headers_float.len();
+
+ self.headers_float.push(PrimitiveHeaderF {
+ local_rect: prim_header.local_rect,
+ local_clip_rect: prim_header.local_clip_rect,
+ });
+
+ self.headers_int.push(PrimitiveHeaderI {
+ z,
+ unused: 0,
+ specific_prim_address: prim_header.specific_prim_address.as_int(),
+ transform_id: prim_header.transform_id,
+ user_data,
+ });
+
+ PrimitiveHeaderIndex(id as i32)
+ }
+}
+
+// This is a convenience type used to make it easier to pass
+// the common parts around during batching.
+#[derive(Debug)]
+pub struct PrimitiveHeader {
+ pub local_rect: LayoutRect,
+ pub local_clip_rect: LayoutRect,
+ pub specific_prim_address: GpuCacheAddress,
+ pub transform_id: TransformPaletteId,
+}
+
+// f32 parts of a primitive header
+#[derive(Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveHeaderF {
+ pub local_rect: LayoutRect,
+ pub local_clip_rect: LayoutRect,
+}
+
+// i32 parts of a primitive header
+// TODO(gw): Compress parts of these down to u16
+#[derive(Debug)]
+#[repr(C)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PrimitiveHeaderI {
+ pub z: ZBufferId,
+ pub specific_prim_address: i32,
+ pub transform_id: TransformPaletteId,
+ pub unused: i32, // To ensure required 16 byte alignment of vertex textures
+ pub user_data: [i32; 4],
+}
+
+pub struct GlyphInstance {
+ pub prim_header_index: PrimitiveHeaderIndex,
+}
+
+impl GlyphInstance {
+ pub fn new(
+ prim_header_index: PrimitiveHeaderIndex,
+ ) -> Self {
+ GlyphInstance {
+ prim_header_index,
+ }
+ }
+
+ // 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,
+ 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,
+ ((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(),
+ ],
+ }
+ }
+}
+
+pub struct SplitCompositeInstance {
+ pub prim_header_index: PrimitiveHeaderIndex,
+ pub polygons_address: i32,
+ pub z: ZBufferId,
+ pub render_task_address: RenderTaskAddress,
+}
+
+impl From<SplitCompositeInstance> for PrimitiveInstanceData {
+ fn from(instance: SplitCompositeInstance) -> Self {
+ PrimitiveInstanceData {
+ data: [
+ instance.prim_header_index.0,
+ instance.polygons_address,
+ instance.z.0,
+ instance.render_task_address.0 as i32,
+ ],
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct QuadInstance {
+ pub render_task_address: RenderTaskAddress,
+ pub prim_address: GpuBufferAddress,
+ pub z_id: ZBufferId,
+ pub transform_id: TransformPaletteId,
+ pub quad_flags: u8,
+ pub edge_flags: u8,
+ pub part_index: u8,
+ pub segment_index: u8,
+}
+
+impl From<QuadInstance> for PrimitiveInstanceData {
+ fn from(instance: QuadInstance) -> Self {
+ /*
+ [32 bits prim address]
+ [8 bits quad flags] [8 bits edge flags] [16 bits render task address]
+ [8 bits segment flags] [24 bits z_id]
+ [8 bits segment index] [24 bits xf_id]
+ */
+ PrimitiveInstanceData {
+ data: [
+ instance.prim_address.as_int(),
+ ((instance.quad_flags as i32) << 24) |
+ ((instance.edge_flags as i32) << 16) |
+ instance.render_task_address.0 as i32,
+ ((instance.part_index as i32) << 24) | instance.z_id.0,
+ ((instance.segment_index as i32) << 24) | instance.transform_id.0 as i32,
+ ],
+ }
+ }
+}
+
+#[cfg_attr(feature = "capture", derive(Serialize))]
+pub struct QuadSegment {
+ pub rect: LayoutRect,
+ pub task_id: RenderTaskId,
+}
+
+#[repr(C)]
+#[derive(Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct MaskInstance {
+ pub prim: PrimitiveInstanceData,
+ pub clip_transform_id: TransformPaletteId,
+ pub clip_address: i32,
+ pub info: [i32; 2],
+}
+
+
+bitflags! {
+ // Note: This can use up to 12 bits due to how it will
+ // be packed in the instance data.
+
+ /// Flags that define how the common brush shader
+ /// code should process this instance.
+ #[cfg_attr(feature = "capture", derive(Serialize))]
+ #[cfg_attr(feature = "replay", derive(Deserialize))]
+ #[derive(MallocSizeOf)]
+ pub struct BrushFlags: u16 {
+ /// Apply perspective interpolation to UVs
+ const PERSPECTIVE_INTERPOLATION = 1;
+ /// Do interpolation relative to segment rect,
+ /// rather than primitive rect.
+ const SEGMENT_RELATIVE = 2;
+ /// Repeat UVs horizontally.
+ const SEGMENT_REPEAT_X = 4;
+ /// Repeat UVs vertically.
+ const SEGMENT_REPEAT_Y = 8;
+ /// Horizontally follow border-image-repeat: round.
+ const SEGMENT_REPEAT_X_ROUND = 16;
+ /// Vertically follow border-image-repeat: round.
+ const SEGMENT_REPEAT_Y_ROUND = 32;
+ /// Middle (fill) area of a border-image-repeat.
+ const SEGMENT_NINEPATCH_MIDDLE = 64;
+ /// The extra segment data is a texel rect.
+ const SEGMENT_TEXEL_RECT = 128;
+ /// Whether to force the anti-aliasing when the primitive
+ /// is axis-aligned.
+ const FORCE_AA = 256;
+ }
+}
+
+/// Convenience structure to encode into PrimitiveInstanceData.
+pub struct BrushInstance {
+ pub prim_header_index: PrimitiveHeaderIndex,
+ pub render_task_address: RenderTaskAddress,
+ pub clip_task_address: RenderTaskAddress,
+ pub segment_index: i32,
+ pub edge_flags: EdgeAaSegmentMask,
+ pub brush_flags: BrushFlags,
+ pub resource_address: i32,
+}
+
+impl From<BrushInstance> for PrimitiveInstanceData {
+ fn from(instance: BrushInstance) -> Self {
+ PrimitiveInstanceData {
+ data: [
+ instance.prim_header_index.0,
+ ((instance.render_task_address.0 as i32) << 16)
+ | instance.clip_task_address.0 as i32,
+ instance.segment_index
+ | ((instance.brush_flags.bits() as i32) << 16)
+ | ((instance.edge_flags.bits() as i32) << 28),
+ instance.resource_address,
+ ]
+ }
+ }
+}
+
+/// 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
+// only flag currently used determines whether the
+// transform is axis-aligned (and this should have
+// pixel snapping applied).
+#[derive(Copy, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct TransformPaletteId(pub u32);
+
+impl TransformPaletteId {
+ /// Identity transform ID.
+ pub const IDENTITY: Self = TransformPaletteId(0);
+
+ /// Extract the transform kind from the id.
+ pub fn transform_kind(&self) -> TransformedRectKind {
+ if (self.0 >> 23) == 0 {
+ TransformedRectKind::AxisAligned
+ } else {
+ TransformedRectKind::Complex
+ }
+ }
+
+ /// 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 {
+ TransformPaletteId((self.0 & 0x7FFFFFu32) | ((kind as u32) << 23))
+ }
+}
+
+/// 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(Clone)]
+pub struct TransformMetadata {
+ transform_kind: TransformedRectKind,
+}
+
+impl TransformMetadata {
+ pub fn invalid() -> Self {
+ TransformMetadata {
+ transform_kind: TransformedRectKind::AxisAligned,
+ }
+ }
+}
+
+#[derive(Debug, Hash, Eq, PartialEq)]
+struct RelativeTransformKey {
+ from_index: SpatialNodeIndex,
+ to_index: SpatialNodeIndex,
+}
+
+// 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 TransformPalette {
+ transforms: Vec<TransformData>,
+ metadata: Vec<TransformMetadata>,
+ map: FastHashMap<RelativeTransformKey, usize>,
+}
+
+impl TransformPalette {
+ pub fn new(
+ count: usize,
+ ) -> Self {
+ let _ = VECS_PER_TRANSFORM;
+
+ let mut transforms = Vec::with_capacity(count);
+ let mut metadata = Vec::with_capacity(count);
+
+ transforms.push(TransformData::invalid());
+ metadata.push(TransformMetadata::invalid());
+
+ TransformPalette {
+ transforms,
+ metadata,
+ map: FastHashMap::default(),
+ }
+ }
+
+ pub fn finish(self) -> Vec<TransformData> {
+ self.transforms
+ }
+
+ fn get_index(
+ &mut self,
+ child_index: SpatialNodeIndex,
+ parent_index: SpatialNodeIndex,
+ spatial_tree: &SpatialTree,
+ ) -> usize {
+ if child_index == parent_index {
+ 0
+ } else {
+ let key = RelativeTransformKey {
+ from_index: child_index,
+ to_index: parent_index,
+ };
+
+ 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,
+ )
+ .into_transform()
+ .with_destination::<PicturePixel>();
+
+ register_transform(
+ metadata,
+ transforms,
+ transform,
+ )
+ })
+ }
+ }
+
+ // 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,
+ ) -> TransformPaletteId {
+ let index = self.get_index(
+ from_index,
+ to_index,
+ spatial_tree,
+ );
+ let transform_kind = self.metadata[index].transform_kind as u32;
+ TransformPaletteId(
+ (index as u32) |
+ (transform_kind << 23)
+ )
+ }
+
+ pub fn get_custom(
+ &mut self,
+ transform: LayoutToPictureTransform,
+ ) -> TransformPaletteId {
+ let index = register_transform(
+ &mut self.metadata,
+ &mut self.transforms,
+ transform,
+ );
+
+ let transform_kind = self.metadata[index].transform_kind as u32;
+ TransformPaletteId(
+ (index as u32) |
+ (transform_kind << 23)
+ )
+ }
+}
+
+// Texture cache resources can be either a simple rect, or define
+// a polygon within a rect by specifying a UV coordinate for each
+// corner. This is useful for rendering screen-space rasterized
+// off-screen surfaces.
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub enum UvRectKind {
+ // The 2d bounds of the texture cache entry define the
+ // valid UV space for this texture cache entry.
+ Rect,
+ // The four vertices below define a quad within
+ // the texture cache entry rect. The shader can
+ // use a bilerp() to correctly interpolate a
+ // UV coord in the vertex shader.
+ Quad {
+ top_left: DeviceHomogeneousVector,
+ top_right: DeviceHomogeneousVector,
+ bottom_left: DeviceHomogeneousVector,
+ bottom_right: DeviceHomogeneousVector,
+ },
+}
+
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct ImageSource {
+ pub p0: DevicePoint,
+ pub p1: DevicePoint,
+ // TODO: It appears that only glyphs make use of user_data (to store glyph offset
+ // and scale).
+ // Perhaps we should separate the two so we don't have to push an empty unused vec4
+ // for all image sources.
+ pub user_data: [f32; 4],
+ pub uv_rect_kind: UvRectKind,
+}
+
+impl ImageSource {
+ pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
+ // see fetch_image_resource in GLSL
+ // has to be VECS_PER_IMAGE_RESOURCE vectors
+ request.push([
+ self.p0.x,
+ self.p0.y,
+ self.p1.x,
+ self.p1.y,
+ ]);
+ request.push(self.user_data);
+
+ // If this is a polygon uv kind, then upload the four vertices.
+ if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
+ // see fetch_image_resource_extra in GLSL
+ //Note: we really need only 3 components per point here: X, Y, and W
+ request.push(top_left);
+ request.push(top_right);
+ request.push(bottom_left);
+ request.push(bottom_right);
+ }
+ }
+}
+
+// Set the local -> world transform for a given spatial
+// node in the transform palette.
+fn register_transform(
+ metadatas: &mut Vec<TransformMetadata>,
+ transforms: &mut Vec<TransformData>,
+ transform: LayoutToPictureTransform,
+) -> usize {
+ // 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 metadata = TransformMetadata {
+ transform_kind: transform.transform_kind()
+ };
+ let data = TransformData {
+ transform,
+ inv_transform,
+ };
+
+ let index = transforms.len();
+ metadatas.push(metadata);
+ transforms.push(data);
+
+ index
+}
+
+pub fn get_shader_opacity(opacity: f32) -> i32 {
+ (opacity * 65535.0).round() as i32
+}