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