webrender/
gpu_types.rs

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
5use api::{AlphaType, PremultipliedColorF, YuvFormat, YuvRangedColorSpace};
6use api::units::*;
7use crate::composite::{CompositeFeatures, CompositorClip};
8use crate::segment::EdgeAaSegmentMask;
9use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
10use crate::gpu_cache::{GpuCacheAddress, GpuDataRequest};
11use crate::internal_types::{FastHashMap, FrameVec, FrameMemory};
12use crate::prim_store::ClipData;
13use crate::render_task::RenderTaskAddress;
14use crate::render_task_graph::RenderTaskId;
15use crate::renderer::{ShaderColorMode, GpuBufferAddress};
16use std::i32;
17use crate::util::{MatrixHelpers, TransformedRectKind};
18use glyph_rasterizer::SubpixelDirection;
19use crate::util::{ScaleOffset, pack_as_float};
20
21
22// Contains type that must exactly match the same structures declared in GLSL.
23
24pub const VECS_PER_TRANSFORM: usize = 8;
25
26#[derive(Copy, Clone, Debug, PartialEq)]
27#[repr(C)]
28#[cfg_attr(feature = "capture", derive(Serialize))]
29#[cfg_attr(feature = "replay", derive(Deserialize))]
30pub struct ZBufferId(pub i32);
31
32impl ZBufferId {
33    pub fn invalid() -> Self {
34        ZBufferId(i32::MAX)
35    }
36}
37
38#[derive(Debug)]
39#[cfg_attr(feature = "capture", derive(Serialize))]
40#[cfg_attr(feature = "replay", derive(Deserialize))]
41pub struct ZBufferIdGenerator {
42    next: i32,
43    max_depth_ids: i32,
44}
45
46impl ZBufferIdGenerator {
47    pub fn new(max_depth_ids: i32) -> Self {
48        ZBufferIdGenerator {
49            next: 0,
50            max_depth_ids,
51        }
52    }
53
54    pub fn next(&mut self) -> ZBufferId {
55        debug_assert!(self.next < self.max_depth_ids);
56        let id = ZBufferId(self.next);
57        self.next += 1;
58        id
59    }
60}
61
62#[derive(Clone, Debug)]
63#[repr(C)]
64#[cfg_attr(feature = "capture", derive(Serialize))]
65#[cfg_attr(feature = "replay", derive(Deserialize))]
66pub struct CopyInstance {
67    pub src_rect: DeviceRect,
68    pub dst_rect: DeviceRect,
69    pub dst_texture_size: DeviceSize,
70}
71
72#[derive(Debug, Copy, Clone)]
73#[cfg_attr(feature = "capture", derive(Serialize))]
74#[cfg_attr(feature = "replay", derive(Deserialize))]
75#[repr(C)]
76pub enum RasterizationSpace {
77    Local = 0,
78    Screen = 1,
79}
80
81#[derive(Debug, Copy, Clone, MallocSizeOf)]
82#[cfg_attr(feature = "capture", derive(Serialize))]
83#[cfg_attr(feature = "replay", derive(Deserialize))]
84#[repr(C)]
85pub enum BoxShadowStretchMode {
86    Stretch = 0,
87    Simple = 1,
88}
89
90#[repr(i32)]
91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "capture", derive(Serialize))]
93#[cfg_attr(feature = "replay", derive(Deserialize))]
94pub enum BlurDirection {
95    Horizontal = 0,
96    Vertical,
97}
98
99impl BlurDirection {
100    pub fn as_int(self) -> i32 {
101        match self {
102            BlurDirection::Horizontal => 0,
103            BlurDirection::Vertical => 1,
104        }
105    }
106}
107
108#[derive(Clone, Debug)]
109#[repr(C)]
110#[cfg_attr(feature = "capture", derive(Serialize))]
111#[cfg_attr(feature = "replay", derive(Deserialize))]
112pub struct BlurInstance {
113    pub task_address: RenderTaskAddress,
114    pub src_task_address: RenderTaskAddress,
115    pub blur_direction: i32,
116    pub blur_std_deviation: f32,
117    pub blur_region: DeviceSize,
118}
119
120#[derive(Clone, Debug)]
121#[repr(C)]
122#[cfg_attr(feature = "capture", derive(Serialize))]
123#[cfg_attr(feature = "replay", derive(Deserialize))]
124pub struct ScalingInstance {
125    pub target_rect: DeviceRect,
126    pub source_rect: DeviceRect,
127    source_rect_type: f32,
128}
129
130impl ScalingInstance {
131    pub fn new(target_rect: DeviceRect, source_rect: DeviceRect, source_rect_normalized: bool) -> Self {
132        let source_rect_type = match source_rect_normalized {
133            true => UV_TYPE_NORMALIZED,
134            false => UV_TYPE_UNNORMALIZED,
135        };
136        Self {
137            target_rect,
138            source_rect,
139            source_rect_type: pack_as_float(source_rect_type),
140        }
141    }
142}
143
144#[derive(Clone, Debug)]
145#[repr(C)]
146#[cfg_attr(feature = "capture", derive(Serialize))]
147#[cfg_attr(feature = "replay", derive(Deserialize))]
148pub struct SvgFilterInstance {
149    pub task_address: RenderTaskAddress,
150    pub input_1_task_address: RenderTaskAddress,
151    pub input_2_task_address: RenderTaskAddress,
152    pub kind: u16,
153    pub input_count: u16,
154    pub generic_int: u16,
155    pub padding: u16,
156    pub extra_data_address: GpuCacheAddress,
157}
158
159#[derive(Clone, Debug)]
160#[repr(C)]
161#[cfg_attr(feature = "capture", derive(Serialize))]
162#[cfg_attr(feature = "replay", derive(Deserialize))]
163pub struct SVGFEFilterInstance {
164    pub target_rect: DeviceRect,
165    pub input_1_content_scale_and_offset: [f32; 4],
166    pub input_2_content_scale_and_offset: [f32; 4],
167    pub input_1_task_address: RenderTaskAddress,
168    pub input_2_task_address: RenderTaskAddress,
169    pub kind: u16,
170    pub input_count: u16,
171    pub extra_data_address: GpuCacheAddress,
172}
173
174#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
175#[repr(C)]
176#[cfg_attr(feature = "capture", derive(Serialize))]
177#[cfg_attr(feature = "replay", derive(Deserialize))]
178pub enum BorderSegment {
179    TopLeft,
180    TopRight,
181    BottomRight,
182    BottomLeft,
183    Left,
184    Top,
185    Right,
186    Bottom,
187}
188
189#[derive(Debug, Clone)]
190#[repr(C)]
191#[cfg_attr(feature = "capture", derive(Serialize))]
192#[cfg_attr(feature = "replay", derive(Deserialize))]
193pub struct BorderInstance {
194    pub task_origin: DevicePoint,
195    pub local_rect: DeviceRect,
196    pub color0: PremultipliedColorF,
197    pub color1: PremultipliedColorF,
198    pub flags: i32,
199    pub widths: DeviceSize,
200    pub radius: DeviceSize,
201    pub clip_params: [f32; 8],
202}
203
204#[derive(Copy, Clone, Debug)]
205#[cfg_attr(feature = "capture", derive(Serialize))]
206#[cfg_attr(feature = "replay", derive(Deserialize))]
207#[repr(C)]
208pub struct ClipMaskInstanceCommon {
209    pub sub_rect: DeviceRect,
210    pub task_origin: DevicePoint,
211    pub screen_origin: DevicePoint,
212    pub device_pixel_scale: f32,
213    pub clip_transform_id: TransformPaletteId,
214    pub prim_transform_id: TransformPaletteId,
215}
216
217#[derive(Clone, Debug)]
218#[cfg_attr(feature = "capture", derive(Serialize))]
219#[cfg_attr(feature = "replay", derive(Deserialize))]
220#[repr(C)]
221pub struct ClipMaskInstanceRect {
222    pub common: ClipMaskInstanceCommon,
223    pub local_pos: LayoutPoint,
224    pub clip_data: ClipData,
225}
226
227#[derive(Clone, Debug)]
228#[cfg_attr(feature = "capture", derive(Serialize))]
229#[cfg_attr(feature = "replay", derive(Deserialize))]
230#[repr(C)]
231pub struct BoxShadowData {
232    pub src_rect_size: LayoutSize,
233    pub clip_mode: i32,
234    pub stretch_mode_x: i32,
235    pub stretch_mode_y: i32,
236    pub dest_rect: LayoutRect,
237}
238
239#[derive(Clone, Debug)]
240#[cfg_attr(feature = "capture", derive(Serialize))]
241#[cfg_attr(feature = "replay", derive(Deserialize))]
242#[repr(C)]
243pub struct ClipMaskInstanceBoxShadow {
244    pub common: ClipMaskInstanceCommon,
245    pub resource_address: GpuCacheAddress,
246    pub shadow_data: BoxShadowData,
247}
248
249// 16 bytes per instance should be enough for anyone!
250#[repr(C)]
251#[derive(Debug, Clone)]
252#[cfg_attr(feature = "capture", derive(Serialize))]
253#[cfg_attr(feature = "replay", derive(Deserialize))]
254pub struct PrimitiveInstanceData {
255    data: [i32; 4],
256}
257
258// Keep these in sync with the correspondong #defines in shared.glsl
259/// Specifies that an RGB CompositeInstance or ScalingInstance's UV coordinates are normalized.
260const UV_TYPE_NORMALIZED: u32 = 0;
261/// Specifies that an RGB CompositeInstance or ScalingInstance's UV coordinates are not normalized.
262const UV_TYPE_UNNORMALIZED: u32 = 1;
263
264/// A GPU-friendly representation of the `ScaleOffset` type
265#[derive(Clone, Debug)]
266#[repr(C)]
267pub struct CompositorTransform {
268    pub sx: f32,
269    pub sy: f32,
270    pub tx: f32,
271    pub ty: f32,
272}
273
274impl From<ScaleOffset> for CompositorTransform {
275    fn from(scale_offset: ScaleOffset) -> Self {
276        CompositorTransform {
277            sx: scale_offset.scale.x,
278            sy: scale_offset.scale.y,
279            tx: scale_offset.offset.x,
280            ty: scale_offset.offset.y,
281        }
282    }
283}
284
285/// Vertex format for picture cache composite shader.
286/// When editing the members, update desc::COMPOSITE
287/// so its list of instance_attributes matches:
288#[derive(Clone, Debug)]
289#[repr(C)]
290pub struct CompositeInstance {
291    // Device space destination rectangle of surface
292    rect: DeviceRect,
293    // Device space destination clip rect for this surface
294    clip_rect: DeviceRect,
295    // Color for solid color tiles, white otherwise
296    color: PremultipliedColorF,
297
298    // Packed into a single vec4 (aParams)
299    _padding: f32,
300    color_space_or_uv_type: f32, // YuvColorSpace for YUV;
301                                 // UV coordinate space for RGB
302    yuv_format: f32,            // YuvFormat
303    yuv_channel_bit_depth: f32,
304
305    // UV rectangles (pixel space) for color / yuv texture planes
306    uv_rects: [TexelRect; 3],
307
308    // Whether to flip the x and y axis respectively, where 0.0 is no-flip and 1.0 is flip.
309    flip: (f32, f32),
310
311    // Optional rounded rect clip to apply during compositing
312    rounded_clip_rect: DeviceRect,
313    rounded_clip_radii: [f32; 4],
314}
315
316impl CompositeInstance {
317    pub fn new(
318        rect: DeviceRect,
319        clip_rect: DeviceRect,
320        color: PremultipliedColorF,
321        flip: (bool, bool),
322        clip: Option<&CompositorClip>,
323    ) -> Self {
324        let uv = TexelRect::new(0.0, 0.0, 1.0, 1.0);
325
326        let (rounded_clip_rect, rounded_clip_radii) = Self::vertex_clip_params(clip, rect);
327
328        CompositeInstance {
329            rect,
330            clip_rect,
331            color,
332            _padding: 0.0,
333            color_space_or_uv_type: pack_as_float(UV_TYPE_NORMALIZED),
334            yuv_format: 0.0,
335            yuv_channel_bit_depth: 0.0,
336            uv_rects: [uv, uv, uv],
337            flip: (flip.0.into(), flip.1.into()),
338            rounded_clip_rect,
339            rounded_clip_radii,
340        }
341    }
342
343    pub fn new_rgb(
344        rect: DeviceRect,
345        clip_rect: DeviceRect,
346        color: PremultipliedColorF,
347        uv_rect: TexelRect,
348        normalized_uvs: bool,
349        flip: (bool, bool),
350        clip: Option<&CompositorClip>,
351    ) -> Self {
352        let (rounded_clip_rect, rounded_clip_radii) = Self::vertex_clip_params(clip, rect);
353
354        let uv_type = match normalized_uvs {
355            true => UV_TYPE_NORMALIZED,
356            false => UV_TYPE_UNNORMALIZED,
357        };
358        CompositeInstance {
359            rect,
360            clip_rect,
361            color,
362            _padding: 0.0,
363            color_space_or_uv_type: pack_as_float(uv_type),
364            yuv_format: 0.0,
365            yuv_channel_bit_depth: 0.0,
366            uv_rects: [uv_rect, uv_rect, uv_rect],
367            flip: (flip.0.into(), flip.1.into()),
368            rounded_clip_rect,
369            rounded_clip_radii,
370        }
371    }
372
373    pub fn new_yuv(
374        rect: DeviceRect,
375        clip_rect: DeviceRect,
376        yuv_color_space: YuvRangedColorSpace,
377        yuv_format: YuvFormat,
378        yuv_channel_bit_depth: u32,
379        uv_rects: [TexelRect; 3],
380        flip: (bool, bool),
381        clip: Option<&CompositorClip>,
382    ) -> Self {
383
384        let (rounded_clip_rect, rounded_clip_radii) = Self::vertex_clip_params(clip, rect);
385
386        CompositeInstance {
387            rect,
388            clip_rect,
389            color: PremultipliedColorF::WHITE,
390            _padding: 0.0,
391            color_space_or_uv_type: pack_as_float(yuv_color_space as u32),
392            yuv_format: pack_as_float(yuv_format as u32),
393            yuv_channel_bit_depth: pack_as_float(yuv_channel_bit_depth),
394            uv_rects,
395            flip: (flip.0.into(), flip.1.into()),
396            rounded_clip_rect,
397            rounded_clip_radii,
398        }
399    }
400
401    // Returns the CompositeFeatures that can be used to composite
402    // this RGB instance.
403    pub fn get_rgb_features(&self) -> CompositeFeatures {
404        let mut features = CompositeFeatures::empty();
405
406        // If the UV rect covers the entire texture then we can avoid UV clamping.
407        // We should try harder to determine this for unnormalized UVs too.
408        if self.color_space_or_uv_type == pack_as_float(UV_TYPE_NORMALIZED)
409            && self.uv_rects[0] == TexelRect::new(0.0, 0.0, 1.0, 1.0)
410        {
411            features |= CompositeFeatures::NO_UV_CLAMP;
412        }
413
414        if self.color == PremultipliedColorF::WHITE {
415            features |= CompositeFeatures::NO_COLOR_MODULATION
416        }
417
418        // If all the clip radii are <= 0.0, then we don't need clip masking
419        if self.rounded_clip_radii.iter().all(|r| *r <= 0.0) {
420            features |= CompositeFeatures::NO_CLIP_MASK
421        }
422
423        features
424    }
425
426    // Returns the CompositeFeatures that can be used to composite
427    // this YUV instance.
428    pub fn get_yuv_features(&self) -> CompositeFeatures {
429        let mut features = CompositeFeatures::empty();
430
431        // If all the clip radii are <= 0.0, then we don't need clip masking
432        if self.rounded_clip_radii.iter().all(|r| *r <= 0.0) {
433            features |= CompositeFeatures::NO_CLIP_MASK
434        }
435
436        features
437    }
438
439    fn vertex_clip_params(
440        clip: Option<&CompositorClip>,
441        default_rect: DeviceRect,
442    ) -> (DeviceRect, [f32; 4]) {
443        match clip {
444            Some(clip) => {
445                (
446                    clip.rect.cast_unit(),
447                    [
448                        clip.radius.top_left.width,
449                        clip.radius.bottom_left.width,
450                        clip.radius.top_right.width,
451                        clip.radius.bottom_right.width,
452                    ],
453                )
454            }
455            None => {
456                (default_rect, [0.0; 4])
457            }
458        }
459    }
460}
461
462/// Vertex format for issuing colored quads.
463#[derive(Debug, Clone)]
464#[repr(C)]
465pub struct ClearInstance {
466    pub rect: [f32; 4],
467    pub color: [f32; 4],
468}
469
470#[derive(Debug, Copy, Clone)]
471#[cfg_attr(feature = "capture", derive(Serialize))]
472#[cfg_attr(feature = "replay", derive(Deserialize))]
473pub struct PrimitiveHeaderIndex(pub i32);
474
475#[derive(Debug)]
476#[repr(C)]
477#[cfg_attr(feature = "capture", derive(Serialize))]
478#[cfg_attr(feature = "replay", derive(Deserialize))]
479pub struct PrimitiveHeaders {
480    // The integer-type headers for a primitive.
481    pub headers_int: FrameVec<PrimitiveHeaderI>,
482    // The float-type headers for a primitive.
483    pub headers_float: FrameVec<PrimitiveHeaderF>,
484}
485
486impl PrimitiveHeaders {
487    pub fn new(memory: &FrameMemory) -> PrimitiveHeaders {
488        PrimitiveHeaders {
489            headers_int: memory.new_vec(),
490            headers_float: memory.new_vec(),
491        }
492    }
493
494    // Add a new primitive header.
495    pub fn push(
496        &mut self,
497        prim_header: &PrimitiveHeader,
498        z: ZBufferId,
499        render_task_address: RenderTaskAddress,
500        user_data: [i32; 4],
501    ) -> PrimitiveHeaderIndex {
502        debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
503        let id = self.headers_float.len();
504
505        self.headers_float.push(PrimitiveHeaderF {
506            local_rect: prim_header.local_rect,
507            local_clip_rect: prim_header.local_clip_rect,
508        });
509
510        self.headers_int.push(PrimitiveHeaderI {
511            z,
512            render_task_address,
513            specific_prim_address: prim_header.specific_prim_address.as_int(),
514            transform_id: prim_header.transform_id,
515            user_data,
516        });
517
518        PrimitiveHeaderIndex(id as i32)
519    }
520}
521
522// This is a convenience type used to make it easier to pass
523// the common parts around during batching.
524#[derive(Debug)]
525pub struct PrimitiveHeader {
526    pub local_rect: LayoutRect,
527    pub local_clip_rect: LayoutRect,
528    pub specific_prim_address: GpuCacheAddress,
529    pub transform_id: TransformPaletteId,
530}
531
532// f32 parts of a primitive header
533#[derive(Debug)]
534#[repr(C)]
535#[cfg_attr(feature = "capture", derive(Serialize))]
536#[cfg_attr(feature = "replay", derive(Deserialize))]
537pub struct PrimitiveHeaderF {
538    pub local_rect: LayoutRect,
539    pub local_clip_rect: LayoutRect,
540}
541
542// i32 parts of a primitive header
543// TODO(gw): Compress parts of these down to u16
544#[derive(Debug)]
545#[repr(C)]
546#[cfg_attr(feature = "capture", derive(Serialize))]
547#[cfg_attr(feature = "replay", derive(Deserialize))]
548pub struct PrimitiveHeaderI {
549    pub z: ZBufferId,
550    pub specific_prim_address: i32,
551    pub transform_id: TransformPaletteId,
552    pub render_task_address: RenderTaskAddress,
553    pub user_data: [i32; 4],
554}
555
556pub struct GlyphInstance {
557    pub prim_header_index: PrimitiveHeaderIndex,
558}
559
560impl GlyphInstance {
561    pub fn new(
562        prim_header_index: PrimitiveHeaderIndex,
563    ) -> Self {
564        GlyphInstance {
565            prim_header_index,
566        }
567    }
568
569    // TODO(gw): Some of these fields can be moved to the primitive
570    //           header since they are constant, and some can be
571    //           compressed to a smaller size.
572    pub fn build(&self,
573        clip_task: RenderTaskAddress,
574        subpx_dir: SubpixelDirection,
575        glyph_index_in_text_run: i32,
576        glyph_uv_rect: GpuCacheAddress,
577        color_mode: ShaderColorMode,
578    ) -> PrimitiveInstanceData {
579        PrimitiveInstanceData {
580            data: [
581                self.prim_header_index.0 as i32,
582                clip_task.0 as i32,
583                (subpx_dir as u32 as i32) << 24
584                | (color_mode as u32 as i32) << 16
585                | glyph_index_in_text_run,
586                glyph_uv_rect.as_int(),
587            ],
588        }
589    }
590}
591
592pub struct SplitCompositeInstance {
593    pub prim_header_index: PrimitiveHeaderIndex,
594    pub polygons_address: i32,
595    pub z: ZBufferId,
596    pub render_task_address: RenderTaskAddress,
597}
598
599impl From<SplitCompositeInstance> for PrimitiveInstanceData {
600    fn from(instance: SplitCompositeInstance) -> Self {
601        PrimitiveInstanceData {
602            data: [
603                instance.prim_header_index.0,
604                instance.polygons_address,
605                instance.z.0,
606                instance.render_task_address.0,
607            ],
608        }
609    }
610}
611
612#[derive(Copy, Clone)]
613#[cfg_attr(feature = "capture", derive(Serialize))]
614#[cfg_attr(feature = "replay", derive(Deserialize))]
615pub struct QuadInstance {
616    pub dst_task_address: RenderTaskAddress,
617    pub prim_address_i: GpuBufferAddress,
618    pub prim_address_f: GpuBufferAddress,
619    pub quad_flags: u8,
620    pub edge_flags: u8,
621    pub part_index: u8,
622    pub segment_index: u8,
623}
624
625impl From<QuadInstance> for PrimitiveInstanceData {
626    fn from(instance: QuadInstance) -> Self {
627        /*
628            [32 prim address_i]
629            [32 prim address_f]
630            [8888 qf ef pi si]
631            [32 render task address]
632        */
633
634        PrimitiveInstanceData {
635            data: [
636                instance.prim_address_i.as_int(),
637                instance.prim_address_f.as_int(),
638
639                ((instance.quad_flags as i32)    << 24) |
640                ((instance.edge_flags as i32)    << 16) |
641                ((instance.part_index as i32)    <<  8) |
642                ((instance.segment_index as i32) <<  0),
643
644                instance.dst_task_address.0,
645            ],
646        }
647    }
648}
649
650#[derive(Debug)]
651#[cfg_attr(feature = "capture", derive(Serialize))]
652pub struct QuadSegment {
653    pub rect: LayoutRect,
654    pub task_id: RenderTaskId,
655}
656
657#[derive(Copy, Debug, Clone, PartialEq)]
658#[cfg_attr(feature = "capture", derive(Serialize))]
659#[cfg_attr(feature = "replay", derive(Deserialize))]
660#[repr(u32)]
661pub enum ClipSpace {
662    Raster = 0,
663    Primitive = 1,
664}
665
666impl ClipSpace {
667    pub fn as_int(self) -> u32 {
668        match self {
669            ClipSpace::Raster => 0,
670            ClipSpace::Primitive => 1,
671        }
672    }
673}
674
675#[repr(C)]
676#[derive(Clone)]
677#[cfg_attr(feature = "capture", derive(Serialize))]
678#[cfg_attr(feature = "replay", derive(Deserialize))]
679pub struct MaskInstance {
680    pub prim: PrimitiveInstanceData,
681    pub clip_transform_id: TransformPaletteId,
682    pub clip_address: i32,
683    pub clip_space: u32,
684    pub unused: i32,
685}
686
687
688// Note: This can use up to 12 bits due to how it will
689// be packed in the instance data.
690
691/// Flags that define how the common brush shader
692/// code should process this instance.
693#[cfg_attr(feature = "capture", derive(Serialize))]
694#[cfg_attr(feature = "replay", derive(Deserialize))]
695#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, MallocSizeOf)]
696pub struct BrushFlags(u16);
697
698bitflags! {
699    impl BrushFlags: u16 {
700        /// Apply perspective interpolation to UVs
701        const PERSPECTIVE_INTERPOLATION = 1;
702        /// Do interpolation relative to segment rect,
703        /// rather than primitive rect.
704        const SEGMENT_RELATIVE = 2;
705        /// Repeat UVs horizontally.
706        const SEGMENT_REPEAT_X = 4;
707        /// Repeat UVs vertically.
708        const SEGMENT_REPEAT_Y = 8;
709        /// Horizontally follow border-image-repeat: round.
710        const SEGMENT_REPEAT_X_ROUND = 16;
711        /// Vertically follow border-image-repeat: round.
712        const SEGMENT_REPEAT_Y_ROUND = 32;
713        /// Whether to position the repetitions so that the middle tile
714        /// is horizontally centered.
715        const SEGMENT_REPEAT_X_CENTERED = 64;
716        /// Whether to position the repetitions so that the middle tile
717        /// is vertically centered.
718        const SEGMENT_REPEAT_Y_CENTERED = 128;
719        /// Middle (fill) area of a border-image-repeat.
720        const SEGMENT_NINEPATCH_MIDDLE = 256;
721        /// The extra segment data is a texel rect.
722        const SEGMENT_TEXEL_RECT = 512;
723        /// Whether to force the anti-aliasing when the primitive
724        /// is axis-aligned.
725        const FORCE_AA = 1024;
726        /// Specifies UV coordinates are normalized
727        const NORMALIZED_UVS = 2048;
728    }
729}
730
731impl core::fmt::Debug for BrushFlags {
732    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
733        if self.is_empty() {
734            write!(f, "{:#x}", Self::empty().bits())
735        } else {
736            bitflags::parser::to_writer(self, f)
737        }
738    }
739}
740
741/// Convenience structure to encode into PrimitiveInstanceData.
742pub struct BrushInstance {
743    pub prim_header_index: PrimitiveHeaderIndex,
744    pub clip_task_address: RenderTaskAddress,
745    pub segment_index: i32,
746    pub edge_flags: EdgeAaSegmentMask,
747    pub brush_flags: BrushFlags,
748    pub resource_address: i32,
749}
750
751impl From<BrushInstance> for PrimitiveInstanceData {
752    fn from(instance: BrushInstance) -> Self {
753        PrimitiveInstanceData {
754            data: [
755                instance.prim_header_index.0,
756                instance.clip_task_address.0,
757                instance.segment_index
758                | ((instance.brush_flags.bits() as i32) << 16)
759                | ((instance.edge_flags.bits() as i32) << 28),
760                instance.resource_address,
761            ]
762        }
763    }
764}
765
766/// Convenience structure to encode into the image brush's user data.
767#[derive(Copy, Clone, Debug)]
768pub struct ImageBrushData {
769    pub color_mode: ShaderColorMode,
770    pub alpha_type: AlphaType,
771    pub raster_space: RasterizationSpace,
772    pub opacity: f32,
773}
774
775impl ImageBrushData {
776    #[inline]
777    pub fn encode(&self) -> [i32; 4] {
778        [
779            self.color_mode as i32 | ((self.alpha_type as i32) << 16),
780            self.raster_space as i32,
781            get_shader_opacity(self.opacity),
782            0,
783        ]
784    }
785}
786
787// Represents the information about a transform palette
788// entry that is passed to shaders. It includes an index
789// into the transform palette, and a set of flags. The
790// only flag currently used determines whether the
791// transform is axis-aligned (and this should have
792// pixel snapping applied).
793#[derive(Copy, Debug, Clone, PartialEq)]
794#[cfg_attr(feature = "capture", derive(Serialize))]
795#[cfg_attr(feature = "replay", derive(Deserialize))]
796#[repr(C)]
797pub struct TransformPaletteId(pub u32);
798
799impl TransformPaletteId {
800    /// Identity transform ID.
801    pub const IDENTITY: Self = TransformPaletteId(0);
802
803    /// Extract the transform kind from the id.
804    pub fn transform_kind(&self) -> TransformedRectKind {
805        if (self.0 >> 23) == 0 {
806            TransformedRectKind::AxisAligned
807        } else {
808            TransformedRectKind::Complex
809        }
810    }
811
812    /// Override the kind of transform stored in this id. This can be useful in
813    /// cases where we don't want shaders to consider certain transforms axis-
814    /// aligned (i.e. perspective warp) even though we may still want to for the
815    /// general case.
816    pub fn override_transform_kind(&self, kind: TransformedRectKind) -> Self {
817        TransformPaletteId((self.0 & 0x7FFFFFu32) | ((kind as u32) << 23))
818    }
819}
820
821/// The GPU data payload for a transform palette entry.
822#[derive(Debug, Clone)]
823#[cfg_attr(feature = "capture", derive(Serialize))]
824#[cfg_attr(feature = "replay", derive(Deserialize))]
825#[repr(C)]
826pub struct TransformData {
827    transform: LayoutToPictureTransform,
828    inv_transform: PictureToLayoutTransform,
829}
830
831impl TransformData {
832    fn invalid() -> Self {
833        TransformData {
834            transform: LayoutToPictureTransform::identity(),
835            inv_transform: PictureToLayoutTransform::identity(),
836        }
837    }
838}
839
840// Extra data stored about each transform palette entry.
841#[derive(Clone)]
842pub struct TransformMetadata {
843    transform_kind: TransformedRectKind,
844}
845
846impl TransformMetadata {
847    pub fn invalid() -> Self {
848        TransformMetadata {
849            transform_kind: TransformedRectKind::AxisAligned,
850        }
851    }
852}
853
854#[derive(Debug, Hash, Eq, PartialEq)]
855struct RelativeTransformKey {
856    from_index: SpatialNodeIndex,
857    to_index: SpatialNodeIndex,
858}
859
860// Stores a contiguous list of TransformData structs, that
861// are ready for upload to the GPU.
862// TODO(gw): For now, this only stores the complete local
863//           to world transform for each spatial node. In
864//           the future, the transform palette will support
865//           specifying a coordinate system that the transform
866//           should be relative to.
867pub struct TransformPalette {
868    transforms: FrameVec<TransformData>,
869    metadata: Vec<TransformMetadata>,
870    map: FastHashMap<RelativeTransformKey, usize>,
871}
872
873impl TransformPalette {
874    pub fn new(
875        count: usize,
876        memory: &FrameMemory,
877    ) -> Self {
878        let _ = VECS_PER_TRANSFORM;
879
880        let mut transforms = memory.new_vec_with_capacity(count);
881        let mut metadata = Vec::with_capacity(count);
882
883        transforms.push(TransformData::invalid());
884        metadata.push(TransformMetadata::invalid());
885
886        TransformPalette {
887            transforms,
888            metadata,
889            map: FastHashMap::default(),
890        }
891    }
892
893    pub fn finish(self) -> FrameVec<TransformData> {
894        self.transforms
895    }
896
897    fn get_index(
898        &mut self,
899        child_index: SpatialNodeIndex,
900        parent_index: SpatialNodeIndex,
901        spatial_tree: &SpatialTree,
902    ) -> usize {
903        if child_index == parent_index {
904            0
905        } else {
906            let key = RelativeTransformKey {
907                from_index: child_index,
908                to_index: parent_index,
909            };
910
911            let metadata = &mut self.metadata;
912            let transforms = &mut self.transforms;
913
914            *self.map
915                .entry(key)
916                .or_insert_with(|| {
917                    let transform = spatial_tree.get_relative_transform(
918                        child_index,
919                        parent_index,
920                    )
921                    .into_transform()
922                    .with_destination::<PicturePixel>();
923
924                    register_transform(
925                        metadata,
926                        transforms,
927                        transform,
928                    )
929                })
930        }
931    }
932
933    // Get a transform palette id for the given spatial node.
934    // TODO(gw): In the future, it will be possible to specify
935    //           a coordinate system id here, to allow retrieving
936    //           transforms in the local space of a given spatial node.
937    pub fn get_id(
938        &mut self,
939        from_index: SpatialNodeIndex,
940        to_index: SpatialNodeIndex,
941        spatial_tree: &SpatialTree,
942    ) -> TransformPaletteId {
943        let index = self.get_index(
944            from_index,
945            to_index,
946            spatial_tree,
947        );
948        let transform_kind = self.metadata[index].transform_kind as u32;
949        TransformPaletteId(
950            (index as u32) |
951            (transform_kind << 23)
952        )
953    }
954
955    pub fn get_custom(
956        &mut self,
957        transform: LayoutToPictureTransform,
958    ) -> TransformPaletteId {
959        let index = register_transform(
960            &mut self.metadata,
961            &mut self.transforms,
962            transform,
963        );
964
965        let transform_kind = self.metadata[index].transform_kind as u32;
966        TransformPaletteId(
967            (index as u32) |
968            (transform_kind << 23)
969        )
970    }
971}
972
973// Texture cache resources can be either a simple rect, or define
974// a polygon within a rect by specifying a UV coordinate for each
975// corner. This is useful for rendering screen-space rasterized
976// off-screen surfaces.
977#[derive(Debug, Copy, Clone)]
978#[cfg_attr(feature = "capture", derive(Serialize))]
979#[cfg_attr(feature = "replay", derive(Deserialize))]
980pub enum UvRectKind {
981    // The 2d bounds of the texture cache entry define the
982    // valid UV space for this texture cache entry.
983    Rect,
984    // The four vertices below define a quad within
985    // the texture cache entry rect. The shader can
986    // use a bilerp() to correctly interpolate a
987    // UV coord in the vertex shader.
988    Quad {
989        top_left: DeviceHomogeneousVector,
990        top_right: DeviceHomogeneousVector,
991        bottom_left: DeviceHomogeneousVector,
992        bottom_right: DeviceHomogeneousVector,
993    },
994}
995
996#[derive(Debug, Copy, Clone)]
997#[cfg_attr(feature = "capture", derive(Serialize))]
998#[cfg_attr(feature = "replay", derive(Deserialize))]
999pub struct ImageSource {
1000    pub p0: DevicePoint,
1001    pub p1: DevicePoint,
1002    // TODO: It appears that only glyphs make use of user_data (to store glyph offset
1003    // and scale).
1004    // Perhaps we should separate the two so we don't have to push an empty unused vec4
1005    // for all image sources.
1006    pub user_data: [f32; 4],
1007    pub uv_rect_kind: UvRectKind,
1008}
1009
1010impl ImageSource {
1011    pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
1012        // see fetch_image_resource in GLSL
1013        // has to be VECS_PER_IMAGE_RESOURCE vectors
1014        request.push([
1015            self.p0.x,
1016            self.p0.y,
1017            self.p1.x,
1018            self.p1.y,
1019        ]);
1020        request.push(self.user_data);
1021
1022        // If this is a polygon uv kind, then upload the four vertices.
1023        if let UvRectKind::Quad { top_left, top_right, bottom_left, bottom_right } = self.uv_rect_kind {
1024            // see fetch_image_resource_extra in GLSL
1025            //Note: we really need only 3 components per point here: X, Y, and W
1026            request.push(top_left);
1027            request.push(top_right);
1028            request.push(bottom_left);
1029            request.push(bottom_right);
1030        }
1031    }
1032}
1033
1034// Set the local -> world transform for a given spatial
1035// node in the transform palette.
1036fn register_transform(
1037    metadatas: &mut Vec<TransformMetadata>,
1038    transforms: &mut FrameVec<TransformData>,
1039    transform: LayoutToPictureTransform,
1040) -> usize {
1041    // TODO: refactor the calling code to not even try
1042    // registering a non-invertible transform.
1043    let inv_transform = transform
1044        .inverse()
1045        .unwrap_or_else(PictureToLayoutTransform::identity);
1046
1047    let metadata = TransformMetadata {
1048        transform_kind: transform.transform_kind()
1049    };
1050    let data = TransformData {
1051        transform,
1052        inv_transform,
1053    };
1054
1055    let index = transforms.len();
1056    metadatas.push(metadata);
1057    transforms.push(data);
1058
1059    index
1060}
1061
1062pub fn get_shader_opacity(opacity: f32) -> i32 {
1063    (opacity * 65535.0).round() as i32
1064}