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