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