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 font_bitmap_strikes: FastHashMap<FontKey, bool>,
488
489 pending_image_requests: FastHashSet<ImageRequest>,
493
494 rasterized_blob_images: FastHashMap<BlobImageKey, RasterizedBlob>,
495
496 deleted_blob_keys: VecDeque<Vec<BlobImageKey>>,
499
500 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
504
505 pending_native_surface_updates: Vec<NativeSurfaceOperation>,
507
508 image_templates_memory: usize,
509 font_templates_memory: usize,
510
511 render_target_pool: Vec<RenderTarget>,
513
514 fallback_handle: TextureCacheHandle,
528 debug_fallback_panic: bool,
529 debug_fallback_pink: bool,
530}
531
532impl ResourceCache {
533 pub fn new(
534 texture_cache: TextureCache,
535 picture_textures: PictureTextures,
536 glyph_rasterizer: GlyphRasterizer,
537 cached_glyphs: GlyphCache,
538 fonts: SharedFontResources,
539 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
540 ) -> Self {
541 ResourceCache {
542 cached_glyphs,
543 cached_images: ResourceClassCache::new(),
544 cached_render_tasks: RenderTaskCache::new(),
545 resources: Resources {
546 fonts,
547 image_templates: ImageTemplates::default(),
548 weak_fonts: WeakTable::new(),
549 },
550 cached_glyph_dimensions: FastHashMap::default(),
551 font_bitmap_strikes: FastHashMap::default(),
552 texture_cache,
553 picture_textures,
554 state: State::Idle,
555 current_frame_id: FrameId::INVALID,
556 pending_image_requests: FastHashSet::default(),
557 glyph_rasterizer,
558 rasterized_blob_images: FastHashMap::default(),
559 deleted_blob_keys: vec![Vec::new(), Vec::new(), Vec::new()].into(),
561 blob_image_handler,
562 pending_native_surface_updates: Vec::new(),
563 #[cfg(feature = "capture")]
564 capture_dirty: true,
565 image_templates_memory: 0,
566 font_templates_memory: 0,
567 render_target_pool: Vec::new(),
568 fallback_handle: TextureCacheHandle::invalid(),
569 debug_fallback_panic: false,
570 debug_fallback_pink: false,
571 }
572 }
573
574 #[cfg(test)]
576 pub fn new_for_testing() -> Self {
577 use rayon::ThreadPoolBuilder;
578
579 let texture_cache = TextureCache::new_for_testing(
580 4096,
581 ImageFormat::RGBA8,
582 );
583 let workers = Arc::new(ThreadPoolBuilder::new().build().unwrap());
584 let glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
585 let cached_glyphs = GlyphCache::new();
586 let fonts = SharedFontResources::new(IdNamespace(0));
587 let picture_textures = PictureTextures::new(
588 crate::tile_cache::TILE_SIZE_DEFAULT,
589 TextureFilter::Nearest,
590 );
591
592 ResourceCache::new(
593 texture_cache,
594 picture_textures,
595 glyph_rasterizer,
596 cached_glyphs,
597 fonts,
598 None,
599 )
600 }
601
602 pub fn max_texture_size(&self) -> i32 {
603 self.texture_cache.max_texture_size()
604 }
605
606 pub fn tiling_threshold(&self) -> i32 {
609 self.texture_cache.tiling_threshold()
610 }
611
612 pub fn enable_multithreading(&mut self, enable: bool) {
613 self.glyph_rasterizer.enable_multithreading(enable);
614 }
615
616 fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool {
617 let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
618 match *data {
619 CachedImageData::Raw(_) | CachedImageData::Blob => size_check,
620 CachedImageData::External(info) => {
621 info.image_type == ExternalImageType::Buffer && size_check
624 }
625 CachedImageData::Snapshot => false,
626 }
627 }
628
629 pub fn request_render_task(
641 &mut self,
642 key: Option<RenderTaskCacheKey>,
643 is_opaque: bool,
644 parent: RenderTaskParent,
645 gpu_buffer_builder: &mut GpuBufferBuilderF,
646 rg_builder: &mut RenderTaskGraphBuilder,
647 surface_builder: &mut SurfaceBuilder,
648 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
649 ) -> RenderTaskId {
650 self.cached_render_tasks.request_render_task(
651 key.clone(),
652 &mut self.texture_cache,
653 is_opaque,
654 parent,
655 gpu_buffer_builder,
656 rg_builder,
657 surface_builder,
658 f
659 )
660 }
661
662 pub fn render_as_image(
663 &mut self,
664 image_key: ImageKey,
665 size: DeviceIntSize,
666 rg_builder: &mut RenderTaskGraphBuilder,
667 gpu_buffer_builder: &mut GpuBufferBuilderF,
668 is_opaque: bool,
669 adjustment: &AdjustedImageSource,
670 f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
671 ) -> RenderTaskId {
672
673 let task_id = f(rg_builder, gpu_buffer_builder);
674
675 let render_task = rg_builder.get_task_mut(task_id);
676
677 let image_result = self.cached_images.entry(image_key).or_insert_with(|| {
695 ImageResult::UntiledAuto(CachedImageInfo {
696 texture_cache_handle: TextureCacheHandle::invalid(),
697 dirty_rect: ImageDirtyRect::All,
698 manual_eviction: true,
699 })
700 });
701
702 let ImageResult::UntiledAuto(ref mut info) = *image_result else {
703 unreachable!("Expected untiled image with auto filter for snapshot");
704 };
705
706 let flags = if is_opaque {
707 ImageDescriptorFlags::IS_OPAQUE
708 } else {
709 ImageDescriptorFlags::empty()
710 };
711
712 let descriptor = ImageDescriptor::new(
713 size.width,
714 size.height,
715 self.texture_cache.shared_color_expected_format(),
716 flags,
717 );
718
719 let force_standalone_texture = true;
726
727 let user_data = [0.0; 4];
730 self.texture_cache.update(
731 &mut info.texture_cache_handle,
732 descriptor,
733 TextureFilter::Linear,
734 None,
735 user_data,
736 DirtyRect::All,
737 gpu_buffer_builder,
738 None,
739 render_task.uv_rect_kind(),
740 Eviction::Manual,
741 TargetShader::Default,
742 force_standalone_texture,
743 );
744
745 let (texture_id, uv_rect, _, _, _) =
749 self.texture_cache.get_cache_location(&info.texture_cache_handle);
750
751 render_task.location = RenderTaskLocation::Static {
752 surface: StaticRenderTaskSurface::TextureCache {
753 texture: texture_id,
754 target_kind: RenderTargetKind::Color,
755 },
756 rect: uv_rect.to_i32(),
757 };
758
759 self.resources.image_templates
760 .get_mut(image_key)
761 .unwrap()
762 .adjustment = *adjustment;
763
764 task_id
765 }
766
767 pub fn post_scene_building_update(
768 &mut self,
769 updates: Vec<ResourceUpdate>,
770 profile: &mut TransactionProfile,
771 ) {
772 #[cfg(feature = "capture")]
776 match updates.is_empty() {
777 false => self.capture_dirty = true,
778 _ => {},
779 }
780
781 for update in updates {
782 match update {
783 ResourceUpdate::AddImage(img) => {
784 if let ImageData::Raw(ref bytes) = img.data {
785 self.image_templates_memory += bytes.len();
786 profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
787 }
788 self.add_image_template(
789 img.key,
790 img.descriptor,
791 img.data.into(),
792 &img.descriptor.size.into(),
793 img.tiling,
794 );
795 profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
796 }
797 ResourceUpdate::UpdateImage(img) => {
798 self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
799 }
800 ResourceUpdate::AddBlobImage(img) => {
801 self.add_image_template(
802 img.key.as_image(),
803 img.descriptor,
804 CachedImageData::Blob,
805 &img.visible_rect,
806 Some(img.tile_size),
807 );
808 }
809 ResourceUpdate::UpdateBlobImage(img) => {
810 self.update_image_template(
811 img.key.as_image(),
812 img.descriptor,
813 CachedImageData::Blob,
814 &to_image_dirty_rect(
815 &img.dirty_rect
816 ),
817 );
818 self.discard_tiles_outside_visible_area(img.key, &img.visible_rect); self.set_image_visible_rect(img.key.as_image(), &img.visible_rect);
820 }
821 ResourceUpdate::DeleteImage(img) => {
822 self.delete_image_template(img);
823 profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
824 profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
825 }
826 ResourceUpdate::DeleteBlobImage(img) => {
827 self.delete_image_template(img.as_image());
828 }
829 ResourceUpdate::AddSnapshotImage(img) => {
830 let format = self.texture_cache.shared_color_expected_format();
831 self.add_image_template(
832 img.key.as_image(),
833 ImageDescriptor {
834 format,
835 size: DeviceIntSize::zero(),
837 stride: None,
838 offset: 0,
839 flags: ImageDescriptorFlags::empty(),
840 },
841 CachedImageData::Snapshot,
842 &DeviceIntRect::zero(),
843 None,
844 );
845 }
846 ResourceUpdate::DeleteSnapshotImage(img) => {
847 self.delete_image_template(img.as_image());
848 }
849 ResourceUpdate::DeleteFont(font) => {
850 if let Some(shared_key) = self.resources.fonts.font_keys.delete_key(&font) {
851 self.delete_font_template(shared_key);
852 if let Some(ref mut handler) = &mut self.blob_image_handler {
853 handler.delete_font(shared_key);
854 }
855 profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
856 profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
857 }
858 }
859 ResourceUpdate::DeleteFontInstance(font) => {
860 if let Some(shared_key) = self.resources.fonts.instance_keys.delete_key(&font) {
861 self.delete_font_instance(shared_key);
862 }
863 if let Some(ref mut handler) = &mut self.blob_image_handler {
864 handler.delete_font_instance(font);
865 }
866 }
867 ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
868 self.discard_tiles_outside_visible_area(key, &area);
869 self.set_image_visible_rect(key.as_image(), &area);
870 }
871 ResourceUpdate::AddFont(font) => {
872 let (key, template) = match font {
875 AddFont::Raw(key, bytes, index) => {
876 (key, FontTemplate::Raw(bytes, index))
877 }
878 AddFont::Native(key, native_font_handle) => {
879 (key, FontTemplate::Native(native_font_handle))
880 }
881 };
882 let shared_key = self.resources.fonts.font_keys.map_key(&key);
883 if !self.glyph_rasterizer.has_font(shared_key) {
884 self.add_font_template(shared_key, template);
885 profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
886 profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
887 }
888 }
889 ResourceUpdate::AddFontInstance(..) => {
890 }
892 }
893 }
894 }
895
896 pub fn add_rasterized_blob_images(
897 &mut self,
898 images: Vec<(BlobImageRequest, BlobImageResult)>,
899 profile: &mut TransactionProfile,
900 ) {
901 for (request, result) in images {
902 let data = match result {
903 Ok(data) => data,
904 Err(..) => {
905 warn!("Failed to rasterize a blob image");
906 continue;
907 }
908 };
909
910 profile.add(profiler::RASTERIZED_BLOBS_PX, data.rasterized_rect.area());
911
912 let tiles = self.rasterized_blob_images.entry(request.key).or_insert_with(
915 || { RasterizedBlob::default() }
916 );
917
918 tiles.insert(request.tile, data);
919
920 match self.cached_images.try_get_mut(&request.key.as_image()) {
921 Some(&mut ImageResult::Multi(ref mut entries)) => {
922 let cached_key = CachedImageKey {
923 rendering: ImageRendering::Auto, tile: Some(request.tile),
925 };
926 if let Some(entry) = entries.try_get_mut(&cached_key) {
927 entry.dirty_rect = DirtyRect::All;
928 }
929 }
930 _ => {}
931 }
932 }
933 }
934
935 pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
936 if let FontTemplate::Raw(ref data, _) = template {
939 self.resources.weak_fonts.insert(Arc::downgrade(data));
940 self.font_templates_memory += data.len();
941 }
942 let has_bitmap_strikes = self.glyph_rasterizer.template_has_bitmap_strikes(&template);
943 self.font_bitmap_strikes.insert(font_key, has_bitmap_strikes);
944 self.glyph_rasterizer.add_font(font_key, template.clone());
945 self.resources.fonts.templates.add_font(font_key, template);
946 }
947
948 pub fn delete_font_template(&mut self, font_key: FontKey) {
949 self.glyph_rasterizer.delete_font(font_key);
950 self.font_bitmap_strikes.remove(&font_key);
951 if let Some(FontTemplate::Raw(data, _)) = self.resources.fonts.templates.delete_font(&font_key) {
952 self.font_templates_memory -= data.len();
953 }
954 self.cached_glyphs.delete_fonts(&[font_key]);
955 }
956
957 pub fn font_has_bitmap_strikes(&self, font_key: FontKey) -> bool {
961 self.font_bitmap_strikes.get(&font_key).copied().unwrap_or(false)
962 }
963
964 pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
965 self.resources.fonts.instances.delete_font_instance(instance_key);
966 }
967
968 pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
969 self.resources.fonts.instances.get_font_instance(instance_key)
970 }
971
972 pub fn get_fonts(&self) -> SharedFontResources {
973 self.resources.fonts.clone()
974 }
975
976 pub fn add_image_template(
977 &mut self,
978 image_key: ImageKey,
979 descriptor: ImageDescriptor,
980 data: CachedImageData,
981 visible_rect: &DeviceIntRect,
982 mut tiling: Option<TileSize>,
983 ) {
984 if let Some(ref mut tile_size) = tiling {
985 *tile_size = (*tile_size).max(16).min(2048);
987 }
988
989 if tiling.is_none() && Self::should_tile(self.tiling_threshold(), &descriptor, &data) {
990 tiling = Some(DEFAULT_TILE_SIZE);
993 }
994
995 let resource = ImageResource {
996 descriptor,
997 data,
998 tiling,
999 visible_rect: *visible_rect,
1000 adjustment: AdjustedImageSource::new(),
1001 generation: ImageGeneration(0),
1002 };
1003
1004 self.resources.image_templates.insert(image_key, resource);
1005 }
1006
1007 pub fn update_image_template(
1008 &mut self,
1009 image_key: ImageKey,
1010 descriptor: ImageDescriptor,
1011 data: CachedImageData,
1012 dirty_rect: &ImageDirtyRect,
1013 ) {
1014 let tiling_threshold = self.tiling_threshold();
1015 let image = match self.resources.image_templates.get_mut(image_key) {
1016 Some(res) => res,
1017 None => panic!("Attempt to update non-existent image"),
1018 };
1019
1020 let mut tiling = image.tiling;
1021 if tiling.is_none() && Self::should_tile(tiling_threshold, &descriptor, &data) {
1022 tiling = Some(DEFAULT_TILE_SIZE);
1023 }
1024
1025 match self.cached_images.try_get_mut(&image_key) {
1028 Some(&mut ImageResult::UntiledAuto(ref mut entry)) => {
1029 entry.dirty_rect = entry.dirty_rect.union(dirty_rect);
1030 }
1031 Some(&mut ImageResult::Multi(ref mut entries)) => {
1032 for (key, entry) in entries.iter_mut() {
1033 let local_dirty_rect = match (tiling, key.tile) {
1035 (Some(tile_size), Some(tile)) => {
1036 dirty_rect.map(|mut rect|{
1037 let tile_offset = DeviceIntPoint::new(
1038 tile.x as i32,
1039 tile.y as i32,
1040 ) * tile_size as i32;
1041 rect = rect.translate(-tile_offset.to_vector());
1042
1043 let tile_rect = compute_tile_size(
1044 &descriptor.size.into(),
1045 tile_size,
1046 tile,
1047 ).into();
1048
1049 rect.intersection(&tile_rect).unwrap_or_else(DeviceIntRect::zero)
1050 })
1051 }
1052 (None, Some(..)) => DirtyRect::All,
1053 _ => *dirty_rect,
1054 };
1055 entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
1056 }
1057 }
1058 _ => {}
1059 }
1060
1061 if image.descriptor.format != descriptor.format {
1062 trace!("Format change {:?} -> {:?}", image.descriptor.format, descriptor.format);
1064 }
1065 *image = ImageResource {
1066 descriptor,
1067 data,
1068 tiling,
1069 visible_rect: descriptor.size.into(),
1070 adjustment: AdjustedImageSource::new(),
1071 generation: ImageGeneration(image.generation.0 + 1),
1072 };
1073 }
1074
1075 pub fn increment_image_generation(&mut self, key: ImageKey) {
1076 if let Some(image) = self.resources.image_templates.get_mut(key) {
1077 image.generation.0 += 1;
1078 }
1079 }
1080
1081 pub fn delete_image_template(&mut self, image_key: ImageKey) {
1082 let value = self.resources.image_templates.remove(image_key);
1084
1085 if let Some(mut cached) = self.cached_images.remove(&image_key) {
1087 cached.drop_from_cache(&mut self.texture_cache);
1088 }
1089
1090 match value {
1091 Some(image) => if image.data.is_blob() {
1092 if let CachedImageData::Raw(data) = image.data {
1093 self.image_templates_memory -= data.len();
1094 }
1095
1096 let blob_key = BlobImageKey(image_key);
1097 self.deleted_blob_keys.back_mut().unwrap().push(blob_key);
1098 self.rasterized_blob_images.remove(&blob_key);
1099 },
1100 None => {
1101 warn!("Delete the non-exist key");
1102 debug!("key={:?}", image_key);
1103 }
1104 }
1105 }
1106
1107 pub fn get_image_generation(&self, key: ImageKey) -> ImageGeneration {
1109 self.resources
1110 .image_templates
1111 .get(key)
1112 .map_or(ImageGeneration::INVALID, |template| template.generation)
1113 }
1114
1115 pub fn request_image(
1119 &mut self,
1120 mut request: ImageRequest,
1121 gpu_buffer: &mut GpuBufferBuilderF,
1122 ) -> DeviceIntSize {
1123 debug_assert_eq!(self.state, State::AddResources);
1124
1125 let template = match self.resources.image_templates.get(request.key) {
1126 Some(template) => template,
1127 None => {
1128 warn!("ERROR: Trying to render deleted / non-existent key");
1129 debug!("key={:?}", request.key);
1130 return DeviceIntSize::zero();
1131 }
1132 };
1133
1134 let size = match request.tile {
1135 Some(tile) => compute_tile_size(&template.visible_rect, template.tiling.unwrap(), tile),
1136 None => template.descriptor.size,
1137 };
1138
1139 if !template.data.uses_texture_cache() {
1141 return size;
1142 }
1143
1144 if template.data.is_snapshot() {
1145 request.rendering = ImageRendering::Auto;
1150 }
1151
1152 let side_size =
1153 template.tiling.map_or(cmp::max(template.descriptor.size.width, template.descriptor.size.height),
1154 |tile_size| tile_size as i32);
1155 if side_size > self.texture_cache.max_texture_size() {
1156 warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
1158 template.descriptor.size.width, template.descriptor.size.height, template.tiling.unwrap_or(0));
1159 self.cached_images.insert(request.key, ImageResult::Err(ImageCacheError::OverLimitSize));
1160 return DeviceIntSize::zero();
1161 }
1162
1163 let storage = match self.cached_images.entry(request.key) {
1164 Occupied(e) => {
1165 let entry = e.into_mut();
1170 if !request.is_untiled_auto() {
1171 let untiled_entry = match entry {
1172 &mut ImageResult::UntiledAuto(ref mut entry) => {
1173 Some(mem::replace(entry, CachedImageInfo {
1174 texture_cache_handle: TextureCacheHandle::invalid(),
1175 dirty_rect: DirtyRect::All,
1176 manual_eviction: false,
1177 }))
1178 }
1179 _ => None
1180 };
1181
1182 if let Some(untiled_entry) = untiled_entry {
1183 let mut entries = ResourceClassCache::new();
1184 let untiled_key = CachedImageKey {
1185 rendering: ImageRendering::Auto,
1186 tile: None,
1187 };
1188 entries.insert(untiled_key, untiled_entry);
1189 *entry = ImageResult::Multi(entries);
1190 }
1191 }
1192 entry
1193 }
1194 Vacant(entry) => {
1195 entry.insert(if request.is_untiled_auto() {
1196 ImageResult::UntiledAuto(CachedImageInfo {
1197 texture_cache_handle: TextureCacheHandle::invalid(),
1198 dirty_rect: DirtyRect::All,
1199 manual_eviction: false,
1200 })
1201 } else {
1202 ImageResult::Multi(ResourceClassCache::new())
1203 })
1204 }
1205 };
1206
1207 let entry = match *storage {
1210 ImageResult::UntiledAuto(ref mut entry) => entry,
1211 ImageResult::Multi(ref mut entries) => {
1212 entries.entry(request.into())
1213 .or_insert(CachedImageInfo {
1214 texture_cache_handle: TextureCacheHandle::invalid(),
1215 dirty_rect: DirtyRect::All,
1216 manual_eviction: false,
1217 })
1218 },
1219 ImageResult::Err(_) => panic!("Errors should already have been handled"),
1220 };
1221
1222 let needs_upload = self.texture_cache.request(&entry.texture_cache_handle, gpu_buffer);
1223
1224 if !needs_upload && entry.dirty_rect.is_empty() {
1225 return size;
1226 }
1227
1228 if !self.pending_image_requests.insert(request) {
1229 return size;
1230 }
1231
1232 if template.data.is_blob() {
1233 let request: BlobImageRequest = request.into();
1234 let missing = match self.rasterized_blob_images.get(&request.key) {
1235 Some(tiles) => !tiles.contains_key(&request.tile),
1236 _ => true,
1237 };
1238
1239 assert!(!missing);
1240 }
1241
1242 size
1243 }
1244
1245 fn discard_tiles_outside_visible_area(
1246 &mut self,
1247 key: BlobImageKey,
1248 area: &DeviceIntRect
1249 ) {
1250 let tile_size = match self.resources.image_templates.get(key.as_image()) {
1251 Some(template) => template.tiling.unwrap(),
1252 None => {
1253 return;
1255 }
1256 };
1257
1258 let tiles = match self.rasterized_blob_images.get_mut(&key) {
1259 Some(tiles) => tiles,
1260 _ => { return; }
1261 };
1262
1263 let tile_range = compute_tile_range(
1264 &area,
1265 tile_size,
1266 );
1267
1268 tiles.retain(|tile, _| { tile_range.contains(*tile) });
1269
1270 let texture_cache = &mut self.texture_cache;
1271 match self.cached_images.try_get_mut(&key.as_image()) {
1272 Some(&mut ImageResult::Multi(ref mut entries)) => {
1273 entries.retain(|key, entry| {
1274 if key.tile.is_none() || tile_range.contains(key.tile.unwrap()) {
1275 return true;
1276 }
1277 entry.mark_unused(texture_cache);
1278 return false;
1279 });
1280 }
1281 _ => {}
1282 }
1283 }
1284
1285 fn set_image_visible_rect(&mut self, key: ImageKey, rect: &DeviceIntRect) {
1286 if let Some(image) = self.resources.image_templates.get_mut(key) {
1287 image.visible_rect = *rect;
1288 image.descriptor.size = rect.size();
1289 }
1290 }
1291
1292 pub fn request_glyphs(
1293 &mut self,
1294 mut font: FontInstance,
1295 glyph_keys: &[GlyphKey],
1296 gpu_buffer: &mut GpuBufferBuilderF,
1297 ) {
1298 debug_assert_eq!(self.state, State::AddResources);
1299
1300 self.glyph_rasterizer.prepare_font(&mut font);
1301 let glyph_key_cache = self.cached_glyphs.insert_glyph_key_cache_for_font(&font);
1302 let texture_cache = &mut self.texture_cache;
1303 self.glyph_rasterizer.request_glyphs(
1304 font,
1305 glyph_keys,
1306 |key| {
1307 let cache_key = key.cache_key();
1308 if let Some(entry) = glyph_key_cache.try_get(&cache_key) {
1309 match entry {
1310 GlyphCacheEntry::Cached(ref glyph) => {
1311 if !texture_cache.request(&glyph.texture_cache_handle, gpu_buffer) {
1312 return false;
1313 }
1314 }
1318 GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => return false,
1320 }
1321 };
1322
1323 glyph_key_cache.add_glyph(cache_key, GlyphCacheEntry::Pending);
1324
1325 true
1326 }
1327 );
1328 }
1329
1330 pub fn pending_updates(&mut self) -> ResourceUpdateList {
1331 ResourceUpdateList {
1332 texture_updates: self.texture_cache.pending_updates(),
1333 native_surface_updates: mem::replace(&mut self.pending_native_surface_updates, Vec::new()),
1334 }
1335 }
1336
1337 pub fn fetch_glyphs<F>(
1338 &self,
1339 mut font: FontInstance,
1340 glyph_keys: &[GlyphKey],
1341 gpu_buffer: &GpuBufferBuilderF,
1342 fetch_buffer: &mut Vec<GlyphFetchResult>,
1343 mut f: F,
1344 ) where
1345 F: FnMut(TextureSource, GlyphFormat, &[GlyphFetchResult]),
1346 {
1347 debug_assert_eq!(self.state, State::QueryResources);
1348
1349 self.glyph_rasterizer.prepare_font(&mut font);
1350 let glyph_key_cache = self.cached_glyphs.get_glyph_key_cache_for_font(&font);
1351
1352 let mut current_texture_id = TextureSource::Invalid;
1353 let mut current_glyph_format = GlyphFormat::Subpixel;
1354 debug_assert!(fetch_buffer.is_empty());
1355
1356 for (loop_index, key) in glyph_keys.iter().enumerate() {
1357 let cache_key = key.cache_key();
1358 let (cache_item, glyph_format, is_packed_glyph) = match *glyph_key_cache.get(&cache_key) {
1359 GlyphCacheEntry::Cached(ref glyph) => {
1360 (self.texture_cache.get(&glyph.texture_cache_handle), glyph.format, glyph.is_packed_glyph)
1361 }
1362 GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
1363 };
1364 if current_texture_id != cache_item.texture_id ||
1365 current_glyph_format != glyph_format {
1366 if !fetch_buffer.is_empty() {
1367 f(current_texture_id, current_glyph_format, fetch_buffer);
1368 fetch_buffer.clear();
1369 }
1370 current_texture_id = cache_item.texture_id;
1371 current_glyph_format = glyph_format;
1372 }
1373 let (subpx_offset_x, subpx_offset_y) = key.subpixel_offset();
1374 fetch_buffer.push(GlyphFetchResult {
1375 index_in_text_run: loop_index as i32,
1376 uv_rect_address: gpu_buffer.resolve_handle(cache_item.uv_rect_handle),
1377 offset: DevicePoint::new(cache_item.user_data[0], cache_item.user_data[1]),
1378 size: cache_item.uv_rect.size(),
1379 scale: cache_item.user_data[2],
1380 subpx_offset_x: subpx_offset_x as u8,
1381 subpx_offset_y: subpx_offset_y as u8,
1382 is_packed_glyph,
1383 });
1384 }
1385
1386 if !fetch_buffer.is_empty() {
1387 f(current_texture_id, current_glyph_format, fetch_buffer);
1388 fetch_buffer.clear();
1389 }
1390 }
1391
1392 pub fn map_font_key(&self, key: FontKey) -> FontKey {
1393 self.resources.fonts.font_keys.map_key(&key)
1394 }
1395
1396 pub fn map_font_instance_key(&self, key: FontInstanceKey) -> FontInstanceKey {
1397 self.resources.fonts.instance_keys.map_key(&key)
1398 }
1399
1400 pub fn get_glyph_dimensions(
1401 &mut self,
1402 font: &FontInstance,
1403 glyph_index: GlyphIndex,
1404 ) -> Option<GlyphDimensions> {
1405 match self.cached_glyph_dimensions.entry((font.instance_key, glyph_index)) {
1406 Occupied(entry) => *entry.get(),
1407 Vacant(entry) => *entry.insert(
1408 self.glyph_rasterizer
1409 .get_glyph_dimensions(font, glyph_index),
1410 ),
1411 }
1412 }
1413
1414 pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
1415 self.glyph_rasterizer.get_glyph_index(font_key, ch)
1416 }
1417
1418 #[inline]
1419 pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
1420 debug_assert_eq!(self.state, State::QueryResources);
1421 let image_info = self.get_image_info(request)?;
1422
1423 if let Ok(item) = self.get_texture_cache_item(&image_info.texture_cache_handle) {
1424 return Ok(item);
1426 }
1427
1428 if self.resources.image_templates
1429 .get(request.key)
1430 .map_or(false, |img| img.data.is_snapshot()) {
1431 if self.debug_fallback_panic {
1432 panic!("Missing snapshot image");
1433 }
1434 return self.get_texture_cache_item(&self.fallback_handle);
1435 }
1436
1437 panic!("Requested image missing from the texture cache");
1438 }
1439
1440 pub fn get_cached_render_task(
1441 &self,
1442 handle: &RenderTaskCacheEntryHandle,
1443 ) -> &RenderTaskCacheEntry {
1444 self.cached_render_tasks.get_cache_entry(handle)
1445 }
1446
1447 #[inline]
1448 fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
1449 match *self.cached_images.get(&request.key) {
1452 ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
1453 ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
1454 ImageResult::Err(_) => Err(()),
1455 }
1456 }
1457
1458 #[inline]
1459 pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> Result<CacheItem, ()> {
1460 if let Some(item) = self.texture_cache.try_get(handle) {
1461 return Ok(item);
1462 }
1463
1464 Err(())
1465 }
1466
1467 pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
1468 let image_template = &self.resources.image_templates.get(image_key);
1469
1470 image_template.map(|image_template| {
1471 let external_image = match image_template.data {
1472 CachedImageData::External(ext_image) => match ext_image.image_type {
1473 ExternalImageType::TextureHandle(_) => Some(ext_image),
1474 ExternalImageType::Buffer => None,
1476 },
1477 CachedImageData::Raw(..)
1479 | CachedImageData::Blob
1480 | CachedImageData::Snapshot
1481 => None,
1482 };
1483
1484 ImageProperties {
1485 descriptor: image_template.descriptor,
1486 external_image,
1487 tiling: image_template.tiling,
1488 visible_rect: image_template.visible_rect,
1489 adjustment: image_template.adjustment,
1490 }
1491 })
1492 }
1493
1494 pub fn begin_frame(&mut self, stamp: FrameStamp, profile: &mut TransactionProfile) {
1495 profile_scope!("begin_frame");
1496 debug_assert_eq!(self.state, State::Idle);
1497 self.state = State::AddResources;
1498 self.texture_cache.begin_frame(stamp, profile);
1499 self.picture_textures.begin_frame(stamp, &mut self.texture_cache.pending_updates);
1500
1501 self.cached_glyphs.begin_frame(
1502 stamp,
1503 &mut self.texture_cache,
1504 &mut self.glyph_rasterizer,
1505 );
1506 self.cached_render_tasks.begin_frame(&mut self.texture_cache);
1507 self.current_frame_id = stamp.frame_id();
1508
1509 let mut v = self.deleted_blob_keys.pop_front().unwrap_or_else(Vec::new);
1512 v.clear();
1513 self.deleted_blob_keys.push_back(v);
1514
1515 self.texture_cache.run_compaction();
1516 }
1517
1518 pub fn block_until_all_resources_added(
1519 &mut self,
1520 gpu_buffer: &mut GpuBufferBuilder,
1521 profile: &mut TransactionProfile,
1522 ) {
1523 profile_scope!("block_until_all_resources_added");
1524
1525 debug_assert_eq!(self.state, State::AddResources);
1526 self.state = State::QueryResources;
1527
1528 let cached_glyphs = &mut self.cached_glyphs;
1529 let texture_cache = &mut self.texture_cache;
1530
1531 self.glyph_rasterizer.resolve_glyphs(
1532 |job, can_use_r8_format| {
1533 let GlyphRasterJob { font, key, result } = job;
1534 let cache_key = key.cache_key();
1535 let glyph_key_cache = cached_glyphs.get_glyph_key_cache_for_font_mut(&*font);
1536 let glyph_info = match result {
1537 Err(_) => GlyphCacheEntry::Blank,
1538 Ok(ref glyph) if glyph.width == 0 || glyph.height == 0 => {
1539 GlyphCacheEntry::Blank
1540 }
1541 Ok(glyph) => {
1542 let mut texture_cache_handle = TextureCacheHandle::invalid();
1543 texture_cache.request(&texture_cache_handle, &mut gpu_buffer.f32);
1544 texture_cache.update(
1545 &mut texture_cache_handle,
1546 ImageDescriptor {
1547 size: size2(glyph.width, glyph.height),
1548 stride: None,
1549 format: glyph.format.image_format(can_use_r8_format),
1550 flags: ImageDescriptorFlags::empty(),
1551 offset: 0,
1552 },
1553 TextureFilter::Linear,
1554 Some(CachedImageData::Raw(Arc::new(glyph.bytes))),
1555 [glyph.left, -glyph.top, glyph.scale, 0.0],
1556 DirtyRect::All,
1557 &mut gpu_buffer.f32,
1558 Some(glyph_key_cache.eviction_notice()),
1559 UvRectKind::Rect,
1560 Eviction::Auto,
1561 TargetShader::Text,
1562 false,
1563 );
1564 GlyphCacheEntry::Cached(CachedGlyphInfo {
1565 texture_cache_handle,
1566 format: glyph.format,
1567 is_packed_glyph: glyph.is_packed_glyph,
1568 })
1569 }
1570 };
1571 glyph_key_cache.insert(cache_key, glyph_info);
1572 },
1573 profile,
1574 );
1575
1576 self.update_texture_cache(gpu_buffer);
1578 }
1579
1580 fn update_texture_cache(&mut self, gpu_buffer: &mut GpuBufferBuilder) {
1581 profile_scope!("update_texture_cache");
1582
1583 if self.fallback_handle == TextureCacheHandle::invalid() {
1584 let fallback_color = if self.debug_fallback_pink {
1585 vec![255, 0, 255, 255]
1586 } else {
1587 vec![0, 0, 0, 0]
1588 };
1589 self.texture_cache.update(
1590 &mut self.fallback_handle,
1591 ImageDescriptor {
1592 size: size2(1, 1),
1593 stride: None,
1594 format: ImageFormat::BGRA8,
1595 flags: ImageDescriptorFlags::empty(),
1596 offset: 0,
1597 },
1598 TextureFilter::Linear,
1599 Some(CachedImageData::Raw(Arc::new(fallback_color))),
1600 [0.0; 4],
1601 DirtyRect::All,
1602 &mut gpu_buffer.f32,
1603 None,
1604 UvRectKind::Rect,
1605 Eviction::Manual,
1606 TargetShader::Default,
1607 false,
1608 );
1609 }
1610
1611 for request in self.pending_image_requests.drain() {
1612 let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
1613 debug_assert!(image_template.data.uses_texture_cache());
1614
1615 let mut updates: SmallVec<[(CachedImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
1616
1617 match image_template.data {
1618 CachedImageData::Snapshot => {
1619 }
1621 CachedImageData::Raw(..)
1622 | CachedImageData::External(..) => {
1623 updates.push((image_template.data.clone(), None));
1626 }
1627 CachedImageData::Blob => {
1628 let blob_image = self.rasterized_blob_images.get_mut(&BlobImageKey(request.key)).unwrap();
1629 let img = &blob_image[&request.tile.unwrap()];
1630 updates.push((
1631 CachedImageData::Raw(Arc::clone(&img.data)),
1632 Some(img.rasterized_rect)
1633 ));
1634 }
1635 };
1636
1637 for (image_data, blob_rasterized_rect) in updates {
1638 let entry = match *self.cached_images.get_mut(&request.key) {
1639 ImageResult::UntiledAuto(ref mut entry) => entry,
1640 ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
1641 ImageResult::Err(_) => panic!("Update requested for invalid entry")
1642 };
1643
1644 let mut descriptor = image_template.descriptor.clone();
1645 let mut dirty_rect = entry.dirty_rect.replace_with_empty();
1646
1647 if let Some(tile) = request.tile {
1648 let tile_size = image_template.tiling.unwrap();
1649 let clipped_tile_size = compute_tile_size(&image_template.visible_rect, tile_size, tile);
1650 let tiled_on_cpu = image_template.data.is_blob();
1654 if !tiled_on_cpu {
1655 debug_assert_eq!(image_template.visible_rect.min, point2(0, 0));
1658 let bpp = descriptor.format.bytes_per_pixel();
1659 let stride = descriptor.compute_stride();
1660 descriptor.stride = Some(stride);
1661 descriptor.offset +=
1662 tile.y as i32 * tile_size as i32 * stride +
1663 tile.x as i32 * tile_size as i32 * bpp;
1664 }
1665
1666 descriptor.size = clipped_tile_size;
1667 }
1668
1669 if let Some(rect) = blob_rasterized_rect {
1673 dirty_rect = DirtyRect::Partial(rect);
1674 }
1675
1676 let filter = match request.rendering {
1677 ImageRendering::Pixelated => {
1678 TextureFilter::Nearest
1679 }
1680 ImageRendering::Auto | ImageRendering::CrispEdges => {
1681 if descriptor.allow_mipmaps() &&
1689 descriptor.size.width > 512 &&
1690 descriptor.size.height > 512 &&
1691 !self.texture_cache.is_allowed_in_shared_cache(
1692 TextureFilter::Linear,
1693 &descriptor,
1694 ) {
1695 TextureFilter::Trilinear
1696 } else {
1697 TextureFilter::Linear
1698 }
1699 }
1700 };
1701
1702 let eviction = match &image_template.data {
1703 CachedImageData::Blob | CachedImageData::Snapshot => {
1704 entry.manual_eviction = true;
1705 Eviction::Manual
1706 }
1707 _ => {
1708 Eviction::Auto
1709 }
1710 };
1711
1712 self.texture_cache.update(
1714 &mut entry.texture_cache_handle,
1715 descriptor,
1716 filter,
1717 Some(image_data),
1718 [0.0; 4],
1719 dirty_rect,
1720 &mut gpu_buffer.f32,
1721 None,
1722 UvRectKind::Rect,
1723 eviction,
1724 TargetShader::Default,
1725 false,
1726 );
1727 }
1728 }
1729 }
1730
1731 pub fn create_compositor_backdrop_surface(
1732 &mut self,
1733 color: ColorF
1734 ) -> NativeSurfaceId {
1735 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1736
1737 self.pending_native_surface_updates.push(
1738 NativeSurfaceOperation {
1739 details: NativeSurfaceOperationDetails::CreateBackdropSurface {
1740 id,
1741 color,
1742 },
1743 }
1744 );
1745
1746 id
1747 }
1748
1749 pub fn create_compositor_surface(
1752 &mut self,
1753 virtual_offset: DeviceIntPoint,
1754 tile_size: DeviceIntSize,
1755 is_opaque: bool,
1756 ) -> NativeSurfaceId {
1757 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1758
1759 self.pending_native_surface_updates.push(
1760 NativeSurfaceOperation {
1761 details: NativeSurfaceOperationDetails::CreateSurface {
1762 id,
1763 virtual_offset,
1764 tile_size,
1765 is_opaque,
1766 },
1767 }
1768 );
1769
1770 id
1771 }
1772
1773 pub fn create_compositor_external_surface(
1774 &mut self,
1775 is_opaque: bool,
1776 ) -> NativeSurfaceId {
1777 let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
1778
1779 self.pending_native_surface_updates.push(
1780 NativeSurfaceOperation {
1781 details: NativeSurfaceOperationDetails::CreateExternalSurface {
1782 id,
1783 is_opaque,
1784 },
1785 }
1786 );
1787
1788 id
1789 }
1790
1791 pub fn destroy_compositor_surface(
1794 &mut self,
1795 id: NativeSurfaceId,
1796 ) {
1797 self.pending_native_surface_updates.push(
1798 NativeSurfaceOperation {
1799 details: NativeSurfaceOperationDetails::DestroySurface {
1800 id,
1801 }
1802 }
1803 );
1804 }
1805
1806 pub fn create_compositor_tile(
1808 &mut self,
1809 id: NativeTileId,
1810 ) {
1811 self.pending_native_surface_updates.push(
1812 NativeSurfaceOperation {
1813 details: NativeSurfaceOperationDetails::CreateTile {
1814 id,
1815 },
1816 }
1817 );
1818 }
1819
1820 pub fn destroy_compositor_tile(
1822 &mut self,
1823 id: NativeTileId,
1824 ) {
1825 self.pending_native_surface_updates.push(
1826 NativeSurfaceOperation {
1827 details: NativeSurfaceOperationDetails::DestroyTile {
1828 id,
1829 },
1830 }
1831 );
1832 }
1833
1834 pub fn attach_compositor_external_image(
1835 &mut self,
1836 id: NativeSurfaceId,
1837 external_image: ExternalImageId,
1838 ) {
1839 self.pending_native_surface_updates.push(
1840 NativeSurfaceOperation {
1841 details: NativeSurfaceOperationDetails::AttachExternalImage {
1842 id,
1843 external_image,
1844 },
1845 }
1846 );
1847 }
1848
1849
1850 pub fn end_frame(&mut self, profile: &mut TransactionProfile) {
1851 debug_assert_eq!(self.state, State::QueryResources);
1852 profile_scope!("end_frame");
1853 self.state = State::Idle;
1854
1855 self.gc_render_targets(
1868 64 * 1024 * 1024,
1869 32 * 1024 * 1024 * 10,
1870 60,
1871 );
1872
1873 self.texture_cache.end_frame(profile);
1874 self.picture_textures.gc(
1875 &mut self.texture_cache.pending_updates,
1876 );
1877
1878 self.picture_textures.update_profile(profile);
1879 }
1880
1881 pub fn set_debug_flags(&mut self, flags: DebugFlags) {
1882 GLYPH_FLASHING.store(flags.contains(DebugFlags::GLYPH_FLASHING), std::sync::atomic::Ordering::Relaxed);
1883 self.texture_cache.set_debug_flags(flags);
1884 self.picture_textures.set_debug_flags(flags);
1885 self.debug_fallback_panic = flags.contains(DebugFlags::MISSING_SNAPSHOT_PANIC);
1886 let fallback_pink = flags.contains(DebugFlags::MISSING_SNAPSHOT_PINK);
1887
1888 if fallback_pink != self.debug_fallback_pink && self.fallback_handle != TextureCacheHandle::invalid() {
1889 self.texture_cache.evict_handle(&self.fallback_handle);
1890 }
1891 self.debug_fallback_pink = fallback_pink;
1892 }
1893
1894 pub fn clear(&mut self, what: ClearCache) {
1895 if what.contains(ClearCache::IMAGES) {
1896 for (_key, mut cached) in self.cached_images.resources.drain() {
1897 cached.drop_from_cache(&mut self.texture_cache);
1898 }
1899 }
1900 if what.contains(ClearCache::GLYPHS) {
1901 self.cached_glyphs.clear();
1902 }
1903 if what.contains(ClearCache::GLYPH_DIMENSIONS) {
1904 self.cached_glyph_dimensions.clear();
1905 }
1906 if what.contains(ClearCache::RENDER_TASKS) {
1907 self.cached_render_tasks.clear();
1908 }
1909 if what.contains(ClearCache::TEXTURE_CACHE) {
1910 self.texture_cache.clear_all();
1911 self.picture_textures.clear(&mut self.texture_cache.pending_updates);
1912 }
1913 if what.contains(ClearCache::RENDER_TARGETS) {
1914 self.clear_render_target_pool();
1915 }
1916 }
1917
1918 pub fn clear_namespace(&mut self, namespace: IdNamespace) {
1919 self.clear_images(|k| k.0 == namespace);
1920
1921 self.resources.fonts.instances.clear_namespace(namespace);
1923 let deleted_keys = self.resources.fonts.templates.clear_namespace(namespace);
1924 self.glyph_rasterizer.delete_fonts(&deleted_keys);
1925 self.cached_glyphs.clear_namespace(namespace);
1926 if let Some(handler) = &mut self.blob_image_handler {
1927 handler.clear_namespace(namespace);
1928 }
1929
1930 let shared_instance_keys = self.resources.fonts.instance_keys.clear_namespace(namespace);
1932 if !shared_instance_keys.is_empty() {
1933 self.resources.fonts.instances.delete_font_instances(&shared_instance_keys);
1934 self.cached_glyphs.delete_font_instances(&shared_instance_keys, &mut self.glyph_rasterizer);
1935 }
1938
1939 let shared_keys = self.resources.fonts.font_keys.clear_namespace(namespace);
1941 if !shared_keys.is_empty() {
1942 self.glyph_rasterizer.delete_fonts(&shared_keys);
1943 self.resources.fonts.templates.delete_fonts(&shared_keys);
1944 self.cached_glyphs.delete_fonts(&shared_keys);
1945 if let Some(handler) = &mut self.blob_image_handler {
1946 for &key in &shared_keys {
1947 handler.delete_font(key);
1948 }
1949 }
1950 }
1951 }
1952
1953 pub fn report_memory(&self, op: VoidPtrToSizeFn) -> MemoryReport {
1962 let mut report = MemoryReport::default();
1963
1964 let mut seen_fonts = std::collections::HashSet::new();
1965 for (_, font) in self.resources.fonts.templates.lock().iter() {
1968 if let FontTemplate::Raw(ref raw, _) = font {
1969 report.fonts += unsafe { op(raw.as_ptr() as *const c_void) };
1970 seen_fonts.insert(raw.as_ptr());
1971 }
1972 }
1973
1974 for font in self.resources.weak_fonts.iter() {
1975 if !seen_fonts.contains(&font.as_ptr()) {
1976 report.weak_fonts += unsafe { op(font.as_ptr() as *const c_void) };
1977 }
1978 }
1979
1980 for (_, image) in self.resources.image_templates.images.iter() {
1982 report.images += match image.data {
1983 CachedImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
1984 CachedImageData::Blob
1985 | CachedImageData::External(..)
1986 | CachedImageData::Snapshot => 0,
1987 }
1988 }
1989
1990 report
2006 }
2007
2008 fn clear_images<F: Fn(&ImageKey) -> bool>(&mut self, f: F) {
2010 let keys = self.resources.image_templates.images.keys().filter(|k| f(*k))
2011 .cloned().collect::<SmallVec<[ImageKey; 16]>>();
2012
2013 for key in keys {
2014 self.delete_image_template(key);
2015 }
2016
2017 #[cfg(feature="leak_checks")]
2018 let check_leaks = true;
2019 #[cfg(not(feature="leak_checks"))]
2020 let check_leaks = false;
2021
2022 if check_leaks {
2023 let blob_f = |key: &BlobImageKey| { f(&key.as_image()) };
2024 assert!(!self.resources.image_templates.images.keys().any(&f));
2025 assert!(!self.cached_images.resources.keys().any(&f));
2026 assert!(!self.rasterized_blob_images.keys().any(&blob_f));
2027 }
2028 }
2029
2030 pub fn get_or_create_render_target_from_pool(
2033 &mut self,
2034 size: DeviceIntSize,
2035 format: ImageFormat,
2036 ) -> CacheTextureId {
2037 for target in &mut self.render_target_pool {
2038 if target.size == size &&
2039 target.format == format &&
2040 !target.is_active {
2041 target.is_active = true;
2044 target.last_frame_used = self.current_frame_id;
2045 return target.texture_id;
2046 }
2047 }
2048
2049 let texture_id = self.texture_cache.alloc_render_target(
2052 size,
2053 format,
2054 );
2055
2056 self.render_target_pool.push(RenderTarget {
2057 size,
2058 format,
2059 texture_id,
2060 is_active: true,
2061 last_frame_used: self.current_frame_id,
2062 });
2063
2064 texture_id
2065 }
2066
2067 pub fn return_render_target_to_pool(
2069 &mut self,
2070 id: CacheTextureId,
2071 ) {
2072 let target = self.render_target_pool
2073 .iter_mut()
2074 .find(|t| t.texture_id == id)
2075 .expect("bug: invalid render target id");
2076
2077 assert!(target.is_active);
2078 target.is_active = false;
2079 }
2080
2081 fn clear_render_target_pool(
2083 &mut self,
2084 ) {
2085 for target in self.render_target_pool.drain(..) {
2086 debug_assert!(!target.is_active);
2087 self.texture_cache.free_render_target(target.texture_id);
2088 }
2089 }
2090
2091 fn gc_render_targets(
2094 &mut self,
2095 total_bytes_threshold: usize,
2096 total_bytes_red_line_threshold: usize,
2097 frames_threshold: u64,
2098 ) {
2099 let mut rt_pool_size_in_bytes: usize = self.render_target_pool
2101 .iter()
2102 .map(|t| t.size_in_bytes())
2103 .sum();
2104
2105 if rt_pool_size_in_bytes <= total_bytes_threshold {
2108 return;
2109 }
2110
2111 self.render_target_pool.sort_by_key(|t| t.last_frame_used);
2113
2114 let mut retained_targets = SmallVec::<[RenderTarget; 8]>::new();
2116
2117 for target in self.render_target_pool.drain(..) {
2118 assert!(!target.is_active);
2119
2120 let above_red_line = rt_pool_size_in_bytes > total_bytes_red_line_threshold;
2125 let above_threshold = rt_pool_size_in_bytes > total_bytes_threshold;
2126 let used_recently = target.used_recently(self.current_frame_id, frames_threshold);
2127 let used_this_frame = target.last_frame_used == self.current_frame_id;
2128
2129 if !used_this_frame && (above_red_line || (above_threshold && !used_recently)) {
2130 rt_pool_size_in_bytes -= target.size_in_bytes();
2131 self.texture_cache.free_render_target(target.texture_id);
2132 } else {
2133 retained_targets.push(target);
2134 }
2135 }
2136
2137 self.render_target_pool.extend(retained_targets);
2138 }
2139
2140 #[cfg(test)]
2141 pub fn validate_surfaces(
2142 &self,
2143 expected_surfaces: &[(i32, i32, ImageFormat)],
2144 ) {
2145 assert_eq!(expected_surfaces.len(), self.render_target_pool.len());
2146
2147 for (expected, surface) in expected_surfaces.iter().zip(self.render_target_pool.iter()) {
2148 assert_eq!(DeviceIntSize::new(expected.0, expected.1), surface.size);
2149 assert_eq!(expected.2, surface.format);
2150 }
2151 }
2152}
2153
2154impl Drop for ResourceCache {
2155 fn drop(&mut self) {
2156 self.clear_images(|_| true);
2157 }
2158}
2159
2160#[cfg(any(feature = "capture", feature = "replay"))]
2161#[cfg_attr(feature = "capture", derive(Serialize))]
2162#[cfg_attr(feature = "replay", derive(Deserialize))]
2163struct PlainFontTemplate {
2164 data: String,
2165 index: u32,
2166}
2167
2168#[cfg(any(feature = "capture", feature = "replay"))]
2169#[cfg_attr(feature = "capture", derive(Serialize))]
2170#[cfg_attr(feature = "replay", derive(Deserialize))]
2171struct PlainImageTemplate {
2172 data: String,
2173 descriptor: ImageDescriptor,
2174 tiling: Option<TileSize>,
2175 generation: ImageGeneration,
2176}
2177
2178#[cfg(any(feature = "capture", feature = "replay"))]
2179#[cfg_attr(feature = "capture", derive(Serialize))]
2180#[cfg_attr(feature = "replay", derive(Deserialize))]
2181pub struct PlainResources {
2182 font_templates: FastHashMap<FontKey, PlainFontTemplate>,
2183 font_instances: Vec<BaseFontInstance>,
2184 image_templates: FastHashMap<ImageKey, PlainImageTemplate>,
2185}
2186
2187#[cfg(feature = "capture")]
2188#[derive(Serialize)]
2189pub struct PlainCacheRef<'a> {
2190 current_frame_id: FrameId,
2191 glyphs: &'a GlyphCache,
2192 glyph_dimensions: &'a GlyphDimensionsCache,
2193 images: &'a ImageCache,
2194 render_tasks: &'a RenderTaskCache,
2195 textures: &'a TextureCache,
2196 picture_textures: &'a PictureTextures,
2197}
2198
2199#[cfg(feature = "replay")]
2200#[derive(Deserialize)]
2201pub struct PlainCacheOwn {
2202 current_frame_id: FrameId,
2203 glyphs: GlyphCache,
2204 glyph_dimensions: GlyphDimensionsCache,
2205 images: ImageCache,
2206 render_tasks: RenderTaskCache,
2207 textures: TextureCache,
2208 picture_textures: PictureTextures,
2209}
2210
2211#[cfg(feature = "replay")]
2212const NATIVE_FONT: &'static [u8] = include_bytes!("../res/Proggy.ttf");
2213
2214fn to_image_dirty_rect(blob_dirty_rect: &BlobDirtyRect) -> ImageDirtyRect {
2216 match *blob_dirty_rect {
2217 DirtyRect::Partial(rect) => DirtyRect::Partial(rect.cast_unit()),
2218 DirtyRect::All => DirtyRect::All,
2219 }
2220}
2221
2222impl ResourceCache {
2223 #[cfg(feature = "capture")]
2224 pub fn save_capture(
2225 &mut self, root: &PathBuf
2226 ) -> (PlainResources, Vec<ExternalCaptureImage>) {
2227 use std::fs;
2228 use std::io::Write;
2229
2230 info!("saving resource cache");
2231 let res = &self.resources;
2232 let path_fonts = root.join("fonts");
2233 if !path_fonts.is_dir() {
2234 fs::create_dir(&path_fonts).unwrap();
2235 }
2236 let path_images = root.join("images");
2237 if !path_images.is_dir() {
2238 fs::create_dir(&path_images).unwrap();
2239 }
2240 let path_blobs = root.join("blobs");
2241 if !path_blobs.is_dir() {
2242 fs::create_dir(&path_blobs).unwrap();
2243 }
2244 let path_externals = root.join("externals");
2245 if !path_externals.is_dir() {
2246 fs::create_dir(&path_externals).unwrap();
2247 }
2248
2249 info!("\tfont templates");
2250 let mut font_paths = FastHashMap::default();
2251 for template in res.fonts.templates.lock().values() {
2252 let data: &[u8] = match *template {
2253 FontTemplate::Raw(ref arc, _) => arc,
2254 FontTemplate::Native(_) => continue,
2255 };
2256 let font_id = res.fonts.templates.len() + 1;
2257 let entry = match font_paths.entry(data.as_ptr()) {
2258 Entry::Occupied(_) => continue,
2259 Entry::Vacant(e) => e,
2260 };
2261 let file_name = format!("{}.raw", font_id);
2262 let short_path = format!("fonts/{}", file_name);
2263 fs::File::create(path_fonts.join(file_name))
2264 .expect(&format!("Unable to create {}", short_path))
2265 .write_all(data)
2266 .unwrap();
2267 entry.insert(short_path);
2268 }
2269
2270 info!("\timage templates");
2271 let mut image_paths = FastHashMap::default();
2272 let mut other_paths = FastHashMap::default();
2273 let mut num_blobs = 0;
2274 let mut external_images = Vec::new();
2275 for (&key, template) in res.image_templates.images.iter() {
2276 let desc = &template.descriptor;
2277 match template.data {
2278 CachedImageData::Raw(ref arc) => {
2279 let image_id = image_paths.len() + 1;
2280 let entry = match image_paths.entry(arc.as_ptr()) {
2281 Entry::Occupied(_) => continue,
2282 Entry::Vacant(e) => e,
2283 };
2284
2285 #[cfg(feature = "png")]
2286 CaptureConfig::save_png(
2287 root.join(format!("images/{}.png", image_id)),
2288 desc.size,
2289 desc.format,
2290 desc.stride,
2291 &arc,
2292 );
2293 let file_name = format!("{}.raw", image_id);
2294 let short_path = format!("images/{}", file_name);
2295 fs::File::create(path_images.join(file_name))
2296 .expect(&format!("Unable to create {}", short_path))
2297 .write_all(&*arc)
2298 .unwrap();
2299 entry.insert(short_path);
2300 }
2301 CachedImageData::Blob => {
2302 warn!("Tiled blob images aren't supported yet");
2303 let result = RasterizedBlobImage {
2304 rasterized_rect: desc.size.into(),
2305 data: Arc::new(vec![0; desc.compute_total_size() as usize])
2306 };
2307
2308 assert_eq!(result.rasterized_rect.size(), desc.size);
2309 assert_eq!(result.data.len(), desc.compute_total_size() as usize);
2310
2311 num_blobs += 1;
2312 #[cfg(feature = "png")]
2313 CaptureConfig::save_png(
2314 root.join(format!("blobs/{}.png", num_blobs)),
2315 desc.size,
2316 desc.format,
2317 desc.stride,
2318 &result.data,
2319 );
2320 let file_name = format!("{}.raw", num_blobs);
2321 let short_path = format!("blobs/{}", file_name);
2322 let full_path = path_blobs.clone().join(&file_name);
2323 fs::File::create(full_path)
2324 .expect(&format!("Unable to create {}", short_path))
2325 .write_all(&result.data)
2326 .unwrap();
2327 other_paths.insert(key, short_path);
2328 }
2329 CachedImageData::Snapshot => {
2330 let short_path = format!("snapshots/{}", external_images.len() + 1);
2331 other_paths.insert(key, short_path.clone());
2332 }
2333 CachedImageData::External(ref ext) => {
2334 let short_path = format!("externals/{}", external_images.len() + 1);
2335 other_paths.insert(key, short_path.clone());
2336 external_images.push(ExternalCaptureImage {
2337 short_path,
2338 descriptor: desc.clone(),
2339 external: ext.clone(),
2340 });
2341 }
2342 }
2343 }
2344
2345 let mut font_templates = FastHashMap::default();
2346 let mut font_remap = FastHashMap::default();
2347 for key in res.fonts.font_keys.keys() {
2349 let shared_key = res.fonts.font_keys.map_key(&key);
2350 let template = match res.fonts.templates.get_font(&shared_key) {
2351 Some(template) => template,
2352 None => {
2353 debug!("Failed serializing font template {:?}", key);
2354 continue;
2355 }
2356 };
2357 let plain_font = match template {
2358 FontTemplate::Raw(arc, index) => {
2359 PlainFontTemplate {
2360 data: font_paths[&arc.as_ptr()].clone(),
2361 index,
2362 }
2363 }
2364 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
2365 FontTemplate::Native(native) => {
2366 PlainFontTemplate {
2367 data: native.path.to_string_lossy().to_string(),
2368 index: native.index,
2369 }
2370 }
2371 #[cfg(any(target_os = "macos", target_os = "ios"))]
2372 FontTemplate::Native(native) => {
2373 PlainFontTemplate {
2374 data: native.name,
2375 index: 0,
2376 }
2377 }
2378 };
2379 font_templates.insert(key, plain_font);
2380 font_remap.insert(shared_key, key);
2382 }
2383 let mut font_instances = Vec::new();
2384 for instance_key in res.fonts.instance_keys.keys() {
2386 let shared_key = res.fonts.instance_keys.map_key(&instance_key);
2387 let instance = match res.fonts.instances.get_font_instance(shared_key) {
2388 Some(instance) => instance,
2389 None => {
2390 debug!("Failed serializing font instance {:?}", instance_key);
2391 continue;
2392 }
2393 };
2394 font_instances.push(BaseFontInstance {
2397 font_key: font_remap.get(&instance.font_key).cloned().unwrap_or(instance.font_key),
2398 instance_key,
2399 ..(*instance).clone()
2400 });
2401 }
2402 let resources = PlainResources {
2403 font_templates,
2404 font_instances,
2405 image_templates: res.image_templates.images
2406 .iter()
2407 .map(|(key, template)| {
2408 (*key, PlainImageTemplate {
2409 data: match template.data {
2410 CachedImageData::Raw(ref arc) => image_paths[&arc.as_ptr()].clone(),
2411 _ => other_paths[key].clone(),
2412 },
2413 descriptor: template.descriptor.clone(),
2414 tiling: template.tiling,
2415 generation: template.generation,
2416 })
2417 })
2418 .collect(),
2419 };
2420
2421 (resources, external_images)
2422 }
2423
2424 #[cfg(feature = "capture")]
2425 pub fn save_caches(&self, _root: &PathBuf) -> PlainCacheRef {
2426 PlainCacheRef {
2427 current_frame_id: self.current_frame_id,
2428 glyphs: &self.cached_glyphs,
2429 glyph_dimensions: &self.cached_glyph_dimensions,
2430 images: &self.cached_images,
2431 render_tasks: &self.cached_render_tasks,
2432 textures: &self.texture_cache,
2433 picture_textures: &self.picture_textures,
2434 }
2435 }
2436
2437 #[cfg(feature = "replay")]
2438 pub fn load_capture(
2439 &mut self,
2440 resources: PlainResources,
2441 caches: Option<PlainCacheOwn>,
2442 config: &CaptureConfig,
2443 ) -> Vec<PlainExternalImage> {
2444 use std::{fs, path::Path};
2445 use crate::texture_cache::TextureCacheConfig;
2446
2447 info!("loading resource cache");
2448 let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
2452
2453 self.clear(ClearCache::all());
2454 self.clear_images(|_| true);
2455
2456 match caches {
2457 Some(cached) => {
2458 self.current_frame_id = cached.current_frame_id;
2459 self.cached_glyphs = cached.glyphs;
2460 self.cached_glyph_dimensions = cached.glyph_dimensions;
2461 self.cached_images = cached.images;
2462 self.cached_render_tasks = cached.render_tasks;
2463 self.texture_cache = cached.textures;
2464 self.picture_textures = cached.picture_textures;
2465 }
2466 None => {
2467 self.current_frame_id = FrameId::INVALID;
2468 self.texture_cache = TextureCache::new(
2469 self.texture_cache.max_texture_size(),
2470 self.texture_cache.tiling_threshold(),
2471 self.texture_cache.color_formats(),
2472 self.texture_cache.swizzle_settings(),
2473 &TextureCacheConfig::DEFAULT,
2474 );
2475 self.picture_textures = PictureTextures::new(
2476 self.picture_textures.default_tile_size(),
2477 self.picture_textures.filter(),
2478 );
2479 }
2480 }
2481
2482 self.glyph_rasterizer.reset();
2483 let res = &mut self.resources;
2484 res.fonts.templates.clear();
2485 res.fonts.instances.clear();
2486 res.image_templates.images.clear();
2487
2488 info!("\tfont templates...");
2489 let root = config.resource_root();
2490 let native_font_replacement = Arc::new(NATIVE_FONT.to_vec());
2491 for (key, plain_template) in resources.font_templates {
2492 let arc = match raw_map.entry(plain_template.data) {
2493 Entry::Occupied(e) => {
2494 e.get().clone()
2495 }
2496 Entry::Vacant(e) => {
2497 let file_path = if Path::new(e.key()).is_absolute() {
2498 PathBuf::from(e.key())
2499 } else {
2500 root.join(e.key())
2501 };
2502 let arc = match fs::read(file_path) {
2503 Ok(buffer) => Arc::new(buffer),
2504 Err(err) => {
2505 error!("Unable to open font template {:?}: {:?}", e.key(), err);
2506 Arc::clone(&native_font_replacement)
2507 }
2508 };
2509 e.insert(arc).clone()
2510 }
2511 };
2512
2513 let template = FontTemplate::Raw(arc, plain_template.index);
2514 if let Some(shared_key) = res.fonts.font_keys.add_key(&key, &template) {
2516 self.glyph_rasterizer.add_font(shared_key, template.clone());
2517 res.fonts.templates.add_font(shared_key, template);
2518 }
2519 }
2520
2521 info!("\tfont instances...");
2522 for instance in resources.font_instances {
2523 let base = BaseFontInstance {
2525 font_key: res.fonts.font_keys.map_key(&instance.font_key),
2526 ..instance
2527 };
2528 if let Some(shared_instance) = res.fonts.instance_keys.add_key(base) {
2529 res.fonts.instances.add_font_instance(shared_instance);
2530 }
2531 }
2532
2533 info!("\timage templates...");
2534 let mut external_images = Vec::new();
2535 for (key, template) in resources.image_templates {
2536 let data = if template.data.starts_with("snapshots/") {
2537 CachedImageData::Snapshot
2540 } else {
2541 match config.deserialize_for_resource::<PlainExternalImage, _>(&template.data) {
2542 Some(plain) => {
2543 let ext_data = plain.external;
2544 external_images.push(plain);
2545 CachedImageData::External(ext_data)
2546 }
2547 None => {
2548 let arc = match raw_map.entry(template.data) {
2549 Entry::Occupied(e) => e.get().clone(),
2550 Entry::Vacant(e) => {
2551 match fs::read(root.join(e.key())) {
2552 Ok(buffer) => {
2553 e.insert(Arc::new(buffer)).clone()
2554 }
2555 Err(err) => {
2556 log::warn!("Unable to open {}: {err:?}", e.key());
2557 continue;
2558 }
2559 }
2560 }
2561 };
2562 CachedImageData::Raw(arc)
2563 }
2564 }
2565 };
2566
2567 res.image_templates.images.insert(key, ImageResource {
2568 data,
2569 descriptor: template.descriptor,
2570 tiling: template.tiling,
2571 visible_rect: template.descriptor.size.into(),
2572 adjustment: AdjustedImageSource::new(), generation: template.generation,
2574 });
2575 }
2576
2577 external_images
2578 }
2579
2580 #[cfg(feature = "capture")]
2581 pub fn save_capture_sequence(&mut self, config: &mut CaptureConfig) -> Vec<ExternalCaptureImage> {
2582 if self.capture_dirty {
2583 self.capture_dirty = false;
2584 config.prepare_resource();
2585 let (resources, deferred) = self.save_capture(&config.resource_root());
2586 config.serialize_for_resource(&resources, "plain-resources.ron");
2587 deferred
2588 } else {
2589 Vec::new()
2590 }
2591 }
2592}