/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{DirtyRect, ImageDescriptor, ImageDescriptorFlags, SnapshotImageKey}; use api::units::*; usecrate::border::BorderSegmentCacheKey; usecrate::box_shadow::BoxShadowCacheKey; usecrate::device::TextureFilter; usecrate::freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; usecrate::internal_types::FastHashMap; usecrate::prim_store::image::ImageCacheKey; usecrate::prim_store::line_dec::LineDecorationCacheKey; usecrate::quad::QuadCacheKey; usecrate::resource_cache::CacheItem; use std::{mem, usize, f32, i32}; usecrate::surface::SurfaceBuilder; usecrate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader}; usecrate::renderer::GpuBufferBuilderF; usecrate::render_target::RenderTargetKind; usecrate::render_task::{RenderTask, StaticRenderTaskSurface, RenderTaskLocation, RenderTaskKind, CachedTask}; usecrate::render_task_graph::{RenderTaskGraphBuilder, RenderTaskId}; use euclid::Scale;
const MAX_CACHE_TASK_SIZE: f32 = 4096.0;
/// Describes a parent dependency for a render task. Render tasks /// may depend on a surface (e.g. when a surface uses a cached border) /// or an arbitrary render task (e.g. when a clip mask uses a blurred /// box-shadow input). pubenum RenderTaskParent { /// Parent is a surface
Surface, /// Parent is a render task
RenderTask(RenderTaskId),
}
#[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pubstruct RenderTaskCacheEntry {
user_data: Option<[f32; 4]>,
target_kind: RenderTargetKind,
is_opaque: bool,
frame_id: u64, pub handle: TextureCacheHandle, /// If a render task was generated for this cache entry on _this_ frame, /// we need to track the task id here. This allows us to hook it up as /// a dependency of any parent tasks that make a reqiest from the render /// task cache. pub render_task_id: Option<RenderTaskId>,
}
// A cache of render tasks that are stored in the texture // cache for usage across frames. #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pubstruct RenderTaskCache {
map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheMarker>>,
cache_entries: FreeList<RenderTaskCacheEntry, RenderTaskCacheMarker>,
frame_id: u64,
}
pubfn begin_frame(
&mutself,
texture_cache: &mut TextureCache,
) { self.frame_id += 1;
profile_scope!("begin_frame"); // Drop any items from the cache that have been // evicted from the texture cache. // // This isn't actually necessary for the texture // cache to be able to evict old render tasks. // It will evict render tasks as required, since // the access time in the texture cache entry will // be stale if this task hasn't been requested // for a while. // // Nonetheless, we should remove stale entries // from here so that this hash map doesn't // grow indefinitely! let cache_entries = &mutself.cache_entries; let frame_id = self.frame_id;
self.map.retain(|_, handle| { letmut retain = texture_cache.is_allocated(
&cache_entries.get(handle).handle,
); if retain { let entry = cache_entries.get_mut(&handle); if frame_id > entry.frame_id + 10 {
texture_cache.evict_handle(&entry.handle);
retain = false;
}
}
if !retain { let handle = mem::replace(handle, FreeListHandle::invalid());
cache_entries.free(handle);
}
retain
});
// Clear out the render task ID of any remaining cache entries that were drawn // on the previous frame, so we don't accidentally hook up stale dependencies // when building the frame graph. for (_, handle) in &self.map { let entry = self.cache_entries.get_mut(handle);
entry.render_task_id = None;
}
}
fn alloc_render_task(
size: DeviceIntSize,
render_task: &mut RenderTask,
entry: &mut RenderTaskCacheEntry,
gpu_buffer: &mut GpuBufferBuilderF,
texture_cache: &mut TextureCache,
) { // Find out what size to alloc in the texture cache. let target_kind = render_task.target_kind();
// Select the right texture page to allocate from. let image_format = match target_kind {
RenderTargetKind::Color => texture_cache.shared_color_expected_format(),
RenderTargetKind::Alpha => texture_cache.shared_alpha_expected_format(),
};
let flags = if entry.is_opaque {
ImageDescriptorFlags::IS_OPAQUE
} else {
ImageDescriptorFlags::empty()
};
let descriptor = ImageDescriptor::new(
size.width,
size.height,
image_format,
flags,
);
// Allocate space in the texture cache, but don't supply // and CPU-side data to be uploaded.
texture_cache.update(
&mut entry.handle,
descriptor,
TextureFilter::Linear,
None,
entry.user_data.unwrap_or([0.0; 4]),
DirtyRect::All,
gpu_buffer,
None,
render_task.uv_rect_kind(),
Eviction::Auto,
TargetShader::Default, false,
);
// Get the allocation details in the texture cache, and store // this in the render task. The renderer will draw this task // into the appropriate rect of the texture cache on this frame. let (texture_id, uv_rect, _, _, _) =
texture_cache.get_cache_location(&entry.handle);
let surface = StaticRenderTaskSurface::TextureCache {
texture: texture_id,
target_kind,
};
pubfn request_render_task(
&mutself,
key: Option<RenderTaskCacheKey>,
texture_cache: &mut TextureCache,
is_opaque: bool,
parent: RenderTaskParent,
gpu_buffer_builder: &mut GpuBufferBuilderF,
rg_builder: &mut RenderTaskGraphBuilder,
surface_builder: &mut SurfaceBuilder,
f: &mutdyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
) -> RenderTaskId { // If this render task cache is being drawn this frame, ensure we hook up the // render task for it as a dependency of any render task that uses this as // an input source. let (task_id, rendered_this_frame) = match key {
None => (f(rg_builder, gpu_buffer_builder), true),
Some(key) => self.request_render_task_impl(
key,
is_opaque,
texture_cache,
gpu_buffer_builder,
rg_builder,
f
)
};
if rendered_this_frame { match parent {
RenderTaskParent::Surface => { // If parent is a surface, use helper fn to add this dependency, // which correctly takes account of the render task configuration // of the surface.
surface_builder.add_child_render_task(
task_id,
rg_builder,
);
}
RenderTaskParent::RenderTask(parent_render_task_id) => { // For render tasks, just add it as a direct dependency on the // task graph builder.
rg_builder.add_dependency(
parent_render_task_id,
task_id,
);
}
}
}
task_id
}
/// Returns the render task id and a boolean indicating whether the /// task was rendered this frame (was not already in cache). fn request_render_task_impl(
&mutself,
key: RenderTaskCacheKey,
is_opaque: bool,
texture_cache: &mut TextureCache,
gpu_buffer_builder: &mut GpuBufferBuilderF,
rg_builder: &mut RenderTaskGraphBuilder,
f: &mutdyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
) -> (RenderTaskId, bool) { let frame_id = self.frame_id; let size = key.size; // Get the texture cache handle for this cache key, // or create one. let cache_entries = &mutself.cache_entries; let entry_handle = self.map.entry(key).or_insert_with(|| { let entry = RenderTaskCacheEntry {
handle: TextureCacheHandle::invalid(),
user_data: None,
target_kind: RenderTargetKind::Color, // will be set below.
is_opaque,
frame_id,
render_task_id: None,
};
cache_entries.insert(entry)
}); let cache_entry = cache_entries.get_mut(entry_handle);
cache_entry.frame_id = self.frame_id;
// Check if this texture cache handle is valid. if texture_cache.request(&cache_entry.handle, gpu_buffer_builder) { // Invoke user closure to get render task chain // to draw this into the texture cache. let render_task_id = f(rg_builder, gpu_buffer_builder);
#[allow(dead_code)] pubfn get_cache_item_for_render_task(&self,
texture_cache: &TextureCache,
key: &RenderTaskCacheKey)
-> CacheItem { // Get the texture cache handle for this cache key. let handle = self.map.get(key).unwrap(); let cache_entry = self.cache_entries.get(handle);
texture_cache.get(&cache_entry.handle)
}
// TODO(gw): Rounding the content rect here to device pixels is not // technically correct. Ideally we should ceil() here, and ensure that // the extra part pixel in the case of fractional sizes is correctly // handled. For now, just use rounding which passes the existing // Gecko tests. // Note: zero-square tasks are prohibited in WR task graph, so // we ensure each dimension to be at least the length of 1 after rounding. pubfn to_cache_size(size: LayoutSize, device_pixel_scale: &mutScale<f32, LayoutPixel, DevicePixel>) -> DeviceIntSize { letmut device_size = (size * *device_pixel_scale).round();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.