Create Render struct

Separate coarse and fine stages as separate methods of Render struct.
This commit is contained in:
Raph Levien 2023-01-24 17:11:29 -08:00
parent e47c5777cc
commit 17907893af

View file

@ -9,6 +9,34 @@ use crate::{
Scene,
};
/// State for a render in progress.
pub struct Render {
/// Size of binning and info combined buffer in u32 units
binning_info_size: u32,
/// Size of tiles buf in tiles
tiles_size: u32,
/// Size of segments buf in segments
segments_size: u32,
/// Size of per-tile command list in u32 units
ptcl_size: u32,
width_in_tiles: u32,
height_in_tiles: u32,
fine: Option<FineResources>,
}
/// Resources produced by pipeline, needed for fine rasterization.
struct FineResources {
config_buf: ResourceProxy,
bump_buf: ResourceProxy,
tile_buf: ResourceProxy,
segments_buf: ResourceProxy,
ptcl_buf: ResourceProxy,
gradient_image: ResourceProxy,
info_bin_data_buf: ResourceProxy,
out_image: ImageProxy,
}
const TAG_MONOID_SIZE: u64 = 12;
const TAG_MONOID_FULL_SIZE: u64 = 20;
const PATH_BBOX_SIZE: u64 = 24;
@ -157,12 +185,49 @@ pub fn render_full(
render_encoding_full(scene.data(), shaders, width, height)
}
/// Create a single recording with both coarse and fine render stages.
///
/// This function is not recommended when the scene can be complex, as it does not
/// implement robust dynamic memory.
pub fn render_encoding_full(
encoding: &Encoding,
shaders: &FullShaders,
width: u32,
height: u32,
) -> (Recording, ResourceProxy) {
let mut render = Render::new();
let mut recording = render.render_encoding_coarse(encoding, shaders, width, height);
let out_image = render.out_image();
render.record_fine(shaders, &mut recording);
(recording, out_image.into())
}
pub fn align_up(len: usize, alignment: u32) -> usize {
len + (len.wrapping_neg() & (alignment as usize - 1))
}
impl Render {
pub fn new() -> Self {
// These sizes are adequate for paris-30k but should probably be dialed down.
Render {
binning_info_size: (1 << 20) / 4,
tiles_size: (1 << 24) / TILE_SIZE as u32,
segments_size: (1 << 26) / SEGMENT_SIZE as u32,
ptcl_size: (1 << 25) / 4 as u32,
width_in_tiles: 0,
height_in_tiles: 0,
fine: None,
}
}
/// Prepare a recording for the coarse rasterization phase.
pub fn render_encoding_coarse(
&mut self,
encoding: &Encoding,
shaders: &FullShaders,
width: u32,
height: u32,
) -> Recording {
use crate::encoding::{resource::ResourceCache, PackedEncoding};
let mut recording = Recording::default();
let mut resources = ResourceCache::new();
@ -196,10 +261,10 @@ pub fn render_encoding_full(
height_in_tiles: new_height / 16,
target_width: width,
target_height: height,
binning_size: ((1 << 20) / 4) - info_size,
tiles_size: (1 << 24) / TILE_SIZE as u32,
segments_size: (1 << 26) / SEGMENT_SIZE as u32,
ptcl_size: (1 << 25) / 4,
binning_size: self.binning_info_size - info_size,
tiles_size: self.tiles_size,
segments_size: self.segments_size,
ptcl_size: self.ptcl_size,
layout: packed.layout,
};
// println!("{:?}", config);
@ -274,7 +339,8 @@ pub fn render_encoding_full(
recording.free_resource(reduced_scan);
}
let drawobj_wgs = (n_drawobj + shaders::PATH_BBOX_WG - 1) / shaders::PATH_BBOX_WG;
let path_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * PATH_BBOX_SIZE, "path_bbox_buf");
let path_bbox_buf =
ResourceProxy::new_buf(n_paths as u64 * PATH_BBOX_SIZE, "path_bbox_buf");
recording.dispatch(
shaders.bbox_clear,
(drawobj_wgs, 1, 1),
@ -319,7 +385,8 @@ pub fn render_encoding_full(
],
);
recording.free_resource(draw_reduced_buf);
let clip_el_buf = ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_EL_SIZE, "clip_el_buf");
let clip_el_buf =
ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_EL_SIZE, "clip_el_buf");
let clip_bic_buf = ResourceProxy::new_buf(
(n_clip / shaders::CLIP_REDUCE_WG) as u64 * CLIP_BIC_SIZE,
"clip_bic_buf",
@ -358,7 +425,8 @@ pub fn render_encoding_full(
recording.free_resource(clip_inp_buf);
recording.free_resource(clip_bic_buf);
recording.free_resource(clip_el_buf);
let draw_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * DRAW_BBOX_SIZE, "draw_bbox_buf");
let draw_bbox_buf =
ResourceProxy::new_buf(n_paths as u64 * DRAW_BBOX_SIZE, "draw_bbox_buf");
let bump_buf = BufProxy::new(BUMP_SIZE, "bump_buf");
let width_in_bins = (config.width_in_tiles + 15) / 16;
let height_in_bins = (config.height_in_tiles + 15) / 16;
@ -443,31 +511,52 @@ pub fn render_encoding_full(
recording.free_resource(draw_monoid_buf);
recording.free_resource(bin_header_buf);
recording.free_resource(path_buf);
// TODO: bump_buf is special
recording.free_resource(bump_buf);
let out_image = ImageProxy::new(width, height, ImageFormat::Rgba8);
recording.dispatch(
shaders.fine,
(config.width_in_tiles, config.height_in_tiles, 1),
[
self.width_in_tiles = config.width_in_tiles;
self.height_in_tiles = config.height_in_tiles;
self.fine = Some(FineResources {
config_buf,
bump_buf,
tile_buf,
segments_buf,
ResourceProxy::Image(out_image),
ptcl_buf,
gradient_image,
info_bin_data_buf,
],
);
recording.free_resource(config_buf);
recording.free_resource(tile_buf);
recording.free_resource(segments_buf);
recording.free_resource(ptcl_buf);
recording.free_resource(gradient_image);
recording.free_resource(info_bin_data_buf);
(recording, ResourceProxy::Image(out_image))
out_image,
});
recording
}
pub fn align_up(len: usize, alignment: u32) -> usize {
len + (len.wrapping_neg() & (alignment as usize - 1))
/// Run fine rasterization assuming the coarse phase succeeded.
pub fn record_fine(&mut self, shaders: &FullShaders, recording: &mut Recording) {
let fine = self.fine.take().unwrap();
recording.free_resource(fine.bump_buf);
recording.dispatch(
shaders.fine,
(self.width_in_tiles, self.height_in_tiles, 1),
[
fine.config_buf,
fine.tile_buf,
fine.segments_buf,
ResourceProxy::Image(fine.out_image),
fine.ptcl_buf,
fine.gradient_image,
fine.info_bin_data_buf,
],
);
recording.free_resource(fine.config_buf);
recording.free_resource(fine.tile_buf);
recording.free_resource(fine.segments_buf);
recording.free_resource(fine.ptcl_buf);
recording.free_resource(fine.gradient_image);
recording.free_resource(fine.info_bin_data_buf);
}
/// Get the output image.
///
/// This is going away, as the caller will add the output image to the bind
/// map.
pub fn out_image(&self) -> ImageProxy {
self.fine.as_ref().unwrap().out_image
}
}