1use api::{ColorF, DocumentId, ExternalImageId, PrimitiveFlags};
6use api::{ImageFormat, NotificationRequest, Shadow, FilterOp, ImageBufferKind};
7use api::units::*;
8use api;
9use crate::render_api::DebugCommand;
10use crate::composite::NativeSurfaceOperation;
11use crate::device::TextureFilter;
12use crate::renderer::{FullFrameStats, PipelineInfo};
13use crate::gpu_cache::GpuCacheUpdateList;
14use crate::frame_builder::Frame;
15use crate::profiler::TransactionProfile;
16use fxhash::FxHasher;
17use plane_split::BspSplitter;
18use smallvec::SmallVec;
19use std::{usize, i32};
20use std::collections::{HashMap, HashSet};
21use std::f32;
22use std::hash::BuildHasherDefault;
23use std::path::PathBuf;
24use std::sync::Arc;
25
26#[cfg(any(feature = "capture", feature = "replay"))]
27use crate::capture::CaptureConfig;
28#[cfg(feature = "capture")]
29use crate::capture::ExternalCaptureImage;
30#[cfg(feature = "replay")]
31use crate::capture::PlainExternalImage;
32
33pub type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
34pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
35
36#[derive(Copy, Clone, Debug)]
38#[cfg_attr(feature = "capture", derive(Serialize))]
39pub struct PlaneSplitAnchor {
40 pub cluster_index: usize,
41 pub instance_index: usize,
42}
43
44impl PlaneSplitAnchor {
45 pub fn new(cluster_index: usize, instance_index: usize) -> Self {
46 PlaneSplitAnchor {
47 cluster_index,
48 instance_index,
49 }
50 }
51}
52
53impl Default for PlaneSplitAnchor {
54 fn default() -> Self {
55 PlaneSplitAnchor {
56 cluster_index: 0,
57 instance_index: 0,
58 }
59 }
60}
61
62pub type PlaneSplitter = BspSplitter<f64, WorldPixel, PlaneSplitAnchor>;
64
65const OPACITY_EPSILON: f32 = 0.001;
67
68#[derive(Clone, Debug, PartialEq)]
70#[cfg_attr(feature = "capture", derive(Serialize))]
71#[cfg_attr(feature = "replay", derive(Deserialize))]
72pub enum Filter {
73 Identity,
74 Blur(f32, f32),
75 Brightness(f32),
76 Contrast(f32),
77 Grayscale(f32),
78 HueRotate(f32),
79 Invert(f32),
80 Opacity(api::PropertyBinding<f32>, f32),
81 Saturate(f32),
82 Sepia(f32),
83 DropShadows(SmallVec<[Shadow; 1]>),
84 ColorMatrix(Box<[f32; 20]>),
85 SrgbToLinear,
86 LinearToSrgb,
87 ComponentTransfer,
88 Flood(ColorF),
89}
90
91impl Filter {
92 pub fn is_visible(&self) -> bool {
93 match *self {
94 Filter::Identity |
95 Filter::Blur(..) |
96 Filter::Brightness(..) |
97 Filter::Contrast(..) |
98 Filter::Grayscale(..) |
99 Filter::HueRotate(..) |
100 Filter::Invert(..) |
101 Filter::Saturate(..) |
102 Filter::Sepia(..) |
103 Filter::DropShadows(..) |
104 Filter::ColorMatrix(..) |
105 Filter::SrgbToLinear |
106 Filter::LinearToSrgb |
107 Filter::ComponentTransfer => true,
108 Filter::Opacity(_, amount) => {
109 amount > OPACITY_EPSILON
110 },
111 Filter::Flood(color) => {
112 color.a > OPACITY_EPSILON
113 }
114 }
115 }
116
117 pub fn is_noop(&self) -> bool {
118 match *self {
119 Filter::Identity => false, Filter::Blur(width, height) => width == 0.0 && height == 0.0,
121 Filter::Brightness(amount) => amount == 1.0,
122 Filter::Contrast(amount) => amount == 1.0,
123 Filter::Grayscale(amount) => amount == 0.0,
124 Filter::HueRotate(amount) => amount == 0.0,
125 Filter::Invert(amount) => amount == 0.0,
126 Filter::Opacity(api::PropertyBinding::Value(amount), _) => amount >= 1.0,
127 Filter::Saturate(amount) => amount == 1.0,
128 Filter::Sepia(amount) => amount == 0.0,
129 Filter::DropShadows(ref shadows) => {
130 for shadow in shadows {
131 if shadow.offset.x != 0.0 || shadow.offset.y != 0.0 || shadow.blur_radius != 0.0 {
132 return false;
133 }
134 }
135
136 true
137 }
138 Filter::ColorMatrix(ref matrix) => {
139 **matrix == [
140 1.0, 0.0, 0.0, 0.0,
141 0.0, 1.0, 0.0, 0.0,
142 0.0, 0.0, 1.0, 0.0,
143 0.0, 0.0, 0.0, 1.0,
144 0.0, 0.0, 0.0, 0.0
145 ]
146 }
147 Filter::Opacity(api::PropertyBinding::Binding(..), _) |
148 Filter::SrgbToLinear |
149 Filter::LinearToSrgb |
150 Filter::ComponentTransfer |
151 Filter::Flood(..) => false,
152 }
153 }
154
155
156 pub fn as_int(&self) -> i32 {
157 match *self {
159 Filter::Identity => 0, Filter::Contrast(..) => 0,
161 Filter::Grayscale(..) => 1,
162 Filter::HueRotate(..) => 2,
163 Filter::Invert(..) => 3,
164 Filter::Saturate(..) => 4,
165 Filter::Sepia(..) => 5,
166 Filter::Brightness(..) => 6,
167 Filter::ColorMatrix(..) => 7,
168 Filter::SrgbToLinear => 8,
169 Filter::LinearToSrgb => 9,
170 Filter::Flood(..) => 10,
171 Filter::ComponentTransfer => 11,
172 Filter::Blur(..) => 12,
173 Filter::DropShadows(..) => 13,
174 Filter::Opacity(..) => 14,
175 }
176 }
177}
178
179impl From<FilterOp> for Filter {
180 fn from(op: FilterOp) -> Self {
181 match op {
182 FilterOp::Identity => Filter::Identity,
183 FilterOp::Blur(w, h) => Filter::Blur(w, h),
184 FilterOp::Brightness(b) => Filter::Brightness(b),
185 FilterOp::Contrast(c) => Filter::Contrast(c),
186 FilterOp::Grayscale(g) => Filter::Grayscale(g),
187 FilterOp::HueRotate(h) => Filter::HueRotate(h),
188 FilterOp::Invert(i) => Filter::Invert(i),
189 FilterOp::Opacity(binding, opacity) => Filter::Opacity(binding, opacity),
190 FilterOp::Saturate(s) => Filter::Saturate(s),
191 FilterOp::Sepia(s) => Filter::Sepia(s),
192 FilterOp::ColorMatrix(mat) => Filter::ColorMatrix(Box::new(mat)),
193 FilterOp::SrgbToLinear => Filter::SrgbToLinear,
194 FilterOp::LinearToSrgb => Filter::LinearToSrgb,
195 FilterOp::ComponentTransfer => Filter::ComponentTransfer,
196 FilterOp::DropShadow(shadow) => Filter::DropShadows(smallvec![shadow]),
197 FilterOp::Flood(color) => Filter::Flood(color),
198 }
199 }
200}
201
202#[cfg_attr(feature = "capture", derive(Serialize))]
203#[cfg_attr(feature = "replay", derive(Deserialize))]
204#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
205pub enum Swizzle {
206 Rgba,
207 Bgra,
208}
209
210impl Default for Swizzle {
211 fn default() -> Self {
212 Swizzle::Rgba
213 }
214}
215
216#[cfg_attr(feature = "capture", derive(Serialize))]
218#[cfg_attr(feature = "replay", derive(Deserialize))]
219#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
220pub struct SwizzleSettings {
221 pub bgra8_sampling_swizzle: Swizzle,
223}
224
225#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
234#[cfg_attr(feature = "capture", derive(Serialize))]
235#[cfg_attr(feature = "replay", derive(Deserialize))]
236pub struct CacheTextureId(pub u32);
237
238impl CacheTextureId {
239 pub const INVALID: CacheTextureId = CacheTextureId(!0);
240}
241
242#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
243#[cfg_attr(feature = "capture", derive(Serialize))]
244#[cfg_attr(feature = "replay", derive(Deserialize))]
245pub struct DeferredResolveIndex(pub u32);
246
247#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
249#[cfg_attr(feature = "capture", derive(Serialize))]
250#[cfg_attr(feature = "replay", derive(Deserialize))]
251pub enum TextureSource {
252 Invalid,
254 TextureCache(CacheTextureId, Swizzle),
256 External(DeferredResolveIndex, ImageBufferKind),
258 Dummy,
261}
262
263impl TextureSource {
264 pub fn image_buffer_kind(&self) -> ImageBufferKind {
265 match *self {
266 TextureSource::TextureCache(..) => ImageBufferKind::Texture2D,
267
268 TextureSource::External(_, image_buffer_kind) => image_buffer_kind,
269
270 TextureSource::Dummy => ImageBufferKind::Texture2D,
272
273 TextureSource::Invalid => ImageBufferKind::Texture2D,
274 }
275 }
276
277 #[inline]
278 pub fn is_compatible(
279 &self,
280 other: &TextureSource,
281 ) -> bool {
282 *self == TextureSource::Invalid ||
283 *other == TextureSource::Invalid ||
284 self == other
285 }
286}
287
288#[derive(Copy, Clone, Debug, PartialEq)]
289#[cfg_attr(feature = "capture", derive(Serialize))]
290#[cfg_attr(feature = "replay", derive(Deserialize))]
291pub struct RenderTargetInfo {
292 pub has_depth: bool,
293}
294
295#[derive(Debug)]
296pub enum TextureUpdateSource {
297 External {
298 id: ExternalImageId,
299 channel_index: u8,
300 },
301 Bytes { data: Arc<Vec<u8>> },
302 DebugClear,
305}
306
307#[derive(Debug)]
309pub struct TextureCacheAllocation {
310 pub id: CacheTextureId,
312 pub kind: TextureCacheAllocationKind,
314}
315
316#[derive(Copy, Clone, Debug, Eq, PartialEq)]
318#[cfg_attr(feature = "capture", derive(Serialize))]
319#[cfg_attr(feature = "replay", derive(Deserialize))]
320pub enum TextureCacheCategory {
321 Atlas,
322 Standalone,
323 PictureTile,
324 RenderTarget,
325}
326
327#[derive(Copy, Clone, Debug, Eq, PartialEq)]
329pub struct TextureCacheAllocInfo {
330 pub width: i32,
331 pub height: i32,
332 pub format: ImageFormat,
333 pub filter: TextureFilter,
334 pub target: ImageBufferKind,
335 pub is_shared_cache: bool,
337 pub has_depth: bool,
339 pub category: TextureCacheCategory
340}
341
342#[derive(Debug)]
344pub enum TextureCacheAllocationKind {
345 Alloc(TextureCacheAllocInfo),
347 Reset(TextureCacheAllocInfo),
349 Free,
351}
352
353#[derive(Debug)]
355pub struct TextureCacheUpdate {
356 pub rect: DeviceIntRect,
357 pub stride: Option<i32>,
358 pub offset: i32,
359 pub format_override: Option<ImageFormat>,
360 pub source: TextureUpdateSource,
361}
362
363#[derive(Default)]
369pub struct TextureUpdateList {
370 pub clears_shared_cache: bool,
373 pub allocations: Vec<TextureCacheAllocation>,
375 pub updates: FastHashMap<CacheTextureId, Vec<TextureCacheUpdate>>,
377}
378
379impl TextureUpdateList {
380 pub fn new() -> Self {
382 TextureUpdateList {
383 clears_shared_cache: false,
384 allocations: Vec::new(),
385 updates: FastHashMap::default(),
386 }
387 }
388
389 pub fn is_nop(&self) -> bool {
391 self.allocations.is_empty() && self.updates.is_empty()
392 }
393
394 #[inline]
396 pub fn note_clear(&mut self) {
397 self.clears_shared_cache = true;
398 }
399
400 #[inline]
402 pub fn push_update(&mut self, id: CacheTextureId, update: TextureCacheUpdate) {
403 self.updates
404 .entry(id)
405 .or_default()
406 .push(update);
407 }
408
409 #[cold]
412 pub fn push_debug_clear(
413 &mut self,
414 id: CacheTextureId,
415 origin: DeviceIntPoint,
416 width: i32,
417 height: i32,
418 ) {
419 let size = DeviceIntSize::new(width, height);
420 let rect = DeviceIntRect::from_origin_and_size(origin, size);
421 self.push_update(id, TextureCacheUpdate {
422 rect,
423 stride: None,
424 offset: 0,
425 format_override: None,
426 source: TextureUpdateSource::DebugClear,
427 });
428 }
429
430
431 pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
433 debug_assert!(!self.allocations.iter().any(|x| x.id == id));
434 self.allocations.push(TextureCacheAllocation {
435 id,
436 kind: TextureCacheAllocationKind::Alloc(info),
437 });
438 }
439
440 pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
443 self.debug_assert_coalesced(id);
444
445 self.updates.remove(&id);
447
448 if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
450 match cur.kind {
451 TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
452 TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
453 TextureCacheAllocationKind::Free => panic!("Resetting freed texture"),
454 }
455 return
456 }
457
458 self.allocations.push(TextureCacheAllocation {
459 id,
460 kind: TextureCacheAllocationKind::Reset(info),
461 });
462 }
463
464 pub fn push_free(&mut self, id: CacheTextureId) {
467 self.debug_assert_coalesced(id);
468
469 self.updates.remove(&id);
471
472 let idx = self.allocations.iter().position(|x| x.id == id);
475 let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
476 match removed_kind {
477 Some(TextureCacheAllocationKind::Alloc(..)) => { },
478 Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
479 Some(TextureCacheAllocationKind::Reset(..)) |
480 None => {
481 self.allocations.push(TextureCacheAllocation {
482 id,
483 kind: TextureCacheAllocationKind::Free,
484 });
485 }
486 };
487 }
488
489 fn debug_assert_coalesced(&self, id: CacheTextureId) {
490 debug_assert!(
491 self.allocations.iter().filter(|x| x.id == id).count() <= 1,
492 "Allocations should have been coalesced",
493 );
494 }
495}
496
497pub struct ResourceUpdateList {
500 pub native_surface_updates: Vec<NativeSurfaceOperation>,
502
503 pub texture_updates: TextureUpdateList,
505}
506
507impl ResourceUpdateList {
508 pub fn is_nop(&self) -> bool {
510 self.texture_updates.is_nop() && self.native_surface_updates.is_empty()
511 }
512}
513
514pub struct RenderedDocument {
516 pub frame: Frame,
517 pub is_new_scene: bool,
518 pub profile: TransactionProfile,
519 pub frame_stats: Option<FullFrameStats>
520}
521
522pub enum DebugOutput {
523 #[cfg(feature = "capture")]
524 SaveCapture(CaptureConfig, Vec<ExternalCaptureImage>),
525 #[cfg(feature = "replay")]
526 LoadCapture(CaptureConfig, Vec<PlainExternalImage>),
527}
528
529#[allow(dead_code)]
530pub enum ResultMsg {
531 DebugCommand(DebugCommand),
532 DebugOutput(DebugOutput),
533 RefreshShader(PathBuf),
534 UpdateGpuCache(GpuCacheUpdateList),
535 UpdateResources {
536 resource_updates: ResourceUpdateList,
537 memory_pressure: bool,
538 },
539 PublishPipelineInfo(PipelineInfo),
540 PublishDocument(
541 DocumentId,
542 RenderedDocument,
543 ResourceUpdateList,
544 ),
545 AppendNotificationRequests(Vec<NotificationRequest>),
546 ForceRedraw,
547}
548
549#[derive(Clone, Debug)]
550pub struct ResourceCacheError {
551 description: String,
552}
553
554impl ResourceCacheError {
555 pub fn new(description: String) -> ResourceCacheError {
556 ResourceCacheError {
557 description,
558 }
559 }
560}
561
562#[derive(Copy, Clone, Debug)]
564pub struct LayoutPrimitiveInfo {
565 pub rect: LayoutRect,
568 pub clip_rect: LayoutRect,
569 pub flags: PrimitiveFlags,
570}
571
572impl LayoutPrimitiveInfo {
573 pub fn with_clip_rect(rect: LayoutRect, clip_rect: LayoutRect) -> Self {
574 Self {
575 rect,
576 clip_rect,
577 flags: PrimitiveFlags::default(),
578 }
579 }
580}