1use api::{DirtyRect, ImageDescriptor, ImageDescriptorFlags, SnapshotImageKey};
7use api::units::*;
8use crate::border::BorderSegmentCacheKey;
9use crate::box_shadow::BoxShadowCacheKey;
10use crate::device::TextureFilter;
11use crate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
12use crate::internal_types::FastHashMap;
13use crate::prim_store::image::ImageCacheKey;
14use crate::prim_store::line_dec::LineDecorationCacheKey;
15use crate::quad::QuadCacheKey;
16use crate::resource_cache::CacheItem;
17use std::{mem, usize, f32, i32};
18use crate::surface::SurfaceBuilder;
19use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
20use crate::renderer::GpuBufferBuilderF;
21use crate::render_target::RenderTargetKind;
22use crate::render_task::{RenderTask, StaticRenderTaskSurface, RenderTaskLocation, RenderTaskKind, CachedTask};
23use crate::render_task_graph::{RenderTaskGraphBuilder, RenderTaskId};
24use euclid::Scale;
25
26const MAX_CACHE_TASK_SIZE: f32 = 4096.0;
27
28pub enum RenderTaskParent {
33 Surface,
35 RenderTask(RenderTaskId),
37}
38
39#[derive(Clone, Debug, Hash, PartialEq, Eq)]
40#[cfg_attr(feature = "capture", derive(Serialize))]
41#[cfg_attr(feature = "replay", derive(Deserialize))]
42pub enum RenderTaskCacheKeyKind {
43 BoxShadow(BoxShadowCacheKey),
44 Image(ImageCacheKey),
45 BorderSegment(BorderSegmentCacheKey),
46 LineDecoration(LineDecorationCacheKey),
47 Snapshot(SnapshotImageKey),
48 Quad(QuadCacheKey),
49}
50
51#[derive(Clone, Debug, Hash, PartialEq, Eq)]
52#[cfg_attr(feature = "capture", derive(Serialize))]
53#[cfg_attr(feature = "replay", derive(Deserialize))]
54pub struct RenderTaskCacheKey {
55 pub origin: DeviceIntPoint,
56 pub size: DeviceIntSize,
57 pub kind: RenderTaskCacheKeyKind,
58}
59
60#[derive(Debug)]
61#[cfg_attr(feature = "capture", derive(Serialize))]
62#[cfg_attr(feature = "replay", derive(Deserialize))]
63pub struct RenderTaskCacheEntry {
64 user_data: Option<[f32; 4]>,
65 target_kind: RenderTargetKind,
66 is_opaque: bool,
67 frame_id: u64,
68 pub handle: TextureCacheHandle,
69 pub render_task_id: Option<RenderTaskId>,
74}
75
76#[derive(Debug, MallocSizeOf)]
77#[cfg_attr(feature = "capture", derive(Serialize))]
78pub enum RenderTaskCacheMarker {}
79
80#[derive(Debug)]
83#[cfg_attr(feature = "capture", derive(Serialize))]
84#[cfg_attr(feature = "replay", derive(Deserialize))]
85pub struct RenderTaskCache {
86 map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheMarker>>,
87 cache_entries: FreeList<RenderTaskCacheEntry, RenderTaskCacheMarker>,
88 frame_id: u64,
89}
90
91pub type RenderTaskCacheEntryHandle = WeakFreeListHandle<RenderTaskCacheMarker>;
92
93impl RenderTaskCache {
94 pub fn new() -> Self {
95 RenderTaskCache {
96 map: FastHashMap::default(),
97 cache_entries: FreeList::new(),
98 frame_id: 0,
99 }
100 }
101
102 pub fn clear(&mut self) {
103 self.map.clear();
104 self.cache_entries.clear();
105 }
106
107 pub fn begin_frame(
108 &mut self,
109 texture_cache: &mut TextureCache,
110 ) {
111 self.frame_id += 1;
112 profile_scope!("begin_frame");
113 let cache_entries = &mut self.cache_entries;
127 let frame_id = self.frame_id;
128
129 self.map.retain(|_, handle| {
130 let mut retain = texture_cache.is_allocated(
131 &cache_entries.get(handle).handle,
132 );
133 if retain {
134 let entry = cache_entries.get_mut(&handle);
135 if frame_id > entry.frame_id + 10 {
136 texture_cache.evict_handle(&entry.handle);
137 retain = false;
138 }
139 }
140
141 if !retain {
142 let handle = mem::replace(handle, FreeListHandle::invalid());
143 cache_entries.free(handle);
144 }
145
146 retain
147 });
148
149 for (_, handle) in &self.map {
153 let entry = self.cache_entries.get_mut(handle);
154 entry.render_task_id = None;
155 }
156 }
157
158 fn alloc_render_task(
159 size: DeviceIntSize,
160 render_task: &mut RenderTask,
161 entry: &mut RenderTaskCacheEntry,
162 gpu_buffer: &mut GpuBufferBuilderF,
163 texture_cache: &mut TextureCache,
164 ) {
165 let target_kind = render_task.target_kind();
167
168 let image_format = match target_kind {
170 RenderTargetKind::Color => texture_cache.shared_color_expected_format(),
171 RenderTargetKind::Alpha => texture_cache.shared_alpha_expected_format(),
172 };
173
174 let flags = if entry.is_opaque {
175 ImageDescriptorFlags::IS_OPAQUE
176 } else {
177 ImageDescriptorFlags::empty()
178 };
179
180 let descriptor = ImageDescriptor::new(
181 size.width,
182 size.height,
183 image_format,
184 flags,
185 );
186
187 texture_cache.update(
190 &mut entry.handle,
191 descriptor,
192 TextureFilter::Linear,
193 None,
194 entry.user_data.unwrap_or([0.0; 4]),
195 DirtyRect::All,
196 gpu_buffer,
197 None,
198 render_task.uv_rect_kind(),
199 Eviction::Auto,
200 TargetShader::Default,
201 false,
202 );
203
204 let (texture_id, uv_rect, _, _, _) =
208 texture_cache.get_cache_location(&entry.handle);
209
210 let surface = StaticRenderTaskSurface::TextureCache {
211 texture: texture_id,
212 target_kind,
213 };
214
215 render_task.location = RenderTaskLocation::Static {
216 surface,
217 rect: uv_rect.to_i32(),
218 };
219 }
220
221 pub fn request_render_task(
222 &mut self,
223 key: Option<RenderTaskCacheKey>,
224 texture_cache: &mut TextureCache,
225 is_opaque: bool,
226 parent: RenderTaskParent,
227 gpu_buffer_builder: &mut GpuBufferBuilderF,
228 rg_builder: &mut RenderTaskGraphBuilder,
229 surface_builder: &mut SurfaceBuilder,
230 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
231 ) -> RenderTaskId {
232 let (task_id, rendered_this_frame) = match key {
236 None => (f(rg_builder, gpu_buffer_builder), true),
237 Some(key) => self.request_render_task_impl(
238 key,
239 is_opaque,
240 texture_cache,
241 gpu_buffer_builder,
242 rg_builder,
243 f
244 )
245 };
246
247 if rendered_this_frame {
248 match parent {
249 RenderTaskParent::Surface => {
250 surface_builder.add_child_render_task(
254 task_id,
255 rg_builder,
256 );
257 }
258 RenderTaskParent::RenderTask(parent_render_task_id) => {
259 rg_builder.add_dependency(
262 parent_render_task_id,
263 task_id,
264 );
265 }
266 }
267 }
268
269 task_id
270 }
271
272 fn request_render_task_impl(
275 &mut self,
276 key: RenderTaskCacheKey,
277 is_opaque: bool,
278 texture_cache: &mut TextureCache,
279 gpu_buffer_builder: &mut GpuBufferBuilderF,
280 rg_builder: &mut RenderTaskGraphBuilder,
281 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
282 ) -> (RenderTaskId, bool) {
283 let frame_id = self.frame_id;
284 let size = key.size;
285 let cache_entries = &mut self.cache_entries;
288 let entry_handle = self.map.entry(key).or_insert_with(|| {
289 let entry = RenderTaskCacheEntry {
290 handle: TextureCacheHandle::invalid(),
291 user_data: None,
292 target_kind: RenderTargetKind::Color, is_opaque,
294 frame_id,
295 render_task_id: None,
296 };
297 cache_entries.insert(entry)
298 });
299 let cache_entry = cache_entries.get_mut(entry_handle);
300 cache_entry.frame_id = self.frame_id;
301
302 if texture_cache.request(&cache_entry.handle, gpu_buffer_builder) {
304 let render_task_id = f(rg_builder, gpu_buffer_builder);
307
308 cache_entry.user_data = None;
309 cache_entry.is_opaque = is_opaque;
310 cache_entry.render_task_id = Some(render_task_id);
311
312 let render_task = rg_builder.get_task_mut(render_task_id);
313 let task_size = render_task.location.size();
314
315 render_task.mark_cached(entry_handle.weak());
316 cache_entry.target_kind = render_task.kind.target_kind();
317
318 RenderTaskCache::alloc_render_task(
319 task_size,
320 render_task,
321 cache_entry,
322 gpu_buffer_builder,
323 texture_cache,
324 );
325 }
326
327 if let Some(render_task_id) = cache_entry.render_task_id {
328 return (render_task_id, true);
329 }
330
331 let target_kind = cache_entry.target_kind;
332 let mut task = RenderTask::new(
333 RenderTaskLocation::CacheRequest { size, },
334 RenderTaskKind::Cached(CachedTask {
335 target_kind,
336 }),
337 );
338 task.mark_cached(entry_handle.weak());
339 let render_task_id = rg_builder.add().init(task);
340
341 (render_task_id, false)
342 }
343
344 pub fn get_cache_entry(
345 &self,
346 handle: &RenderTaskCacheEntryHandle,
347 ) -> &RenderTaskCacheEntry {
348 self.cache_entries
349 .get_opt(handle)
350 .expect("bug: invalid render task cache handle")
351 }
352
353 #[allow(dead_code)]
354 pub fn get_cache_item_for_render_task(&self,
355 texture_cache: &TextureCache,
356 key: &RenderTaskCacheKey)
357 -> CacheItem {
358 let handle = self.map.get(key).unwrap();
360 let cache_entry = self.cache_entries.get(handle);
361 texture_cache.get(&cache_entry.handle)
362 }
363
364 #[allow(dead_code)]
365 pub fn get_allocated_size_for_render_task(&self,
366 texture_cache: &TextureCache,
367 key: &RenderTaskCacheKey)
368 -> Option<usize> {
369 let handle = self.map.get(key).unwrap();
370 let cache_entry = self.cache_entries.get(handle);
371 texture_cache.get_allocated_size(&cache_entry.handle)
372 }
373}
374
375pub fn to_cache_size(size: LayoutSize, device_pixel_scale: &mut Scale<f32, LayoutPixel, DevicePixel>) -> DeviceIntSize {
383 let mut device_size = (size * *device_pixel_scale).round();
384
385 if device_size.width > MAX_CACHE_TASK_SIZE || device_size.height > MAX_CACHE_TASK_SIZE {
386 let scale = MAX_CACHE_TASK_SIZE / f32::max(device_size.width, device_size.height);
387 *device_pixel_scale = *device_pixel_scale * Scale::new(scale);
388 device_size = (size * *device_pixel_scale).round();
389 }
390
391 DeviceIntSize::new(
392 1.max(device_size.width as i32),
393 1.max(device_size.height as i32),
394 )
395}