Making bevy_render an optional dependency for bevy_gizmos (#14448)

# Objective

This PR makes `bevy_render` an optional dependency for `bevy_gizmos`,
thereby allowing `bevy_gizmos` to be used with alternative rendering
backend.

Previously `bevy_gizmos` assumes that one of `bevy_pbr` or `bevy_sprite`
will be enabled. Here we introduced a new feature named `bevy_render`
which disables all rendering-related code paths. An alternative renderer
will then take the `LineGizmo` assets (made public in this PR) and issue
draw calls on their own. A new field `config_ty` was added to
`LineGizmo` to help looking up the related configuration info.

---

## Migration Guide
No user-visible changes needed from the users.
This commit is contained in:
Zhixing Zhang 2024-08-06 07:09:10 -06:00 committed by GitHub
parent e85c072372
commit 5fd0661c15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 103 additions and 67 deletions

View file

@ -91,6 +91,10 @@ impl AssetProcessor {
Self { server, data }
}
pub fn data(&self) -> &Arc<AssetProcessorData> {
&self.data
}
/// The "internal" [`AssetServer`] used by the [`AssetProcessor`]. This is _separate_ from the asset processor used by
/// the main App. It has different processor-specific configuration and a different ID space.
pub fn server(&self) -> &AssetServer {

View file

@ -11,6 +11,7 @@ keywords = ["bevy"]
[features]
webgl = []
webgpu = []
bevy_render = ["dep:bevy_render", "bevy_core_pipeline"]
[dependencies]
# Bevy
@ -21,10 +22,10 @@ bevy_color = { path = "../bevy_color", version = "0.15.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.15.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.15.0-dev", optional = true }
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.15.0-dev", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.15.0-dev" }
bevy_gizmos_macros = { path = "macros", version = "0.15.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.15.0-dev" }

View file

@ -5,7 +5,6 @@ pub use bevy_gizmos_macros::GizmoConfigGroup;
use bevy_ecs::{component::Component, reflect::ReflectResource, system::Resource};
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
use bevy_render::view::RenderLayers;
use bevy_utils::TypeIdMap;
use core::panic;
use std::{
@ -164,7 +163,8 @@ pub struct GizmoConfig {
/// Describes which rendering layers gizmos will be rendered to.
///
/// Gizmos will only be rendered to cameras with intersecting layers.
pub render_layers: RenderLayers,
#[cfg(feature = "bevy_render")]
pub render_layers: bevy_render::view::RenderLayers,
/// Describe how lines should join
pub line_joints: GizmoLineJoint,
@ -178,6 +178,7 @@ impl Default for GizmoConfig {
line_perspective: false,
line_style: GizmoLineStyle::Solid,
depth_bias: 0.,
#[cfg(feature = "bevy_render")]
render_layers: Default::default(),
line_joints: GizmoLineJoint::None,
@ -185,13 +186,15 @@ impl Default for GizmoConfig {
}
}
#[cfg(feature = "bevy_render")]
#[derive(Component)]
pub(crate) struct GizmoMeshConfig {
pub line_perspective: bool,
pub line_style: GizmoLineStyle,
pub render_layers: RenderLayers,
pub render_layers: bevy_render::view::RenderLayers,
}
#[cfg(feature = "bevy_render")]
impl From<&GizmoConfig> for GizmoMeshConfig {
fn from(item: &GizmoConfig) -> Self {
GizmoMeshConfig {

View file

@ -31,6 +31,7 @@ pub enum GizmoRenderSystem {
QueueLineGizmos3d,
}
#[cfg(feature = "bevy_render")]
pub mod aabb;
pub mod arcs;
pub mod arrows;
@ -42,19 +43,20 @@ pub mod grid;
pub mod primitives;
pub mod rounded_box;
#[cfg(feature = "bevy_pbr")]
#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
pub mod light;
#[cfg(feature = "bevy_sprite")]
#[cfg(all(feature = "bevy_sprite", feature = "bevy_render"))]
mod pipeline_2d;
#[cfg(feature = "bevy_pbr")]
#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
mod pipeline_3d;
/// The `bevy_gizmos` prelude.
pub mod prelude {
#[cfg(feature = "bevy_render")]
pub use crate::aabb::{AabbGizmoConfigGroup, ShowAabbGizmo};
#[doc(hidden)]
pub use crate::{
aabb::{AabbGizmoConfigGroup, ShowAabbGizmo},
config::{
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore,
GizmoLineJoint, GizmoLineStyle,
@ -64,13 +66,12 @@ pub mod prelude {
AppGizmoBuilder,
};
#[cfg(feature = "bevy_pbr")]
#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))]
pub use crate::light::{LightGizmoColor, LightGizmoConfigGroup, ShowLightGizmo};
}
use aabb::AabbGizmoPlugin;
use bevy_app::{App, FixedFirst, FixedLast, Last, Plugin, RunFixedMainLoop};
use bevy_asset::{load_internal_asset, Asset, AssetApp, Assets, Handle};
use bevy_asset::{Asset, AssetApp, Assets, Handle};
use bevy_color::LinearRgba;
use bevy_ecs::{
component::Component,
@ -83,6 +84,7 @@ use bevy_ecs::{
};
use bevy_math::Vec3;
use bevy_reflect::TypePath;
#[cfg(feature = "bevy_render")]
use bevy_render::{
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
@ -100,14 +102,15 @@ use bevy_utils::TypeIdMap;
use bytemuck::cast_slice;
use config::{
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoLineJoint,
GizmoMeshConfig,
};
use gizmos::{GizmoStorage, Swap};
#[cfg(feature = "bevy_pbr")]
use light::LightGizmoPlugin;
use std::{any::TypeId, mem};
#[cfg(feature = "bevy_render")]
const LINE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(7414812689238026784);
#[cfg(feature = "bevy_render")]
const LINE_JOINT_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(1162780797909187908);
/// A [`Plugin`] that provides an immediate mode drawing api for visual debugging.
@ -118,58 +121,60 @@ pub struct GizmoPlugin;
impl Plugin for GizmoPlugin {
fn build(&self, app: &mut bevy_app::App) {
// Gizmos cannot work without either a 3D or 2D renderer.
#[cfg(all(not(feature = "bevy_pbr"), not(feature = "bevy_sprite")))]
bevy_utils::tracing::error!(
"bevy_gizmos requires either bevy_pbr or bevy_sprite. Please enable one."
);
load_internal_asset!(app, LINE_SHADER_HANDLE, "lines.wgsl", Shader::from_wgsl);
load_internal_asset!(
app,
LINE_JOINT_SHADER_HANDLE,
"line_joints.wgsl",
Shader::from_wgsl
);
#[cfg(feature = "bevy_render")]
{
use bevy_asset::load_internal_asset;
load_internal_asset!(app, LINE_SHADER_HANDLE, "lines.wgsl", Shader::from_wgsl);
load_internal_asset!(
app,
LINE_JOINT_SHADER_HANDLE,
"line_joints.wgsl",
Shader::from_wgsl
);
}
app.register_type::<GizmoConfig>()
.register_type::<GizmoConfigStore>()
.add_plugins(UniformComponentPlugin::<LineGizmoUniform>::default())
.init_asset::<LineGizmo>()
.add_plugins(RenderAssetPlugin::<GpuLineGizmo>::default())
.init_resource::<LineGizmoHandles>()
// We insert the Resource GizmoConfigStore into the world implicitly here if it does not exist.
.init_gizmo_group::<DefaultGizmoConfigGroup>()
.add_plugins(AabbGizmoPlugin);
.init_gizmo_group::<DefaultGizmoConfigGroup>();
#[cfg(feature = "bevy_render")]
app.add_plugins(aabb::AabbGizmoPlugin)
.add_plugins(UniformComponentPlugin::<LineGizmoUniform>::default())
.add_plugins(RenderAssetPlugin::<GpuLineGizmo>::default());
#[cfg(feature = "bevy_pbr")]
app.add_plugins(LightGizmoPlugin);
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
#[cfg(feature = "bevy_render")]
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.add_systems(
Render,
prepare_line_gizmo_bind_group.in_set(RenderSet::PrepareBindGroups),
);
render_app.add_systems(
Render,
prepare_line_gizmo_bind_group.in_set(RenderSet::PrepareBindGroups),
);
render_app.add_systems(ExtractSchedule, extract_gizmo_data);
render_app.add_systems(ExtractSchedule, extract_gizmo_data);
#[cfg(feature = "bevy_sprite")]
if app.is_plugin_added::<bevy_sprite::SpritePlugin>() {
app.add_plugins(pipeline_2d::LineGizmo2dPlugin);
#[cfg(feature = "bevy_sprite")]
if app.is_plugin_added::<bevy_sprite::SpritePlugin>() {
app.add_plugins(pipeline_2d::LineGizmo2dPlugin);
} else {
bevy_utils::tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?");
}
#[cfg(feature = "bevy_pbr")]
if app.is_plugin_added::<bevy_pbr::PbrPlugin>() {
app.add_plugins(pipeline_3d::LineGizmo3dPlugin);
} else {
bevy_utils::tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?");
}
} else {
bevy_utils::tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?");
}
#[cfg(feature = "bevy_pbr")]
if app.is_plugin_added::<bevy_pbr::PbrPlugin>() {
app.add_plugins(pipeline_3d::LineGizmo3dPlugin);
} else {
bevy_utils::tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?");
bevy_utils::tracing::warn!("bevy_render feature is enabled but RenderApp was not detected. Are you sure you loaded GizmoPlugin after RenderPlugin?");
}
}
#[cfg(feature = "bevy_render")]
fn finish(&self, app: &mut bevy_app::App) {
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
@ -361,14 +366,14 @@ fn update_gizmo_meshes<Config: GizmoConfigGroup>(
list.positions = mem::take(&mut storage.list_positions);
list.colors = mem::take(&mut storage.list_colors);
} else {
let mut list = LineGizmo {
let list = LineGizmo {
strip: false,
..Default::default()
config_ty: TypeId::of::<Config>(),
positions: mem::take(&mut storage.list_positions),
colors: mem::take(&mut storage.list_colors),
joints: GizmoLineJoint::None,
};
list.positions = mem::take(&mut storage.list_positions);
list.colors = mem::take(&mut storage.list_colors);
*handle = Some(line_gizmos.add(list));
}
}
@ -384,20 +389,20 @@ fn update_gizmo_meshes<Config: GizmoConfigGroup>(
strip.colors = mem::take(&mut storage.strip_colors);
strip.joints = config.line_joints;
} else {
let mut strip = LineGizmo {
let strip = LineGizmo {
strip: true,
joints: config.line_joints,
..Default::default()
config_ty: TypeId::of::<Config>(),
positions: mem::take(&mut storage.strip_positions),
colors: mem::take(&mut storage.strip_colors),
};
strip.positions = mem::take(&mut storage.strip_positions);
strip.colors = mem::take(&mut storage.strip_colors);
*handle = Some(line_gizmos.add(strip));
}
}
}
#[cfg(feature = "bevy_render")]
fn extract_gizmo_data(
mut commands: Commands,
handles: Extract<Res<LineGizmoHandles>>,
@ -431,11 +436,12 @@ fn extract_gizmo_data(
_padding: Default::default(),
},
(*handle).clone_weak(),
GizmoMeshConfig::from(config),
config::GizmoMeshConfig::from(config),
));
}
}
#[cfg(feature = "bevy_render")]
#[derive(Component, ShaderType, Clone, Copy)]
struct LineGizmoUniform {
line_width: f32,
@ -447,16 +453,22 @@ struct LineGizmoUniform {
_padding: f32,
}
#[derive(Asset, Debug, Default, Clone, TypePath)]
struct LineGizmo {
positions: Vec<Vec3>,
colors: Vec<LinearRgba>,
/// A gizmo asset that represents a line.
#[derive(Asset, Debug, Clone, TypePath)]
pub struct LineGizmo {
/// Positions of the gizmo's vertices
pub positions: Vec<Vec3>,
/// Colors of the gizmo's vertices
pub colors: Vec<LinearRgba>,
/// Whether this gizmo's topology is a line-strip or line-list
strip: bool,
pub strip: bool,
/// Whether this gizmo should draw line joints. This is only applicable if the gizmo's topology is line-strip.
joints: GizmoLineJoint,
pub joints: GizmoLineJoint,
/// The type of the gizmo's configuration group
pub config_ty: TypeId,
}
#[cfg(feature = "bevy_render")]
#[derive(Debug, Clone)]
struct GpuLineGizmo {
position_buffer: Buffer,
@ -466,6 +478,7 @@ struct GpuLineGizmo {
joints: GizmoLineJoint,
}
#[cfg(feature = "bevy_render")]
impl RenderAsset for GpuLineGizmo {
type SourceAsset = LineGizmo;
type Param = SRes<RenderDevice>;
@ -498,16 +511,19 @@ impl RenderAsset for GpuLineGizmo {
}
}
#[cfg(feature = "bevy_render")]
#[derive(Resource)]
struct LineGizmoUniformBindgroupLayout {
layout: BindGroupLayout,
}
#[cfg(feature = "bevy_render")]
#[derive(Resource)]
struct LineGizmoUniformBindgroup {
bindgroup: BindGroup,
}
#[cfg(feature = "bevy_render")]
fn prepare_line_gizmo_bind_group(
mut commands: Commands,
line_gizmo_uniform_layout: Res<LineGizmoUniformBindgroupLayout>,
@ -525,7 +541,9 @@ fn prepare_line_gizmo_bind_group(
}
}
#[cfg(feature = "bevy_render")]
struct SetLineGizmoBindGroup<const I: usize>;
#[cfg(feature = "bevy_render")]
impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I> {
type Param = SRes<LineGizmoUniformBindgroup>;
type ViewQuery = ();
@ -551,7 +569,9 @@ impl<const I: usize, P: PhaseItem> RenderCommand<P> for SetLineGizmoBindGroup<I>
}
}
#[cfg(feature = "bevy_render")]
struct DrawLineGizmo;
#[cfg(feature = "bevy_render")]
impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
type Param = SRes<RenderAssets<GpuLineGizmo>>;
type ViewQuery = ();
@ -597,7 +617,9 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineGizmo {
}
}
#[cfg(feature = "bevy_render")]
struct DrawLineJointGizmo;
#[cfg(feature = "bevy_render")]
impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
type Param = SRes<RenderAssets<GpuLineGizmo>>;
type ViewQuery = ();
@ -649,6 +671,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawLineJointGizmo {
}
}
#[cfg(feature = "bevy_render")]
fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec<VertexBufferLayout> {
use VertexFormat::*;
let mut position_layout = VertexBufferLayout {
@ -705,6 +728,7 @@ fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec<VertexBufferLayout> {
}
}
#[cfg(feature = "bevy_render")]
fn line_joint_gizmo_vertex_buffer_layouts() -> Vec<VertexBufferLayout> {
use VertexFormat::*;
let mut position_layout = VertexBufferLayout {

View file

@ -152,7 +152,11 @@ accesskit_unix = ["bevy_winit/accesskit_unix"]
bevy_text = ["dep:bevy_text", "bevy_ui?/bevy_text"]
bevy_render = ["dep:bevy_render", "bevy_scene?/bevy_render"]
bevy_render = [
"dep:bevy_render",
"bevy_scene?/bevy_render",
"bevy_gizmos?/bevy_render",
]
# Enable assertions to check the validity of parameters passed to glam
glam_assert = ["bevy_math/glam_assert"]