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
This commit is contained in:
atlv 2025-07-05 10:39:41 -04:00 committed by GitHub
parent 1b09c4051e
commit d0896bf10a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 20 deletions

View File

@ -12,8 +12,6 @@ use bevy_math::{
use bevy_render::{ use bevy_render::{
camera::Camera, camera::Camera,
primitives::{Aabb, Frustum, HalfSpace, Sphere}, primitives::{Aabb, Frustum, HalfSpace, Sphere},
render_resource::BufferBindingType,
renderer::{RenderAdapter, RenderDevice},
view::{RenderLayers, ViewVisibility}, view::{RenderLayers, ViewVisibility},
}; };
use bevy_transform::components::GlobalTransform; use bevy_transform::components::GlobalTransform;
@ -21,12 +19,10 @@ use bevy_utils::prelude::default;
use tracing::warn; use tracing::warn;
use crate::{ use crate::{
decal::{self, clustered::ClusteredDecal}, decal::clustered::ClusteredDecal, prelude::EnvironmentMapLight, ClusterConfig, ClusterFarZMode,
prelude::EnvironmentMapLight, Clusters, ExtractedPointLight, GlobalClusterSettings, GlobalVisibleClusterableObjects,
ClusterConfig, ClusterFarZMode, Clusters, ExtractedPointLight, GlobalVisibleClusterableObjects,
LightProbe, PointLight, SpotLight, ViewClusterBindings, VisibleClusterableObjects, LightProbe, PointLight, SpotLight, ViewClusterBindings, VisibleClusterableObjects,
VolumetricLight, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, VolumetricLight, MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS,
MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS,
}; };
const NDC_MIN: Vec2 = Vec2::NEG_ONE; const NDC_MIN: Vec2 = Vec2::NEG_ONE;
@ -180,9 +176,9 @@ pub(crate) fn assign_objects_to_clusters(
mut clusterable_objects: Local<Vec<ClusterableObjectAssignmentData>>, mut clusterable_objects: Local<Vec<ClusterableObjectAssignmentData>>,
mut cluster_aabb_spheres: Local<Vec<Option<Sphere>>>, mut cluster_aabb_spheres: Local<Vec<Option<Sphere>>>,
mut max_clusterable_objects_warning_emitted: Local<bool>, mut max_clusterable_objects_warning_emitted: Local<bool>,
(render_device, render_adapter): (Option<Res<RenderDevice>>, Option<Res<RenderAdapter>>), global_cluster_settings: Option<Res<GlobalClusterSettings>>,
) { ) {
let (Some(render_device), Some(render_adapter)) = (render_device, render_adapter) else { let Some(global_cluster_settings) = global_cluster_settings else {
return; 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. // 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 // 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 // cluster light probes on such platforms (mainly WebGL 2). Besides, those
// platforms typically lack bindless textures, so multiple light probes // platforms typically lack bindless textures, so multiple light probes
// wouldn't be supported anyhow. // wouldn't be supported anyhow.
if supports_storage_buffers { if global_cluster_settings.supports_storage_buffers {
clusterable_objects.extend(light_probes_query.iter().map( clusterable_objects.extend(light_probes_query.iter().map(
|(entity, transform, is_reflection_probe)| ClusterableObjectAssignmentData { |(entity, transform, is_reflection_probe)| ClusterableObjectAssignmentData {
entity, entity,
@ -259,7 +248,7 @@ pub(crate) fn assign_objects_to_clusters(
} }
// Add decals if the current platform supports them. // 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)| { clusterable_objects.extend(decals_query.iter().map(|(entity, transform)| {
ClusterableObjectAssignmentData { ClusterableObjectAssignmentData {
entity, entity,
@ -272,7 +261,7 @@ pub(crate) fn assign_objects_to_clusters(
} }
if clusterable_objects.len() > MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS 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| { clusterable_objects.sort_by_cached_key(|clusterable_object| {
( (

View File

@ -21,7 +21,7 @@ use bevy_render::{
BindingResource, BufferBindingType, ShaderSize as _, ShaderType, StorageBuffer, BindingResource, BufferBindingType, ShaderSize as _, ShaderType, StorageBuffer,
UniformBuffer, UniformBuffer,
}, },
renderer::{RenderDevice, RenderQueue}, renderer::{RenderAdapter, RenderDevice, RenderQueue},
sync_world::RenderEntity, sync_world::RenderEntity,
Extract, 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: // 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 // 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::<RenderDevice>();
let adapter = world.resource::<RenderAdapter>();
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 /// Configure the far z-plane mode used for the furthest depth slice for clustered forward
/// rendering /// rendering
#[derive(Debug, Copy, Clone, Reflect)] #[derive(Debug, Copy, Clone, Reflect)]

View File

@ -396,6 +396,9 @@ impl Plugin for PbrPlugin {
.init_resource::<ShadowSamplers>() .init_resource::<ShadowSamplers>()
.init_resource::<GlobalClusterableObjectMeta>() .init_resource::<GlobalClusterableObjectMeta>()
.init_resource::<FallbackBindlessResources>(); .init_resource::<FallbackBindlessResources>();
let global_cluster_settings = make_global_cluster_settings(render_app.world());
app.insert_resource(global_cluster_settings);
} }
} }