Bug 1922323 - Make it possible to conditionally cache render tasks. r=gfx-reviewers,gw

This will be needed by some quad rendering optimizations and the view-transition snapshotting infrastructure.
The main change in this patch is that ResourceCache::request_render_task now takes an optional cache key and only creates a cached render task if the cache key is supplied.
The patch ballooned into including a few cosmetic changes:
 - user_data was always None so the parameter was removed
 - the closure is not generic anymore
 - arguments were shuffled a bit to put parameters at the beginning and the &mut builders together at the end.

Differential Revision: https://phabricator.services.mozilla.com/D224446
This commit is contained in:
Nicolas Silva 2024-10-14 16:27:49 +00:00
parent 3f27ff750f
commit 68b9bb0f07
8 changed files with 126 additions and 107 deletions

View File

@ -403,18 +403,17 @@ fn prepare_interned_prim_for_render(
// happens, we can use the cache handle immediately, and not need
// to temporarily store it in the primitive instance.
*render_task = Some(frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: task_size,
kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()),
},
}),
false,
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false,
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, _| {
&mut |rg_builder, _| {
rg_builder.add().init(RenderTask::new_dynamic(
task_size,
RenderTaskKind::new_line_decoration(
@ -561,15 +560,14 @@ fn prepare_interned_prim_for_render(
};
handles.push(frame_state.resource_cache.request_render_task(
cache_key,
Some(cache_key),
false, // TODO(gw): We don't calculate opacity for borders yet!
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false, // TODO(gw): We don't calculate opacity for borders yet!
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, _| {
&mut |rg_builder, _| {
rg_builder.add().init(RenderTask::new_dynamic(
cache_size,
RenderTaskKind::new_border_segment(

View File

@ -283,18 +283,17 @@ impl ConicGradientTemplate {
};
let task_id = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: self.task_size,
kind: RenderTaskCacheKeyKind::ConicGradient(cache_key),
},
}),
false,
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false,
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, gpu_buffer_builder| {
&mut |rg_builder, gpu_buffer_builder| {
let stops = GradientGpuBlockBuilder::build(
false,
gpu_buffer_builder,
@ -472,4 +471,4 @@ pub fn conic_gradient_pattern(
base_color: ColorF::WHITE,
is_opaque,
}
}
}

View File

@ -515,18 +515,17 @@ impl LinearGradientTemplate {
};
frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: self.task_size,
kind: RenderTaskCacheKeyKind::FastLinearGradient(gradient),
},
}),
false,
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false,
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, _| {
&mut |rg_builder, _| {
rg_builder.add().init(RenderTask::new_dynamic(
self.task_size,
RenderTaskKind::FastLinearGradient(gradient),
@ -545,18 +544,17 @@ impl LinearGradientTemplate {
};
frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: self.task_size,
kind: RenderTaskCacheKeyKind::LinearGradient(cache_key),
},
}),
false,
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false,
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, gpu_buffer_builder| {
&mut |rg_builder, gpu_buffer_builder| {
let stops = Some(GradientGpuBlockBuilder::build(
self.reverse_stops,
gpu_buffer_builder,

View File

@ -249,18 +249,17 @@ impl RadialGradientTemplate {
};
let task_id = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: task_size,
kind: RenderTaskCacheKeyKind::RadialGradient(cache_key),
},
}),
false,
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
false,
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, gpu_buffer_builder| {
&mut |rg_builder, gpu_buffer_builder| {
let stops = GradientGpuBlockBuilder::build(
false,
gpu_buffer_builder,
@ -605,4 +604,4 @@ pub fn radial_gradient_pattern(
base_color: ColorF::WHITE,
is_opaque,
}
}
}

View File

@ -250,18 +250,17 @@ impl ImageData {
// Request a pre-rendered image task.
let cached_task_handle = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size,
kind: RenderTaskCacheKeyKind::Image(image_cache_key),
},
}),
descriptor.is_opaque(),
RenderTaskParent::Surface,
frame_state.gpu_cache,
&mut frame_state.frame_gpu_data.f32,
frame_state.rg_builder,
None,
descriptor.is_opaque(),
RenderTaskParent::Surface,
&mut frame_state.surface_builder,
|rg_builder, _| {
&mut |rg_builder, _| {
// Create a task to blit from the texture cache to
// a normal transient render task surface.
// TODO: figure out if/when we can do a blit instead.

View File

@ -667,18 +667,17 @@ impl RenderTaskKind {
// Request a cacheable render task with a blurred, minimal
// sized box-shadow rect.
source.render_task = Some(resource_cache.request_render_task(
RenderTaskCacheKey {
Some(RenderTaskCacheKey {
size: cache_size,
kind: RenderTaskCacheKeyKind::BoxShadow(cache_key),
},
}),
false,
RenderTaskParent::RenderTask(clip_task_id),
gpu_cache,
gpu_buffer_builder,
rg_builder,
None,
false,
RenderTaskParent::RenderTask(clip_task_id),
surface_builder,
|rg_builder, _| {
&mut |rg_builder, _| {
let clip_data = ClipData::rounded_rect(
source.minimal_shadow_rect.size(),
&source.shadow_radius,

View File

@ -222,22 +222,71 @@ impl RenderTaskCache {
};
}
pub fn request_render_task<F>(
pub fn request_render_task(
&mut self,
key: Option<RenderTaskCacheKey>,
texture_cache: &mut TextureCache,
is_opaque: bool,
parent: RenderTaskParent,
gpu_cache: &mut GpuCache,
gpu_buffer_builder: &mut GpuBufferBuilderF,
rg_builder: &mut RenderTaskGraphBuilder,
surface_builder: &mut SurfaceBuilder,
f: &mut dyn 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_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(
&mut self,
key: RenderTaskCacheKey,
is_opaque: bool,
texture_cache: &mut TextureCache,
gpu_cache: &mut GpuCache,
gpu_buffer_builder: &mut GpuBufferBuilderF,
rg_builder: &mut RenderTaskGraphBuilder,
user_data: Option<[f32; 4]>,
is_opaque: bool,
parent: RenderTaskParent,
surface_builder: &mut SurfaceBuilder,
f: F,
) -> Result<RenderTaskId, ()>
where
F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> Result<RenderTaskId, ()>,
{
f: &mut dyn 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,
@ -246,7 +295,7 @@ impl RenderTaskCache {
let entry_handle = self.map.entry(key).or_insert_with(|| {
let entry = RenderTaskCacheEntry {
handle: TextureCacheHandle::invalid(),
user_data,
user_data: None,
target_kind: RenderTargetKind::Color, // will be set below.
is_opaque,
frame_id,
@ -261,9 +310,9 @@ impl RenderTaskCache {
if texture_cache.request(&cache_entry.handle, gpu_cache) {
// 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)?;
let render_task_id = f(rg_builder, gpu_buffer_builder);
cache_entry.user_data = user_data;
cache_entry.user_data = None;
cache_entry.is_opaque = is_opaque;
cache_entry.render_task_id = Some(render_task_id);
@ -282,31 +331,8 @@ impl RenderTaskCache {
);
}
// 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.
if let Some(render_task_id) = cache_entry.render_task_id {
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(
render_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,
render_task_id,
);
}
}
return Ok(render_task_id);
return (render_task_id, true);
}
let target_kind = cache_entry.target_kind;
@ -319,7 +345,7 @@ impl RenderTaskCache {
task.mark_cached(entry_handle.weak());
let render_task_id = rg_builder.add().init(task);
Ok(render_task_id)
(render_task_id, false)
}
pub fn get_cache_entry(

View File

@ -576,38 +576,39 @@ impl ResourceCache {
}
}
// Request the texture cache item for a cacheable render
// task. If the item is already cached, the texture cache
// handle will be returned. Otherwise, the user supplied
// closure will be invoked to generate the render task
// chain that is required to draw this task.
pub fn request_render_task<F>(
/// Request an optionally cacheable render task.
///
/// If the render task cache key is None, the render task is
/// not cached.
/// Otherwise, if the item is already cached, the texture cache
/// handle will be returned. Otherwise, the user supplied
/// closure will be invoked to generate the render task
/// chain that is required to draw this task.
///
/// This function takes care of adding the render task as a
/// dependency to its parent task or surface.
pub fn request_render_task(
&mut self,
key: RenderTaskCacheKey,
key: Option<RenderTaskCacheKey>,
is_opaque: bool,
parent: RenderTaskParent,
gpu_cache: &mut GpuCache,
gpu_buffer_builder: &mut GpuBufferBuilderF,
rg_builder: &mut RenderTaskGraphBuilder,
user_data: Option<[f32; 4]>,
is_opaque: bool,
parent: RenderTaskParent,
surface_builder: &mut SurfaceBuilder,
f: F,
) -> RenderTaskId
where
F: FnOnce(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
{
f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
) -> RenderTaskId {
self.cached_render_tasks.request_render_task(
key,
&mut self.texture_cache,
is_opaque,
parent,
gpu_cache,
gpu_buffer_builder,
rg_builder,
user_data,
is_opaque,
parent,
surface_builder,
|render_graph, gpu_buffer_builder| Ok(f(render_graph, gpu_buffer_builder))
).expect("Failed to request a render task from the resource cache!")
f
)
}
pub fn post_scene_building_update(