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::{DebugCommand, DocumentId, ExternalImageData, ExternalImageId};
6 use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
7 use api::{ImageFormat, WorldPixel, NotificationRequest};
8 use device::TextureFilter;
9 use renderer::PipelineInfo;
10 use gpu_cache::GpuCacheUpdateList;
11 use fxhash::FxHasher;
12 use plane_split::BspSplitter;
13 use profiler::BackendProfileCounters;
14 use std::{usize, i32};
15 use std::collections::{HashMap, HashSet};
16 use std::f32;
17 use std::hash::BuildHasherDefault;
18 use std::path::PathBuf;
19 use std::sync::Arc;
20 
21 #[cfg(feature = "capture")]
22 use capture::{CaptureConfig, ExternalCaptureImage};
23 #[cfg(feature = "replay")]
24 use capture::PlainExternalImage;
25 use tiling;
26 
27 pub type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
28 pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
29 
30 /// A concrete plane splitter type used in WebRender.
31 pub type PlaneSplitter = BspSplitter<f64, WorldPixel>;
32 
33 /// An ID for a texture that is owned by the `texture_cache` module.
34 ///
35 /// This can include atlases or standalone textures allocated via the texture
36 /// cache (e.g.  if an image is too large to be added to an atlas). The texture
37 /// cache manages the allocation and freeing of these IDs, and the rendering
38 /// thread maintains a map from cache texture ID to native texture.
39 ///
40 /// We never reuse IDs, so we use a u64 here to be safe.
41 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
42 #[cfg_attr(feature = "capture", derive(Serialize))]
43 #[cfg_attr(feature = "replay", derive(Deserialize))]
44 pub struct CacheTextureId(pub u64);
45 
46 /// Canonical type for texture layer indices.
47 ///
48 /// WebRender is currently not very consistent about layer index types. Some
49 /// places use i32 (since that's the type used in various OpenGL APIs), some
50 /// places use u32 (since having it be signed is non-sensical, but the
51 /// underlying graphics APIs generally operate on 32-bit integers) and some
52 /// places use usize (since that's most natural in Rust).
53 ///
54 /// Going forward, we aim to us usize throughout the codebase, since that allows
55 /// operations like indexing without a cast, and convert to the required type in
56 /// the device module when making calls into the platform layer.
57 pub type LayerIndex = usize;
58 
59 /// Identifies a render pass target that is persisted until the end of the frame.
60 ///
61 /// By default, only the targets of the immediately-preceding pass are bound as
62 /// inputs to the next pass. However, tasks can opt into having their target
63 /// preserved in a list until the end of the frame, and this type specifies the
64 /// index in that list.
65 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
66 #[cfg_attr(feature = "capture", derive(Serialize))]
67 #[cfg_attr(feature = "replay", derive(Deserialize))]
68 pub struct SavedTargetIndex(pub usize);
69 
70 impl SavedTargetIndex {
71     pub const PENDING: Self = SavedTargetIndex(!0);
72 }
73 
74 /// Identifies the source of an input texture to a shader.
75 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
76 #[cfg_attr(feature = "capture", derive(Serialize))]
77 #[cfg_attr(feature = "replay", derive(Deserialize))]
78 pub enum TextureSource {
79     /// Equivalent to `None`, allowing us to avoid using `Option`s everywhere.
80     Invalid,
81     /// An entry in the texture cache.
82     TextureCache(CacheTextureId),
83     /// An external image texture, mananged by the embedding.
84     External(ExternalImageData),
85     /// The alpha target of the immediately-preceding pass.
86     PrevPassAlpha,
87     /// The color target of the immediately-preceding pass.
88     PrevPassColor,
89     /// A render target from an earlier pass. Unlike the immediately-preceding
90     /// passes, these are not made available automatically, but are instead
91     /// opt-in by the `RenderTask` (see `mark_for_saving()`).
92     RenderTaskCache(SavedTargetIndex),
93 }
94 
95 pub const ORTHO_NEAR_PLANE: f32 = -100000.0;
96 pub const ORTHO_FAR_PLANE: f32 = 100000.0;
97 
98 #[derive(Copy, Clone, Debug, PartialEq)]
99 #[cfg_attr(feature = "capture", derive(Serialize))]
100 #[cfg_attr(feature = "replay", derive(Deserialize))]
101 pub struct RenderTargetInfo {
102     pub has_depth: bool,
103 }
104 
105 #[derive(Debug)]
106 pub enum TextureUpdateSource {
107     External {
108         id: ExternalImageId,
109         channel_index: u8,
110     },
111     Bytes { data: Arc<Vec<u8>> },
112     /// Clears the target area, rather than uploading any pixels. Used when the
113     /// texture cache debug display is active.
114     DebugClear,
115 }
116 
117 /// Command to allocate, reallocate, or free a texture for the texture cache.
118 #[derive(Debug)]
119 pub struct TextureCacheAllocation {
120     /// The virtual ID (i.e. distinct from device ID) of the texture.
121     pub id: CacheTextureId,
122     /// Details corresponding to the operation in question.
123     pub kind: TextureCacheAllocationKind,
124 }
125 
126 /// Information used when allocating / reallocating.
127 #[derive(Debug)]
128 pub struct TextureCacheAllocInfo {
129     pub width: i32,
130     pub height: i32,
131     pub layer_count: i32,
132     pub format: ImageFormat,
133     pub filter: TextureFilter,
134     /// Indicates whether this corresponds to one of the shared texture caches.
135     pub is_shared_cache: bool,
136 }
137 
138 /// Sub-operation-specific information for allocation operations.
139 #[derive(Debug)]
140 pub enum TextureCacheAllocationKind {
141     /// Performs an initial texture allocation.
142     Alloc(TextureCacheAllocInfo),
143     /// Reallocates the texture. The existing live texture with the same id
144     /// will be deallocated and its contents blitted over. The new size must
145     /// be greater than the old size.
146     Realloc(TextureCacheAllocInfo),
147     /// Frees the texture and the corresponding cache ID.
148     Free,
149 }
150 
151 /// Command to update the contents of the texture cache.
152 #[derive(Debug)]
153 pub struct TextureCacheUpdate {
154     pub id: CacheTextureId,
155     pub rect: DeviceIntRect,
156     pub stride: Option<i32>,
157     pub offset: i32,
158     pub layer_index: i32,
159     pub source: TextureUpdateSource,
160 }
161 
162 /// Atomic set of commands to manipulate the texture cache, generated on the
163 /// RenderBackend thread and executed on the Renderer thread.
164 ///
165 /// The list of allocation operations is processed before the updates. This is
166 /// important to allow coalescing of certain allocation operations.
167 #[derive(Default)]
168 pub struct TextureUpdateList {
169     /// Commands to alloc/realloc/free the textures. Processed first.
170     pub allocations: Vec<TextureCacheAllocation>,
171     /// Commands to update the contents of the textures. Processed second.
172     pub updates: Vec<TextureCacheUpdate>,
173 }
174 
175 impl TextureUpdateList {
176     /// Mints a new `TextureUpdateList`.
new() -> Self177     pub fn new() -> Self {
178         TextureUpdateList {
179             allocations: Vec::new(),
180             updates: Vec::new(),
181         }
182     }
183 
184     /// Pushes an update operation onto the list.
185     #[inline]
push_update(&mut self, update: TextureCacheUpdate)186     pub fn push_update(&mut self, update: TextureCacheUpdate) {
187         self.updates.push(update);
188     }
189 
190     /// Sends a command to the Renderer to clear the portion of the shared region
191     /// we just freed. Used when the texture cache debugger is enabled.
192     #[cold]
push_debug_clear( &mut self, id: CacheTextureId, origin: DeviceIntPoint, width: i32, height: i32, layer_index: usize )193     pub fn push_debug_clear(
194         &mut self,
195         id: CacheTextureId,
196         origin: DeviceIntPoint,
197         width: i32,
198         height: i32,
199         layer_index: usize
200     ) {
201         let size = DeviceIntSize::new(width, height);
202         let rect = DeviceIntRect::new(origin, size);
203         self.push_update(TextureCacheUpdate {
204             id,
205             rect,
206             source: TextureUpdateSource::DebugClear,
207             stride: None,
208             offset: 0,
209             layer_index: layer_index as i32,
210         });
211     }
212 
213 
214     /// Pushes an allocation operation onto the list.
push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo)215     pub fn push_alloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
216         debug_assert!(!self.allocations.iter().any(|x| x.id == id));
217         self.allocations.push(TextureCacheAllocation {
218             id,
219             kind: TextureCacheAllocationKind::Alloc(info),
220         });
221     }
222 
223     /// Pushes a reallocation operation onto the list, potentially coalescing
224     /// with previous operations.
push_realloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo)225     pub fn push_realloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
226         self.debug_assert_coalesced(id);
227 
228         // Coallesce this realloc into a previous alloc or realloc, if available.
229         if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
230             match cur.kind {
231                 TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
232                 TextureCacheAllocationKind::Realloc(ref mut i) => *i = info,
233                 TextureCacheAllocationKind::Free => panic!("Reallocating freed texture"),
234             }
235 
236             return;
237         }
238 
239         self.allocations.push(TextureCacheAllocation {
240             id,
241             kind: TextureCacheAllocationKind::Realloc(info),
242         });
243     }
244 
245     /// Pushes a free operation onto the list, potentially coalescing with
246     /// previous operations.
push_free(&mut self, id: CacheTextureId)247     pub fn push_free(&mut self, id: CacheTextureId) {
248         self.debug_assert_coalesced(id);
249 
250         // Drop any unapplied updates to the to-be-freed texture.
251         self.updates.retain(|x| x.id != id);
252 
253         // Drop any allocations for it as well. If we happen to be allocating and
254         // freeing in the same batch, we can collapse them to a no-op.
255         let idx = self.allocations.iter().position(|x| x.id == id);
256         let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
257         match removed_kind {
258             Some(TextureCacheAllocationKind::Alloc(..)) => { /* no-op! */ },
259             Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
260             Some(TextureCacheAllocationKind::Realloc(..)) | None => {
261                 self.allocations.push(TextureCacheAllocation {
262                     id,
263                     kind: TextureCacheAllocationKind::Free,
264                 });
265             }
266         };
267     }
268 
debug_assert_coalesced(&self, id: CacheTextureId)269     fn debug_assert_coalesced(&self, id: CacheTextureId) {
270         debug_assert!(
271             self.allocations.iter().filter(|x| x.id == id).count() <= 1,
272             "Allocations should have been coalesced",
273         );
274     }
275 }
276 
277 /// Wraps a tiling::Frame, but conceptually could hold more information
278 pub struct RenderedDocument {
279     pub frame: tiling::Frame,
280     pub is_new_scene: bool,
281 }
282 
283 pub enum DebugOutput {
284     FetchDocuments(String),
285     FetchClipScrollTree(String),
286     #[cfg(feature = "capture")]
287     SaveCapture(CaptureConfig, Vec<ExternalCaptureImage>),
288     #[cfg(feature = "replay")]
289     LoadCapture(PathBuf, Vec<PlainExternalImage>),
290 }
291 
292 #[allow(dead_code)]
293 pub enum ResultMsg {
294     DebugCommand(DebugCommand),
295     DebugOutput(DebugOutput),
296     RefreshShader(PathBuf),
297     UpdateGpuCache(GpuCacheUpdateList),
298     UpdateResources {
299         updates: TextureUpdateList,
300         memory_pressure: bool,
301     },
302     PublishPipelineInfo(PipelineInfo),
303     PublishDocument(
304         DocumentId,
305         RenderedDocument,
306         TextureUpdateList,
307         BackendProfileCounters,
308     ),
309     AppendNotificationRequests(Vec<NotificationRequest>),
310 }
311 
312 #[derive(Clone, Debug)]
313 pub struct ResourceCacheError {
314     description: String,
315 }
316 
317 impl ResourceCacheError {
new(description: String) -> ResourceCacheError318     pub fn new(description: String) -> ResourceCacheError {
319         ResourceCacheError {
320             description,
321         }
322     }
323 }
324