Bug 1611176 - Avoid expensive memmoves when adding render tasks. r=gw

On pages with many render tasks (typically a lot of text shadows), we spend a lot of time moving RenderTask which is a fairly large struct into the render graph's buffer. This patch avoids it by using the VecHelper trick of allocaitng space before initializing the value. Some RenderTask::new_* methods which take the render task graph in parameter were modified to add the task and return the task ID to work around borrow-checking restriction.

Differential Revision: https://phabricator.services.mozilla.com/D60854

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Silva 2020-01-23 19:26:13 +00:00
Родитель 6836a4dde4
Коммит ea36628e1e
6 изменённых файлов: 262 добавлений и 272 удалений

Просмотреть файл

@ -270,20 +270,20 @@ impl FrameBuilder {
fb_config: &scene.config,
};
let root_render_task = RenderTask::new_picture(
RenderTaskLocation::Fixed(scene.output_rect),
scene.output_rect.size.to_f32(),
scene.root_pic_index,
DeviceIntPoint::zero(),
UvRectKind::Rect,
ROOT_SPATIAL_NODE_INDEX,
global_device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let root_render_task_id = render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Fixed(scene.output_rect),
scene.output_rect.size.to_f32(),
scene.root_pic_index,
DeviceIntPoint::zero(),
UvRectKind::Rect,
ROOT_SPATIAL_NODE_INDEX,
global_device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let root_render_task_id = render_tasks.add(root_render_task);
// Construct a dummy root surface, that represents the
// main framebuffer surface.
let root_surface = SurfaceInfo::new(

Просмотреть файл

@ -3755,20 +3755,20 @@ impl PicturePrimitive {
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
pic_index,
device_rect.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let picture_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
pic_index,
device_rect.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task_id = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
@ -3818,20 +3818,22 @@ impl PicturePrimitive {
true,
);
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
pic_index,
device_rect.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
);
picture_task.mark_for_saving();
let picture_task_id = frame_state.render_tasks.add().init({
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
pic_index,
device_rect.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
);
picture_task.mark_for_saving();
let picture_task_id = frame_state.render_tasks.add(picture_task);
picture_task
});
self.secondary_render_task_id = Some(picture_task_id);
@ -3865,19 +3867,7 @@ impl PicturePrimitive {
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
);
let readback_task_id = frame_state.render_tasks.add(
let readback_task_id = frame_state.render_tasks.add().init(
RenderTask::new_readback(clipped)
);
@ -3888,7 +3878,19 @@ impl PicturePrimitive {
self.secondary_render_task_id = Some(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
let render_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
Some((render_task_id, render_task_id))
}
@ -3901,20 +3903,20 @@ impl PicturePrimitive {
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let render_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let render_task_id = frame_state.render_tasks.add(picture_task);
Some((render_task_id, render_task_id))
}
PictureCompositeMode::ComponentTransferFilter(..) => {
@ -3926,20 +3928,20 @@ impl PicturePrimitive {
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let render_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let render_task_id = frame_state.render_tasks.add(picture_task);
Some((render_task_id, render_task_id))
}
PictureCompositeMode::TileCache { .. } => {
@ -4138,23 +4140,23 @@ impl PicturePrimitive {
tile_cache.current_tile_size,
);
let task = RenderTask::new_picture(
RenderTaskLocation::PictureCache {
size: tile_cache.current_tile_size,
surface,
},
tile_cache.current_tile_size.to_f32(),
pic_index,
content_origin.to_i32(),
UvRectKind::Rect,
surface_spatial_node_index,
device_pixel_scale,
*visibility_mask,
Some(scissor_rect.to_i32()),
let render_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::PictureCache {
size: tile_cache.current_tile_size,
surface,
},
tile_cache.current_tile_size.to_f32(),
pic_index,
content_origin.to_i32(),
UvRectKind::Rect,
surface_spatial_node_index,
device_pixel_scale,
*visibility_mask,
Some(scissor_rect.to_i32()),
)
);
let render_task_id = frame_state.render_tasks.add(task);
frame_state.render_tasks.add_dependency(
frame_state.surfaces[parent_surface_index.0].render_tasks.unwrap().port,
render_task_id,
@ -4202,20 +4204,20 @@ impl PicturePrimitive {
supports_snapping,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let render_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let render_task_id = frame_state.render_tasks.add(picture_task);
Some((render_task_id, render_task_id))
}
PictureCompositeMode::SvgFilter(ref primitives, ref filter_datas) => {
@ -4227,20 +4229,20 @@ impl PicturePrimitive {
true,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
let picture_task_id = frame_state.render_tasks.add().init(
RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
pic_index,
clipped.origin,
uv_rect_kind,
surface_spatial_node_index,
device_pixel_scale,
PrimitiveVisibilityMask::all(),
None,
)
);
let picture_task_id = frame_state.render_tasks.add(picture_task);
let filter_task_id = RenderTask::new_svg_filter(
primitives,
filter_datas,

Просмотреть файл

@ -237,35 +237,24 @@ impl ImageData {
// Create a task to blit from the texture cache to
// a normal transient render task surface. This will
// copy only the sub-rect, if specified.
let cache_to_target_task = if false {
// TODO: figure out if/when this can be used
RenderTask::new_blit_with_padding(
*size,
padding,
BlitSource::Image { key: image_cache_key },
)
} else {
RenderTask::new_scaling_with_padding(
BlitSource::Image { key: image_cache_key },
render_tasks,
target_kind,
*size,
padding,
)
};
let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
// TODO: figure out if/when we can do a blit instead.
let cache_to_target_task_id = RenderTask::new_scaling_with_padding(
BlitSource::Image { key: image_cache_key },
render_tasks,
target_kind,
*size,
padding,
);
// Create a task to blit the rect from the child render
// task above back into the right spot in the persistent
// render target cache.
let target_to_cache_task = RenderTask::new_blit(
render_tasks.add().init(RenderTask::new_blit(
*size,
BlitSource::RenderTask {
task_id: cache_to_target_task_id,
},
);
render_tasks.add(target_to_cache_task)
))
}
));
}

Просмотреть файл

@ -1063,7 +1063,7 @@ impl BrushSegment {
}
};
let clip_task = RenderTask::new_mask(
let clip_task_id = RenderTask::new_mask(
device_rect.to_i32(),
clip_chain.clips_range,
root_spatial_node_index,
@ -1075,8 +1075,6 @@ impl BrushSegment {
device_pixel_scale,
frame_context.fb_config,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);
let port = frame_state
.surfaces[surface_index.0]
.render_tasks
@ -2903,14 +2901,13 @@ impl PrimitiveStore {
None,
false,
|render_tasks| {
let task = RenderTask::new_line_decoration(
render_tasks.add().init(RenderTask::new_line_decoration(
task_size,
cache_key.style,
cache_key.orientation,
cache_key.wavy_line_thickness.to_f32_px(),
LayoutSize::from_au(cache_key.size),
);
render_tasks.add(task)
))
}
));
}
@ -3025,7 +3022,7 @@ impl PrimitiveStore {
None,
false, // TODO(gw): We don't calculate opacity for borders yet!
|render_tasks| {
let task = RenderTask::new_border_segment(
render_tasks.add().init(RenderTask::new_border_segment(
cache_size,
build_border_instances(
&segment.cache_key,
@ -3033,9 +3030,7 @@ impl PrimitiveStore {
&border_data.border,
scale,
),
);
render_tasks.add(task)
))
}
));
}
@ -3207,15 +3202,13 @@ impl PrimitiveStore {
None,
prim_data.stops_opacity.is_opaque,
|render_tasks| {
let task = RenderTask::new_gradient(
render_tasks.add().init(RenderTask::new_gradient(
size,
stops,
orientation,
start_point,
end_point,
);
render_tasks.add(task)
))
}
));
}
@ -4024,7 +4017,7 @@ impl PrimitiveInstance {
prim_info.clipped_world_rect,
device_pixel_scale,
) {
let clip_task = RenderTask::new_mask(
let clip_task_id = RenderTask::new_mask(
device_rect,
prim_info.clip_chain.clips_range,
root_spatial_node_index,
@ -4036,8 +4029,6 @@ impl PrimitiveInstance {
device_pixel_scale,
frame_context.fb_config,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);
if self.is_chased() {
println!("\tcreated task {:?} with device rect {:?}",
clip_task_id, device_rect);

Просмотреть файл

@ -526,7 +526,7 @@ impl RenderTask {
clip_data_store: &mut ClipDataStore,
device_pixel_scale: DevicePixelScale,
fb_config: &FrameBuilderConfig,
) -> Self {
) -> RenderTaskId {
// Step through the clip sources that make up this mask. If we find
// any box-shadow clip sources, request that image from the render
// task cache. This allows the blurred box-shadow rect to be cached
@ -563,15 +563,13 @@ impl RenderTask {
false,
|render_tasks| {
// Draw the rounded rect.
let mask_task = RenderTask::new_rounded_rect_mask(
let mask_task_id = render_tasks.add().init(RenderTask::new_rounded_rect_mask(
cache_size,
clip_data_address,
source.minimal_shadow_rect.origin,
device_pixel_scale,
fb_config,
);
let mask_task_id = render_tasks.add(mask_task);
));
// Blur it
RenderTask::new_blur(
@ -610,16 +608,18 @@ impl RenderTask {
ClearMode::DontCare
};
RenderTask::with_dynamic_location(
outer_rect.size,
smallvec![],
RenderTaskKind::CacheMask(CacheMaskTask {
actual_rect: outer_rect,
clip_node_range,
root_spatial_node_index,
device_pixel_scale,
}),
clear_mode,
render_tasks.add().init(
RenderTask::with_dynamic_location(
outer_rect.size,
smallvec![],
RenderTaskKind::CacheMask(CacheMaskTask {
actual_rect: outer_rect,
clip_node_range,
root_spatial_node_index,
device_pixel_scale,
}),
clear_mode,
)
)
}
@ -720,13 +720,12 @@ impl RenderTask {
};
downscaling_src_task_id = cached_task.unwrap_or_else(|| {
let downscaling_task = RenderTask::new_scaling(
RenderTask::new_scaling(
downscaling_src_task_id,
render_tasks,
target_kind,
adjusted_blur_target_size,
);
render_tasks.add(downscaling_task)
)
});
if let Some(ref mut cache) = blur_cache {
@ -747,7 +746,7 @@ impl RenderTask {
let blur_region = blur_region / (scale_factor as i32);
let blur_task_id = cached_task.unwrap_or_else(|| {
let blur_task_v = RenderTask::with_dynamic_location(
let blur_task_v = render_tasks.add().init(RenderTask::with_dynamic_location(
adjusted_blur_target_size,
smallvec![downscaling_src_task_id],
RenderTaskKind::VerticalBlur(BlurTask {
@ -758,13 +757,11 @@ impl RenderTask {
uv_rect_kind,
}),
clear_mode,
);
));
let blur_task_v_id = render_tasks.add(blur_task_v);
let blur_task_h = RenderTask::with_dynamic_location(
render_tasks.add().init(RenderTask::with_dynamic_location(
adjusted_blur_target_size,
smallvec![blur_task_v_id],
smallvec![blur_task_v],
RenderTaskKind::HorizontalBlur(BlurTask {
blur_std_deviation: adjusted_blur_std_deviation.width,
target_kind,
@ -773,9 +770,7 @@ impl RenderTask {
uv_rect_kind,
}),
clear_mode,
);
render_tasks.add(blur_task_h)
))
});
if let Some(ref mut cache) = blur_cache {
@ -804,7 +799,7 @@ impl RenderTask {
render_tasks: &mut RenderTaskGraph,
target_kind: RenderTargetKind,
size: DeviceIntSize,
) -> Self {
) -> RenderTaskId {
Self::new_scaling_with_padding(
BlitSource::RenderTask { task_id: src_task_id },
render_tasks,
@ -820,22 +815,24 @@ impl RenderTask {
target_kind: RenderTargetKind,
padded_size: DeviceIntSize,
padding: DeviceIntSideOffsets,
) -> Self {
) -> RenderTaskId {
let (uv_rect_kind, children, image) = match source {
BlitSource::RenderTask { task_id } => (render_tasks[task_id].uv_rect_kind(), smallvec![task_id], None),
BlitSource::Image { key } => (UvRectKind::Rect, smallvec![], Some(key)),
};
RenderTask::with_dynamic_location(
padded_size,
children,
RenderTaskKind::Scaling(ScalingTask {
target_kind,
image,
uv_rect_kind,
padding,
}),
ClearMode::DontCare,
render_tasks.add().init(
RenderTask::with_dynamic_location(
padded_size,
children,
RenderTaskKind::Scaling(ScalingTask {
target_kind,
image,
uv_rect_kind,
padding,
}),
ClearMode::DontCare,
)
)
}
@ -871,22 +868,20 @@ impl RenderTask {
match (input_color_space, color_space) {
(ColorSpace::Srgb, ColorSpace::LinearRgb) => {
let task = RenderTask::new_svg_filter_primitive(
task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::SrgbToLinear,
);
task_id = render_tasks.add(task);
));
},
(ColorSpace::LinearRgb, ColorSpace::Srgb) => {
let task = RenderTask::new_svg_filter_primitive(
task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::LinearToSrgb,
);
task_id = render_tasks.add(task);
));
},
_ => {},
}
@ -930,22 +925,20 @@ impl RenderTask {
primitive.color_space
);
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_1_task_id, input_2_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Blend(blend.mode),
);
render_tasks.add(task)
))
},
FilterPrimitiveKind::Flood(ref flood) => {
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![],
content_size,
uv_rect_kind,
SvgFilterInfo::Flood(flood.color),
);
render_tasks.add(task)
))
}
FilterPrimitiveKind::Blur(ref blur) => {
let blur_std_deviation = blur.radius * device_pixel_scale.0;
@ -959,17 +952,16 @@ impl RenderTask {
primitive.color_space
);
// TODO: This is a hack to ensure that a blur task's input is always in the blur's previous pass.
let svg_task = RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Identity,
);
RenderTask::new_blur(
DeviceSize::new(blur_std_deviation, blur_std_deviation),
render_tasks.add(svg_task),
// TODO: This is a hack to ensure that a blur task's input is always
// in the blur's previous pass.
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Identity,
)),
render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
@ -988,13 +980,12 @@ impl RenderTask {
primitive.color_space
);
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Opacity(opacity.opacity),
);
render_tasks.add(task)
))
}
FilterPrimitiveKind::ColorMatrix(ref color_matrix) => {
let input_task_id = get_task_input(
@ -1007,13 +998,12 @@ impl RenderTask {
primitive.color_space
);
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::ColorMatrix(Box::new(color_matrix.matrix)),
);
render_tasks.add(task)
))
}
FilterPrimitiveKind::DropShadow(ref drop_shadow) => {
let input_task_id = get_task_input(
@ -1029,13 +1019,14 @@ impl RenderTask {
let blur_std_deviation = drop_shadow.shadow.blur_radius * device_pixel_scale.0;
let offset = drop_shadow.shadow.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
let offset_task = RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Offset(offset),
let offset_task_id = render_tasks.add().init(
RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Offset(offset),
)
);
let offset_task_id = render_tasks.add(offset_task);
let blur_task_id = RenderTask::new_blur(
DeviceSize::new(blur_std_deviation, blur_std_deviation),
@ -1047,13 +1038,12 @@ impl RenderTask {
content_size,
);
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id, blur_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::DropShadow(drop_shadow.shadow.color),
);
render_tasks.add(task)
))
}
FilterPrimitiveKind::ComponentTransfer(ref component_transfer) => {
let input_task_id = get_task_input(
@ -1071,13 +1061,12 @@ impl RenderTask {
if filter_data.is_identity() {
input_task_id
} else {
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::ComponentTransfer(filter_data.clone()),
);
render_tasks.add(task)
))
}
}
FilterPrimitiveKind::Offset(ref info) => {
@ -1092,13 +1081,12 @@ impl RenderTask {
);
let offset = info.offset * LayoutToWorldScale::new(1.0) * device_pixel_scale;
let offset_task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Offset(offset),
);
render_tasks.add(offset_task)
))
}
FilterPrimitiveKind::Composite(info) => {
let input_1_task_id = get_task_input(
@ -1120,13 +1108,12 @@ impl RenderTask {
primitive.color_space
);
let task = RenderTask::new_svg_filter_primitive(
render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![input_1_task_id, input_2_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::Composite(info.operator),
);
render_tasks.add(task)
))
}
};
outputs.push(render_task_id);
@ -1137,13 +1124,12 @@ impl RenderTask {
// Convert to sRGB if needed
if filter_primitives.last().unwrap().color_space == ColorSpace::LinearRgb {
let task = RenderTask::new_svg_filter_primitive(
render_task_id = render_tasks.add().init(RenderTask::new_svg_filter_primitive(
smallvec![render_task_id],
content_size,
uv_rect_kind,
SvgFilterInfo::LinearToSrgb,
);
render_task_id = render_tasks.add(task);
));
}
render_task_id
@ -1558,6 +1544,7 @@ impl RenderTask {
}
/// Mark this render task for keeping the results alive up until the end of the frame.
#[inline]
pub fn mark_for_saving(&mut self) {
match self.location {
RenderTaskLocation::Fixed(..) |

Просмотреть файл

@ -11,6 +11,7 @@ use crate::render_target::{RenderTarget, RenderTargetKind, RenderTargetList, Col
use crate::render_target::{PictureCacheTarget, TextureCacheRenderTarget, AlphaRenderTarget};
use crate::render_task::{BlitSource, RenderTask, RenderTaskKind, RenderTaskAddress, RenderTaskData};
use crate::render_task::{RenderTaskLocation};
use crate::util::{VecHelper, Allocation};
use std::{cmp, usize, f32, i32, u32};
#[cfg_attr(feature = "capture", derive(Serialize))]
@ -27,6 +28,28 @@ pub struct RenderTaskGraph {
frame_id: FrameId,
}
/// Allows initializing a render task directly into the render task buffer.
///
/// See utils::VecHelpers. RenderTask is fairly large so avoiding the move when
/// pushing into the vector can save a lot of exensive memcpys on pages with many
/// render tasks.
pub struct RenderTaskAllocation<'a> {
alloc: Allocation<'a, RenderTask>,
#[cfg(debug_assertions)]
frame_id: FrameId,
}
impl<'l> RenderTaskAllocation<'l> {
#[inline(always)]
pub fn init(self, value: RenderTask) -> RenderTaskId {
RenderTaskId {
index: self.alloc.init(value) as u32,
#[cfg(debug_assertions)]
frame_id: self.frame_id,
}
}
}
impl RenderTaskGraph {
pub fn new(frame_id: FrameId, counters: &RenderTaskGraphCounters) -> Self {
// Preallocate a little more than what we needed in the previous frame so that small variations
@ -49,11 +72,9 @@ impl RenderTaskGraph {
}
}
pub fn add(&mut self, task: RenderTask) -> RenderTaskId {
let index = self.tasks.len() as _;
self.tasks.push(task);
RenderTaskId {
index,
pub fn add(&mut self) -> RenderTaskAllocation {
RenderTaskAllocation {
alloc: self.tasks.alloc(),
#[cfg(debug_assertions)]
frame_id: self.frame_id,
}
@ -174,13 +195,13 @@ impl RenderTaskGraph {
passes.reserve(max_depth as usize + 1);
for _ in 0..max_depth {
passes.push(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
passes.alloc().init(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
}
if for_main_framebuffer {
passes.push(RenderPass::new_main_framebuffer(screen_size, gpu_supports_fast_clears));
passes.alloc().init(RenderPass::new_main_framebuffer(screen_size, gpu_supports_fast_clears));
} else {
passes.push(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
passes.alloc().init(RenderPass::new_off_screen(screen_size, gpu_supports_fast_clears));
}
// Assign tasks to their render passes.
@ -315,7 +336,7 @@ impl RenderTaskGraph {
frame_id: self.frame_id,
};
self.tasks.push(blit);
self.tasks.alloc().init(blit);
passes[child_pass_index as usize + 1].tasks.push(blit_id);
@ -715,11 +736,11 @@ fn diamond_task_graph() {
let counters = RenderTaskGraphCounters::new();
let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
let a = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let b1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
let a = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let b1 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
let b2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a]));
let main_pic = tasks.add(RenderTask::new_test(
let main_pic = tasks.add().init(RenderTask::new_test(
color,
RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
smallvec![b1, b2],
@ -752,31 +773,31 @@ fn blur_task_graph() {
let counters = RenderTaskGraphCounters::new();
let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
let pic = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let scale1 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![pic]));
let scale2 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale1]));
let scale3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale2]));
let scale4 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale3]));
let pic = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let scale1 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![pic]));
let scale2 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale1]));
let scale3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale2]));
let scale4 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale3]));
let vblur1 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
let hblur1 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur1]));
let vblur1 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
let hblur1 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur1]));
let vblur2 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
let hblur2 = tasks.add(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur2]));
let vblur2 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![scale4]));
let hblur2 = tasks.add().init(RenderTask::new_test(color, dyn_location(40, 40), smallvec![vblur2]));
// Insert a task that is an even number of passes away from its dependency.
// This means the source and destination are on the same target and we have to resolve
// this conflict by automatically inserting a blit task.
let vblur3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale3]));
let hblur3 = tasks.add(RenderTask::new_test(color, dyn_location(80, 80), smallvec![vblur3]));
let vblur3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![scale3]));
let hblur3 = tasks.add().init(RenderTask::new_test(color, dyn_location(80, 80), smallvec![vblur3]));
// Insert a task that is an odd number > 1 of passes away from its dependency.
// This should force us to mark the dependency "for saving" to keep its content valid
// until the task can access it.
let vblur4 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale2]));
let hblur4 = tasks.add(RenderTask::new_test(color, dyn_location(160, 160), smallvec![vblur4]));
let vblur4 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![scale2]));
let hblur4 = tasks.add().init(RenderTask::new_test(color, dyn_location(160, 160), smallvec![vblur4]));
let main_pic = tasks.add(RenderTask::new_test(
let main_pic = tasks.add().init(RenderTask::new_test(
color,
RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
smallvec![hblur1, hblur2, hblur3, hblur4],
@ -837,14 +858,14 @@ fn culled_tasks() {
let counters = RenderTaskGraphCounters::new();
let mut tasks = RenderTaskGraph::new(FrameId::first(), &counters);
let a1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let _a2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a1]));
let a1 = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let _a2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![a1]));
let b1 = tasks.add(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let b2 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b1]));
let _b3 = tasks.add(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b2]));
let b1 = tasks.add().init(RenderTask::new_test(color, dyn_location(640, 640), SmallVec::new()));
let b2 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b1]));
let _b3 = tasks.add().init(RenderTask::new_test(color, dyn_location(320, 320), smallvec![b2]));
let main_pic = tasks.add(RenderTask::new_test(
let main_pic = tasks.add().init(RenderTask::new_test(
color,
RenderTaskLocation::Fixed(rect(0, 0, 3200, 1800)),
smallvec![b2],