Skip to main content

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