Skip to content

Commit

Permalink
Disable clustered decals on Metal. (#17554)
Browse files Browse the repository at this point in the history
Unfortunately, Apple platforms don't have enough texture bindings to
properly support clustered decals. This should be fixed once `wgpu` has
first-class bindless texture support. In the meantime, we disable them.

Closes #17553.

---------

Co-authored-by: Alice Cecile <[email protected]>
  • Loading branch information
pcwalton and alice-i-cecile authored Jan 27, 2025
1 parent dda9788 commit 7aeb1c5
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 14 deletions.
6 changes: 4 additions & 2 deletions crates/bevy_pbr/src/cluster/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use bevy_utils::prelude::default;
use tracing::warn;

use crate::{
binding_arrays_are_usable, decal::clustered::ClusteredDecal, prelude::EnvironmentMapLight,
decal::{self, clustered::ClusteredDecal},
prelude::EnvironmentMapLight,
ClusterConfig, ClusterFarZMode, Clusters, ExtractedPointLight, GlobalVisibleClusterableObjects,
LightProbe, PointLight, SpotLight, ViewClusterBindings, VisibleClusterableObjects,
VolumetricLight, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
Expand Down Expand Up @@ -257,7 +258,8 @@ pub(crate) fn assign_objects_to_clusters(
));
}

if binding_arrays_are_usable(&render_device, &render_adapter) {
// Add decals if the current platform supports them.
if decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
clusterable_objects.extend(decals_query.iter().map(|(entity, transform)| {
ClusterableObjectAssignmentData {
entity,
Expand Down
28 changes: 22 additions & 6 deletions crates/bevy_pbr/src/decal/clustered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//!
//! Clustered decals are the highest-quality types of decals that Bevy supports,
//! but they require bindless textures. This means that they presently can't be
//! used on WebGL 2 or WebGPU. Bevy's clustered decals can be used with forward
//! or deferred rendering and don't require a prepass.
//! used on WebGL 2, WebGPU, macOS, or iOS. Bevy's clustered decals can be used
//! with forward or deferred rendering and don't require a prepass.
//!
//! On their own, clustered decals only project the base color of a texture. You
//! can, however, use the built-in *tag* field to customize the appearance of a
Expand Down Expand Up @@ -77,8 +77,8 @@ pub struct ClusteredDecalPlugin;
///
/// Clustered decals are the highest-quality types of decals that Bevy supports,
/// but they require bindless textures. This means that they presently can't be
/// used on WebGL 2 or WebGPU. Bevy's clustered decals can be used with forward
/// or deferred rendering and don't require a prepass.
/// used on WebGL 2, WebGPU, macOS, or iOS. Bevy's clustered decals can be used
/// with forward or deferred rendering and don't require a prepass.
#[derive(Component, Debug, Clone, Reflect, ExtractComponent)]
#[reflect(Component, Debug)]
#[require(Transform, Visibility, VisibilityClass)]
Expand Down Expand Up @@ -263,7 +263,7 @@ pub(crate) fn get_bind_group_layout_entries(
) -> Option<[BindGroupLayoutEntryBuilder; 3]> {
// If binding arrays aren't supported on the current platform, we have no
// bind group layout entries.
if !binding_arrays_are_usable(render_device, render_adapter) {
if !clustered_decals_are_usable(render_device, render_adapter) {
return None;
}

Expand All @@ -290,7 +290,7 @@ impl<'a> RenderViewClusteredDecalBindGroupEntries<'a> {
render_adapter: &RenderAdapter,
) -> Option<RenderViewClusteredDecalBindGroupEntries<'a>> {
// Skip the entries if decals are unsupported on the current platform.
if !binding_arrays_are_usable(render_device, render_adapter) {
if !clustered_decals_are_usable(render_device, render_adapter) {
return None;
}

Expand Down Expand Up @@ -367,3 +367,19 @@ fn upload_decals(

decals_buffer.write_buffer(&render_device, &render_queue);
}

/// Returns true if clustered decals are usable on the current platform or false
/// otherwise.
///
/// Clustered decals are currently disabled on macOS and iOS due to insufficient
/// texture bindings and limited bindless support in `wgpu`.
pub fn clustered_decals_are_usable(
render_device: &RenderDevice,
render_adapter: &RenderAdapter,
) -> bool {
// Disable binding arrays on Metal. There aren't enough texture bindings available.
// See issue #17553.
// Re-enable this when `wgpu` has first-class bindless.
binding_arrays_are_usable(render_device, render_adapter)
&& cfg!(not(any(target_os = "macos", target_os = "ios")))
}
9 changes: 8 additions & 1 deletion crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,9 @@ pub struct MeshPipeline {
/// This affects whether reflection probes can be used.
pub binding_arrays_are_usable: bool,

/// Whether clustered decals are usable on the current render device.
pub clustered_decals_are_usable: bool,

/// Whether skins will use uniform buffers on account of storage buffers
/// being unavailable on this platform.
pub skins_use_uniform_buffers: bool,
Expand Down Expand Up @@ -1589,6 +1592,10 @@ impl FromWorld for MeshPipeline {
mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
&render_device,
&render_adapter,
),
skins_use_uniform_buffers: skin::skins_use_uniform_buffers(&render_device),
}
}
Expand Down Expand Up @@ -2295,7 +2302,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
}

if self.binding_arrays_are_usable {
if self.clustered_decals_are_usable {
shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
}

Expand Down
24 changes: 19 additions & 5 deletions examples/3d/clustered_decals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
use std::f32::consts::{FRAC_PI_3, PI};
use std::fmt::{self, Formatter};
use std::process;

use bevy::pbr::{ExtendedMaterial, MaterialExtension};
use bevy::window::SystemCursorIcon;
use bevy::winit::cursor::CursorIcon;
use bevy::{
color::palettes::css::{LIME, ORANGE_RED, SILVER},
input::mouse::AccumulatedMouseMotion,
pbr::decal::clustered::ClusteredDecal,
pbr::{
decal::{self, clustered::ClusteredDecal},
ExtendedMaterial, MaterialExtension,
},
prelude::*,
render::render_resource::{AsBindGroup, ShaderRef},
render::{
render_resource::{AsBindGroup, ShaderRef},
renderer::{RenderAdapter, RenderDevice},
},
window::SystemCursorIcon,
winit::cursor::CursorIcon,
};
use ops::{acos, cos, sin};
use widgets::{
Expand Down Expand Up @@ -152,9 +158,17 @@ fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
app_status: Res<AppStatus>,
render_device: Res<RenderDevice>,
render_adapter: Res<RenderAdapter>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, CustomDecalExtension>>>,
) {
// Error out if clustered decals aren't supported on the current platform.
if !decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
eprintln!("Clustered decals aren't usable on this platform.");
process::exit(1);
}

spawn_cube(&mut commands, &mut meshes, &mut materials);
spawn_camera(&mut commands);
spawn_light(&mut commands);
Expand Down

0 comments on commit 7aeb1c5

Please sign in to comment.