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::{
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<Vec<ClusterableObjectAssignmentData>>,
mut cluster_aabb_spheres: Local<Vec<Option<Sphere>>>,
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;
};
@ -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| {
(

View File

@ -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::<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
/// rendering
#[derive(Debug, Copy, Clone, Reflect)]

View File

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