Skip to content

Commit

Permalink
Merge pull request #400 from linebender/dynamic-aa-setting
Browse files Browse the repository at this point in the history
Support setting AA method dynamically
  • Loading branch information
armansito authored Nov 1, 2023
2 parents ddca7c5 + 876a934 commit 1e7f850
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 84 deletions.
4 changes: 3 additions & 1 deletion examples/headless/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,11 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> {
let queue = &device_handle.queue;
let mut renderer = vello::Renderer::new(
device,
&RendererOptions {
RendererOptions {
surface_format: None,
timestamp_period: queue.get_timestamp_period(),
use_cpu: false,
antialiasing_support: vello::AaSupport::area_only(),
},
)
.or_else(|_| bail!("Got non-Send/Sync error from creating renderer"))?;
Expand Down Expand Up @@ -140,6 +141,7 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> {
.unwrap_or(vello::peniko::Color::BLACK),
width,
height,
antialiasing_method: vello::AaConfig::Area,
};
let mut scene = Scene::new();
let mut builder = SceneBuilder::for_scene(&mut scene);
Expand Down
3 changes: 2 additions & 1 deletion examples/scenes/src/test_scenes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,10 +1246,11 @@ fn splash_screen(sb: &mut SceneBuilder, params: &mut SceneParams) {
" Space: reset transform",
" S: toggle stats",
" V: toggle vsync",
" M: cycle AA method",
" Q, E: rotate",
];
// Tweak to make it fit with tiger
let a = Affine::scale(0.12) * Affine::translate((-90.0, -50.0));
let a = Affine::scale(0.11) * Affine::translate((-90.0, -50.0));
for (i, s) in strings.iter().enumerate() {
let text_size = if i == 0 { 60.0 } else { 40.0 };
params.text.add(
Expand Down
2 changes: 2 additions & 0 deletions examples/with_bevy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl FromWorld for VelloRenderer {
&RendererOptions {
surface_format: None,
timestamp_period: queue.0.get_timestamp_period(),
antialiasing_support: vello::AaSupport::area_only(),
},
)
.unwrap(),
Expand Down Expand Up @@ -65,6 +66,7 @@ fn render_scenes(
base_color: vello::peniko::Color::AQUAMARINE,
width: gpu_image.size.x as u32,
height: gpu_image.size.y as u32,
antialiasing_method: vello::AaConfig::Area,
};
renderer
.0
Expand Down
38 changes: 30 additions & 8 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use vello::util::RenderSurface;
use vello::{
kurbo::{Affine, Vec2},
util::RenderContext,
Renderer, Scene, SceneBuilder,
AaConfig, Renderer, Scene, SceneBuilder,
};
use vello::{BumpAllocators, RendererOptions, SceneFragment};

Expand Down Expand Up @@ -85,10 +85,11 @@ fn run(
renderers[id] = Some(
Renderer::new(
&render_cx.devices[id].device,
&RendererOptions {
RendererOptions {
surface_format: Some(render_state.surface.format),
timestamp_period: render_cx.devices[id].queue.get_timestamp_period(),
use_cpu: use_cpu,
antialiasing_support: vello::AaSupport::all(),
},
)
.expect("Could create renderer"),
Expand All @@ -111,6 +112,11 @@ fn run(
let mut scene_complexity: Option<BumpAllocators> = None;
let mut complexity_shown = false;
let mut vsync_on = true;

const AA_CONFIGS: [AaConfig; 3] = [AaConfig::Area, AaConfig::Msaa8, AaConfig::Msaa16];
// We allow cycling through AA configs in either direction, so use a signed index
let mut aa_config_ix: i32 = 0;

let mut frame_start_time = Instant::now();
let start = Instant::now();

Expand All @@ -130,6 +136,7 @@ fn run(
let mut profile_stored = None;
let mut prev_scene_ix = scene_ix - 1;
let mut profile_taken = Instant::now();
let mut modifiers = ModifiersState::default();
// _event_loop is used on non-wasm platforms to create new windows
event_loop.run(move |event, _event_loop, control_flow| match event {
Event::WindowEvent {
Expand All @@ -144,6 +151,7 @@ fn run(
}
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::ModifiersChanged(m) => modifiers = *m,
WindowEvent::KeyboardInput { input, .. } => {
if input.state == ElementState::Pressed {
match input.virtual_keycode {
Expand Down Expand Up @@ -173,6 +181,13 @@ fn run(
Some(VirtualKeyCode::C) => {
stats.clear_min_and_max();
}
Some(VirtualKeyCode::M) => {
aa_config_ix = if modifiers.shift() {
aa_config_ix.saturating_sub(1)
} else {
aa_config_ix.saturating_add(1)
};
}
Some(VirtualKeyCode::P) => {
if let Some(renderer) = &renderers[render_state.surface.dev_id] {
if let Some(profile_result) = &renderer
Expand Down Expand Up @@ -324,6 +339,8 @@ fn run(

// Allow looping forever
scene_ix = scene_ix.rem_euclid(scenes.scenes.len() as i32);
aa_config_ix = aa_config_ix.rem_euclid(AA_CONFIGS.len() as i32);

let example_scene = &mut scenes.scenes[scene_ix as usize];
if prev_scene_ix != scene_ix {
transform = Affine::IDENTITY;
Expand All @@ -348,14 +365,17 @@ fn run(

// If the user specifies a base color in the CLI we use that. Otherwise we use any
// color specified by the scene. The default is black.
let base_color = args
.args
.base_color
.or(scene_params.base_color)
.unwrap_or(Color::BLACK);
let antialiasing_method = AA_CONFIGS[aa_config_ix as usize];
let render_params = vello::RenderParams {
base_color: args
.args
.base_color
.or(scene_params.base_color)
.unwrap_or(Color::BLACK),
base_color,
width,
height,
antialiasing_method,
};
let mut builder = SceneBuilder::for_scene(&mut scene);
let mut transform = transform;
Expand All @@ -376,6 +396,7 @@ fn run(
stats.samples(),
complexity_shown.then_some(scene_complexity).flatten(),
vsync_on,
antialiasing_method,
);
if let Some(profiling_result) = renderers[render_state.surface.dev_id]
.as_mut()
Expand Down Expand Up @@ -492,12 +513,13 @@ fn run(
eprintln!("Creating renderer {id}");
Renderer::new(
&render_cx.devices[id].device,
&RendererOptions {
RendererOptions {
surface_format: Some(render_state.surface.format),
timestamp_period: render_cx.devices[id]
.queue
.get_timestamp_period(),
use_cpu,
antialiasing_support: vello::AaSupport::all(),
},
)
.expect("Could create renderer")
Expand Down
11 changes: 10 additions & 1 deletion examples/with_winit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::{collections::VecDeque, time::Duration};
use vello::{
kurbo::{Affine, Line, PathEl, Rect, Stroke},
peniko::{Brush, Color, Fill},
BumpAllocators, SceneBuilder,
AaConfig, BumpAllocators, SceneBuilder,
};
use wgpu_profiler::GpuTimerScopeResult;

Expand All @@ -44,6 +44,7 @@ impl Snapshot {
samples: T,
bump: Option<BumpAllocators>,
vsync: bool,
aa_config: AaConfig,
) where
T: Iterator<Item = &'a u64>,
{
Expand All @@ -67,6 +68,14 @@ impl Snapshot {
format!("Frame Time (min): {:.2} ms", self.frame_time_min_ms),
format!("Frame Time (max): {:.2} ms", self.frame_time_max_ms),
format!("VSync: {}", if vsync { "on" } else { "off" }),
format!(
"AA method: {}",
match aa_config {
AaConfig::Area => "Analytic Area",
AaConfig::Msaa16 => "16xMSAA",
AaConfig::Msaa8 => "8xMSAA",
}
),
format!("Resolution: {viewport_width}x{viewport_height}"),
];
if let Some(bump) = &bump {
Expand Down
69 changes: 51 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,43 @@ pub type Error = Box<dyn std::error::Error>;
/// Specialization of `Result` for our catch-all error type.
pub type Result<T> = std::result::Result<T, Error>;

/// Possible configurations for antialiasing.
#[derive(PartialEq, Eq)]
#[allow(unused)]
enum AaConfig {
/// Represents the antialiasing method to use during a render pass.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum AaConfig {
Area,
Msaa8,
Msaa16,
}

/// Configuration of antialiasing. Currently this is static, but could be switched to
/// a launch option or even finer-grained.
const ANTIALIASING: AaConfig = AaConfig::Msaa16;
/// Represents the set of antialiasing configurations to enable during pipeline creation.
pub struct AaSupport {
pub area: bool,
pub msaa8: bool,
pub msaa16: bool,
}

impl AaSupport {
pub fn all() -> Self {
Self {
area: true,
msaa8: true,
msaa16: true,
}
}

pub fn area_only() -> Self {
Self {
area: true,
msaa8: false,
msaa16: false,
}
}
}

/// Renders a scene into a texture or surface.
#[cfg(feature = "wgpu")]
pub struct Renderer {
options: RendererOptions,
engine: WgpuEngine,
shaders: FullShaders,
blit: Option<BlitPipeline>,
Expand All @@ -86,8 +107,6 @@ pub struct Renderer {
profiler: GpuProfiler,
#[cfg(feature = "wgpu-profiler")]
pub profile_result: Option<Vec<wgpu_profiler::GpuTimerScopeResult>>,
#[cfg(feature = "hot_reload")]
use_cpu: bool,
}

/// Parameters used in a single render that are configurable by the client.
Expand All @@ -99,40 +118,54 @@ pub struct RenderParams {
/// Dimensions of the rasterization target
pub width: u32,
pub height: u32,

/// The anti-aliasing algorithm. The selected algorithm must have been initialized while
/// constructing the `Renderer`.
pub antialiasing_method: AaConfig,
}

#[cfg(feature = "wgpu")]
pub struct RendererOptions {
/// The format of the texture used for surfaces with this renderer/device
/// If None, the renderer cannot be used with surfaces
pub surface_format: Option<TextureFormat>,

/// The timestamp period from [`wgpu::Queue::get_timestamp_period`]
/// Used when the wgpu-profiler feature is enabled
pub timestamp_period: f32,

/// If true, run all stages up to fine rasterization on the CPU.
// TODO: Consider evolving this so that the CPU stages can be configured dynamically via
// `RenderParams`.
pub use_cpu: bool,

/// Represents the enabled set of AA configurations. This will be used to determine which
/// pipeline permutations should be compiled at startup.
pub antialiasing_support: AaSupport,
}

#[cfg(feature = "wgpu")]
impl Renderer {
/// Creates a new renderer for the specified device.
pub fn new(device: &Device, render_options: &RendererOptions) -> Result<Self> {
let mut engine = WgpuEngine::new(render_options.use_cpu);
let shaders = shaders::full_shaders(device, &mut engine)?;
let blit = render_options
pub fn new(device: &Device, options: RendererOptions) -> Result<Self> {
let mut engine = WgpuEngine::new(options.use_cpu);
let shaders = shaders::full_shaders(device, &mut engine, &options)?;
let blit = options
.surface_format
.map(|surface_format| BlitPipeline::new(device, surface_format));
#[cfg(feature = "wgpu-profiler")]
let timestamp_period = options.timestamp_period;
Ok(Self {
options,
engine,
shaders,
blit,
target: None,
// Use 3 pending frames
#[cfg(feature = "wgpu-profiler")]
profiler: GpuProfiler::new(3, render_options.timestamp_period, device.features()),
profiler: GpuProfiler::new(3, timestamp_period, device.features()),
#[cfg(feature = "wgpu-profiler")]
profile_result: None,
#[cfg(feature = "hot_reload")]
use_cpu: render_options.use_cpu,
})
}

Expand Down Expand Up @@ -237,8 +270,8 @@ impl Renderer {
#[cfg(feature = "hot_reload")]
pub async fn reload_shaders(&mut self, device: &Device) -> Result<()> {
device.push_error_scope(wgpu::ErrorFilter::Validation);
let mut engine = WgpuEngine::new(self.use_cpu);
let shaders = shaders::full_shaders(device, &mut engine)?;
let mut engine = WgpuEngine::new(self.options.use_cpu);
let shaders = shaders::full_shaders(device, &mut engine, &self.options)?;
let error = device.pop_error_scope().await;
if let Some(error) = error {
return Err(error.into());
Expand Down
Loading

0 comments on commit 1e7f850

Please sign in to comment.