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