Add even more documentation and comments

This commit is contained in:
Patrick Walton 2024-11-19 11:13:28 -08:00
parent 07ba73b76f
commit 79d726699e
7 changed files with 52 additions and 3 deletions

View file

@ -394,6 +394,8 @@ pub struct MaterialPipeline<M: Material> {
pub material_layout: BindGroupLayout,
pub vertex_shader: Option<Handle<Shader>>,
pub fragment_shader: Option<Handle<Shader>>,
/// Whether this material *actually* uses bindless resources, taking the
/// platform support (or lack thereof) of bindless resources into account.
pub bindless: bool,
pub marker: PhantomData<M>,
}
@ -596,6 +598,7 @@ fn extract_mesh_materials<M: Material>(
if view_visibility.get() {
material_instances.insert(entity.into(), material.id());
// Allocate a slot for this material in the bind group.
let material_id = material.id().untyped();
material_ids
.mesh_to_material

View file

@ -484,7 +484,11 @@ where
}
}
/// Returns true if the material uses bindless resources or false if it doesn't.
/// Returns true if the material will *actually* use bindless resources or false
/// if it won't.
///
/// This takes the platform support (or lack thereof) for bindless resources
/// into account.
pub fn material_uses_bindless_resources<M>(render_device: &RenderDevice) -> bool
where
M: Material,

View file

@ -52,6 +52,9 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
let mut attr_prepared_data_ident = None;
let mut attr_bindless_count = None;
// `actual_bindless_slot_count` holds the actual number of bindless slots
// per bind group, taking into account whether the current platform supports
// bindless resources.
let actual_bindless_slot_count = Ident::new("actual_bindless_slot_count", Span::call_site());
// Read struct-level attributes
@ -427,6 +430,9 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
let struct_name_literal = struct_name_literal.as_str();
let mut field_struct_impls = Vec::new();
// The `BufferBindingType` and corresponding `BufferUsages` used for
// uniforms. We need this because bindless uniforms don't exist, so in
// bindless mode we must promote uniforms to storage buffers.
let uniform_binding_type = Ident::new("uniform_binding_type", Span::call_site());
let uniform_buffer_usages = Ident::new("uniform_buffer_usages", Span::call_site());
@ -556,6 +562,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
(prepared_data.clone(), prepared_data)
};
// Calculate the actual number of bindless slots, taking hardware
// limitations into account.
let (bindless_slot_count, actual_bindless_slot_count_declaration) = match attr_bindless_count {
Some(bindless_count) => (
quote! { const BINDLESS_SLOT_COUNT: Option<u32> = Some(#bindless_count); },

View file

@ -26,6 +26,7 @@ pub enum PrepareAssetError<E: Send + Sync + 'static> {
AsBindGroupError(AsBindGroupError),
}
/// The system set during which we extract modified assets to the render world.
#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
pub struct ExtractAssetsSet;
@ -68,7 +69,17 @@ pub trait RenderAsset: Send + Sync + 'static + Sized {
param: &mut SystemParamItem<Self::Param>,
) -> Result<Self, PrepareAssetError<Self::SourceAsset>>;
fn finalize_asset(_: AssetId<Self::SourceAsset>, _: &mut SystemParamItem<Self::Param>) {}
/// Called whenever the [`RenderAsset::SourceAsset`] has been removed.
///
/// You can implement this method if you need to access ECS data (via
/// `_param`) in order to perform cleanup tasks when the asset is removed.
///
/// The default implementation does nothing.
fn finalize_asset(
_source_asset: AssetId<Self::SourceAsset>,
_param: &mut SystemParamItem<Self::Param>,
) {
}
}
/// This plugin extracts the changed assets from the "app world" into the "render world"

View file

@ -257,6 +257,9 @@ impl Deref for BindGroup {
/// In your shader, the index of the element of each binding array
/// corresponding to the mesh currently being drawn can be retrieved with
/// `mesh[in.instance_index].material_bind_group_slot`.
/// * Bindless uniforms don't exist, so in bindless mode all uniforms and
/// uniform buffers are automatically replaced with read-only storage
/// buffers.
/// * The purpose of bindless mode is to improve performance by reducing
/// state changes. By grouping resources together into binding arrays, Bevy
/// doesn't have to modify GPU state as often, decreasing API and driver
@ -327,6 +330,13 @@ pub trait AsBindGroup {
type Param: SystemParam + 'static;
/// The number of slots per bind group, if bindless mode is enabled.
///
/// If this bind group doesn't use bindless, then this will be `None`.
///
/// Note that the *actual* slot count may be different from this value, due
/// to platform limitations. For example, if bindless resources aren't
/// supported on this platform, the actual slot count will be 1.
const BINDLESS_SLOT_COUNT: Option<u32> = None;
/// label
@ -412,6 +422,8 @@ pub struct UnpreparedBindGroup<T> {
pub data: T,
}
/// A pair of binding index and binding resource, used as part of
/// [`PreparedBindGroup`] and [`UnpreparedBindGroup`].
#[derive(Deref, DerefMut)]
pub struct BindingResources(pub Vec<(u32, OwnedBindingResource)>);

View file

@ -35,6 +35,7 @@ pub struct FallbackImage {
}
impl FallbackImage {
/// Returns the appropriate fallback image for the given texture dimension.
pub fn get(&self, texture_dimension: TextureViewDimension) -> &GpuImage {
match texture_dimension {
TextureViewDimension::D1 => &self.d1,

View file

@ -5,16 +5,23 @@ use bevy::render::render_resource::{AsBindGroup, ShaderRef};
const SHADER_ASSET_PATH: &str = "shaders/bindless_material.wgsl";
// `#[bindless(4)]` indicates that we want Bevy to group materials into bind
// groups of at most 4 materials each.
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
#[bindless(4)]
struct BindlessMaterial {
// This will be exposed to the shader as a binding array of 4 *storage*
// buffers (as bindless uniforms don't exist).
#[uniform(0)]
color: LinearRgba,
// This will be exposed to the shader as a binding array of 4 textures and a
// binding array of 4 samplers.
#[texture(1)]
#[sampler(2)]
color_texture: Option<Handle<Image>>,
}
// The entry point.
fn main() {
App::new()
.add_plugins((
@ -25,12 +32,14 @@ fn main() {
.run();
}
// Creates a simple scene.
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<BindlessMaterial>>,
asset_server: Res<AssetServer>,
) {
// Add a cube with a blue tinted texture.
commands.spawn((
Mesh3d(meshes.add(Cuboid::default())),
MeshMaterial3d(materials.add(BindlessMaterial {
@ -40,6 +49,7 @@ fn setup(
Transform::from_xyz(-2.0, 0.5, 0.0),
));
// Add a cube with a red tinted texture.
commands.spawn((
Mesh3d(meshes.add(Cylinder::default())),
MeshMaterial3d(materials.add(BindlessMaterial {
@ -49,7 +59,7 @@ fn setup(
Transform::from_xyz(2.0, 0.5, 0.0),
));
// camera
// Add a camera.
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),