Source code

Revision control

Other Tools

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