Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use api::{AddFont, BlobImageResources, AsyncBlobImageRasterizer, ResourceUpdate};
6
use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest, RasterizedBlobImage};
7
use api::{ClearCache, DebugFlags, FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
8
use api::{ExternalImageData, ExternalImageType, BlobImageResult, BlobImageParams};
9
use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
10
use api::{DirtyRect, GlyphDimensions, IdNamespace};
11
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering, TileSize};
12
use api::{BlobImageData, BlobImageKey, MemoryReport, VoidPtrToSizeFn};
13
use api::units::*;
14
#[cfg(feature = "capture")]
15
use crate::capture::ExternalCaptureImage;
16
#[cfg(feature = "replay")]
17
use crate::capture::PlainExternalImage;
18
#[cfg(any(feature = "replay", feature = "png"))]
19
use crate::capture::CaptureConfig;
20
use crate::composite::{NativeSurfaceId, NativeSurfaceOperation, NativeTileId, NativeSurfaceOperationDetails};
21
use crate::device::TextureFilter;
22
use euclid::{point2, size2};
23
use crate::glyph_cache::GlyphCache;
24
use crate::glyph_cache::GlyphCacheEntry;
25
use crate::glyph_rasterizer::{GLYPH_FLASHING, BaseFontInstance, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
26
use crate::gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
27
use crate::gpu_types::UvRectKind;
28
use crate::image::{compute_tile_size, compute_tile_rect, compute_tile_range, for_each_tile_in_range};
29
use crate::image::compute_valid_tiles_if_bounds_change;
30
use crate::internal_types::{FastHashMap, FastHashSet, TextureSource, ResourceUpdateList};
31
use crate::profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
32
use crate::render_backend::{FrameId, FrameStamp};
33
use crate::render_task_graph::{RenderTaskGraph, RenderTaskId};
34
use crate::render_task_cache::{RenderTaskCache, RenderTaskCacheKey};
35
use crate::render_task_cache::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle};
36
use smallvec::SmallVec;
37
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
38
use std::collections::hash_map::{Iter, IterMut};
39
use std::collections::VecDeque;
40
use std::{cmp, mem};
41
use std::fmt::Debug;
42
use std::hash::Hash;
43
use std::os::raw::c_void;
44
#[cfg(any(feature = "capture", feature = "replay"))]
45
use std::path::PathBuf;
46
use std::sync::{Arc, RwLock};
47
use std::sync::atomic::{AtomicUsize, Ordering};
48
use std::time::SystemTime;
49
use std::u32;
50
use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction};
51
use crate::util::drain_filter;
52
53
const DEFAULT_TILE_SIZE: TileSize = 512;
54
55
// Counter for generating unique native surface ids
56
static NEXT_NATIVE_SURFACE_ID: AtomicUsize = AtomicUsize::new(0);
57
58
#[cfg_attr(feature = "capture", derive(Serialize))]
59
#[cfg_attr(feature = "replay", derive(Deserialize))]
60
pub struct GlyphFetchResult {
61
pub index_in_text_run: i32,
62
pub uv_rect_address: GpuCacheAddress,
63
}
64
65
// These coordinates are always in texels.
66
// They are converted to normalized ST
67
// values in the vertex shader. The reason
68
// for this is that the texture may change
69
// dimensions (e.g. the pages in a texture
70
// atlas can grow). When this happens, by
71
// storing the coordinates as texel values
72
// we don't need to go through and update
73
// various CPU-side structures.
74
#[derive(Debug, Clone)]
75
#[cfg_attr(feature = "capture", derive(Serialize))]
76
#[cfg_attr(feature = "replay", derive(Deserialize))]
77
pub struct CacheItem {
78
pub texture_id: TextureSource,
79
pub uv_rect_handle: GpuCacheHandle,
80
pub uv_rect: DeviceIntRect,
81
pub texture_layer: i32,
82
}
83
84
impl CacheItem {
85
pub fn invalid() -> Self {
86
CacheItem {
87
texture_id: TextureSource::Invalid,
88
uv_rect_handle: GpuCacheHandle::new(),
89
uv_rect: DeviceIntRect::zero(),
90
texture_layer: 0,
91
}
92
}
93
}
94
95
/// Represents the backing store of an image in the cache.
96
/// This storage can take several forms.
97
#[derive(Clone, Debug)]
98
pub enum CachedImageData {
99
/// A simple series of bytes, provided by the embedding and owned by WebRender.
100
/// The format is stored out-of-band, currently in ImageDescriptor.
101
Raw(Arc<Vec<u8>>),
102
/// An series of commands that can be rasterized into an image via an
103
/// embedding-provided callback.
104
///
105
/// The commands are stored elsewhere and this variant is used as a placeholder.
106
Blob,
107
/// An image owned by the embedding, and referenced by WebRender. This may
108
/// take the form of a texture or a heap-allocated buffer.
109
External(ExternalImageData),
110
}
111
112
impl From<ImageData> for CachedImageData {
113
fn from(img_data: ImageData) -> Self {
114
match img_data {
115
ImageData::Raw(data) => CachedImageData::Raw(data),
116
ImageData::External(data) => CachedImageData::External(data),
117
}
118
}
119
}
120
121
impl CachedImageData {
122
/// Returns true if this represents a blob.
123
#[inline]
124
pub fn is_blob(&self) -> bool {
125
match *self {
126
CachedImageData::Blob => true,
127
_ => false,
128
}
129
}
130
131
/// Returns true if this variant of CachedImageData should go through the texture
132
/// cache.
133
#[inline]
134
pub fn uses_texture_cache(&self) -> bool {
135
match *self {
136
CachedImageData::External(ref ext_data) => match ext_data.image_type {
137
ExternalImageType::TextureHandle(_) => false,
138
ExternalImageType::Buffer => true,
139
},
140
CachedImageData::Blob => true,
141
CachedImageData::Raw(_) => true,
142
}
143
}
144
}
145
146
#[derive(Debug)]
147
#[cfg_attr(feature = "capture", derive(Serialize))]
148
#[cfg_attr(feature = "replay", derive(Deserialize))]
149
pub struct ImageProperties {
150
pub descriptor: ImageDescriptor,
151
pub external_image: Option<ExternalImageData>,
152
pub tiling: Option<TileSize>,
153
// Potentially a subset of the image's total rectangle. This rectangle is what
154
// we map to the (layout space) display item bounds.
155
pub visible_rect: DeviceIntRect,
156
}
157
158
#[derive(Debug, Copy, Clone, PartialEq)]
159
enum State {
160
Idle,
161
AddResources,
162
QueryResources,
163
}
164
165
/// Post scene building state.
166
enum RasterizedBlob {
167
Tiled(FastHashMap<TileOffset, RasterizedBlobImage>),
168
NonTiled(Vec<RasterizedBlobImage>),
169
}
170
171
/// Pre scene building state.
172
/// We use this to generate the async blob rendering requests.
173
struct BlobImageTemplate {
174
descriptor: ImageDescriptor,
175
tiling: Option<TileSize>,
176
dirty_rect: BlobDirtyRect,
177
/// See ImageResource::visible_rect.
178
visible_rect: DeviceIntRect,
179
// If the active rect of the blob changes, this represents the
180
// range of tiles that remain valid. This must be taken into
181
// account in addition to the valid rect when submitting blob
182
// rasterization requests.
183
// `None` means the bounds have not changed (tiles are still valid).
184
// `Some(TileRange::zero())` means all of the tiles are invalid.
185
valid_tiles_after_bounds_change: Option<TileRange>,
186
}
187
188
#[cfg_attr(feature = "capture", derive(Serialize))]
189
#[cfg_attr(feature = "replay", derive(Deserialize))]
190
#[derive(Debug, Copy, Clone, PartialEq)]
191
pub struct ImageGeneration(pub u32);
192
193
impl ImageGeneration {
194
pub const INVALID: ImageGeneration = ImageGeneration(u32::MAX);
195
}
196
197
struct ImageResource {
198
data: CachedImageData,
199
descriptor: ImageDescriptor,
200
tiling: Option<TileSize>,
201
/// This is used to express images that are virtually very large
202
/// but with only a visible sub-set that is valid at a given time.
203
visible_rect: DeviceIntRect,
204
generation: ImageGeneration,
205
}
206
207
#[derive(Clone, Debug)]
208
pub struct ImageTiling {
209
pub image_size: DeviceIntSize,
210
pub tile_size: TileSize,
211
}
212
213
#[derive(Default)]
214
struct ImageTemplates {
215
images: FastHashMap<ImageKey, ImageResource>,
216
}
217
218
impl ImageTemplates {
219
fn insert(&mut self, key: ImageKey, resource: ImageResource) {
220
self.images.insert(key, resource);
221
}
222
223
fn remove(&mut self, key: ImageKey) -> Option<ImageResource> {
224
self.images.remove(&key)
225
}
226
227
fn get(&self, key: ImageKey) -> Option<&ImageResource> {
228
self.images.get(&key)
229
}
230
231
fn get_mut(&mut self, key: ImageKey) -> Option<&mut ImageResource> {
232
self.images.get_mut(&key)
233
}
234
}
235
236
#[cfg_attr(feature = "capture", derive(Serialize))]
237
#[cfg_attr(feature = "replay", derive(Deserialize))]
238
struct CachedImageInfo {
239
texture_cache_handle: TextureCacheHandle,
240
dirty_rect: ImageDirtyRect,
241
manual_eviction: bool,
242
}
243
244
impl CachedImageInfo {
245
fn mark_unused(&mut self, texture_cache: &mut TextureCache) {
246
texture_cache.mark_unused(&self.texture_cache_handle);
247
self.manual_eviction = false;
248
}
249
}
250
251
#[cfg(debug_assertions)]
252
impl Drop for CachedImageInfo {
253
fn drop(&mut self) {
254
debug_assert!(!self.manual_eviction, "Manual eviction requires cleanup");
255
}
256
}
257
258
#[cfg_attr(feature = "capture", derive(Serialize))]
259
#[cfg_attr(feature = "replay", derive(Deserialize))]
260
pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
261
resources: FastHashMap<K, V>,
262
pub user_data: U,
263
}
264
265
impl<K, V, U> ResourceClassCache<K, V, U>
266
where
267
K: Clone + Hash + Eq + Debug,
268
U: Default,
269
{
270
pub fn new() -> Self {
271
ResourceClassCache {
272
resources: FastHashMap::default(),
273
user_data: Default::default(),
274
}
275
}
276
277
pub fn get(&self, key: &K) -> &V {
278
self.resources.get(key)
279
.expect("Didn't find a cached resource with that ID!")
280
}
281
282
pub fn try_get(&self, key: &K) -> Option<&V> {
283
self.resources.get(key)
284
}
285
286
pub fn insert(&mut self, key: K, value: V) {
287
self.resources.insert(key, value);
288
}
289
290
pub fn remove(&mut self, key: &K) -> Option<V> {
291
self.resources.remove(key)
292
}
293
294
pub fn get_mut(&mut self, key: &K) -> &mut V {
295
self.resources.get_mut(key)
296
.expect("Didn't find a cached resource with that ID!")
297
}
298
299
pub fn try_get_mut(&mut self, key: &K) -> Option<&mut V> {
300
self.resources.get_mut(key)
301
}
302
303
pub fn entry(&mut self, key: K) -> Entry<K, V> {
304
self.resources.entry(key)
305
}
306
307
pub fn iter(&self) -> Iter<K, V> {
308
self.resources.iter()
309
}
310
311
pub fn iter_mut(&mut self) -> IterMut<K, V> {
312
self.resources.iter_mut()
313
}
314
315
pub fn is_empty(&mut self) -> bool {
316
self.resources.is_empty()
317
}
318
319
pub fn clear(&mut self) {
320
self.resources.clear();
321
}
322
323
pub fn retain<F>(&mut self, f: F)
324
where
325
F: FnMut(&K, &mut V) -> bool,
326
{
327
self.resources.retain(f);
328
}
329
}
330
331
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
332
#[cfg_attr(feature = "capture", derive(Serialize))]
333
#[cfg_attr(feature = "replay", derive(Deserialize))]
334
struct CachedImageKey {
335
pub rendering: ImageRendering,
336
pub tile: Option<TileOffset>,
337
}
338
339
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
340
#[cfg_attr(feature = "capture", derive(Serialize))]
341
#[cfg_attr(feature = "replay", derive(Deserialize))]
342
pub struct ImageRequest {
343
pub key: ImageKey,
344
pub rendering: ImageRendering,
345
pub tile: Option<TileOffset>,
346
}
347
348
impl ImageRequest {
349
pub fn with_tile(&self, offset: TileOffset) -> Self {
350
ImageRequest {
351
key: self.key,
352
rendering: self.rendering,
353
tile: Some(offset),
354
}
355
}
356
357
pub fn is_untiled_auto(&self) -> bool {
358
self.tile.is_none() && self.rendering == ImageRendering::Auto
359
}
360
}
361
362
impl Into<BlobImageRequest> for ImageRequest {
363
fn into(self) -> BlobImageRequest {
364
BlobImageRequest {
365
key: BlobImageKey(self.key),
366
tile: self.tile,
367
}
368
}
369
}
370
371
impl Into<CachedImageKey> for ImageRequest {
372
fn into(self) -> CachedImageKey {
373
CachedImageKey {
374
rendering: self.rendering,
375
tile: self.tile,
376
}
377
}
378
}
379
380
#[derive(Debug)]
381
#[cfg_attr(feature = "capture", derive(Clone, Serialize))]
382
#[cfg_attr(feature = "replay", derive(Deserialize))]
383
pub enum ImageCacheError {
384
OverLimitSize,
385
}
386
387
#[cfg_attr(feature = "capture", derive(Serialize))]
388
#[cfg_attr(feature = "replay", derive(Deserialize))]
389
enum ImageResult {
390
UntiledAuto(CachedImageInfo),
391
Multi(ResourceClassCache<CachedImageKey, CachedImageInfo, ()>),
392
Err(ImageCacheError),
393
}
394
395
impl ImageResult {
396
/// Releases any texture cache entries held alive by this ImageResult.
397
fn drop_from_cache(&mut self, texture_cache: &mut TextureCache) {
398
match *self {
399
ImageResult::UntiledAuto(ref mut entry) => {
400
entry.mark_unused(texture_cache);
401
},
402
ImageResult::Multi(ref mut entries) => {
403
for entry in entries.resources.values_mut() {
404
entry.mark_unused(texture_cache);
405
}
406
},
407
ImageResult::Err(_) => {},
408
}
409
}
410
}
411
412
type ImageCache = ResourceClassCache<ImageKey, ImageResult, ()>;
413
pub type FontInstanceMap = Arc<RwLock<FastHashMap<FontInstanceKey, Arc<BaseFontInstance>>>>;
414
415
#[derive(Default)]
416
struct Resources {
417
font_templates: FastHashMap<FontKey, FontTemplate>,
418
font_instances: FontInstanceMap,
419
image_templates: ImageTemplates,
420
}
421
422
impl BlobImageResources for Resources {
423
fn get_font_data(&self, key: FontKey) -> &FontTemplate {
424
self.font_templates.get(&key).unwrap()
425
}
426
fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
427
match self.font_instances.read().unwrap().get(&key) {
428
Some(instance) => Some(FontInstanceData {
429
font_key: instance.font_key,
430
size: instance.size,
431
options: Some(FontInstanceOptions {
432
render_mode: instance.render_mode,
433
flags: instance.flags,
434
bg_color: instance.bg_color,
435
synthetic_italics: instance.synthetic_italics,
436
}),
437
platform_options: instance.platform_options,
438
variations: instance.variations.clone(),
439
}),
440
None => None,
441
}
442
}
443
}
444
445
// We only use this to report glyph dimensions to the user of the API, so using
446
// the font instance key should be enough. If we start using it to cache dimensions
447
// for internal font instances we should change the hash key accordingly.
448
pub type GlyphDimensionsCache = FastHashMap<(FontInstanceKey, GlyphIndex), Option<GlyphDimensions>>;
449
450
#[derive(Clone, Copy, Debug, PartialEq)]
451
pub struct BlobImageRasterizerEpoch(usize);
452
453
/// Stores parameters for clearing blob image tiles.
454
///
455
/// TODO(nical) this can be removed.
456
#[derive(Clone, Copy, Debug)]
457
pub struct BlobImageClearParams {
458
pub key: BlobImageKey,
459
/// Originally requested tile range to rasterize.
460
pub original_tile_range: TileRange,
461
/// Actual tile range that is requested to rasterize by
462
/// AsyncBlobImageRasterizer.
463
pub actual_tile_range: TileRange,
464
}
465
466
/// Information attached to AsyncBlobImageRasterizer.
467
#[derive(Clone, Debug)]
468
pub struct AsyncBlobImageInfo {
469
pub epoch: BlobImageRasterizerEpoch,
470
pub clear_requests: Vec<BlobImageClearParams>,
471
}
472
473
/// High-level container for resources managed by the `RenderBackend`.
474
///
475
/// This includes a variety of things, including images, fonts, and glyphs,
476
/// which may be stored as memory buffers, GPU textures, or handles to resources
477
/// managed by the OS or other parts of WebRender.
478
pub struct ResourceCache {
479
cached_glyphs: GlyphCache,
480
cached_images: ImageCache,
481
cached_render_tasks: RenderTaskCache,
482
483
resources: Resources,
484
state: State,
485
current_frame_id: FrameId,
486
487
pub texture_cache: TextureCache,
488
489
/// TODO(gw): We should expire (parts of) this cache semi-regularly!
490
cached_glyph_dimensions: GlyphDimensionsCache,
491
glyph_rasterizer: GlyphRasterizer,
492
493
/// The set of images that aren't present or valid in the texture cache,
494
/// and need to be rasterized and/or uploaded this frame. This includes
495
/// both blobs and regular images.
496
pending_image_requests: FastHashSet<ImageRequest>,
497
498
blob_image_handler: Option<Box<dyn BlobImageHandler>>,
499
rasterized_blob_images: FastHashMap<BlobImageKey, RasterizedBlob>,
500
blob_image_templates: FastHashMap<BlobImageKey, BlobImageTemplate>,
501
502
/// If while building a frame we encounter blobs that we didn't already
503
/// rasterize, add them to this list and rasterize them synchronously.
504
missing_blob_images: Vec<BlobImageParams>,
505
/// The rasterizer associated with the current scene.
506
blob_image_rasterizer: Option<Box<dyn AsyncBlobImageRasterizer>>,
507
/// An epoch of the stored blob image rasterizer, used to skip the ones
508
/// coming from low-priority scene builds if the current one is newer.
509
/// This is to be removed when we get rid of the whole "missed" blob
510
/// images concept.
511
/// The produced one gets bumped whenever we produce a rasteriezer,
512
/// which then travels through the scene building and eventually gets
513
/// consumed back by us, bumping the consumed epoch.
514
blob_image_rasterizer_produced_epoch: BlobImageRasterizerEpoch,
515
blob_image_rasterizer_consumed_epoch: BlobImageRasterizerEpoch,
516
/// A log of the last three frames worth of deleted image keys kept
517
/// for debugging purposes.
518
deleted_blob_keys: VecDeque<Vec<BlobImageKey>>,
519
520
/// A list of queued compositor surface updates to apply next frame.
521
pending_native_surface_updates: Vec<NativeSurfaceOperation>,
522
}
523
524
impl ResourceCache {
525
pub fn new(
526
texture_cache: TextureCache,
527
glyph_rasterizer: GlyphRasterizer,
528
cached_glyphs: GlyphCache,
529
blob_image_handler: Option<Box<dyn BlobImageHandler>>,
530
) -> Self {
531
ResourceCache {
532
cached_glyphs,
533
cached_images: ResourceClassCache::new(),
534
cached_render_tasks: RenderTaskCache::new(),
535
resources: Resources::default(),
536
cached_glyph_dimensions: FastHashMap::default(),
537
texture_cache,
538
state: State::Idle,
539
current_frame_id: FrameId::INVALID,
540
pending_image_requests: FastHashSet::default(),
541
glyph_rasterizer,
542
blob_image_handler,
543
rasterized_blob_images: FastHashMap::default(),
544
blob_image_templates: FastHashMap::default(),
545
missing_blob_images: Vec::new(),
546
blob_image_rasterizer: None,
547
blob_image_rasterizer_produced_epoch: BlobImageRasterizerEpoch(0),
548
blob_image_rasterizer_consumed_epoch: BlobImageRasterizerEpoch(0),
549
// We want to keep three frames worth of delete blob keys
550
deleted_blob_keys: vec![Vec::new(), Vec::new(), Vec::new()].into(),
551
pending_native_surface_updates: Vec::new(),
552
}
553
}
554
555
pub fn max_texture_size(&self) -> i32 {
556
self.texture_cache.max_texture_size()
557
}
558
559
pub fn enable_multithreading(&mut self, enable: bool) {
560
self.glyph_rasterizer.enable_multithreading(enable);
561
if let Some(ref mut handler) = self.blob_image_handler {
562
handler.enable_multithreading(enable);
563
}
564
}
565
566
fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool {
567
let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
568
match *data {
569
CachedImageData::Raw(_) | CachedImageData::Blob => size_check,
570
CachedImageData::External(info) => {
571
// External handles already represent existing textures so it does
572
// not make sense to tile them into smaller ones.
573
info.image_type == ExternalImageType::Buffer && size_check
574
}
575
}
576
}
577
578
// Request the texture cache item for a cacheable render
579
// task. If the item is already cached, the texture cache
580
// handle will be returned. Otherwise, the user supplied
581
// closure will be invoked to generate the render task
582
// chain that is required to draw this task.
583
pub fn request_render_task<F>(
584
&mut self,
585
key: RenderTaskCacheKey,
586
gpu_cache: &mut GpuCache,
587
render_tasks: &mut RenderTaskGraph,
588
user_data: Option<[f32; 3]>,
589
is_opaque: bool,
590
f: F,
591
) -> RenderTaskCacheEntryHandle
592
where
593
F: FnOnce(&mut RenderTaskGraph) -> RenderTaskId,
594
{
595
self.cached_render_tasks.request_render_task(
596
key,
597
&mut self.texture_cache,
598
gpu_cache,
599
render_tasks,
600
user_data,
601
is_opaque,
602
|render_graph| Ok(f(render_graph))
603
).expect("Failed to request a render task from the resource cache!")
604
}
605
606
pub fn post_scene_building_update(
607
&mut self,
608
updates: Vec<ResourceUpdate>,
609
profile_counters: &mut ResourceProfileCounters,
610
) {
611
// TODO, there is potential for optimization here, by processing updates in
612
// bulk rather than one by one (for example by sorting allocations by size or
613
// in a way that reduces fragmentation in the atlas).
614
615
for update in updates {
616
match update {
617
ResourceUpdate::AddImage(img) => {
618
if let ImageData::Raw(ref bytes) = img.data {
619
profile_counters.image_templates.inc(bytes.len());
620
}
621
self.add_image_template(
622
img.key,
623
img.descriptor,
624
img.data.into(),
625
&img.descriptor.size.into(),
626
img.tiling,
627
);
628
}
629
ResourceUpdate::UpdateImage(img) => {
630
self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
631
}
632
ResourceUpdate::AddBlobImage(img) => {
633
self.add_image_template(
634
img.key.as_image(),
635
img.descriptor,
636
CachedImageData::Blob,
637
&img.visible_rect,
638
img.tiling,
639
);
640
}
641
ResourceUpdate::UpdateBlobImage(img) => {
642
self.update_image_template(
643
img.key.as_image(),
644
img.descriptor,
645
CachedImageData::Blob,
646
&to_image_dirty_rect(
647
&img.dirty_rect
648
),
649
);
650
self.discard_tiles_outside_visible_area(img.key, &img.visible_rect); // TODO: remove?
651
self.set_image_visible_rect(img.key.as_image(), &img.visible_rect);
652
}
653
ResourceUpdate::DeleteImage(img) => {
654
self.delete_image_template(img);
655
}
656
ResourceUpdate::DeleteFont(font) => {
657
self.delete_font_template(font);
658
}
659
ResourceUpdate::DeleteFontInstance(font) => {
660
self.delete_font_instance(font);
661
}
662
ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
663
self.discard_tiles_outside_visible_area(key, &area);
664
self.set_image_visible_rect(key.as_image(), &area);
665
}
666
ResourceUpdate::AddFont(_) |
667
ResourceUpdate::AddFontInstance(_) => {
668
// Handled in update_resources_pre_scene_building
669
}
670
}
671
}
672
}
673
674
pub fn pre_scene_building_update(
675
&mut self,
676
updates: &mut Vec<ResourceUpdate>,
677
profile_counters: &mut ResourceProfileCounters,
678
) {
679
for update in updates.iter() {
680
match *update {
681
ResourceUpdate::AddBlobImage(ref img) => {
682
self.add_blob_image(
683
img.key,
684
&img.descriptor,
685
img.tiling,
686
Arc::clone(&img.data),
687
&img.visible_rect,
688
);
689
}
690
ResourceUpdate::UpdateBlobImage(ref img) => {
691
debug_assert_eq!(img.visible_rect.size, img.descriptor.size);
692
self.update_blob_image(
693
img.key,
694
Some(&img.descriptor),
695
Some(&img.dirty_rect),
696
Some(Arc::clone(&img.data)),
697
&img.visible_rect,
698
);
699
}
700
ResourceUpdate::SetBlobImageVisibleArea(ref key, ref area) => {
701
self.update_blob_image(*key, None, None, None, area);
702
}
703
_ => {}
704
}
705
}
706
707
drain_filter(
708
updates,
709
|update| match *update {
710
ResourceUpdate::AddFont(_) |
711
ResourceUpdate::AddFontInstance(_) => true,
712
_ => false,
713
},
714
// Updates that were moved out of the array:
715
|update: ResourceUpdate| match update {
716
ResourceUpdate::AddFont(font) => {
717
match font {
718
AddFont::Raw(id, bytes, index) => {
719
profile_counters.font_templates.inc(bytes.len());
720
self.add_font_template(id, FontTemplate::Raw(Arc::new(bytes), index));
721
}
722
AddFont::Native(id, native_font_handle) => {
723
self.add_font_template(id, FontTemplate::Native(native_font_handle));
724
}
725
}
726
}
727
ResourceUpdate::AddFontInstance(instance) => {
728
self.add_font_instance(
729
instance.key,
730
instance.font_key,
731
instance.glyph_size,
732
instance.options,
733
instance.platform_options,
734
instance.variations,
735
);
736
}
737
_ => { unreachable!(); }
738
}
739
);
740
}
741
742
pub fn set_blob_rasterizer(
743
&mut self, rasterizer: Box<dyn AsyncBlobImageRasterizer>,
744
supp: AsyncBlobImageInfo,
745
) {
746
if self.blob_image_rasterizer_consumed_epoch.0 < supp.epoch.0 {
747
self.blob_image_rasterizer = Some(rasterizer);
748
self.blob_image_rasterizer_consumed_epoch = supp.epoch;
749
}
750
}
751
752
pub fn add_rasterized_blob_images(
753
&mut self,
754
images: Vec<(BlobImageRequest, BlobImageResult)>,
755
texture_cache_profile: &mut TextureCacheProfileCounters,
756
) {
757
for (request, result) in images {
758
let data = match result {
759
Ok(data) => data,
760
Err(..) => {
761
warn!("Failed to rasterize a blob image");
762
continue;
763
}
764
};
765
766
texture_cache_profile.rasterized_blob_pixels.inc(data.rasterized_rect.area() as usize);
767
768
// First make sure we have an entry for this key (using a placeholder
769
// if need be).
770
let image = self.rasterized_blob_images.entry(request.key).or_insert_with(
771
|| { RasterizedBlob::Tiled(FastHashMap::default()) }
772
);
773
774
if let Some(tile) = request.tile {
775
if let RasterizedBlob::NonTiled(..) = *image {
776
*image = RasterizedBlob::Tiled(FastHashMap::default());
777
}
778
779
if let RasterizedBlob::Tiled(ref mut tiles) = *image {
780
tiles.insert(tile, data);
781
}
782
783
match self.cached_images.try_get_mut(&request.key.as_image()) {
784
Some(&mut ImageResult::Multi(ref mut entries)) => {
785
let cached_key = CachedImageKey {
786
rendering: ImageRendering::Auto, // TODO(nical)
787
tile: Some(tile),
788
};
789
if let Some(entry) = entries.try_get_mut(&cached_key) {
790
entry.dirty_rect = DirtyRect::All;
791
}
792
}
793
_ => {}
794
}
795
796
} else if let RasterizedBlob::NonTiled(ref mut queue) = *image {
797
// If our new rasterized rect overwrites items in the queue, discard them.
798
queue.retain(|img| {
799
!data.rasterized_rect.contains_rect(&img.rasterized_rect)
800
});
801
802
queue.push(data);
803
} else {
804
*image = RasterizedBlob::NonTiled(vec![data]);
805
}
806
}
807
}
808
809
pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
810
// Push the new font to the font renderer, and also store
811
// it locally for glyph metric requests.
812
self.glyph_rasterizer.add_font(font_key, template.clone());
813
self.resources.font_templates.insert(font_key, template);
814
}
815
816
pub fn delete_font_template(&mut self, font_key: FontKey) {
817
self.glyph_rasterizer.delete_font(font_key);
818
self.resources.font_templates.remove(&font_key);
819
self.cached_glyphs
820
.clear_fonts(&mut self.texture_cache, |font| font.font_key == font_key);
821
if let Some(ref mut r) = self.blob_image_handler {
822
r.delete_font(font_key);
823
}
824
}
825
826
pub fn add_font_instance(
827
&mut self,
828
instance_key: FontInstanceKey,
829
font_key: FontKey,
830
size: Au,
831
options: Option<FontInstanceOptions>,
832
platform_options: Option<FontInstancePlatformOptions>,
833
variations: Vec<FontVariation>,
834
) {
835
let FontInstanceOptions {
836
render_mode,
837
flags,
838
bg_color,
839
synthetic_italics,
840
..
841
} = options.unwrap_or_default();
842
let instance = Arc::new(BaseFontInstance {
843
instance_key,
844
font_key,
845
size,
846
bg_color,
847
render_mode,
848
flags,
849
synthetic_italics,
850
platform_options,
851
variations,
852
});
853
self.resources.font_instances
854
.write()
855
.unwrap()
856
.insert(instance_key, instance);
857
}
858
859
pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
860
self.resources.font_instances
861
.write()
862
.unwrap()
863
.remove(&instance_key);
864
if let Some(ref mut r) = self.blob_image_handler {
865
r.delete_font_instance(instance_key);
866
}
867
}
868
869
pub fn get_font_instances(&self) -> FontInstanceMap {
870
self.resources.font_instances.clone()
871
}
872
873
pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
874
let instance_map = self.resources.font_instances.read().unwrap();
875
instance_map.get(&instance_key).map(|instance| { Arc::clone(instance) })
876
}
877
878
pub fn add_image_template(
879
&mut self,
880
image_key: ImageKey,
881
descriptor: ImageDescriptor,
882
data: CachedImageData,
883
visible_rect: &DeviceIntRect,
884
mut tiling: Option<TileSize>,
885
) {
886
if tiling.is_none() && Self::should_tile(self.max_texture_size(), &descriptor, &data) {
887
// We aren't going to be able to upload a texture this big, so tile it, even
888
// if tiling was not requested.
889
tiling = Some(DEFAULT_TILE_SIZE);
890
}
891
892
let resource = ImageResource {
893
descriptor,
894
data,
895
tiling,
896
visible_rect: *visible_rect,
897
generation: ImageGeneration(0),
898
};
899
900
self.resources.image_templates.insert(image_key, resource);
901
}
902
903
pub fn update_image_template(
904
&mut self,
905
image_key: ImageKey,
906
descriptor: ImageDescriptor,
907
data: CachedImageData,
908
dirty_rect: &ImageDirtyRect,
909
) {
910
let max_texture_size = self.max_texture_size();
911
let image = match self.resources.image_templates.get_mut(image_key) {
912
Some(res) => res,
913
None => panic!("Attempt to update non-existent image"),
914
};
915
916
let mut tiling = image.tiling;
917
if tiling.is_none() && Self::should_tile(max_texture_size, &descriptor, &data) {
918
tiling = Some(DEFAULT_TILE_SIZE);
919
}
920
921
// Each cache entry stores its own copy of the image's dirty rect. This allows them to be
922
// updated independently.
923
match self.cached_images.try_get_mut(&image_key) {
924
Some(&mut ImageResult::UntiledAuto(ref mut entry)) => {
925
entry.dirty_rect = entry.dirty_rect.union(dirty_rect);
926
}
927
Some(&mut ImageResult::Multi(ref mut entries)) => {
928
for (key, entry) in entries.iter_mut() {
929
// We want the dirty rect relative to the tile and not the whole image.
930
let local_dirty_rect = match (tiling, key.tile) {
931
(Some(tile_size), Some(tile)) => {
932
dirty_rect.map(|mut rect|{
933
let tile_offset = DeviceIntPoint::new(
934
tile.x as i32,
935
tile.y as i32,
936
) * tile_size as i32;
937
rect.origin -= tile_offset.to_vector();
938
939
let tile_rect = compute_tile_size(
940
&descriptor.size.into(),
941
tile_size,
942
tile,
943
).into();
944
945
rect.intersection(&tile_rect).unwrap_or_else(DeviceIntRect::zero)
946
})
947
}
948
(None, Some(..)) => DirtyRect::All,
949
_ => *dirty_rect,
950
};
951
entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
952
}
953
}
954
_ => {}
955
}
956
957
if image.descriptor.format != descriptor.format {
958
// could be a stronger warning/error?
959
trace!("Format change {:?} -> {:?}", image.descriptor.format, descriptor.format);
960
}
961
*image = ImageResource {
962
descriptor,
963
data,
964
tiling,
965
visible_rect: descriptor.size.into(),
966
generation: ImageGeneration(image.generation.0 + 1),
967
};
968
}
969
970
// Happens before scene building.
971
pub fn add_blob_image(
972
&mut self,
973
key: BlobImageKey,
974
descriptor: &ImageDescriptor,
975
mut tiling: Option<TileSize>,
976
data: Arc<BlobImageData>,
977
visible_rect: &DeviceIntRect,
978
) {
979
let max_texture_size = self.max_texture_size();
980
tiling = get_blob_tiling(tiling, visible_rect.size, max_texture_size);
981
982
self.blob_image_handler.as_mut().unwrap().add(key, data, visible_rect, tiling);
983
984
self.blob_image_templates.insert(
985
key,
986
BlobImageTemplate {
987
descriptor: *descriptor,
988
tiling,
989
dirty_rect: DirtyRect::All,
990
valid_tiles_after_bounds_change: None,
991
visible_rect: *visible_rect,
992
},
993
);
994
}
995
996
// Happens before scene building.
997
pub fn update_blob_image(
998
&mut self,
999
key: BlobImageKey,
1000
descriptor: Option<&ImageDescriptor>,
1001
dirty_rect: Option<&BlobDirtyRect>,
1002
data: Option<Arc<BlobImageData>>,
1003
visible_rect: &DeviceIntRect,
1004
) {
1005
if let Some(data) = data {
1006
let dirty_rect = dirty_rect.unwrap();
1007
self.blob_image_handler.as_mut().unwrap().update(key, data, visible_rect, dirty_rect);
1008
}
1009
1010
let max_texture_size = self.max_texture_size();
1011
1012
let image = self.blob_image_templates
1013
.get_mut(&key)
1014
.expect("Attempt to update non-existent blob image");
1015
1016
let mut valid_tiles_after_bounds_change = None;
1017
1018
if let Some(tile_size) = image.tiling {
1019
valid_tiles_after_bounds_change = compute_valid_tiles_if_bounds_change(
1020
&image.visible_rect,
1021
visible_rect,
1022
tile_size,
1023
);
1024
}
1025
1026
match (image.valid_tiles_after_bounds_change, valid_tiles_after_bounds_change) {
1027
(Some(old), Some(ref mut new)) => {
1028
*new = new.intersection(&old).unwrap_or_else(TileRange::zero);
1029
}
1030
(Some(old), None) => {
1031
valid_tiles_after_bounds_change = Some(old);
1032
}
1033
_ => {}
1034
}
1035
1036
let blob_size = visible_rect.size;
1037
1038
if let Some(descriptor) = descriptor {
1039
image.descriptor = *descriptor;
1040
} else {
1041
// make sure the descriptor size matches the visible rect.
1042
// This might not be necessary but let's stay on the safe side.
1043
image.descriptor.size = blob_size;
1044
}
1045
1046
if let Some(dirty_rect) = dirty_rect {
1047
image.dirty_rect = image.dirty_rect.union(dirty_rect);
1048
}
1049
1050
image.tiling = get_blob_tiling(image.tiling, blob_size, max_texture_size);
1051
image.valid_tiles_after_bounds_change = valid_tiles_after_bounds_change;
1052
image.visible_rect = *visible_rect;
1053
}
1054
1055
pub fn delete_image_template(&mut self, image_key: ImageKey) {
1056
// Remove the template.
1057
let value = self.resources.image_templates.remove(image_key);
1058
1059
// Release the corresponding texture cache entry, if any.
1060
if let Some(mut cached) = self.cached_images.remove(&image_key) {
1061
cached.drop_from_cache(&mut self.texture_cache);
1062
}
1063
1064
match value {
1065
Some(image) => if image.data.is_blob() {
1066
let blob_key = BlobImageKey(image_key);
1067
self.blob_image_handler.as_mut().unwrap().delete(blob_key);
1068
self.deleted_blob_keys.back_mut().unwrap().push(blob_key);
1069
self.blob_image_templates.remove(&blob_key);
1070
self.rasterized_blob_images.remove(&blob_key);
1071
},
1072
None => {
1073
warn!("Delete the non-exist key");
1074
debug!("key={:?}", image_key);
1075
}
1076
}
1077
}
1078
1079
/// Return the current generation of an image template
1080
pub fn get_image_generation(&self, key: ImageKey) -> ImageGeneration {
1081
self.resources
1082
.image_templates
1083
.get(key)
1084
.map_or(ImageGeneration::INVALID, |template| template.generation)
1085
}
1086
1087
pub fn request_image(
1088
&mut self,
1089
request: ImageRequest,
1090
gpu_cache: &mut GpuCache,
1091
) {
1092
debug_assert_eq!(self.state, State::AddResources);
1093
1094
let template = match self.resources.image_templates.get(request.key) {
1095
Some(template) => template,
1096
None => {
1097
warn!("ERROR: Trying to render deleted / non-existent key");
1098
debug!("key={:?}", request.key);
1099
return
1100
}
1101
};
1102
1103
// Images that don't use the texture cache can early out.
1104
if !template.data.uses_texture_cache() {
1105
return;
1106
}
1107
1108
let side_size =
1109
template.tiling.map_or(cmp::max(template.descriptor.size.width, template.descriptor.size.height),
1110
|tile_size| tile_size as i32);
1111
if side_size > self.texture_cache.max_texture_size() {
1112
// The image or tiling size is too big for hardware texture size.
1113
warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
1114
template.descriptor.size.width, template.descriptor.size.height, template.tiling.unwrap_or(0));
1115
self.cached_images.insert(request.key, ImageResult::Err(ImageCacheError::OverLimitSize));
1116
return;
1117
}
1118
1119
let storage = match self.cached_images.entry(request.key) {
1120
Occupied(e) => {
1121
// We might have an existing untiled entry, and need to insert
1122
// a second entry. In such cases we need to move the old entry
1123
// out first, replacing it with a dummy entry, and then creating
1124
// the tiled/multi-entry variant.
1125
let entry = e.into_mut();
1126
if !request.is_untiled_auto() {
1127
let untiled_entry = match entry {
1128
&mut ImageResult::UntiledAuto(ref mut entry) => {
1129
Some(mem::replace(entry, CachedImageInfo {
1130
texture_cache_handle: TextureCacheHandle::invalid(),
1131
dirty_rect: DirtyRect::All,
1132
manual_eviction: false,
1133
}))
1134
}
1135
_ => None
1136
};
1137
1138
if let Some(untiled_entry) = untiled_entry {
1139
let mut entries = ResourceClassCache::new();
1140
let untiled_key = CachedImageKey {
1141
rendering: ImageRendering::Auto,
1142
tile: None,
1143
};
1144
entries.insert(untiled_key, untiled_entry);
1145
*entry = ImageResult::Multi(entries);
1146
}
1147
}
1148
entry
1149
}
1150
Vacant(entry) => {
1151
entry.insert(if request.is_untiled_auto() {
1152
ImageResult::UntiledAuto(CachedImageInfo {
1153
texture_cache_handle: TextureCacheHandle::invalid(),
1154
dirty_rect: DirtyRect::All,
1155
manual_eviction: false,
1156
})
1157
} else {
1158
ImageResult::Multi(ResourceClassCache::new())
1159
})
1160
}
1161
};
1162
1163
// If this image exists in the texture cache, *and* the dirty rect
1164
// in the cache is empty, then it is valid to use as-is.
1165
let entry = match *storage {
1166
ImageResult::UntiledAuto(ref mut entry) => entry,
1167
ImageResult::Multi(ref mut entries) => {
1168
entries.entry(request.into())
1169
.or_insert(CachedImageInfo {
1170
texture_cache_handle: TextureCacheHandle::invalid(),
1171
dirty_rect: DirtyRect::All,
1172
manual_eviction: false,
1173
})
1174
},
1175
ImageResult::Err(_) => panic!("Errors should already have been handled"),
1176
};
1177
1178
let needs_upload = self.texture_cache.request(&entry.texture_cache_handle, gpu_cache);
1179
1180
if !needs_upload && entry.dirty_rect.is_empty() {
1181
return
1182
}
1183
1184
if !self.pending_image_requests.insert(request) {
1185
return
1186
}
1187
1188
if template.data.is_blob() {
1189
let request: BlobImageRequest = request.into();
1190
let missing = match (self.rasterized_blob_images.get(&request.key), request.tile) {
1191
(Some(RasterizedBlob::Tiled(tiles)), Some(tile)) => !tiles.contains_key(&tile),
1192
(Some(RasterizedBlob::NonTiled(ref queue)), None) => queue.is_empty(),
1193
_ => true,
1194
};
1195
1196
// For some reason the blob image is missing. We'll fall back to
1197
// rasterizing it on the render backend thread.
1198
if missing {
1199
let descriptor = BlobImageDescriptor {
1200
rect: match template.tiling {
1201
Some(tile_size) => {
1202
let tile = request.tile.unwrap();
1203
blob_rect(compute_tile_rect(
1204
&template.visible_rect,
1205
tile_size,
1206
tile,
1207
))
1208
}
1209
None => blob_size(template.visible_rect.size).into(),
1210
},
1211
format: template.descriptor.format,
1212
};
1213
1214
assert!(!descriptor.rect.is_empty());
1215
1216
if !self.blob_image_templates.contains_key(&request.key) {
1217
panic!("already missing blob image key {:?} deleted: {:?}", request, self.deleted_blob_keys);
1218
}
1219
1220
self.missing_blob_images.push(
1221
BlobImageParams {
1222
request,
1223
descriptor,
1224
dirty_rect: DirtyRect::All,
1225
}
1226
);
1227
}
1228
}
1229
}
1230
1231
pub fn create_blob_scene_builder_requests(
1232
&mut self,
1233
keys: &[BlobImageKey]
1234
) -> (Option<(Box<dyn AsyncBlobImageRasterizer>, AsyncBlobImageInfo)>, Vec<BlobImageParams>) {
1235
if self.blob_image_handler.is_none() || keys.is_empty() {
1236
return (None, Vec::new());
1237
}
1238
1239
let mut blob_request_params = Vec::new();
1240
for key in keys {
1241
let template = self.blob_image_templates.get_mut(key).unwrap();
1242
1243
if let Some(tile_size) = template.tiling {
1244
// If we know that only a portion of the blob image is in the viewport,
1245
// only request these visible tiles since blob images can be huge.
1246
let tiles = compute_tile_range(
1247
&template.visible_rect,
1248
tile_size,
1249
);
1250
1251
let image_dirty_rect = to_image_dirty_rect(&template.dirty_rect);
1252
// Don't request tiles that weren't invalidated.
1253
let dirty_tiles = match image_dirty_rect {
1254
DirtyRect::Partial(dirty_rect) => {
1255
let dirty_rect = DeviceIntRect {
1256
origin: point2(
1257
dirty_rect.origin.x,
1258
dirty_rect.origin.y,
1259
),
1260
size: size2(
1261
dirty_rect.size.width,
1262
dirty_rect.size.height,
1263
),
1264
};
1265
1266
compute_tile_range(
1267
&dirty_rect,
1268
tile_size,
1269
)
1270
}
1271
DirtyRect::All => tiles,
1272
};
1273
1274
for_each_tile_in_range(&tiles, |tile| {
1275
let still_valid = template.valid_tiles_after_bounds_change
1276
.map(|valid_tiles| valid_tiles.contains(tile))
1277
.unwrap_or(true);
1278
1279
if still_valid && !dirty_tiles.contains(tile) {
1280
return;
1281
}
1282
1283
let descriptor = BlobImageDescriptor {
1284
rect: blob_rect(compute_tile_rect(
1285
&template.visible_rect,
1286
tile_size,
1287
tile,
1288
)),
1289
format: template.descriptor.format,
1290
};
1291
1292
assert!(descriptor.rect.size.width > 0 && descriptor.rect.size.height > 0);
1293
// TODO: We only track dirty rects for non-tiled blobs but we
1294
// should also do it with tiled ones unless we settle for a small
1295
// tile size.
1296
blob_request_params.push(
1297
BlobImageParams {
1298
request: BlobImageRequest {
1299
key: *key,
1300
tile: Some(tile),
1301
},
1302
descriptor,
1303
dirty_rect: DirtyRect::All,
1304
}
1305
);
1306
});
1307
1308
template.valid_tiles_after_bounds_change = None;
1309
} else {
1310
let mut needs_upload = match self.cached_images.try_get(&key.as_image()) {
1311
Some(&ImageResult::UntiledAuto(ref entry)) => {
1312
self.texture_cache.needs_upload(&entry.texture_cache_handle)
1313
}
1314
_ => true,
1315
};
1316
1317
// If the queue of rasterized updates is growing it probably means that
1318
// the texture is not getting uploaded because the display item is off-screen.
1319
// In that case we are better off
1320
// - Either not kicking rasterization for that image (avoid wasted cpu work
1321
// but will jank next time the item is visible because of lazy rasterization.
1322
// - Clobber the update queue by pushing an update with a larger dirty rect
1323
// to prevent it from accumulating.
1324
//
1325
// We do the latter here but it's not ideal and might want to revisit and do
1326
// the former instead.
1327
match self.rasterized_blob_images.get(key) {
1328
Some(RasterizedBlob::NonTiled(ref queue)) => {
1329
if queue.len() > 2 {
1330
needs_upload = true;
1331
}
1332
}
1333
_ => {},
1334
};
1335
1336
let dirty_rect = if needs_upload {
1337
// The texture cache entry has been evicted, treat it as all dirty.
1338
DirtyRect::All
1339
} else {
1340
template.dirty_rect
1341
};
1342
1343
assert!(template.visible_rect.size.width > 0 && template.visible_rect.size.height > 0);
1344
blob_request_params.push(
1345
BlobImageParams {
1346
request: BlobImageRequest {
1347
key: *key,
1348
tile: None,
1349
},
1350
descriptor: BlobImageDescriptor {
1351
rect: blob_size(template.visible_rect.size).into(),
1352
format: template.descriptor.format,
1353
},
1354
dirty_rect,
1355
}
1356
);
1357
}
1358
template.dirty_rect = DirtyRect::empty();
1359
}
1360
self.blob_image_rasterizer_produced_epoch.0 += 1;
1361
let info = AsyncBlobImageInfo {
1362
epoch: self.blob_image_rasterizer_produced_epoch,
1363
clear_requests: Vec::new(),
1364
};
1365
let handler = self.blob_image_handler.as_mut().unwrap();
1366
handler.prepare_resources(&self.resources, &blob_request_params);
1367
(Some((handler.create_blob_rasterizer(), info)), blob_request_params)
1368
}
1369
1370
fn discard_tiles_outside_visible_area(
1371
&mut self,
1372
key: BlobImageKey,
1373
area: &DeviceIntRect
1374
) {
1375
let template = match self.blob_image_templates.get(&key) {
1376
Some(template) => template,
1377
None => {
1378
//println!("Missing image template (key={:?})!", key);
1379
return;
1380
}
1381
};
1382
let tile_size = match template.tiling {
1383
Some(size) => size,
1384
None => { return; }
1385
};
1386
1387
let tiles = match self.rasterized_blob_images.get_mut(&key) {
1388
Some(RasterizedBlob::Tiled(tiles)) => tiles,
1389
_ => { return; }
1390
};
1391
1392
let tile_range = compute_tile_range(
1393
&area,
1394
tile_size,
1395
);
1396
1397
tiles.retain(|tile, _| { tile_range.contains(*tile) });
1398
1399
let texture_cache = &mut self.texture_cache;
1400
match self.cached_images.try_get_mut(&key.as_image()) {
1401
Some(&mut ImageResult::Multi(ref mut entries)) => {
1402
entries.retain(|key, entry| {
1403
if key.tile.is_none() || tile_range.contains(key.tile.unwrap()) {
1404
return true;
1405
}
1406
entry.mark_unused(texture_cache);
1407
return false;
1408
});
1409
}
1410
_ => {}
1411
}
1412
}
1413
1414
fn set_image_visible_rect(&mut self, key: ImageKey, rect: &DeviceIntRect) {
1415
if let Some(image) = self.resources.image_templates.get_mut(key) {
1416
image.visible_rect = *rect;
1417
image.descriptor.size = rect.size;
1418
}
1419
}
1420
1421
pub fn request_glyphs(
1422
&mut self,
1423
mut font: FontInstance,
1424
glyph_keys: &[GlyphKey],
1425
gpu_cache: &mut GpuCache,
1426
render_task_tree: &mut RenderTaskGraph,
1427
) {
1428
debug_assert_eq!(self.state, State::AddResources);
1429
1430
self.glyph_rasterizer.prepare_font(&mut font);
1431
self.glyph_rasterizer.request_glyphs(
1432
&mut self.cached_glyphs,
1433
font,
1434
glyph_keys,
1435
&mut self.texture_cache,
1436
gpu_cache,
1437
&mut self.cached_render_tasks,
1438
render_task_tree,
1439
);
1440
}
1441
1442
pub fn pending_updates(&mut self) -> ResourceUpdateList {
1443
ResourceUpdateList {
1444
texture_updates: self.texture_cache.pending_updates(),
1445
native_surface_updates: mem::replace(&mut self.pending_native_surface_updates, Vec::new()),
1446
}
1447
}
1448
1449
pub fn fetch_glyphs<F>(
1450
&self,
1451
mut font: FontInstance,
1452
glyph_keys: &[GlyphKey],
1453
fetch_buffer: &mut Vec<GlyphFetchResult>,
1454
gpu_cache: &mut GpuCache,
1455
mut f: F,
1456
) where
1457
F: FnMut(TextureSource, GlyphFormat, &[GlyphFetchResult]),
1458
{
1459
debug_assert_eq!(self.state, State::QueryResources);
1460
1461
self.glyph_rasterizer.prepare_font(&mut font);
1462
let glyph_key_cache = self.cached_glyphs.get_glyph_key_cache_for_font(&font);
1463
1464
let mut current_texture_id = TextureSource::Invalid;
1465
let mut current_glyph_format = GlyphFormat::Subpixel;
1466
debug_assert!(fetch_buffer.is_empty());
1467
1468
for (loop_index, key) in glyph_keys.iter().enumerate() {
1469
let (cache_item, glyph_format) = match *glyph_key_cache.get(key) {
1470
GlyphCacheEntry::Cached(ref glyph) => {
1471
(self.texture_cache.get(&glyph.texture_cache_handle), glyph.format)
1472
}
1473
GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
1474
};
1475
if current_texture_id != cache_item.texture_id ||
1476
current_glyph_format != glyph_format {
1477
if !fetch_buffer.is_empty() {
1478
f(current_texture_id, current_glyph_format, fetch_buffer);
1479
fetch_buffer.clear();
1480
}
1481
current_texture_id = cache_item.texture_id;
1482
current_glyph_format = glyph_format;
1483
}
1484
fetch_buffer.push(GlyphFetchResult {
1485
index_in_text_run: loop_index as i32,
1486
uv_rect_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
1487
});
1488
}
1489
1490
if !fetch_buffer.is_empty() {
1491
f(current_texture_id, current_glyph_format, fetch_buffer);
1492
fetch_buffer.clear();
1493
}
1494
}
1495
1496
pub fn get_glyph_dimensions(
1497
&mut self,
1498
font: &FontInstance,
1499
glyph_index: GlyphIndex,
1500
) -> Option<GlyphDimensions> {
1501
match self.cached_glyph_dimensions.entry((font.instance_key, glyph_index)) {
1502
Occupied(entry) => *entry.get(),
1503
Vacant(entry) => *entry.insert(
1504
self.glyph_rasterizer
1505
.get_glyph_dimensions(font, glyph_index),
1506
),
1507
}
1508
}
1509
1510
pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
1511
self.glyph_rasterizer.get_glyph_index(font_key, ch)
1512
}
1513
1514
#[inline]
1515
pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
1516
debug_assert_eq!(self.state, State::QueryResources);
1517
let image_info = self.get_image_info(request)?;
1518
Ok(self.get_texture_cache_item(&image_info.texture_cache_handle))
1519
}
1520
1521
pub fn get_cached_render_task(
1522
&self,
1523
handle: &RenderTaskCacheEntryHandle,
1524
) -> &RenderTaskCacheEntry {
1525
self.cached_render_tasks.get_cache_entry(handle)
1526
}
1527
1528
#[inline]
1529
fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
1530
// TODO(Jerry): add a debug option to visualize the corresponding area for
1531
// the Err() case of CacheItem.
1532
match *self.cached_images.get(&request.key) {
1533
ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
1534
ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
1535
ImageResult::Err(_) => Err(()),
1536
}
1537
}
1538
1539
#[inline]
1540
pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> CacheItem {
1541
self.texture_cache.get(handle)
1542
}
1543
1544
pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
1545
let image_template = &self.resources.image_templates.get(image_key);
1546
1547
image_template.map(|image_template| {
1548
let external_image = match image_template.data {
1549
CachedImageData::External(ext_image) => match ext_image.image_type {
1550
ExternalImageType::TextureHandle(_) => Some(ext_image),
1551
// external buffer uses resource_cache.
1552
ExternalImageType::Buffer => None,
1553
},
1554
// raw and blob image are all using resource_cache.
1555
CachedImageData::Raw(..) | CachedImageData::Blob => None,
1556
};
1557
1558
ImageProperties {
1559
descriptor: image_template.descriptor,
1560
external_image,
1561
tiling: image_template.tiling,
1562
visible_rect: image_template.visible_rect,
1563
}
1564
})
1565
}
1566
1567
pub fn prepare_for_frames(&mut self, time: SystemTime) {
1568
self.texture_cache.prepare_for_frames(time);
1569
}
1570
1571
pub fn bookkeep_after_frames(&mut self) {
1572
self.texture_cache.bookkeep_after_frames();
1573
}
1574
1575
pub fn requires_frame_build(&self) -> bool {
1576
self.texture_cache.requires_frame_build()
1577
}
1578
1579
pub fn begin_frame(&mut self, stamp: FrameStamp) {
1580
debug_assert_eq!(self.state, State::Idle);
1581
self.state = State::AddResources;
1582
self.texture_cache.begin_frame(stamp);
1583
self.cached_glyphs.begin_frame(
1584
stamp,
1585
&mut self.texture_cache,
1586
&self.cached_render_tasks,
1587
&mut self.glyph_rasterizer,
1588
);
1589
self.cached_render_tasks.begin_frame(&mut self.texture_cache);
1590
self.current_frame_id = stamp.frame_id();
1591
1592
// pop the old frame and push a new one
1593
self.deleted_blob_keys.pop_front();
1594
self.deleted_blob_keys.push_back(Vec::new());
1595
}
1596
1597
pub fn block_until_all_resources_added(
1598
&mut self,
1599
gpu_cache: &mut GpuCache,
1600
render_tasks: &mut RenderTaskGraph,
1601
texture_cache_profile: &mut TextureCacheProfileCounters,
1602
) {
1603
profile_scope!("block_until_all_resources_added");
1604
1605
debug_assert_eq!(self.state, State::AddResources);
1606
self.state = State::QueryResources;
1607
1608
self.glyph_rasterizer.resolve_glyphs(
1609
&mut self.cached_glyphs,
1610
&mut self.texture_cache,
1611
gpu_cache,
1612
&mut self.cached_render_tasks,
1613
render_tasks,
1614
texture_cache_profile,
1615
);
1616
1617
self.rasterize_missing_blob_images(texture_cache_profile);
1618
1619
// Apply any updates of new / updated images (incl. blobs) to the texture cache.
1620
self.update_texture_cache(gpu_cache);
1621
}
1622
1623
fn rasterize_missing_blob_images(
1624
&mut self,
1625
texture_cache_profile: &mut TextureCacheProfileCounters,
1626
) {
1627
if self.missing_blob_images.is_empty() {
1628
return;
1629
}
1630
1631
self.blob_image_handler
1632
.as_mut()
1633
.unwrap()
1634
.prepare_resources(&self.resources, &self.missing_blob_images);
1635
1636
1637
for blob_image in &self.missing_blob_images {
1638
if !self.blob_image_templates.contains_key(&blob_image.request.key) {
1639
panic!("missing blob image key {:?} deleted: {:?}", blob_image, self.deleted_blob_keys);
1640
}
1641
}
1642
let is_low_priority = false;
1643
let rasterized_blobs = self.blob_image_rasterizer
1644
.as_mut()
1645
.unwrap()
1646
.rasterize(&self.missing_blob_images, is_low_priority);
1647
1648
self.add_rasterized_blob_images(rasterized_blobs, texture_cache_profile);
1649
1650
self.missing_blob_images.clear();
1651
}
1652
1653
fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
1654
for request in self.pending_image_requests.drain() {
1655
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
1656
debug_assert!(image_template.data.uses_texture_cache());
1657
1658
let mut updates: SmallVec<[(CachedImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
1659
1660
match image_template.data {
1661
CachedImageData::Raw(..) | CachedImageData::External(..) => {
1662
// Safe to clone here since the Raw image data is an
1663
// Arc, and the external image data is small.
1664
updates.push((image_template.data.clone(), None));
1665
}
1666
CachedImageData::Blob => {
1667
1668
let blob_image = self.rasterized_blob_images.get_mut(&BlobImageKey(request.key)).unwrap();
1669
match (blob_image, request.tile) {
1670
(RasterizedBlob::Tiled(ref tiles), Some(tile)) => {
1671
let img = &tiles[&tile];
1672
updates.push((
1673
CachedImageData::Raw(Arc::clone(&img.data)),
1674
Some(img.rasterized_rect)
1675
));
1676
}
1677
(RasterizedBlob::NonTiled(ref mut queue), None) => {
1678
for img in queue.drain(..) {
1679
updates.push((
1680
CachedImageData::Raw(img.data),
1681
Some(img.rasterized_rect)
1682
));
1683
}
1684
}
1685
_ => {
1686
debug_assert!(false, "invalid blob image request during frame building");
1687
continue;
1688
}
1689
}
1690
}
1691
};
1692
1693
for (image_data, blob_rasterized_rect) in updates {
1694
let entry = match *self.cached_images.get_mut(&request.key) {
1695
ImageResult::UntiledAuto(ref mut entry) => entry,
1696
ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
1697
ImageResult::Err(_) => panic!("Update requested for invalid entry")
1698
};
1699
1700
let mut descriptor = image_template.descriptor.clone();
1701
let mut dirty_rect = entry.dirty_rect.replace_with_empty();
1702
1703
if let Some(tile) = request.tile {
1704
let tile_size = image_template.tiling.unwrap();
1705
let clipped_tile_size = compute_tile_size(&image_template.visible_rect, tile_size, tile);
1706
// The tiled image could be stored on the CPU as one large image or be
1707
// already broken up into tiles. This affects the way we compute the stride
1708
// and offset.
1709
let tiled_on_cpu = image_template.data.is_blob();
1710
if !tiled_on_cpu {
1711
// we don't expect to have partial tiles at the top and left of non-blob
1712
// images.