1use api::{BlobImageRequest, ImageDescriptorFlags, ImageFormat, RasterizedBlobImage};
6use api::{DebugFlags, FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
7use api::{ExternalImageData, ExternalImageType, ExternalImageId, BlobImageResult};
8use api::{DirtyRect, GlyphDimensions, IdNamespace, DEFAULT_TILE_SIZE};
9use api::{ColorF, ImageData, ImageDescriptor, ImageKey, ImageRendering, TileSize};
10use api::{BlobImageHandler, BlobImageKey, VoidPtrToSizeFn};
11use api::units::*;
12use euclid::size2;
13use crate::render_target::RenderTargetKind;
14use crate::render_task::{RenderTaskLocation, StaticRenderTaskSurface};
15use crate::{render_api::{ClearCache, AddFont, ResourceUpdate, MemoryReport}, util::WeakTable};
16use crate::prim_store::image::AdjustedImageSource;
17use crate::image_tiling::{compute_tile_size, compute_tile_range};
18#[cfg(feature = "capture")]
19use crate::capture::ExternalCaptureImage;
20#[cfg(feature = "replay")]
21use crate::capture::PlainExternalImage;
22#[cfg(any(feature = "replay", feature = "png", feature="capture"))]
23use crate::capture::CaptureConfig;
24use crate::composite::{NativeSurfaceId, NativeSurfaceOperation, NativeTileId, NativeSurfaceOperationDetails};
25use crate::device::TextureFilter;
26use crate::glyph_cache::{GlyphCache, CachedGlyphInfo};
27use crate::glyph_cache::GlyphCacheEntry;
28use glyph_rasterizer::{GLYPH_FLASHING, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer, GlyphRasterJob};
29use glyph_rasterizer::{SharedFontResources, BaseFontInstance};
30use crate::gpu_types::UvRectKind;
31use crate::internal_types::{
32 CacheTextureId, FastHashMap, FastHashSet, TextureSource, ResourceUpdateList,
33 FrameId, FrameStamp,
34};
35use crate::profiler::{self, TransactionProfile, bytes_to_mb};
36use crate::render_task_graph::{RenderTaskId, RenderTaskGraphBuilder};
37use crate::render_task_cache::{RenderTaskCache, RenderTaskCacheKey, RenderTaskParent};
38use crate::render_task_cache::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle};
39use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF, GpuBufferHandle};
40use crate::surface::SurfaceBuilder;
41use euclid::point2;
42use smallvec::SmallVec;
43use std::collections::hash_map::Entry::{self, Occupied, Vacant};
44use std::collections::hash_map::{Iter, IterMut};
45use std::collections::VecDeque;
46use std::{cmp, mem};
47use std::fmt::Debug;
48use std::hash::Hash;
49use std::os::raw::c_void;
50#[cfg(any(feature = "capture", feature = "replay"))]
51use std::path::PathBuf;
52use std::sync::Arc;
53use std::sync::atomic::{AtomicUsize, Ordering};
54use std::u32;
55use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
56use crate::picture_textures::PictureTextures;
57use peek_poke::PeekPoke;
58
59static NEXT_NATIVE_SURFACE_ID: AtomicUsize = AtomicUsize::new(0);
61
62#[cfg_attr(feature = "capture", derive(Serialize))]
63#[cfg_attr(feature = "replay", derive(Deserialize))]
64pub struct GlyphFetchResult {
65 pub index_in_text_run: i32,
66 pub uv_rect_address: GpuBufferAddress,
67 pub offset: DevicePoint,
68 pub size: DeviceIntSize,
69 pub scale: f32,
70 pub subpx_offset_x: u8,
71 pub subpx_offset_y: u8,
72 pub is_packed_glyph: bool,
73}
74
75#[derive(Debug, Clone)]
85#[cfg_attr(feature = "capture", derive(Serialize))]
86#[cfg_attr(feature = "replay", derive(Deserialize))]
87pub struct CacheItem {
88 pub texture_id: TextureSource,
89 pub uv_rect_handle: GpuBufferHandle,
90 pub uv_rect: DeviceIntRect,
91 pub user_data: [f32; 4],
92}
93
94impl CacheItem {
95 pub fn invalid() -> Self {
96 CacheItem {
97 texture_id: TextureSource::Invalid,
98 uv_rect_handle: GpuBufferHandle::INVALID,
99 uv_rect: DeviceIntRect::zero(),
100 user_data: [0.0; 4],
101 }
102 }
103
104 pub fn is_valid(&self) -> bool {
105 self.texture_id != TextureSource::Invalid
106 }
107}
108
109#[derive(Clone, Debug)]
112pub enum CachedImageData {
113 Raw(Arc<Vec<u8>>),
116 Blob,
121 Snapshot,
126 External(ExternalImageData),
129}
130
131impl From<ImageData> for CachedImageData {
132 fn from(img_data: ImageData) -> Self {
133 match img_data {
134 ImageData::Raw(data) => CachedImageData::Raw(data),
135 ImageData::External(data) => CachedImageData::External(data),
136 }
137 }
138}
139
140impl CachedImageData {
141 #[inline]
143 pub fn is_blob(&self) -> bool {
144 match *self {
145 CachedImageData::Blob => true,
146 _ => false,
147 }
148 }
149
150 #[inline]
151 pub fn is_snapshot(&self) -> bool {
152 match *self {
153 CachedImageData::Snapshot => true,
154 _ => false,
155 }
156 }
157
158 #[inline]
161 pub fn uses_texture_cache(&self) -> bool {
162 match *self {
163 CachedImageData::External(ref ext_data) => match ext_data.image_type {
164 ExternalImageType::TextureHandle(_) => false,
165 ExternalImageType::Buffer => true,
166 },
167 CachedImageData::Blob => true,
168 CachedImageData::Raw(_) => true,
169 CachedImageData::Snapshot => true,
170 }
171 }
172}
173
174#[derive(Debug)]
175#[cfg_attr(feature = "capture", derive(Serialize))]
176#[cfg_attr(feature = "replay", derive(Deserialize))]
177pub struct ImageProperties {
178 pub descriptor: ImageDescriptor,
179 pub external_image: Option<ExternalImageData>,
180 pub tiling: Option<TileSize>,
181 pub visible_rect: DeviceIntRect,
184 pub adjustment: AdjustedImageSource,
185}
186
187#[derive(Debug, Copy, Clone, PartialEq)]
188enum State {
189 Idle,
190 AddResources,
191 QueryResources,
192}
193
194type RasterizedBlob = FastHashMap<TileOffset, RasterizedBlobImage>;
196
197#[cfg_attr(feature = "capture", derive(Serialize))]
198#[cfg_attr(feature = "replay", derive(Deserialize))]
199#[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
200pub struct ImageGeneration(pub u32);
201
202impl ImageGeneration {
203 pub const INVALID: ImageGeneration = ImageGeneration(u32::MAX);
204}
205
206struct ImageResource {
207 data: CachedImageData,
208 descriptor: ImageDescriptor,
209 tiling: Option<TileSize>,
210 visible_rect: DeviceIntRect,
213 adjustment: AdjustedImageSource,
214 generation: ImageGeneration,
215}
216
217#[derive(Default)]
218struct ImageTemplates {
219 images: FastHashMap<ImageKey, ImageResource>,
220}
221
222impl ImageTemplates {
223 fn insert(&mut self, key: ImageKey, resource: ImageResource) {
224 self.images.insert(key, resource);
225 }
226
227 fn remove(&mut self, key: ImageKey) -> Option<ImageResource> {
228 self.images.remove(&key)
229 }
230
231 fn get(&self, key: ImageKey) -> Option<&ImageResource> {
232 self.images.get(&key)
233 }
234
235 fn get_mut(&mut self, key: ImageKey) -> Option<&mut ImageResource> {
236 self.images.get_mut(&key)
237 }
238}
239
240#[cfg_attr(feature = "capture", derive(Serialize))]
241#[cfg_attr(feature = "replay", derive(Deserialize))]
242struct CachedImageInfo {
243 texture_cache_handle: TextureCacheHandle,
244 dirty_rect: ImageDirtyRect,
245 manual_eviction: bool,
246}
247
248impl CachedImageInfo {
249 fn mark_unused(&mut self, texture_cache: &mut TextureCache) {
250 texture_cache.evict_handle(&self.texture_cache_handle);
251 self.manual_eviction = false;
252 }
253}
254
255#[cfg(debug_assertions)]
256impl Drop for CachedImageInfo {
257 fn drop(&mut self) {
258 debug_assert!(!self.manual_eviction, "Manual eviction requires cleanup");
259 }
260}
261
262#[cfg_attr(feature = "capture", derive(Serialize))]
263#[cfg_attr(feature = "replay", derive(Deserialize))]
264pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
265 resources: FastHashMap<K, V>,
266 pub user_data: U,
267}
268
269impl<K, V, U> ResourceClassCache<K, V, U>
270where
271 K: Clone + Hash + Eq + Debug,
272 U: Default,
273{
274 pub fn new() -> Self {
275 ResourceClassCache {
276 resources: FastHashMap::default(),
277 user_data: Default::default(),
278 }
279 }
280
281 pub fn get(&self, key: &K) -> &V {
282 self.resources.get(key)
283 .expect("Didn't find a cached resource with that ID!")
284 }
285
286 pub fn try_get(&self, key: &K) -> Option<&V> {
287 self.resources.get(key)
288 }
289
290 pub fn insert(&mut self, key: K, value: V) {
291 self.resources.insert(key, value);
292 }
293
294 pub fn remove(&mut self, key: &K) -> Option<V> {
295 self.resources.remove(key)
296 }
297
298 pub fn get_mut(&mut self, key: &K) -> &mut V {
299 self.resources.get_mut(key)
300 .expect("Didn't find a cached resource with that ID!")
301 }
302
303 pub fn try_get_mut(&mut self, key: &K) -> Option<&mut V> {
304 self.resources.get_mut(key)
305 }
306
307 pub fn entry(&mut self, key: K) -> Entry<K, V> {
308 self.resources.entry(key)
309 }
310
311 pub fn iter(&self) -> Iter<K, V> {
312 self.resources.iter()
313 }
314
315 pub fn iter_mut(&mut self) -> IterMut<K, V> {
316 self.resources.iter_mut()
317 }
318
319 pub fn is_empty(&mut self) -> bool {
320 self.resources.is_empty()
321 }
322
323 pub fn clear(&mut self) {
324 self.resources.clear();
325 }
326
327 pub fn retain<F>(&mut self, f: F)
328 where
329 F: FnMut(&K, &mut V) -> bool,
330 {
331 self.resources.retain(f);
332 }
333}
334
335#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
336#[cfg_attr(feature = "capture", derive(Serialize))]
337#[cfg_attr(feature = "replay", derive(Deserialize))]
338struct CachedImageKey {
339 pub rendering: ImageRendering,
340 pub tile: Option<TileOffset>,
341}
342
343#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
344#[cfg_attr(feature = "capture", derive(Serialize))]
345#[cfg_attr(feature = "replay", derive(Deserialize))]
346pub struct ImageRequest {
347 pub key: ImageKey,
348 pub rendering: ImageRendering,
349 pub tile: Option<TileOffset>,
350}
351
352impl ImageRequest {
353 pub fn with_tile(&self, offset: TileOffset) -> Self {
354 ImageRequest {
355 key: self.key,
356 rendering: self.rendering,
357 tile: Some(offset),
358 }
359 }
360
361 pub fn is_untiled_auto(&self) -> bool {
362 self.tile.is_none() && self.rendering == ImageRendering::Auto
363 }
364}
365
366impl Into<BlobImageRequest> for ImageRequest {
367 fn into(self) -> BlobImageRequest {
368 BlobImageRequest {
369 key: BlobImageKey(self.key),
370 tile: self.tile.unwrap(),
371 }
372 }
373}
374
375impl Into<CachedImageKey> for ImageRequest {
376 fn into(self) -> CachedImageKey {
377 CachedImageKey {
378 rendering: self.rendering,
379 tile: self.tile,
380 }
381 }
382}
383
384#[derive(Debug)]
385#[cfg_attr(feature = "capture", derive(Clone, Serialize))]
386#[cfg_attr(feature = "replay", derive(Deserialize))]
387pub enum ImageCacheError {
388 OverLimitSize,
389}
390
391#[cfg_attr(feature = "capture", derive(Serialize))]
392#[cfg_attr(feature = "replay", derive(Deserialize))]
393enum ImageResult {
394 UntiledAuto(CachedImageInfo),
395 Multi(ResourceClassCache<CachedImageKey, CachedImageInfo, ()>),
396 Err(ImageCacheError),
397}
398
399impl ImageResult {
400 fn drop_from_cache(&mut self, texture_cache: &mut TextureCache) {
402 match *self {
403 ImageResult::UntiledAuto(ref mut entry) => {
404 entry.mark_unused(texture_cache);
405 },
406 ImageResult::Multi(ref mut entries) => {
407 for entry in entries.resources.values_mut() {
408 entry.mark_unused(texture_cache);
409 }
410 },
411 ImageResult::Err(_) => {},
412 }
413 }
414}
415
416type ImageCache = ResourceClassCache<ImageKey, ImageResult, ()>;
417
418struct Resources {
419 fonts: SharedFontResources,
420 image_templates: ImageTemplates,
421 weak_fonts: WeakTable
425}
426
427pub type GlyphDimensionsCache = FastHashMap<(FontInstanceKey, GlyphIndex), Option<GlyphDimensions>>;
431
432struct RenderTarget {
434 size: DeviceIntSize,
435 format: ImageFormat,
436 texture_id: CacheTextureId,
437 is_active: bool,
439 last_frame_used: FrameId,
440}
441
442impl RenderTarget {
443 fn size_in_bytes(&self) -> usize {
444 let bpp = self.format.bytes_per_pixel() as usize;
445 (self.size.width * self.size.height) as usize * bpp
446 }
447
448 pub fn used_recently(&self, current_frame_id: FrameId, threshold: u64) -> bool {
451 self.last_frame_used + threshold >= current_frame_id
452 }
453}
454
455pub struct ResourceCache {
461 cached_glyphs: GlyphCache,
462 cached_images: ImageCache,
463 cached_render_tasks: RenderTaskCache,
464
465 resources: Resources,
466 state: State,
467 current_frame_id: FrameId,
468
469 #[cfg(feature = "capture")]
470 capture_dirty: bool,
474
475 pub texture_cache: TextureCache,
476 pub picture_textures: PictureTextures,
477
478 cached_glyph_dimensions: GlyphDimensionsCache,
480 glyph_rasterizer: GlyphRasterizer,
481
482 pending_image_requests: FastHashSet<ImageRequest>,
486
487 rasterized_blob_images: FastHashMap<BlobImageKey, RasterizedBlob>,
488
489 deleted_blob_keys: VecDeque<Vec<BlobImageKey>>,
492
493 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
497
498 pending_native_surface_updates: Vec<NativeSurfaceOperation>,
500
501 image_templates_memory: usize,
502 font_templates_memory: usize,
503
504 render_target_pool: Vec<RenderTarget>,
506
507 fallback_handle: TextureCacheHandle,
521 debug_fallback_panic: bool,
522 debug_fallback_pink: bool,
523}
524
525impl ResourceCache {
526 pub fn new(
527 texture_cache: TextureCache,
528 picture_textures: PictureTextures,
529 glyph_rasterizer: GlyphRasterizer,
530 cached_glyphs: GlyphCache,
531 fonts: SharedFontResources,
532 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
533 ) -> Self {
534 ResourceCache {
535 cached_glyphs,
536 cached_images: ResourceClassCache::new(),
537 cached_render_tasks: RenderTaskCache::new(),
538 resources: Resources {
539 fonts,
540 image_templates: ImageTemplates::default(),
541 weak_fonts: WeakTable::new(),
542 },
543 cached_glyph_dimensions: FastHashMap::default(),
544 texture_cache,
545 picture_textures,
546 state: State::Idle,
547 current_frame_id: FrameId::INVALID,
548 pending_image_requests: FastHashSet::default(),
549 glyph_rasterizer,
550 rasterized_blob_images: FastHashMap::default(),
551 deleted_blob_keys: vec![Vec::new(), Vec::new(), Vec::new()].into(),
553 blob_image_handler,
554 pending_native_surface_updates: Vec::new(),
555 #[cfg(feature = "capture")]
556 capture_dirty: true,
557 image_templates_memory: 0,
558 font_templates_memory: 0,
559 render_target_pool: Vec::new(),
560 fallback_handle: TextureCacheHandle::invalid(),
561 debug_fallback_panic: false,
562 debug_fallback_pink: false,
563 }
564 }
565
566 #[cfg(test)]
568 pub fn new_for_testing() -> Self {
569 use rayon::ThreadPoolBuilder;
570
571 let texture_cache = TextureCache::new_for_testing(
572 4096,
573 ImageFormat::RGBA8,
574 );
575 let workers = Arc::new(ThreadPoolBuilder::new().build().unwrap());
576 let glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
577 let cached_glyphs = GlyphCache::new();
578 let fonts = SharedFontResources::new(IdNamespace(0));
579 let picture_textures = PictureTextures::new(
580 crate::tile_cache::TILE_SIZE_DEFAULT,
581 TextureFilter::Nearest,
582 );
583
584 ResourceCache::new(
585 texture_cache,
586 picture_textures,
587 glyph_rasterizer,
588 cached_glyphs,
589 fonts,
590 None,
591 )
592 }
593
594 pub fn max_texture_size(&self) -> i32 {
595 self.texture_cache.max_texture_size()
596 }
597
598 pub fn tiling_threshold(&self) -> i32 {
601 self.texture_cache.tiling_threshold()
602 }
603
604 pub fn enable_multithreading(&mut self, enable: bool) {
605 self.glyph_rasterizer.enable_multithreading(enable);
606 }
607
608 fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool {
609 let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
610 match *data {
611 CachedImageData::Raw(_) | CachedImageData::Blob => size_check,
612 CachedImageData::External(info) => {
613 info.image_type == ExternalImageType::Buffer && size_check
616 }
617 CachedImageData::Snapshot => false,
618 }
619 }
620
621 pub fn request_render_task(
633 &mut self,
634 key: Option<RenderTaskCacheKey>,
635 is_opaque: bool,
636 parent: RenderTaskParent,
637 gpu_buffer_builder: &mut GpuBufferBuilderF,
638 rg_builder: &mut RenderTaskGraphBuilder,
639 surface_builder: &mut SurfaceBuilder,
640 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
641 ) -> RenderTaskId {
642 self.cached_render_tasks.request_render_task(
643 key.clone(),
644 &mut self.texture_cache,
645 is_opaque,
646 parent,
647 gpu_buffer_builder,
648 rg_builder,
649 surface_builder,
650 f
651 )
652 }
653
654 pub fn render_as_image(
655 &mut self,
656 image_key: ImageKey,
657 size: DeviceIntSize,
658 rg_builder: &mut RenderTaskGraphBuilder,
659 gpu_buffer_builder: &mut GpuBufferBuilderF,
660 is_opaque: bool,
661 adjustment: &AdjustedImageSource,
662 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
663 ) -> RenderTaskId {
664
665 let task_id = f(rg_builder, gpu_buffer_builder);
666
667 let render_task = rg_builder.get_task_mut(task_id);
668
669 let image_result = self.cached_images.entry(image_key).or_insert_with(|| {
687 ImageResult::UntiledAuto(CachedImageInfo {
688 texture_cache_handle: TextureCacheHandle::invalid(),
689 dirty_rect: ImageDirtyRect::All,
690 manual_eviction: true,
691 })
692 });
693
694 let ImageResult::UntiledAuto(ref mut info) = *image_result else {
695 unreachable!("Expected untiled image with auto filter for snapshot");
696 };
697
698 let flags = if is_opaque {
699 ImageDescriptorFlags::IS_OPAQUE
700 } else {
701 ImageDescriptorFlags::empty()
702 };
703
704 let descriptor = ImageDescriptor::new(
705 size.width,
706 size.height,
707 self.texture_cache.shared_color_expected_format(),
708 flags,
709 );
710
711 let force_standalone_texture = true;
718
719 let user_data = [0.0; 4];
722 self.texture_cache.update(
723 &mut info.texture_cache_handle,
724 descriptor,
725 TextureFilter::Linear,
726 None,
727 user_data,
728 DirtyRect::All,
729 gpu_buffer_builder,
730 None,
731 render_task.uv_rect_kind(),
732 Eviction::Manual,
733 TargetShader::Default,
734 force_standalone_texture,
735 );
736
737 let (texture_id, uv_rect, _, _, _) =
741 self.texture_cache.get_cache_location(&info.texture_cache_handle);
742
743 render_task.location = RenderTaskLocation::Static {
744 surface: StaticRenderTaskSurface::TextureCache {
745 texture: texture_id,
746 target_kind: RenderTargetKind::Color,
747 },
748 rect: uv_rect.to_i32(),
749 };
750
751 self.resources.image_templates
752 .get_mut(image_key)
753 .unwrap()
754 .adjustment = *adjustment;
755
756 task_id
757 }
758
759 pub fn post_scene_building_update(
760 &mut self,
761 updates: Vec<ResourceUpdate>,
762 profile: &mut TransactionProfile,
763 ) {
764 #[cfg(feature = "capture")]
768 match updates.is_empty() {
769 false => self.capture_dirty = true,
770 _ => {},
771 }
772
773 for update in updates {
774 match update {
775 ResourceUpdate::AddImage(img) => {
776 if let ImageData::Raw(ref bytes) = img.data {
777 self.image_templates_memory += bytes.len();
778 profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
779 }
780 self.add_image_template(
781 img.key,
782 img.descriptor,
783 img.data.into(),
784 &img.descriptor.size.into(),
785 img.tiling,
786 );
787 profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
788 }
789 ResourceUpdate::UpdateImage(img) => {
790 self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
791 }
792 ResourceUpdate::AddBlobImage(img) => {
793 self.add_image_template(
794 img.key.as_image(),
795 img.descriptor,
796 CachedImageData::Blob,
797 &img.visible_rect,
798 Some(img.tile_size),
799 );
800 }
801 ResourceUpdate::UpdateBlobImage(img) => {
802 self.update_image_template(
803 img.key.as_image(),
804 img.descriptor,
805 CachedImageData::Blob,
806 &to_image_dirty_rect(
807 &img.dirty_rect
808 ),
809 );
810 self.discard_tiles_outside_visible_area(img.key, &img.visible_rect); self.set_image_visible_rect(img.key.as_image(), &img.visible_rect);
812 }
813 ResourceUpdate::DeleteImage(img) => {
814 self.delete_image_template(img);
815 profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
816 profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
817 }
818 ResourceUpdate::DeleteBlobImage(img) => {
819 self.delete_image_template(img.as_image());
820 }
821 ResourceUpdate::AddSnapshotImage(img) => {
822 let format = self.texture_cache.shared_color_expected_format();
823 self.add_image_template(
824 img.key.as_image(),
825 ImageDescriptor {
826 format,
827 size: DeviceIntSize::zero(),
829 stride: None,
830 offset: 0,
831 flags: ImageDescriptorFlags::empty(),
832 },
833 CachedImageData::Snapshot,
834 &DeviceIntRect::zero(),
835 None,
836 );
837 }
838 ResourceUpdate::DeleteSnapshotImage(img) => {
839 self.delete_image_template(img.as_image());
840 }
841 ResourceUpdate::DeleteFont(font) => {
842 if let Some(shared_key) = self.resources.fonts.font_keys.delete_key(&font) {
843 self.delete_font_template(shared_key);
844 if let Some(ref mut handler) = &mut self.blob_image_handler {
845 handler.delete_font(shared_key);
846 }
847 profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
848 profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
849 }
850 }
851 ResourceUpdate::DeleteFontInstance(font) => {
852 if let Some(shared_key) = self.resources.fonts.instance_keys.delete_key(&font) {
853 self.delete_font_instance(shared_key);
854 }
855 if let Some(ref mut handler) = &mut self.blob_image_handler {
856 handler.delete_font_instance(font);
857 }
858 }
859 ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
860 self.discard_tiles_outside_visible_area(key, &area);
861 self.set_image_visible_rect(key.as_image(), &area);
862 }
863 ResourceUpdate::AddFont(font) => {
864 let (key, template) = match font {
867 AddFont::Raw(key, bytes, index) => {
868 (key, FontTemplate::Raw(bytes, index))
869 }
870 AddFont::Native(key, native_font_handle) => {
871 (key, FontTemplate::Native(native_font_handle))
872 }
873 };
874 let shared_key = self.resources.fonts.font_keys.map_key(&key);
875 if !self.glyph_rasterizer.has_font(shared_key) {
876 self.add_font_template(shared_key, template);
877 profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
878 profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
879 }
880 }
881 ResourceUpdate::AddFontInstance(..) => {
882 }
884 }
885 }
886 }
887
888 pub fn add_rasterized_blob_images(
889 &mut self,
890 images: Vec<(BlobImageRequest, BlobImageResult)>,
891 profile: &mut TransactionProfile,
892 ) {
893 for (request, result) in images {
894 let data = match result {
895 Ok(data) => data,
896 Err(..) => {
897 warn!("Failed to rasterize a blob image");
898 continue;
899 }
900 };
901
902 profile.add(profiler::RASTERIZED_BLOBS_PX, data.rasterized_rect.area());
903
904 let tiles = self.rasterized_blob_images.entry(request.key).or_insert_with(
907 || { RasterizedBlob::default() }
908 );
909
910 tiles.insert(request.tile, data);
911
912 match self.cached_images.try_get_mut(&request.key.as_image()) {
913 Some(&mut ImageResult::Multi(ref mut entries)) => {
914 let cached_key = CachedImageKey {
915 rendering: ImageRendering::Auto, tile: Some(request.tile),
917 };
918 if let Some(entry) = entries.try_get_mut(&cached_key) {
919 entry.dirty_rect = DirtyRect::All;
920 }
921 }
922 _ => {}
923 }
924 }
925 }
926
927 pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
928 if let FontTemplate::Raw(ref data, _) = template {
931 self.resources.weak_fonts.insert(Arc::downgrade(data));
932 self.font_templates_memory += data.len();
933 }
934 self.glyph_rasterizer.add_font(font_key, template.clone());
935 self.resources.fonts.templates.add_font(font_key, template);
936 }
937
938 pub fn delete_font_template(&mut self, font_key: FontKey) {
939 self.glyph_rasterizer.delete_font(font_key);
940 if let Some(FontTemplate::Raw(data, _)) = self.resources.fonts.templates.delete_font(&font_key) {
941 self.font_templates_memory -= data.len();
942 }
943 self.cached_glyphs.delete_fonts(&[font_key]);
944 }
945
946 pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
947 self.resources.fonts.instances.delete_font_instance(instance_key);
948 }
949
950 pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
951 self.resources.fonts.instances.get_font_instance(instance_key)
952 }
953
954 pub fn get_fonts(&self) -> SharedFontResources {
955 self.resources.fonts.clone()
956 }
957
958 pub fn add_image_template(
959 &mut self,
960 image_key: ImageKey,
961 descriptor: ImageDescriptor,
962 data: CachedImageData,
963 visible_rect: &DeviceIntRect,
964 mut tiling: Option<TileSize>,
965 ) {
966 if let Some(ref mut tile_size) = tiling {
967 *tile_size = (*tile_size).max(16).min(2048);
969 }
970
971 if tiling.is_none() && Self::should_tile(self.tiling_threshold(), &descriptor, &data) {
972 tiling = Some(DEFAULT_TILE_SIZE);
975 }
976
977 let resource = ImageResource {
978 descriptor,
979 data,
980 tiling,
981 visible_rect: *visible_rect,
982 adjustment: AdjustedImageSource::new(),
983 generation: ImageGeneration(0),
984 };
985
986 self.resources.image_templates.insert(image_key, resource);
987 }
988
989 pub fn update_image_template(
990 &mut self,
991 image_key: ImageKey,
992 descriptor: ImageDescriptor,
993 data: CachedImageData,
994 dirty_rect: &ImageDirtyRect,
995 ) {
996 let tiling_threshold = self.tiling_threshold();
997 let image = match self.resources.image_templates.get_mut(image_key) {
998 Some(res) => res,
999 None => panic!("Attempt to update non-existent image"),
1000 };
1001
1002 let mut tiling = image.tiling;
1003 if tiling.is_none() && Self::should_tile(tiling_threshold, &descriptor, &data) {
1004 tiling = Some(DEFAULT_TILE_SIZE);
1005 }
1006
1007 match self.cached_images.try_get_mut(&image_key) {
1010 Some(&mut ImageResult::UntiledAuto(ref mut entry)) => {
1011 entry.dirty_rect = entry.dirty_rect.union(dirty_rect);
1012 }
1013 Some(&mut ImageResult::Multi(ref mut entries)) => {
1014 for (key, entry) in entries.iter_mut() {
1015 let local_dirty_rect = match (tiling, key.tile) {
1017 (Some(tile_size), Some(tile)) => {
1018 dirty_rect.map(|mut rect|{
1019 let tile_offset = DeviceIntPoint::new(
1020 tile.x as i32,
1021 tile.y as i32,
1022 ) * tile_size as i32;
1023 rect = rect.translate(-tile_offset.to_vector());
1024
1025 let tile_rect = compute_tile_size(
1026 &descriptor.size.into(),
1027 tile_size,
1028 tile,
1029 ).into();
1030
1031 rect.intersection(&tile_rect).unwrap_or_else(DeviceIntRect::zero)
1032 })
1033 }
1034 (None, Some(..)) => DirtyRect::All,
1035 _ => *dirty_rect,
1036 };
1037 entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
1038 }
1039 }
1040 _ => {}
1041 }
1042
1043 if image.descriptor.format != descriptor.format {
1044 trace!("Format change {:?} -> {:?}", image.descriptor.format, descriptor.format);
1046 }
1047 *image = ImageResource {
1048 descriptor,
1049 data,
1050 tiling,
1051 visible_rect: descriptor.size.into(),
1052 adjustment: AdjustedImageSource::new(),
1053 generation: ImageGeneration(image.generation.0 + 1),
1054 };
1055 }
1056
1057 pub fn increment_image_generation(&mut self, key: ImageKey) {
1058 if let Some(image) = self.resources.image_templates.get_mut(key) {
1059 image.generation.0 += 1;
1060 }
1061 }
1062
1063 pub fn delete_image_template(&mut self, image_key: ImageKey) {
1064 let value = self.resources.image_templates.remove(image_key);
1066
1067 if let Some(mut cached) = self.cached_images.remove(&image_key) {
1069 cached.drop_from_cache(&mut self.texture_cache);
1070 }
1071
1072 match value {
1073 Some(image) => if image.data.is_blob() {
1074 if let CachedImageData::Raw(data) = image.data {
1075 self.image_templates_memory -= data.len();
1076 }
1077
1078 let blob_key = BlobImageKey(image_key);
1079 self.deleted_blob_keys.back_mut().unwrap().push(blob_key);
1080 self.rasterized_blob_images.remove(&blob_key);
1081 },
1082 None => {
1083 warn!("Delete the non-exist key");
1084 debug!("key={:?}", image_key);
1085 }
1086 }
1087 }
1088
1089 pub fn get_image_generation(&self, key: ImageKey) -> ImageGeneration {
1091 self.resources
1092 .image_templates
1093 .get(key)
1094 .map_or(ImageGeneration::INVALID, |template| template.generation)
1095 }
1096
1097 pub fn request_image(
1101 &mut self,
1102 mut request: ImageRequest,
1103 gpu_buffer: &mut GpuBufferBuilderF,
1104 ) -> DeviceIntSize {
1105 debug_assert_eq!(self.state, State::AddResources);
1106
1107 let template = match self.resources.image_templates.get(request.key) {
1108 Some(template) => template,
1109 None => {
1110 warn!("ERROR: Trying to render deleted / non-existent key");
1111 debug!("key={:?}", request.key);
1112 return DeviceIntSize::zero();
1113 }
1114 };
1115
1116 let size = match request.tile {
1117 Some(tile) => compute_tile_size(&template.visible_rect, template.tiling.unwrap(), tile),
1118 None => template.descriptor.size,
1119 };
1120
1121 if !template.data.uses_texture_cache() {
1123 return size;
1124 }
1125
1126 if template.data.is_snapshot() {
1127 request.rendering = ImageRendering::Auto;
1132 }
1133
1134 let side_size =
1135 template.tiling.map_or(cmp::max(template.descriptor.size.width, template.descriptor.size.height),
1136 |tile_size| tile_size as i32);
1137 if side_size > self.texture_cache.max_texture_size() {
1138 warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
1140 template.descriptor.size.width, template.descriptor.size.height, template.tiling.unwrap_or(0));
1141 self.cached_images.insert(request.key, ImageResult::Err(ImageCacheError::OverLimitSize));
1142 return DeviceIntSize::zero();
1143 }
1144
1145 let storage = match self.cached_images.entry(request.key) {
1146 Occupied(e) => {
1147 let entry = e.into_mut();
1152 if !request.is_untiled_auto() {
1153 let untiled_entry = match entry {
1154 &mut ImageResult::UntiledAuto(ref mut entry) => {
1155 Some(mem::replace(entry, CachedImageInfo {
1156 texture_cache_handle: TextureCacheHandle::invalid(),
1157 dirty_rect: DirtyRect::All,
1158 manual_eviction: false,
1159 }))
1160 }
1161 _ => None
1162 };
1163
1164 if let Some(untiled_entry) = untiled_entry {
1165 let mut entries = ResourceClassCache::new();
1166 let untiled_key = CachedImageKey {
1167 rendering: ImageRendering::Auto,
1168 tile: None,
1169 };
1170 entries.insert(untiled_key, untiled_entry);
1171 *entry = ImageResult::Multi(entries);
1172 }
1173 }
1174 entry
1175 }
1176 Vacant(entry) => {
1177 entry.insert(if request.is_untiled_auto() {
1178 ImageResult::UntiledAuto(CachedImageInfo {
1179 texture_cache_handle: TextureCacheHandle::invalid(),
1180 dirty_rect: DirtyRect::All,
1181 manual_eviction: false,
1182 })
1183 } else {
1184 ImageResult::Multi(ResourceClassCache::new())
1185 })
1186 }
1187 };
1188
1189 let entry = match *storage {
1192 ImageResult::UntiledAuto(ref mut entry) => entry,
1193 ImageResult::Multi(ref mut entries) => {
1194 entries.entry(request.into())
1195 .or_insert(CachedImageInfo {
1196 texture_cache_handle: TextureCacheHandle::invalid(),
1197 dirty_rect: DirtyRect::All,
1198 manual_eviction: false,
1199 })
1200 },
1201 ImageResult::Err(_) => panic!("Errors should already have been handled"),
1202 };
1203
1204 let needs_upload = self.texture_cache.request(&entry.texture_cache_handle, gpu_buffer);
1205
1206 if !needs_upload && entry.dirty_rect.is_empty() {
1207 return size;
1208 }
1209
1210 if !self.pending_image_requests.insert(request) {
1211 return size;
1212 }
1213
1214 if template.data.is_blob() {
1215 let request: BlobImageRequest = request.into();
1216 let missing = match self.rasterized_blob_images.get(&request.key) {
1217 Some(tiles) => !tiles.contains_key(&request.tile),
1218 _ => true,
1219 };
1220
1221 assert!(!missing);
1222 }
1223
1224 size
1225 }
1226
1227 fn discard_tiles_outside_visible_area(
1228 &mut self,
1229 key: BlobImageKey,
1230 area: &DeviceIntRect
1231 ) {
1232 let tile_size = match self.resources.image_templates.get(key.as_image()) {
1233 Some(template) => template.tiling.unwrap(),
1234 None => {
1235 return;
1237 }
1238 };
1239
1240 let tiles = match self.rasterized_blob_images.get_mut(&key) {
1241 Some(tiles) => tiles,
1242 _ => { return; }
1243 };
1244
1245 let tile_range = compute_tile_range(
1246 &area,
1247 tile_size,
1248 );
1249
1250 tiles.retain(|tile, _| { tile_range.contains(*tile) });
1251
1252 let texture_cache = &mut self.texture_cache;
1253 match self.cached_images.try_get_mut(&key.as_image()) {
1254 Some(&mut ImageResult::Multi(ref mut entries)) => {
1255 entries.retain(|key, entry| {
1256 if key.tile.is_none() || tile_range.contains(key.tile.unwrap()) {
1257 return true;
1258 }
1259 entry.mark_unused(texture_cache);
1260 return false;
1261 });
1262 }
1263 _ => {}
1264 }
1265 }
1266
1267 fn set_image_visible_rect(&mut self, key: ImageKey, rect: &DeviceIntRect) {
1268 if let Some(image) = self.resources.image_templates.get_mut(key) {
1269 image.visible_rect = *rect;
1270 image.descriptor.size = rect.size();
1271 }
1272 }
1273
1274 pub fn request_glyphs(
1275 &mut self,
1276 mut font: FontInstance,
1277 glyph_keys: &[GlyphKey],
1278 gpu_buffer: &mut GpuBufferBuilderF,
1279 ) {
1280 debug_assert_eq!(self.state, State::AddResources);
1281
1282 self.glyph_rasterizer.prepare_font(&mut font);
1283 let glyph_key_cache = self.cached_glyphs.insert_glyph_key_cache_for_font(&font);
1284 let texture_cache = &mut self.texture_cache;
1285 self.glyph_rasterizer.request_glyphs(
1286 font,
1287 glyph_keys,
1288 |key| {
1289 let cache_key = key.cache_key();
1290 if let Some(entry) = glyph_key_cache.try_get(&cache_key) {
1291 match entry {
1292 GlyphCacheEntry::Cached(ref glyph) => {
1293 if !texture_cache.request(&glyph.texture_cache_handle, gpu_buffer) {
1294 return false;
1295 }
1296 }
1300 GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => return false,
1302 }
1303 };
1304
1305 glyph_key_cache.add_glyph(cache_key, GlyphCacheEntry::Pending);
1306
1307 true
1308 }
1309 );
1310 }
1311
1312 pub fn pending_updates(&mut self) -> ResourceUpdateList {
1313 ResourceUpdateList {
1314 texture_updates: self.texture_cache.pending_updates(),
1315 native_surface_updates: mem::replace(&mut self.pending_native_surface_updates, Vec::new()),
1316 }
1317 }
1318
1319 pub fn fetch_glyphs<F>(
1320 &self,
1321 mut font: FontInstance,
1322 glyph_keys: &[GlyphKey],
1323 gpu_buffer: &GpuBufferBuilderF,
1324 fetch_buffer: &mut Vec<GlyphFetchResult>,
1325 mut f: F,
1326 ) where
1327 F: FnMut(TextureSource, GlyphFormat, &[GlyphFetchResult]),
1328 {
1329 debug_assert_eq!(self.state, State::QueryResources);
1330
1331 self.glyph_rasterizer.prepare_font(&mut font);
1332 let glyph_key_cache = self.cached_glyphs.get_glyph_key_cache_for_font(&font);
1333
1334 let mut current_texture_id = TextureSource::Invalid;
1335 let mut current_glyph_format = GlyphFormat::Subpixel;
1336 debug_assert!(fetch_buffer.is_empty());
1337
1338 for (loop_index, key) in glyph_keys.iter().enumerate() {
1339 let cache_key = key.cache_key();
1340 let (cache_item, glyph_format, is_packed_glyph) = match *glyph_key_cache.get(&cache_key) {
1341 GlyphCacheEntry::Cached(ref glyph) => {
1342 (self.texture_cache.get(&glyph.texture_cache_handle), glyph.format, glyph.is_packed_glyph)
1343 }
1344 GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
1345 };
1346 if current_texture_id != cache_item.texture_id ||
1347 current_glyph_format != glyph_format {
1348 if !fetch_buffer.is_empty() {
1349 f(current_texture_id, current_glyph_format, fetch_buffer);
1350 fetch_buffer.clear();
1351 }
1352 current_texture_id = cache_item.texture_id;
1353 current_glyph_format = glyph_format;
1354 }
1355 let (subpx_offset_x, subpx_offset_y) = key.subpixel_offset();
1356 fetch_buffer.push(GlyphFetchResult {
1357 index_in_text_run: loop_index as i32,
1358 uv_rect_address: gpu_buffer.resolve_handle(cache_item.uv_rect_handle),
1359 offset: DevicePoint::new(cache_item.user_data[0], cache_item.user_data[1]),
1360 size: cache_item.uv_rect.size(),
1361 scale: cache_item.user_data[2],
1362 subpx_offset_x: subpx_offset_x as u8,
1363 subpx_offset_y: subpx_offset_y as u8,
1364 is_packed_glyph,
1365 });
1366 }
1367
1368 if !fetch_buffer.is_empty() {
1369 f(current_texture_id, current_glyph_format, fetch_buffer);
1370 fetch_buffer.clear();
1371 }
1372 }
1373
1374 pub fn map_font_key(&self, key: FontKey) -> FontKey {
1375 self.resources.fonts.font_keys.map_key(&key)
1376 }
1377
1378 pub fn map_font_instance_key(&self, key: FontInstanceKey) -> FontInstanceKey {
1379 self.resources.fonts.instance_keys.map_key(&key)
1380 }
1381
1382 pub fn get_glyph_dimensions(
1383 &mut self,
1384 font: &FontInstance,
1385 glyph_index: GlyphIndex,
1386 ) -> Option<GlyphDimensions> {
1387 match self.cached_glyph_dimensions.entry((font.instance_key, glyph_index)) {
1388 Occupied(entry) => *entry.get(),
1389 Vacant(entry) => *entry.insert(
1390 self.glyph_rasterizer
1391 .get_glyph_dimensions(font, glyph_index),
1392 ),
1393 }
1394 }
1395
1396 pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
1397 self.glyph_rasterizer.get_glyph_index(font_key, ch)
1398 }
1399
1400 #[inline]
1401 pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
1402 debug_assert_eq!(self.state, State::QueryResources);
1403 let image_info = self.get_image_info(request)?;
1404
1405 if let Ok(item) = self.get_texture_cache_item(&image_info.texture_cache_handle) {
1406 return Ok(item);
1408 }
1409
1410 if self.resources.image_templates
1411 .get(request.key)
1412 .map_or(false, |img| img.data.is_snapshot()) {
1413 if self.debug_fallback_panic {
1414 panic!("Missing snapshot image");
1415 }
1416 return self.get_texture_cache_item(&self.fallback_handle);
1417 }
1418
1419 panic!("Requested image missing from the texture cache");
1420 }
1421
1422 pub fn get_cached_render_task(
1423 &self,
1424 handle: &RenderTaskCacheEntryHandle,
1425 ) -> &RenderTaskCacheEntry {
1426 self.cached_render_tasks.get_cache_entry(handle)
1427 }
1428
1429 #[inline]
1430 fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
1431 match *self.cached_images.get(&request.key) {
1434 ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
1435 ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
1436 ImageResult::Err(_) => Err(()),
1437 }
1438 }
1439
1440 #[inline]
1441 pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> Result<CacheItem, ()> {
1442 if let Some(item) = self.texture_cache.try_get(handle) {
1443 return Ok(item);
1444 }
1445
1446 Err(())
1447 }
1448
1449 pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
1450 let image_template = &self.resources.image_templates.get(image_key);
1451
1452 image_template.map(|image_template| {
1453 let external_image = match image_template.data {
1454 CachedImageData::External(ext_image) => match ext_image.image_type {
1455 ExternalImageType::TextureHandle(_) => Some(ext_image),
1456 ExternalImageType::Buffer => None,
1458 },
1459 CachedImageData::Raw(..)
1461 | CachedImageData::Blob
1462 | CachedImageData::Snapshot
1463 => None,
1464 };
1465
1466 ImageProperties {
1467 descriptor: image_template.descriptor,
1468 external_image,
1469 tiling: image_template.tiling,
1470 visible_rect: image_template.visible_rect,
1471 adjustment: image_template.adjustment,
1472 }
1473 })
1474 }
1475
1476 pub fn begin_frame(&mut self, stamp: FrameStamp, profile: &mut TransactionProfile) {
1477 profile_scope!("begin_frame");
1478 debug_assert_eq!(self.state, State::Idle);
1479 self.state = State::AddResources;
1480 self.texture_cache.begin_frame(stamp, profile);
1481 self.picture_textures.begin_frame(stamp, &mut self.texture_cache.pending_updates);
1482
1483 self.cached_glyphs.begin_frame(
1484 stamp,
1485 &mut self.texture_cache,
1486 &mut self.glyph_rasterizer,
1487 );
1488 self.cached_render_tasks.begin_frame(&mut self.texture_cache);
1489 self.current_frame_id = stamp.frame_id();
1490
1491 let mut v = self.deleted_blob_keys.pop_front().unwrap_or_else(Vec::new);
1494 v.clear();
1495 self.deleted_blob_keys.push_back(v);
1496
1497 self.texture_cache.run_compaction();
1498 }
1499
1500 pub fn block_until_all_resources_added(
1501 &mut self,
1502 gpu_buffer: &mut GpuBufferBuilder,
1503 profile: &mut TransactionProfile,
1504 ) {
1505 profile_scope!("block_until_all_resources_added");
1506
1507 debug_assert_eq!(self.state, State::AddResources);
1508 self.state = State::QueryResources;
1509
1510 let cached_glyphs = &mut self.cached_glyphs;
1511 let texture_cache = &mut self.texture_cache;
1512
1513 self.glyph_rasterizer.resolve_glyphs(
1514 |job, can_use_r8_format| {
1515 let GlyphRasterJob { font, key, result } = job;
1516 let cache_key = key.cache_key();
1517 let glyph_key_cache = cached_glyphs.get_glyph_key_cache_for_font_mut(&*font);
1518 let glyph_info = match result {
1519 Err(_) => GlyphCacheEntry::Blank,
1520 Ok(ref glyph) if glyph.width == 0 || glyph.height == 0 => {
1521 GlyphCacheEntry::Blank
1522 }
1523 Ok(glyph) => {
1524 let mut texture_cache_handle = TextureCacheHandle::invalid();
1525 texture_cache.request(&texture_cache_handle, &mut gpu_buffer.f32);
1526 texture_cache.update(
1527 &mut texture_cache_handle,
1528 ImageDescriptor {
1529 size: size2(glyph.width, glyph.height),
1530 stride: None,
1531 format: glyph.format.image_format(can_use_r8_format),
1532 flags: ImageDescriptorFlags::empty(),
1533 offset: 0,
1534 },
1535 TextureFilter::Linear,
1536 Some(CachedImageData::Raw(Arc::new(glyph.bytes))),
1537 [glyph.left, -glyph.top, glyph.scale, 0.0],
1538 DirtyRect::All,
1539 &mut gpu_buffer.f32,
1540 Some(glyph_key_cache.eviction_notice()),
1541 UvRectKind::Rect,
1542 Eviction::Auto,
1543 TargetShader::Text,
1544 false,
1545 );
1546 GlyphCacheEntry::Cached(CachedGlyphInfo {
1547 texture_cache_handle,
1548 format: glyph.format,
1549 is_packed_glyph: glyph.is_packed_glyph,
1550 })
1551 }
1552 };
1553 glyph_key_cache.insert(cache_key, glyph_info);
1554 },
1555 profile,
1556 );
1557
1558 self.update_texture_cache(gpu_buffer);
1560 }
1561
1562 fn update_texture_cache(&mut self, gpu_buffer: &mut GpuBufferBuilder) {
1563 profile_scope!("update_texture_cache");
1564
1565 if self.fallback_handle == TextureCacheHandle::invalid() {
1566 let fallback_color = if self.debug_fallback_pink {
1567 vec![255, 0, 255, 255]
1568 } else {
1569 vec![0, 0, 0, 0]
1570 };
1571 self.texture_cache.update(
1572 &mut self.fallback_handle,
1573 ImageDescriptor {
1574 size: size2(1, 1),
1575 stride: None,
1576 format: ImageFormat::BGRA8,
1577 flags: ImageDescriptorFlags::empty(),
1578 offset: 0,
1579 },
1580 TextureFilter::Linear,
1581 Some(CachedImageData::Raw(Arc::new(fallback_color))),
1582 [0.0; 4],
1583 DirtyRect::All,
1584 &mut gpu_buffer.f32,
1585 None,
1586 UvRectKind::Rect,
1587 Eviction::Manual,
1588 TargetShader::Default,
1589 false,
1590 );
1591 }
1592
1593 for request in self.pending_image_requests.drain() {
1594 let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
1595 debug_assert!(image_template.data.uses_texture_cache());
1596
1597 let mut updates: SmallVec<[(CachedImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
1598
1599 match image_template.data {
1600 CachedImageData::Snapshot => {
1601 }
1603 CachedImageData::Raw(..)
1604 | CachedImageData::External(..) => {
1605 updates.push((image_template.data.clone(), None));
1608 }
1609 CachedImageData::Blob => {
1610 let blob_image = self.rasterized_blob_images.get_mut(&BlobImageKey(request.key)).unwrap();
1611 let img = &blob_image[&request.tile.unwrap()];
1612 updates.push((
1613 CachedImageData::Raw(Arc::clone(&img.data)),
1614 Some(img.rasterized_rect)
1615 ));
1616 }
1617 };
1618
1619 for (image_data, blob_rasterized_rect) in updates {
1620 let entry = match *self.cached_images.get_mut(&request.key) {
1621 ImageResult::UntiledAuto(ref mut entry) => entry,
1622 ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
1623 ImageResult::Err(_) => panic!("Update requested for invalid entry")
1624 };
1625
1626 let mut descriptor = image_template.descriptor.clone();
1627 let mut dirty_rect = entry.dirty_rect.replace_with_empty();
1628
1629 if let Some(tile) = request.tile {
1630 let tile_size = image_template.tiling.unwrap();
1631 let clipped_tile_size = compute_tile_size(&image_template.visible_rect, tile_size, tile);
1632 let tiled_on_cpu = image_template.data.is_blob();
1636 if !tiled_on_cpu {
1637 debug_assert_eq!(image_template.visible_rect.min, point2(0, 0));
1640 let bpp = descriptor.format.bytes_per_pixel();
1641 let stride = descriptor.compute_stride();
1642 descriptor.stride = Some(stride);
1643 descriptor.offset +=
1644 tile.y as i32 * tile_size as i32 * stride +
1645 tile.x as i32 * tile_size as i32 * bpp;
1646 }
1647
1648 descriptor.size = clipped_tile_size;
1649 }
1650
1651 if let Some(rect) = blob_rasterized_rect {
1655 dirty_rect = DirtyRect::Partial(rect);
1656 }
1657
1658 let filter = match request.rendering {
1659 ImageRendering::Pixelated => {
1660 TextureFilter::Nearest
1661 }
1662 ImageRendering::Auto | ImageRendering::CrispEdges => {
1663 if descriptor.allow_mipmaps() &&
1671 descriptor.size.width > 512 &&
1672 descriptor.size.height > 512 &&
1673 !self.texture_cache.is_allowed_in_shared_cache(
1674 TextureFilter::Linear,
1675 &descriptor,
1676 ) {
1677 TextureFilter::Trilinear
1678 } else {
1679 TextureFilter::Linear
1680 }
1681 }
1682 };
1683
1684 let eviction = match &image_template.data {
1685 CachedImageData::Blob | CachedImageData::Snapshot => {
1686 entry.manual_eviction = true;
1687 Eviction::Manual
1688 }
1689 _ => {
1690 Eviction::Auto
1691 }
1692 };
1693
1694 self.texture_cache.update(
1696 &mut entry.texture_cache_handle,
1697 descriptor,
1698 filter,
1699 Some(image_data),
1700 [0.0; 4],
1701 dirty_rect,
1702 &mut gpu_buffer.f32,
1703 None,
1704 UvRectKind::Rect,
1705 eviction,
1706 TargetShader::Default,
1707 false,
1708 );
1709 }
1710 }
1711 }
1712
1713 pub fn create_compositor_backdrop_surface(
1714 &mut self,
1715 color: ColorF
1716 ) -> NativeSurfaceId {
1717 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1718
1719 self.pending_native_surface_updates.push(
1720 NativeSurfaceOperation {
1721 details: NativeSurfaceOperationDetails::CreateBackdropSurface {
1722 id,
1723 color,
1724 },
1725 }
1726 );
1727
1728 id
1729 }
1730
1731 pub fn create_compositor_surface(
1734 &mut self,
1735 virtual_offset: DeviceIntPoint,
1736 tile_size: DeviceIntSize,
1737 is_opaque: bool,
1738 ) -> NativeSurfaceId {
1739 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1740
1741 self.pending_native_surface_updates.push(
1742 NativeSurfaceOperation {
1743 details: NativeSurfaceOperationDetails::CreateSurface {
1744 id,
1745 virtual_offset,
1746 tile_size,
1747 is_opaque,
1748 },
1749 }
1750 );
1751
1752 id
1753 }
1754
1755 pub fn create_compositor_external_surface(
1756 &mut self,
1757 is_opaque: bool,
1758 ) -> NativeSurfaceId {
1759 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1760
1761 self.pending_native_surface_updates.push(
1762 NativeSurfaceOperation {
1763 details: NativeSurfaceOperationDetails::CreateExternalSurface {
1764 id,
1765 is_opaque,
1766 },
1767 }
1768 );
1769
1770 id
1771 }
1772
1773 pub fn destroy_compositor_surface(
1776 &mut self,
1777 id: NativeSurfaceId,
1778 ) {
1779 self.pending_native_surface_updates.push(
1780 NativeSurfaceOperation {
1781 details: NativeSurfaceOperationDetails::DestroySurface {
1782 id,
1783 }
1784 }
1785 );
1786 }
1787
1788 pub fn create_compositor_tile(
1790 &mut self,
1791 id: NativeTileId,
1792 ) {
1793 self.pending_native_surface_updates.push(
1794 NativeSurfaceOperation {
1795 details: NativeSurfaceOperationDetails::CreateTile {
1796 id,
1797 },
1798 }
1799 );
1800 }
1801
1802 pub fn destroy_compositor_tile(
1804 &mut self,
1805 id: NativeTileId,
1806 ) {
1807 self.pending_native_surface_updates.push(
1808 NativeSurfaceOperation {
1809 details: NativeSurfaceOperationDetails::DestroyTile {
1810 id,
1811 },
1812 }
1813 );
1814 }
1815
1816 pub fn attach_compositor_external_image(
1817 &mut self,
1818 id: NativeSurfaceId,
1819 external_image: ExternalImageId,
1820 ) {
1821 self.pending_native_surface_updates.push(
1822 NativeSurfaceOperation {
1823 details: NativeSurfaceOperationDetails::AttachExternalImage {
1824 id,
1825 external_image,
1826 },
1827 }
1828 );
1829 }
1830
1831
1832 pub fn end_frame(&mut self, profile: &mut TransactionProfile) {
1833 debug_assert_eq!(self.state, State::QueryResources);
1834 profile_scope!("end_frame");
1835 self.state = State::Idle;
1836
1837 self.gc_render_targets(
1850 64 * 1024 * 1024,
1851 32 * 1024 * 1024 * 10,
1852 60,
1853 );
1854
1855 self.texture_cache.end_frame(profile);
1856 self.picture_textures.gc(
1857 &mut self.texture_cache.pending_updates,
1858 );
1859
1860 self.picture_textures.update_profile(profile);
1861 }
1862
1863 pub fn set_debug_flags(&mut self, flags: DebugFlags) {
1864 GLYPH_FLASHING.store(flags.contains(DebugFlags::GLYPH_FLASHING), std::sync::atomic::Ordering::Relaxed);
1865 self.texture_cache.set_debug_flags(flags);
1866 self.picture_textures.set_debug_flags(flags);
1867 self.debug_fallback_panic = flags.contains(DebugFlags::MISSING_SNAPSHOT_PANIC);
1868 let fallback_pink = flags.contains(DebugFlags::MISSING_SNAPSHOT_PINK);
1869
1870 if fallback_pink != self.debug_fallback_pink && self.fallback_handle != TextureCacheHandle::invalid() {
1871 self.texture_cache.evict_handle(&self.fallback_handle);
1872 }
1873 self.debug_fallback_pink = fallback_pink;
1874 }
1875
1876 pub fn clear(&mut self, what: ClearCache) {
1877 if what.contains(ClearCache::IMAGES) {
1878 for (_key, mut cached) in self.cached_images.resources.drain() {
1879 cached.drop_from_cache(&mut self.texture_cache);
1880 }
1881 }
1882 if what.contains(ClearCache::GLYPHS) {
1883 self.cached_glyphs.clear();
1884 }
1885 if what.contains(ClearCache::GLYPH_DIMENSIONS) {
1886 self.cached_glyph_dimensions.clear();
1887 }
1888 if what.contains(ClearCache::RENDER_TASKS) {
1889 self.cached_render_tasks.clear();
1890 }
1891 if what.contains(ClearCache::TEXTURE_CACHE) {
1892 self.texture_cache.clear_all();
1893 self.picture_textures.clear(&mut self.texture_cache.pending_updates);
1894 }
1895 if what.contains(ClearCache::RENDER_TARGETS) {
1896 self.clear_render_target_pool();
1897 }
1898 }
1899
1900 pub fn clear_namespace(&mut self, namespace: IdNamespace) {
1901 self.clear_images(|k| k.0 == namespace);
1902
1903 self.resources.fonts.instances.clear_namespace(namespace);
1905 let deleted_keys = self.resources.fonts.templates.clear_namespace(namespace);
1906 self.glyph_rasterizer.delete_fonts(&deleted_keys);
1907 self.cached_glyphs.clear_namespace(namespace);
1908 if let Some(handler) = &mut self.blob_image_handler {
1909 handler.clear_namespace(namespace);
1910 }
1911
1912 let shared_instance_keys = self.resources.fonts.instance_keys.clear_namespace(namespace);
1914 if !shared_instance_keys.is_empty() {
1915 self.resources.fonts.instances.delete_font_instances(&shared_instance_keys);
1916 self.cached_glyphs.delete_font_instances(&shared_instance_keys, &mut self.glyph_rasterizer);
1917 }
1920
1921 let shared_keys = self.resources.fonts.font_keys.clear_namespace(namespace);
1923 if !shared_keys.is_empty() {
1924 self.glyph_rasterizer.delete_fonts(&shared_keys);
1925 self.resources.fonts.templates.delete_fonts(&shared_keys);
1926 self.cached_glyphs.delete_fonts(&shared_keys);
1927 if let Some(handler) = &mut self.blob_image_handler {
1928 for &key in &shared_keys {
1929 handler.delete_font(key);
1930 }
1931 }
1932 }
1933 }
1934
1935 pub fn report_memory(&self, op: VoidPtrToSizeFn) -> MemoryReport {
1944 let mut report = MemoryReport::default();
1945
1946 let mut seen_fonts = std::collections::HashSet::new();
1947 for (_, font) in self.resources.fonts.templates.lock().iter() {
1950 if let FontTemplate::Raw(ref raw, _) = font {
1951 report.fonts += unsafe { op(raw.as_ptr() as *const c_void) };
1952 seen_fonts.insert(raw.as_ptr());
1953 }
1954 }
1955
1956 for font in self.resources.weak_fonts.iter() {
1957 if !seen_fonts.contains(&font.as_ptr()) {
1958 report.weak_fonts += unsafe { op(font.as_ptr() as *const c_void) };
1959 }
1960 }
1961
1962 for (_, image) in self.resources.image_templates.images.iter() {
1964 report.images += match image.data {
1965 CachedImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
1966 CachedImageData::Blob
1967 | CachedImageData::External(..)
1968 | CachedImageData::Snapshot => 0,
1969 }
1970 }
1971
1972 report
1988 }
1989
1990 fn clear_images<F: Fn(&ImageKey) -> bool>(&mut self, f: F) {
1992 let keys = self.resources.image_templates.images.keys().filter(|k| f(*k))
1993 .cloned().collect::<SmallVec<[ImageKey; 16]>>();
1994
1995 for key in keys {
1996 self.delete_image_template(key);
1997 }
1998
1999 #[cfg(feature="leak_checks")]
2000 let check_leaks = true;
2001 #[cfg(not(feature="leak_checks"))]
2002 let check_leaks = false;
2003
2004 if check_leaks {
2005 let blob_f = |key: &BlobImageKey| { f(&key.as_image()) };
2006 assert!(!self.resources.image_templates.images.keys().any(&f));
2007 assert!(!self.cached_images.resources.keys().any(&f));
2008 assert!(!self.rasterized_blob_images.keys().any(&blob_f));
2009 }
2010 }
2011
2012 pub fn get_or_create_render_target_from_pool(
2015 &mut self,
2016 size: DeviceIntSize,
2017 format: ImageFormat,
2018 ) -> CacheTextureId {
2019 for target in &mut self.render_target_pool {
2020 if target.size == size &&
2021 target.format == format &&
2022 !target.is_active {
2023 target.is_active = true;
2026 target.last_frame_used = self.current_frame_id;
2027 return target.texture_id;
2028 }
2029 }
2030
2031 let texture_id = self.texture_cache.alloc_render_target(
2034 size,
2035 format,
2036 );
2037
2038 self.render_target_pool.push(RenderTarget {
2039 size,
2040 format,
2041 texture_id,
2042 is_active: true,
2043 last_frame_used: self.current_frame_id,
2044 });
2045
2046 texture_id
2047 }
2048
2049 pub fn return_render_target_to_pool(
2051 &mut self,
2052 id: CacheTextureId,
2053 ) {
2054 let target = self.render_target_pool
2055 .iter_mut()
2056 .find(|t| t.texture_id == id)
2057 .expect("bug: invalid render target id");
2058
2059 assert!(target.is_active);
2060 target.is_active = false;
2061 }
2062
2063 fn clear_render_target_pool(
2065 &mut self,
2066 ) {
2067 for target in self.render_target_pool.drain(..) {
2068 debug_assert!(!target.is_active);
2069 self.texture_cache.free_render_target(target.texture_id);
2070 }
2071 }
2072
2073 fn gc_render_targets(
2076 &mut self,
2077 total_bytes_threshold: usize,
2078 total_bytes_red_line_threshold: usize,
2079 frames_threshold: u64,
2080 ) {
2081 let mut rt_pool_size_in_bytes: usize = self.render_target_pool
2083 .iter()
2084 .map(|t| t.size_in_bytes())
2085 .sum();
2086
2087 if rt_pool_size_in_bytes <= total_bytes_threshold {
2090 return;
2091 }
2092
2093 self.render_target_pool.sort_by_key(|t| t.last_frame_used);
2095
2096 let mut retained_targets = SmallVec::<[RenderTarget; 8]>::new();
2098
2099 for target in self.render_target_pool.drain(..) {
2100 assert!(!target.is_active);
2101
2102 let above_red_line = rt_pool_size_in_bytes > total_bytes_red_line_threshold;
2107 let above_threshold = rt_pool_size_in_bytes > total_bytes_threshold;
2108 let used_recently = target.used_recently(self.current_frame_id, frames_threshold);
2109 let used_this_frame = target.last_frame_used == self.current_frame_id;
2110
2111 if !used_this_frame && (above_red_line || (above_threshold && !used_recently)) {
2112 rt_pool_size_in_bytes -= target.size_in_bytes();
2113 self.texture_cache.free_render_target(target.texture_id);
2114 } else {
2115 retained_targets.push(target);
2116 }
2117 }
2118
2119 self.render_target_pool.extend(retained_targets);
2120 }
2121
2122 #[cfg(test)]
2123 pub fn validate_surfaces(
2124 &self,
2125 expected_surfaces: &[(i32, i32, ImageFormat)],
2126 ) {
2127 assert_eq!(expected_surfaces.len(), self.render_target_pool.len());
2128
2129 for (expected, surface) in expected_surfaces.iter().zip(self.render_target_pool.iter()) {
2130 assert_eq!(DeviceIntSize::new(expected.0, expected.1), surface.size);
2131 assert_eq!(expected.2, surface.format);
2132 }
2133 }
2134}
2135
2136impl Drop for ResourceCache {
2137 fn drop(&mut self) {
2138 self.clear_images(|_| true);
2139 }
2140}
2141
2142#[cfg(any(feature = "capture", feature = "replay"))]
2143#[cfg_attr(feature = "capture", derive(Serialize))]
2144#[cfg_attr(feature = "replay", derive(Deserialize))]
2145struct PlainFontTemplate {
2146 data: String,
2147 index: u32,
2148}
2149
2150#[cfg(any(feature = "capture", feature = "replay"))]
2151#[cfg_attr(feature = "capture", derive(Serialize))]
2152#[cfg_attr(feature = "replay", derive(Deserialize))]
2153struct PlainImageTemplate {
2154 data: String,
2155 descriptor: ImageDescriptor,
2156 tiling: Option<TileSize>,
2157 generation: ImageGeneration,
2158}
2159
2160#[cfg(any(feature = "capture", feature = "replay"))]
2161#[cfg_attr(feature = "capture", derive(Serialize))]
2162#[cfg_attr(feature = "replay", derive(Deserialize))]
2163pub struct PlainResources {
2164 font_templates: FastHashMap<FontKey, PlainFontTemplate>,
2165 font_instances: Vec<BaseFontInstance>,
2166 image_templates: FastHashMap<ImageKey, PlainImageTemplate>,
2167}
2168
2169#[cfg(feature = "capture")]
2170#[derive(Serialize)]
2171pub struct PlainCacheRef<'a> {
2172 current_frame_id: FrameId,
2173 glyphs: &'a GlyphCache,
2174 glyph_dimensions: &'a GlyphDimensionsCache,
2175 images: &'a ImageCache,
2176 render_tasks: &'a RenderTaskCache,
2177 textures: &'a TextureCache,
2178 picture_textures: &'a PictureTextures,
2179}
2180
2181#[cfg(feature = "replay")]
2182#[derive(Deserialize)]
2183pub struct PlainCacheOwn {
2184 current_frame_id: FrameId,
2185 glyphs: GlyphCache,
2186 glyph_dimensions: GlyphDimensionsCache,
2187 images: ImageCache,
2188 render_tasks: RenderTaskCache,
2189 textures: TextureCache,
2190 picture_textures: PictureTextures,
2191}
2192
2193#[cfg(feature = "replay")]
2194const NATIVE_FONT: &'static [u8] = include_bytes!("../res/Proggy.ttf");
2195
2196fn to_image_dirty_rect(blob_dirty_rect: &BlobDirtyRect) -> ImageDirtyRect {
2198 match *blob_dirty_rect {
2199 DirtyRect::Partial(rect) => DirtyRect::Partial(rect.cast_unit()),
2200 DirtyRect::All => DirtyRect::All,
2201 }
2202}
2203
2204impl ResourceCache {
2205 #[cfg(feature = "capture")]
2206 pub fn save_capture(
2207 &mut self, root: &PathBuf
2208 ) -> (PlainResources, Vec<ExternalCaptureImage>) {
2209 use std::fs;
2210 use std::io::Write;
2211
2212 info!("saving resource cache");
2213 let res = &self.resources;
2214 let path_fonts = root.join("fonts");
2215 if !path_fonts.is_dir() {
2216 fs::create_dir(&path_fonts).unwrap();
2217 }
2218 let path_images = root.join("images");
2219 if !path_images.is_dir() {
2220 fs::create_dir(&path_images).unwrap();
2221 }
2222 let path_blobs = root.join("blobs");
2223 if !path_blobs.is_dir() {
2224 fs::create_dir(&path_blobs).unwrap();
2225 }
2226 let path_externals = root.join("externals");
2227 if !path_externals.is_dir() {
2228 fs::create_dir(&path_externals).unwrap();
2229 }
2230
2231 info!("\tfont templates");
2232 let mut font_paths = FastHashMap::default();
2233 for template in res.fonts.templates.lock().values() {
2234 let data: &[u8] = match *template {
2235 FontTemplate::Raw(ref arc, _) => arc,
2236 FontTemplate::Native(_) => continue,
2237 };
2238 let font_id = res.fonts.templates.len() + 1;
2239 let entry = match font_paths.entry(data.as_ptr()) {
2240 Entry::Occupied(_) => continue,
2241 Entry::Vacant(e) => e,
2242 };
2243 let file_name = format!("{}.raw", font_id);
2244 let short_path = format!("fonts/{}", file_name);
2245 fs::File::create(path_fonts.join(file_name))
2246 .expect(&format!("Unable to create {}", short_path))
2247 .write_all(data)
2248 .unwrap();
2249 entry.insert(short_path);
2250 }
2251
2252 info!("\timage templates");
2253 let mut image_paths = FastHashMap::default();
2254 let mut other_paths = FastHashMap::default();
2255 let mut num_blobs = 0;
2256 let mut external_images = Vec::new();
2257 for (&key, template) in res.image_templates.images.iter() {
2258 let desc = &template.descriptor;
2259 match template.data {
2260 CachedImageData::Raw(ref arc) => {
2261 let image_id = image_paths.len() + 1;
2262 let entry = match image_paths.entry(arc.as_ptr()) {
2263 Entry::Occupied(_) => continue,
2264 Entry::Vacant(e) => e,
2265 };
2266
2267 #[cfg(feature = "png")]
2268 CaptureConfig::save_png(
2269 root.join(format!("images/{}.png", image_id)),
2270 desc.size,
2271 desc.format,
2272 desc.stride,
2273 &arc,
2274 );
2275 let file_name = format!("{}.raw", image_id);
2276 let short_path = format!("images/{}", file_name);
2277 fs::File::create(path_images.join(file_name))
2278 .expect(&format!("Unable to create {}", short_path))
2279 .write_all(&*arc)
2280 .unwrap();
2281 entry.insert(short_path);
2282 }
2283 CachedImageData::Blob => {
2284 warn!("Tiled blob images aren't supported yet");
2285 let result = RasterizedBlobImage {
2286 rasterized_rect: desc.size.into(),
2287 data: Arc::new(vec![0; desc.compute_total_size() as usize])
2288 };
2289
2290 assert_eq!(result.rasterized_rect.size(), desc.size);
2291 assert_eq!(result.data.len(), desc.compute_total_size() as usize);
2292
2293 num_blobs += 1;
2294 #[cfg(feature = "png")]
2295 CaptureConfig::save_png(
2296 root.join(format!("blobs/{}.png", num_blobs)),
2297 desc.size,
2298 desc.format,
2299 desc.stride,
2300 &result.data,
2301 );
2302 let file_name = format!("{}.raw", num_blobs);
2303 let short_path = format!("blobs/{}", file_name);
2304 let full_path = path_blobs.clone().join(&file_name);
2305 fs::File::create(full_path)
2306 .expect(&format!("Unable to create {}", short_path))
2307 .write_all(&result.data)
2308 .unwrap();
2309 other_paths.insert(key, short_path);
2310 }
2311 CachedImageData::Snapshot => {
2312 let short_path = format!("snapshots/{}", external_images.len() + 1);
2313 other_paths.insert(key, short_path.clone());
2314 }
2315 CachedImageData::External(ref ext) => {
2316 let short_path = format!("externals/{}", external_images.len() + 1);
2317 other_paths.insert(key, short_path.clone());
2318 external_images.push(ExternalCaptureImage {
2319 short_path,
2320 descriptor: desc.clone(),
2321 external: ext.clone(),
2322 });
2323 }
2324 }
2325 }
2326
2327 let mut font_templates = FastHashMap::default();
2328 let mut font_remap = FastHashMap::default();
2329 for key in res.fonts.font_keys.keys() {
2331 let shared_key = res.fonts.font_keys.map_key(&key);
2332 let template = match res.fonts.templates.get_font(&shared_key) {
2333 Some(template) => template,
2334 None => {
2335 debug!("Failed serializing font template {:?}", key);
2336 continue;
2337 }
2338 };
2339 let plain_font = match template {
2340 FontTemplate::Raw(arc, index) => {
2341 PlainFontTemplate {
2342 data: font_paths[&arc.as_ptr()].clone(),
2343 index,
2344 }
2345 }
2346 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
2347 FontTemplate::Native(native) => {
2348 PlainFontTemplate {
2349 data: native.path.to_string_lossy().to_string(),
2350 index: native.index,
2351 }
2352 }
2353 #[cfg(any(target_os = "macos", target_os = "ios"))]
2354 FontTemplate::Native(native) => {
2355 PlainFontTemplate {
2356 data: native.name,
2357 index: 0,
2358 }
2359 }
2360 };
2361 font_templates.insert(key, plain_font);
2362 font_remap.insert(shared_key, key);
2364 }
2365 let mut font_instances = Vec::new();
2366 for instance_key in res.fonts.instance_keys.keys() {
2368 let shared_key = res.fonts.instance_keys.map_key(&instance_key);
2369 let instance = match res.fonts.instances.get_font_instance(shared_key) {
2370 Some(instance) => instance,
2371 None => {
2372 debug!("Failed serializing font instance {:?}", instance_key);
2373 continue;
2374 }
2375 };
2376 font_instances.push(BaseFontInstance {
2379 font_key: font_remap.get(&instance.font_key).cloned().unwrap_or(instance.font_key),
2380 instance_key,
2381 ..(*instance).clone()
2382 });
2383 }
2384 let resources = PlainResources {
2385 font_templates,
2386 font_instances,
2387 image_templates: res.image_templates.images
2388 .iter()
2389 .map(|(key, template)| {
2390 (*key, PlainImageTemplate {
2391 data: match template.data {
2392 CachedImageData::Raw(ref arc) => image_paths[&arc.as_ptr()].clone(),
2393 _ => other_paths[key].clone(),
2394 },
2395 descriptor: template.descriptor.clone(),
2396 tiling: template.tiling,
2397 generation: template.generation,
2398 })
2399 })
2400 .collect(),
2401 };
2402
2403 (resources, external_images)
2404 }
2405
2406 #[cfg(feature = "capture")]
2407 pub fn save_caches(&self, _root: &PathBuf) -> PlainCacheRef {
2408 PlainCacheRef {
2409 current_frame_id: self.current_frame_id,
2410 glyphs: &self.cached_glyphs,
2411 glyph_dimensions: &self.cached_glyph_dimensions,
2412 images: &self.cached_images,
2413 render_tasks: &self.cached_render_tasks,
2414 textures: &self.texture_cache,
2415 picture_textures: &self.picture_textures,
2416 }
2417 }
2418
2419 #[cfg(feature = "replay")]
2420 pub fn load_capture(
2421 &mut self,
2422 resources: PlainResources,
2423 caches: Option<PlainCacheOwn>,
2424 config: &CaptureConfig,
2425 ) -> Vec<PlainExternalImage> {
2426 use std::{fs, path::Path};
2427 use crate::texture_cache::TextureCacheConfig;
2428
2429 info!("loading resource cache");
2430 let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
2434
2435 self.clear(ClearCache::all());
2436 self.clear_images(|_| true);
2437
2438 match caches {
2439 Some(cached) => {
2440 self.current_frame_id = cached.current_frame_id;
2441 self.cached_glyphs = cached.glyphs;
2442 self.cached_glyph_dimensions = cached.glyph_dimensions;
2443 self.cached_images = cached.images;
2444 self.cached_render_tasks = cached.render_tasks;
2445 self.texture_cache = cached.textures;
2446 self.picture_textures = cached.picture_textures;
2447 }
2448 None => {
2449 self.current_frame_id = FrameId::INVALID;
2450 self.texture_cache = TextureCache::new(
2451 self.texture_cache.max_texture_size(),
2452 self.texture_cache.tiling_threshold(),
2453 self.texture_cache.color_formats(),
2454 self.texture_cache.swizzle_settings(),
2455 &TextureCacheConfig::DEFAULT,
2456 );
2457 self.picture_textures = PictureTextures::new(
2458 self.picture_textures.default_tile_size(),
2459 self.picture_textures.filter(),
2460 );
2461 }
2462 }
2463
2464 self.glyph_rasterizer.reset();
2465 let res = &mut self.resources;
2466 res.fonts.templates.clear();
2467 res.fonts.instances.clear();
2468 res.image_templates.images.clear();
2469
2470 info!("\tfont templates...");
2471 let root = config.resource_root();
2472 let native_font_replacement = Arc::new(NATIVE_FONT.to_vec());
2473 for (key, plain_template) in resources.font_templates {
2474 let arc = match raw_map.entry(plain_template.data) {
2475 Entry::Occupied(e) => {
2476 e.get().clone()
2477 }
2478 Entry::Vacant(e) => {
2479 let file_path = if Path::new(e.key()).is_absolute() {
2480 PathBuf::from(e.key())
2481 } else {
2482 root.join(e.key())
2483 };
2484 let arc = match fs::read(file_path) {
2485 Ok(buffer) => Arc::new(buffer),
2486 Err(err) => {
2487 error!("Unable to open font template {:?}: {:?}", e.key(), err);
2488 Arc::clone(&native_font_replacement)
2489 }
2490 };
2491 e.insert(arc).clone()
2492 }
2493 };
2494
2495 let template = FontTemplate::Raw(arc, plain_template.index);
2496 if let Some(shared_key) = res.fonts.font_keys.add_key(&key, &template) {
2498 self.glyph_rasterizer.add_font(shared_key, template.clone());
2499 res.fonts.templates.add_font(shared_key, template);
2500 }
2501 }
2502
2503 info!("\tfont instances...");
2504 for instance in resources.font_instances {
2505 let base = BaseFontInstance {
2507 font_key: res.fonts.font_keys.map_key(&instance.font_key),
2508 ..instance
2509 };
2510 if let Some(shared_instance) = res.fonts.instance_keys.add_key(base) {
2511 res.fonts.instances.add_font_instance(shared_instance);
2512 }
2513 }
2514
2515 info!("\timage templates...");
2516 let mut external_images = Vec::new();
2517 for (key, template) in resources.image_templates {
2518 let data = if template.data.starts_with("snapshots/") {
2519 CachedImageData::Snapshot
2522 } else {
2523 match config.deserialize_for_resource::<PlainExternalImage, _>(&template.data) {
2524 Some(plain) => {
2525 let ext_data = plain.external;
2526 external_images.push(plain);
2527 CachedImageData::External(ext_data)
2528 }
2529 None => {
2530 let arc = match raw_map.entry(template.data) {
2531 Entry::Occupied(e) => e.get().clone(),
2532 Entry::Vacant(e) => {
2533 match fs::read(root.join(e.key())) {
2534 Ok(buffer) => {
2535 e.insert(Arc::new(buffer)).clone()
2536 }
2537 Err(err) => {
2538 log::warn!("Unable to open {}: {err:?}", e.key());
2539 continue;
2540 }
2541 }
2542 }
2543 };
2544 CachedImageData::Raw(arc)
2545 }
2546 }
2547 };
2548
2549 res.image_templates.images.insert(key, ImageResource {
2550 data,
2551 descriptor: template.descriptor,
2552 tiling: template.tiling,
2553 visible_rect: template.descriptor.size.into(),
2554 adjustment: AdjustedImageSource::new(), generation: template.generation,
2556 });
2557 }
2558
2559 external_images
2560 }
2561
2562 #[cfg(feature = "capture")]
2563 pub fn save_capture_sequence(&mut self, config: &mut CaptureConfig) -> Vec<ExternalCaptureImage> {
2564 if self.capture_dirty {
2565 self.capture_dirty = false;
2566 config.prepare_resource();
2567 let (resources, deferred) = self.save_capture(&config.resource_root());
2568 config.serialize_for_resource(&resources, "plain-resources.ron");
2569 deferred
2570 } else {
2571 Vec::new()
2572 }
2573 }
2574}