From d0896bf10abfd6823cbe57a64f7a908dc0fda4b3 Mon Sep 17 00:00:00 2001 From: atlv Date: Sat, 5 Jul 2025 10:39:41 -0400 Subject: [PATCH] make cluster assign not depend on RenderAdapter/RenderDevice (#19957) # Objective - Make bevy_light possible by making it possible to split out clusterable into bevy_camera ## Solution - Use a resource to store cluster settings instead of recalculating it every time from the render adapter/device ## Testing - 3d_scene runs --- crates/bevy_pbr/src/cluster/assign.rs | 27 ++++++++------------------- crates/bevy_pbr/src/cluster/mod.rs | 23 ++++++++++++++++++++++- crates/bevy_pbr/src/lib.rs | 3 +++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/crates/bevy_pbr/src/cluster/assign.rs b/crates/bevy_pbr/src/cluster/assign.rs index b0c0fb6347..c2526bc2ff 100644 --- a/crates/bevy_pbr/src/cluster/assign.rs +++ b/crates/bevy_pbr/src/cluster/assign.rs @@ -12,8 +12,6 @@ use bevy_math::{ use bevy_render::{ camera::Camera, primitives::{Aabb, Frustum, HalfSpace, Sphere}, - render_resource::BufferBindingType, - renderer::{RenderAdapter, RenderDevice}, view::{RenderLayers, ViewVisibility}, }; use bevy_transform::components::GlobalTransform; @@ -21,12 +19,10 @@ use bevy_utils::prelude::default; use tracing::warn; use crate::{ - decal::{self, clustered::ClusteredDecal}, - prelude::EnvironmentMapLight, - ClusterConfig, ClusterFarZMode, Clusters, ExtractedPointLight, GlobalVisibleClusterableObjects, + decal::clustered::ClusteredDecal, prelude::EnvironmentMapLight, ClusterConfig, ClusterFarZMode, + Clusters, ExtractedPointLight, GlobalClusterSettings, GlobalVisibleClusterableObjects, LightProbe, PointLight, SpotLight, ViewClusterBindings, VisibleClusterableObjects, - VolumetricLight, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS, + VolumetricLight, MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS, }; const NDC_MIN: Vec2 = Vec2::NEG_ONE; @@ -180,9 +176,9 @@ pub(crate) fn assign_objects_to_clusters( mut clusterable_objects: Local>, mut cluster_aabb_spheres: Local>>, mut max_clusterable_objects_warning_emitted: Local, - (render_device, render_adapter): (Option>, Option>), + global_cluster_settings: Option>, ) { - let (Some(render_device), Some(render_adapter)) = (render_device, render_adapter) else { + let Some(global_cluster_settings) = global_cluster_settings else { return; }; @@ -229,20 +225,13 @@ pub(crate) fn assign_objects_to_clusters( ), ); - let clustered_forward_buffer_binding_type = - render_device.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); - let supports_storage_buffers = matches!( - clustered_forward_buffer_binding_type, - BufferBindingType::Storage { .. } - ); - // Gather up light probes, but only if we're clustering them. // // UBOs aren't large enough to hold indices for light probes, so we can't // cluster light probes on such platforms (mainly WebGL 2). Besides, those // platforms typically lack bindless textures, so multiple light probes // wouldn't be supported anyhow. - if supports_storage_buffers { + if global_cluster_settings.supports_storage_buffers { clusterable_objects.extend(light_probes_query.iter().map( |(entity, transform, is_reflection_probe)| ClusterableObjectAssignmentData { entity, @@ -259,7 +248,7 @@ pub(crate) fn assign_objects_to_clusters( } // Add decals if the current platform supports them. - if decal::clustered::clustered_decals_are_usable(&render_device, &render_adapter) { + if global_cluster_settings.clustered_decals_are_usable { clusterable_objects.extend(decals_query.iter().map(|(entity, transform)| { ClusterableObjectAssignmentData { entity, @@ -272,7 +261,7 @@ pub(crate) fn assign_objects_to_clusters( } if clusterable_objects.len() > MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS - && !supports_storage_buffers + && !global_cluster_settings.supports_storage_buffers { clusterable_objects.sort_by_cached_key(|clusterable_object| { ( diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index 501f4091fc..7f90a4becb 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -21,7 +21,7 @@ use bevy_render::{ BindingResource, BufferBindingType, ShaderSize as _, ShaderType, StorageBuffer, UniformBuffer, }, - renderer::{RenderDevice, RenderQueue}, + renderer::{RenderAdapter, RenderDevice, RenderQueue}, sync_world::RenderEntity, Extract, }; @@ -63,6 +63,27 @@ const CLUSTER_COUNT_MASK: u32 = (1 << CLUSTER_COUNT_SIZE) - 1; // The z-slicing method mentioned in the aortiz article is originally from Tiago Sousa's Siggraph 2016 talk about Doom 2016: // http://advances.realtimerendering.com/s2016/Siggraph2016_idTech6.pdf +#[derive(Resource)] +pub struct GlobalClusterSettings { + pub supports_storage_buffers: bool, + pub clustered_decals_are_usable: bool, +} + +pub(crate) fn make_global_cluster_settings(world: &World) -> GlobalClusterSettings { + let device = world.resource::(); + let adapter = world.resource::(); + let clustered_decals_are_usable = + crate::decal::clustered::clustered_decals_are_usable(device, adapter); + let supports_storage_buffers = matches!( + device.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT), + BufferBindingType::Storage { .. } + ); + GlobalClusterSettings { + supports_storage_buffers, + clustered_decals_are_usable, + } +} + /// Configure the far z-plane mode used for the furthest depth slice for clustered forward /// rendering #[derive(Debug, Copy, Clone, Reflect)] diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 86d2bf8ede..0604c06328 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -396,6 +396,9 @@ impl Plugin for PbrPlugin { .init_resource::() .init_resource::() .init_resource::(); + + let global_cluster_settings = make_global_cluster_settings(render_app.world()); + app.insert_resource(global_cluster_settings); } }