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