Skip to content

Commit 7aeb1c5

Browse files
Disable clustered decals on Metal. (#17554)
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 <alice.i.cecile@gmail.com>
1 parent dda9788 commit 7aeb1c5

File tree

4 files changed

+53
-14
lines changed

4 files changed

+53
-14
lines changed

crates/bevy_pbr/src/cluster/assign.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use bevy_utils::prelude::default;
2121
use tracing::warn;
2222

2323
use crate::{
24-
binding_arrays_are_usable, decal::clustered::ClusteredDecal, prelude::EnvironmentMapLight,
24+
decal::{self, clustered::ClusteredDecal},
25+
prelude::EnvironmentMapLight,
2526
ClusterConfig, ClusterFarZMode, Clusters, ExtractedPointLight, GlobalVisibleClusterableObjects,
2627
LightProbe, PointLight, SpotLight, ViewClusterBindings, VisibleClusterableObjects,
2728
VolumetricLight, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
@@ -257,7 +258,8 @@ pub(crate) fn assign_objects_to_clusters(
257258
));
258259
}
259260

260-
if binding_arrays_are_usable(&render_device, &render_adapter) {
261+
// Add decals if the current platform supports them.
262+
if decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
261263
clusterable_objects.extend(decals_query.iter().map(|(entity, transform)| {
262264
ClusterableObjectAssignmentData {
263265
entity,

crates/bevy_pbr/src/decal/clustered.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
//!
77
//! Clustered decals are the highest-quality types of decals that Bevy supports,
88
//! but they require bindless textures. This means that they presently can't be
9-
//! used on WebGL 2 or WebGPU. Bevy's clustered decals can be used with forward
10-
//! or deferred rendering and don't require a prepass.
9+
//! used on WebGL 2, WebGPU, macOS, or iOS. Bevy's clustered decals can be used
10+
//! with forward or deferred rendering and don't require a prepass.
1111
//!
1212
//! On their own, clustered decals only project the base color of a texture. You
1313
//! can, however, use the built-in *tag* field to customize the appearance of a
@@ -77,8 +77,8 @@ pub struct ClusteredDecalPlugin;
7777
///
7878
/// Clustered decals are the highest-quality types of decals that Bevy supports,
7979
/// but they require bindless textures. This means that they presently can't be
80-
/// used on WebGL 2 or WebGPU. Bevy's clustered decals can be used with forward
81-
/// or deferred rendering and don't require a prepass.
80+
/// used on WebGL 2, WebGPU, macOS, or iOS. Bevy's clustered decals can be used
81+
/// with forward or deferred rendering and don't require a prepass.
8282
#[derive(Component, Debug, Clone, Reflect, ExtractComponent)]
8383
#[reflect(Component, Debug)]
8484
#[require(Transform, Visibility, VisibilityClass)]
@@ -263,7 +263,7 @@ pub(crate) fn get_bind_group_layout_entries(
263263
) -> Option<[BindGroupLayoutEntryBuilder; 3]> {
264264
// If binding arrays aren't supported on the current platform, we have no
265265
// bind group layout entries.
266-
if !binding_arrays_are_usable(render_device, render_adapter) {
266+
if !clustered_decals_are_usable(render_device, render_adapter) {
267267
return None;
268268
}
269269

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

@@ -367,3 +367,19 @@ fn upload_decals(
367367

368368
decals_buffer.write_buffer(&render_device, &render_queue);
369369
}
370+
371+
/// Returns true if clustered decals are usable on the current platform or false
372+
/// otherwise.
373+
///
374+
/// Clustered decals are currently disabled on macOS and iOS due to insufficient
375+
/// texture bindings and limited bindless support in `wgpu`.
376+
pub fn clustered_decals_are_usable(
377+
render_device: &RenderDevice,
378+
render_adapter: &RenderAdapter,
379+
) -> bool {
380+
// Disable binding arrays on Metal. There aren't enough texture bindings available.
381+
// See issue #17553.
382+
// Re-enable this when `wgpu` has first-class bindless.
383+
binding_arrays_are_usable(render_device, render_adapter)
384+
&& cfg!(not(any(target_os = "macos", target_os = "ios")))
385+
}

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,9 @@ pub struct MeshPipeline {
15281528
/// This affects whether reflection probes can be used.
15291529
pub binding_arrays_are_usable: bool,
15301530

1531+
/// Whether clustered decals are usable on the current render device.
1532+
pub clustered_decals_are_usable: bool,
1533+
15311534
/// Whether skins will use uniform buffers on account of storage buffers
15321535
/// being unavailable on this platform.
15331536
pub skins_use_uniform_buffers: bool,
@@ -1589,6 +1592,10 @@ impl FromWorld for MeshPipeline {
15891592
mesh_layouts: MeshLayouts::new(&render_device, &render_adapter),
15901593
per_object_buffer_batch_size: GpuArrayBuffer::<MeshUniform>::batch_size(&render_device),
15911594
binding_arrays_are_usable: binding_arrays_are_usable(&render_device, &render_adapter),
1595+
clustered_decals_are_usable: decal::clustered::clustered_decals_are_usable(
1596+
&render_device,
1597+
&render_adapter,
1598+
),
15921599
skins_use_uniform_buffers: skin::skins_use_uniform_buffers(&render_device),
15931600
}
15941601
}
@@ -2295,7 +2302,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
22952302
shader_defs.push("IRRADIANCE_VOLUMES_ARE_USABLE".into());
22962303
}
22972304

2298-
if self.binding_arrays_are_usable {
2305+
if self.clustered_decals_are_usable {
22992306
shader_defs.push("CLUSTERED_DECALS_ARE_USABLE".into());
23002307
}
23012308

examples/3d/clustered_decals.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@
22
33
use std::f32::consts::{FRAC_PI_3, PI};
44
use std::fmt::{self, Formatter};
5+
use std::process;
56

6-
use bevy::pbr::{ExtendedMaterial, MaterialExtension};
7-
use bevy::window::SystemCursorIcon;
8-
use bevy::winit::cursor::CursorIcon;
97
use bevy::{
108
color::palettes::css::{LIME, ORANGE_RED, SILVER},
119
input::mouse::AccumulatedMouseMotion,
12-
pbr::decal::clustered::ClusteredDecal,
10+
pbr::{
11+
decal::{self, clustered::ClusteredDecal},
12+
ExtendedMaterial, MaterialExtension,
13+
},
1314
prelude::*,
14-
render::render_resource::{AsBindGroup, ShaderRef},
15+
render::{
16+
render_resource::{AsBindGroup, ShaderRef},
17+
renderer::{RenderAdapter, RenderDevice},
18+
},
19+
window::SystemCursorIcon,
20+
winit::cursor::CursorIcon,
1521
};
1622
use ops::{acos, cos, sin};
1723
use widgets::{
@@ -152,9 +158,17 @@ fn setup(
152158
mut commands: Commands,
153159
asset_server: Res<AssetServer>,
154160
app_status: Res<AppStatus>,
161+
render_device: Res<RenderDevice>,
162+
render_adapter: Res<RenderAdapter>,
155163
mut meshes: ResMut<Assets<Mesh>>,
156164
mut materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, CustomDecalExtension>>>,
157165
) {
166+
// Error out if clustered decals aren't supported on the current platform.
167+
if !decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) {
168+
eprintln!("Clustered decals aren't usable on this platform.");
169+
process::exit(1);
170+
}
171+
158172
spawn_cube(&mut commands, &mut meshes, &mut materials);
159173
spawn_camera(&mut commands);
160174
spawn_light(&mut commands);

0 commit comments

Comments
 (0)