Skip to content

Commit

Permalink
refactor: core pipeline changes (#73)
Browse files Browse the repository at this point in the history
Addresses some friction where the `VelloRenderer` was not a resource and
required Locals temporarily. This was mainly observed in the `cube3d`
example. Likewise, the rendering params such as `use_cpu` and
`antialiasing` were not configurable and the use of `RenderLayers` were
cleaned up after @ChristopherBiscardi brought up some comments after
#71.

@ChristopherBiscardi Please let me know if you still have concerns with
RenderLayers.
  • Loading branch information
simbleau committed Aug 4, 2024
1 parent f21cdc2 commit e801777
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 136 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe
- There is now a `default_font` feature that uses the same `FiraMono-subset.ttf` font used in the bevy/default_font feature.
- There is now a `render_layers` example.
- There is now a `cube_3d` example.
- You may now choose the render layers for the Vello canvas. This can be configured through the `VelloPlugin`.
- You may now choose to use CPU rendering with Vello and configure anti-aliasing. This can be configured through the `VelloPlugin`.

### Changed

- `VelloPlugin` now has configuration. To retain previous behavior, use `VelloPlugin::default()`.
- `VelloRenderer` is now a resource.
- The `VelloRenderer` will attempt CPU fallback if it cannot obtain a GPU.
- The font API has changed significantly. Please visit `examples/text` for further usage. This is to prepare for additional text features such as linebreak behavior, bounded text, and text justification.
- `VelloText` has been renamed to `VelloTextSection`.
- `VelloText.content` has been renamed to `VelloText.value`.
Expand All @@ -27,11 +31,13 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe
- The field `VelloAssetBundle.vector` was renamed to `VelloAssetBundle.asset`.
- Renamed `VelloAssetAlignment` to `VelloAssetAnchor`. Fields were renamed `alignment` were renamed to `asset_anchor`.
- Renamed `VelloTextAlignment` to `VelloTextAnchor`. Fields were renamed `alignment` were renamed to `text_anchor`.
- The `SSRenderTarget` (fullscreen quad that renders your frame) no longer renders at a zepth of `-0.001`. This was a legacy hack used to ensure Gizmos rendered on-top.
- The `SSRenderTarget` (fullscreen quad that renders your frame) no longer renders at a zepth of `-0.001`. This was a legacy hack used to ensure Gizmos rendered on-top. `RenderLayers` should be used now (there's an example).

### Removed

- Removed `ZFunction`s from the render pipeline. Now ordering is based solely on the `Transform`'s z component. If you dependeded on this behavior, you'll need to adjust the transform Z in a system prior to render.
- `VelloRenderPlugin` is now private, as it is not helpful for downstream developers to add manually.
- Removed `VelloCanvasMaterial` from prelude, as it is not typical to use.

### Fixed

Expand Down
15 changes: 10 additions & 5 deletions examples/cube3d/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ fn main() {
let mut app = App::new();

app.add_plugins(DefaultPlugins)
.add_plugins(VelloPlugin::default())
.add_plugins(VelloPlugin {
use_cpu: false,
antialiasing: vello::AaConfig::Msaa8,
..default()
})
.add_systems(Startup, setup)
.add_systems(Update, cube_rotator_system)
.add_plugins(ExtractComponentPlugin::<VelloTarget>::default());
Expand Down Expand Up @@ -115,15 +119,14 @@ fn setup(
}

fn render_texture(
mut vello_renderer: Local<Option<VelloRenderer>>,
renderer: Res<VelloRenderer>,
render_settings: Res<VelloRenderSettings>,
target: Query<&VelloTarget>,
device: Res<RenderDevice>,
gpu_images: Res<RenderAssets<GpuImage>>,
queue: Res<RenderQueue>,
time: Res<Time>,
) {
let renderer =
vello_renderer.get_or_insert_with(|| VelloRenderer::from_device(device.wgpu_device()));
let target = target.single();

let mut scene = VelloScene::default();
Expand All @@ -147,9 +150,11 @@ fn render_texture(
base_color: vello::peniko::Color::WHITE,
width: gpu_image.size.x,
height: gpu_image.size.y,
antialiasing_method: vello::AaConfig::Area,
antialiasing_method: render_settings.antialiasing,
};
renderer
.lock()
.unwrap()
.render_to_texture(
device.wgpu_device(),
&queue,
Expand Down
48 changes: 12 additions & 36 deletions examples/render_layers/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@ use bevy_vello::{prelude::*, VelloPlugin};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(VelloPlugin::default())
.add_systems(
Startup,
(
setup_canvas,
setup_gizmos,
setup_animation,
setup_background,
),
)
.add_plugins(VelloPlugin {
canvas_render_layers: RenderLayers::layer(1).with(2),
..default()
})
.add_systems(Startup, (setup_gizmos, setup_scene))
.add_systems(Update, (animation, background, run_gizmos))
.run();
}
Expand All @@ -28,11 +23,6 @@ struct AnimationScene;
#[derive(Component)]
struct BackgroundScene;

fn setup_canvas(mut settings: ResMut<VelloRenderSettings>) {
// There's only 1 Vello canvas, so as long as you use a layer that has a camera, you're good!
settings.canvas_render_layers = RenderLayers::layer(3); // the gizmo camera layer
}

fn setup_gizmos(mut commands: Commands, mut config_store: ResMut<GizmoConfigStore>) {
// This camera can only see Gizmos.
commands.spawn((
Expand All @@ -50,42 +40,28 @@ fn setup_gizmos(mut commands: Commands, mut config_store: ResMut<GizmoConfigStor
config.render_layers = RenderLayers::layer(3);
}

fn setup_animation(mut commands: Commands) {
fn setup_scene(mut commands: Commands) {
commands.spawn((
Camera2dBundle {
camera: Camera {
// This camera will render AFTER the blue background camera!
order: 0,
// This camera will render first.
order: -1,
..default()
},
..default()
},
RenderLayers::layer(2),
RenderLayers::layer(1).with(2),
));

commands.spawn((
VelloSceneBundle::default(),
AnimationScene,
RenderLayers::layer(2),
));
}

fn setup_background(mut commands: Commands) {
commands.spawn((
Camera2dBundle {
camera: Camera {
// Render first
order: -1,
..default()
},
..default()
},
BackgroundScene,
RenderLayers::layer(1),
));
commands.spawn((
VelloSceneBundle::default(),
BackgroundScene,
RenderLayers::layer(1),
AnimationScene,
RenderLayers::layer(2),
));
}

Expand Down
18 changes: 2 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub mod prelude {
pub use crate::{
debug::DebugVisualizations,
integrations::{VectorFile, VelloAsset, VelloAssetAnchor},
render::{VelloCanvasMaterial, VelloRenderSettings},
render::VelloRenderSettings,
text::{VelloFont, VelloTextAnchor, VelloTextSection, VelloTextStyle},
CoordinateSpace, VelloAssetBundle, VelloScene, VelloSceneBundle, VelloTextBundle,
};
Expand Down Expand Up @@ -113,23 +113,9 @@ pub struct VelloTextBundle {
}

/// A simple newtype component wrapper for [`vello::Scene`] for rendering.
#[derive(Component, Default, Clone)]
#[derive(Component, Default, Clone, Deref, DerefMut)]
pub struct VelloScene(vello::Scene);

impl std::ops::Deref for VelloScene {
type Target = vello::Scene;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl std::ops::DerefMut for VelloScene {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl VelloScene {
pub fn new() -> Self {
Self::default()
Expand Down
51 changes: 39 additions & 12 deletions src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
use crate::{
debug::DebugVisualizationsPlugin, render::VelloRenderPlugin, text::VelloFontLoader, VelloAsset,
VelloFont, VelloRenderSettings,
debug::DebugVisualizationsPlugin,
render::{VelloCanvasSettings, VelloRenderPlugin},
text::VelloFontLoader,
VelloAsset, VelloFont, VelloRenderSettings,
};
use bevy::{asset::load_internal_binary_asset, prelude::*, render::view::RenderLayers};
use vello::AaConfig;

#[derive(Resource, Default, Debug)]
#[derive(Clone)]
pub struct VelloPlugin {
/// The render layers that will be used for the Vello canvas mesh.
pub canvas_render_layers: RenderLayers,

/// Use CPU instead of GPU
pub use_cpu: bool,

/// Which antialiasing strategy to use
pub antialiasing: AaConfig,
}

impl Default for VelloPlugin {
fn default() -> Self {
let default_canvas_settings = VelloCanvasSettings::default();
let default_render_settings = VelloRenderSettings::default();
Self {
canvas_render_layers: default_canvas_settings.render_layers,
use_cpu: default_render_settings.use_cpu,
antialiasing: default_render_settings.antialiasing,
}
}
}

impl Plugin for VelloPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(VelloRenderPlugin)
.insert_resource(VelloRenderSettings {
canvas_render_layers: self.canvas_render_layers.clone(),
})
.add_plugins(DebugVisualizationsPlugin)
.init_asset::<VelloAsset>()
.init_asset::<VelloFont>()
.init_asset_loader::<VelloFontLoader>();
app.add_plugins(VelloRenderPlugin {
canvas_settings: VelloCanvasSettings {
render_layers: self.canvas_render_layers.clone(),
},
render_settings: VelloRenderSettings {
use_cpu: self.use_cpu,
antialiasing: self.antialiasing,
},
})
.add_plugins(DebugVisualizationsPlugin)
.init_asset::<VelloAsset>()
.init_asset::<VelloFont>()
.init_asset_loader::<VelloFontLoader>();
#[cfg(feature = "svg")]
app.add_plugins(crate::integrations::svg::SvgIntegrationPlugin);
#[cfg(feature = "lottie")]
Expand All @@ -29,7 +56,7 @@ impl Plugin for VelloPlugin {
load_internal_binary_asset!(
app,
Handle::default(),
"text/FiraMono-subset.ttf",
"text/FiraMono/FiraMono-subset.ttf",
|bytes: &[u8], _path: String| { VelloFont::new(bytes.to_vec()) }
);
}
Expand Down
81 changes: 70 additions & 11 deletions src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ use bevy::{
AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError,
VertexBufferLayout, VertexFormat, VertexStepMode,
},
renderer::RenderDevice,
view::RenderLayers,
},
sprite::{Material2d, Material2dKey},
};
use std::sync::{Arc, Mutex};
use vello::{AaConfig, AaSupport};

mod extract;
mod plugin;
mod prepare;
mod systems;

pub use plugin::VelloRenderPlugin;
pub use plugin::VelloRenderSettings;
pub(crate) use plugin::VelloRenderPlugin;

/// A handle to the screen space render target shader.
pub const SSRT_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(2314894693238056781);
Expand Down Expand Up @@ -60,26 +63,82 @@ impl Material2d for VelloCanvasMaterial {
}
}

#[derive(Deref, DerefMut)]
pub struct VelloRenderer(vello::Renderer);
#[derive(Resource, Deref, DerefMut)]
pub struct VelloRenderer(Arc<Mutex<vello::Renderer>>);

impl VelloRenderer {
pub fn from_device(device: &vello::wgpu::Device) -> Self {
let renderer = vello::Renderer::new(
pub fn try_new(
device: &vello::wgpu::Device,
settings: &VelloRenderSettings,
) -> Result<Self, vello::Error> {
vello::Renderer::new(
device,
vello::RendererOptions {
surface_format: None,
use_cpu: false,
antialiasing_support: vello::AaSupport::area_only(),
use_cpu: settings.use_cpu,
// TODO: Vello doesn't currently allow adding additional AA support after initialization, so we need to use all support modes here instead.
antialiasing_support: AaSupport::all(),
num_init_threads: None,
},
)
// TODO: Attempt CPU fallback. Support changing antialias settings.
.expect("No GPU Device");
VelloRenderer(renderer)
.map(Mutex::new)
.map(Arc::new)
.map(VelloRenderer)
}
}

impl FromWorld for VelloRenderer {
fn from_world(world: &mut World) -> Self {
match VelloRenderer::try_new(
world.get_resource::<RenderDevice>().unwrap().wgpu_device(),
world.get_resource::<VelloRenderSettings>().unwrap(),
) {
Ok(r) => r,
Err(e) => {
error!("Attempting safe-mode fallback, failed to initialize renderer: {e:}");
{
let mut settings = world.get_resource_mut::<VelloRenderSettings>().unwrap();
settings.use_cpu = true;
settings.antialiasing = AaConfig::Area;
}
match VelloRenderer::try_new(
world.get_resource::<RenderDevice>().unwrap().wgpu_device(),
world.get_resource::<VelloRenderSettings>().unwrap(),
) {
Ok(r) => r,
Err(e) => panic!("Failed to start vello: {e}"),
}
}
}
}
}

#[derive(Resource, Deref, DerefMut, Default)]
#[cfg(feature = "lottie")]
pub struct VelatoRenderer(velato::Renderer);

/// Render settings for Vello.
#[derive(Resource, Clone)]
pub struct VelloRenderSettings {
/// Use CPU instead of GPU
pub use_cpu: bool,

/// Which antialiasing strategy to use
pub antialiasing: AaConfig,
}

impl Default for VelloRenderSettings {
fn default() -> Self {
Self {
use_cpu: false,
antialiasing: AaConfig::Area,
}
}
}

/// Canvas settings for Vello.
#[derive(Resource, Clone, Debug, Default, PartialEq)]
pub(crate) struct VelloCanvasSettings {
/// The render layers that will be used for the Vello canvas mesh.
pub render_layers: RenderLayers,
}
Loading

0 comments on commit e801777

Please sign in to comment.