Skip to content

Commit 132f203

Browse files
committed
bevy_pbr: Add SupportedBindingTypes that can be constructed from RenderDevice::limits()
1 parent d1e7d22 commit 132f203

File tree

6 files changed

+76
-34
lines changed

6 files changed

+76
-34
lines changed

crates/bevy_pbr/src/lib.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use bevy_render::{
4040
prelude::Color,
4141
render_graph::RenderGraph,
4242
render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions},
43-
render_resource::{Shader, SpecializedMeshPipelines},
43+
render_resource::{Shader, SpecializedMeshPipelines, SupportedBindingTypes},
4444
renderer::RenderDevice,
4545
view::VisibilitySystems,
4646
RenderApp, RenderStage,
@@ -127,14 +127,10 @@ impl Plugin for PbrPlugin {
127127
},
128128
);
129129

130-
// NOTE: 3 storage buffer bindings are needed for clustered-forward rendering so check
131-
// that at least that many are supported
132-
let use_storage_buffers = app
133-
.world
134-
.resource::<RenderDevice>()
135-
.limits()
136-
.max_storage_buffers_per_shader_stage
137-
>= 3;
130+
let supported_binding_types = SupportedBindingTypes::from_device(
131+
app.world.resource::<RenderDevice>(),
132+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
133+
);
138134

139135
let render_app = match app.get_sub_app_mut(RenderApp) {
140136
Ok(render_app) => render_app,
@@ -174,7 +170,7 @@ impl Plugin for PbrPlugin {
174170
.init_resource::<ShadowPipeline>()
175171
.init_resource::<DrawFunctions<Shadow>>()
176172
.init_resource::<LightMeta>()
177-
.insert_resource(GlobalLightMeta::new(use_storage_buffers))
173+
.insert_resource(GlobalLightMeta::new(supported_binding_types))
178174
.init_resource::<SpecializedMeshPipelines<ShadowPipeline>>();
179175

180176
let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);

crates/bevy_pbr/src/light.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use bevy_render::{
99
color::Color,
1010
prelude::Image,
1111
primitives::{Aabb, CubemapFrusta, Frustum, Sphere},
12+
render_resource::SupportedBindingTypes,
1213
renderer::RenderDevice,
1314
view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities},
1415
};
@@ -18,7 +19,7 @@ use bevy_window::Windows;
1819

1920
use crate::{
2021
calculate_cluster_factors, CubeMapFace, CubemapVisibleEntities, ViewClusterBindings,
21-
CUBE_MAP_FACES, MAX_POINT_LIGHTS, POINT_LIGHT_NEAR_Z,
22+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, CUBE_MAP_FACES, MAX_POINT_LIGHTS, POINT_LIGHT_NEAR_Z,
2223
};
2324

2425
/// A light that emits light in all directions from a central point.
@@ -729,10 +730,12 @@ pub(crate) fn assign_lights_to_clusters(
729730
),
730731
);
731732

732-
// NOTE: Clustered-forward rendering requires 3 buffer bindings so only use storage buffers
733-
// if at least 3 are supported
734-
let use_storage_buffers = render_device.limits().max_storage_buffers_per_shader_stage >= 3;
735-
if !use_storage_buffers && lights.len() > MAX_POINT_LIGHTS {
733+
let supports_storage_buffers = SupportedBindingTypes::from_device(
734+
render_device.into_inner(),
735+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
736+
)
737+
.contains(SupportedBindingTypes::STORAGE);
738+
if lights.len() > MAX_POINT_LIGHTS && !supports_storage_buffers {
736739
lights.sort_by(|light_1, light_2| {
737740
point_light_order(
738741
(&light_1.entity, &light_1.shadows_enabled),

crates/bevy_pbr/src/pbr_material.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{AlphaMode, MaterialPipeline, SpecializedMaterial, PBR_SHADER_HANDLE};
1+
use crate::{
2+
AlphaMode, MaterialPipeline, SpecializedMaterial, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
3+
PBR_SHADER_HANDLE,
4+
};
25
use bevy_asset::{AssetServer, Handle};
36
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
47
use bevy_math::Vec4;
@@ -370,9 +373,11 @@ impl SpecializedMaterial for StandardMaterial {
370373
StandardMaterialKey {
371374
normal_map: render_asset.has_normal_map,
372375
cull_mode: render_asset.cull_mode,
373-
// NOTE: Clustered-forward rendering requires 3 storage buffer bindings so check that
374-
// at least that many are supported.
375-
use_storage_buffers: render_device.limits().max_storage_buffers_per_shader_stage >= 3,
376+
use_storage_buffers: SupportedBindingTypes::from_device(
377+
render_device,
378+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
379+
)
380+
.contains(SupportedBindingTypes::STORAGE),
376381
}
377382
}
378383

crates/bevy_pbr/src/render/light.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ pub enum GpuPointLights {
102102
}
103103

104104
impl GpuPointLights {
105-
fn new(use_storage_buffers: bool) -> Self {
106-
if use_storage_buffers {
105+
fn new(supported_binding_types: SupportedBindingTypes) -> Self {
106+
if supported_binding_types.contains(SupportedBindingTypes::STORAGE) {
107107
Self::storage()
108108
} else {
109109
Self::uniform()
@@ -595,15 +595,19 @@ pub struct ViewLightsUniformOffset {
595595
pub offset: u32,
596596
}
597597

598+
// NOTE: Clustered-forward rendering requires 3 storage buffer bindings so check that
599+
// at least that many are supported using this constant and SupportedBindingType::from_device()
600+
pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3;
601+
598602
pub struct GlobalLightMeta {
599603
pub gpu_point_lights: GpuPointLights,
600604
pub entity_to_index: HashMap<Entity, usize>,
601605
}
602606

603607
impl GlobalLightMeta {
604-
pub fn new(use_storage_buffers: bool) -> Self {
608+
pub fn new(supported_binding_types: SupportedBindingTypes) -> Self {
605609
Self {
606-
gpu_point_lights: GpuPointLights::new(use_storage_buffers),
610+
gpu_point_lights: GpuPointLights::new(supported_binding_types),
607611
entity_to_index: HashMap::default(),
608612
}
609613
}
@@ -1018,8 +1022,8 @@ enum ViewClusterBuffers {
10181022
}
10191023

10201024
impl ViewClusterBuffers {
1021-
fn new(use_storage_buffers: bool) -> Self {
1022-
if use_storage_buffers {
1025+
fn new(supported_binding_types: SupportedBindingTypes) -> Self {
1026+
if supported_binding_types.contains(SupportedBindingTypes::STORAGE) {
10231027
Self::storage()
10241028
} else {
10251029
Self::uniform()
@@ -1053,11 +1057,11 @@ impl ViewClusterBindings {
10531057
const MAX_UNIFORM_ITEMS: usize = Self::MAX_OFFSETS / 4;
10541058
pub const MAX_INDICES: usize = 16384;
10551059

1056-
pub fn new(use_storage_buffers: bool) -> Self {
1060+
pub fn new(supported_binding_types: SupportedBindingTypes) -> Self {
10571061
Self {
10581062
n_indices: 0,
10591063
n_offsets: 0,
1060-
buffers: ViewClusterBuffers::new(use_storage_buffers),
1064+
buffers: ViewClusterBuffers::new(supported_binding_types),
10611065
}
10621066
}
10631067

@@ -1199,9 +1203,12 @@ pub fn prepare_clusters(
11991203
With<RenderPhase<Transparent3d>>,
12001204
>,
12011205
) {
1202-
let use_storage_buffers = render_device.limits().max_storage_buffers_per_shader_stage >= 3;
1206+
let render_device = render_device.into_inner();
1207+
let supported_binding_types =
1208+
SupportedBindingTypes::from_device(render_device, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
1209+
let supports_storage_buffers = supported_binding_types.contains(SupportedBindingTypes::STORAGE);
12031210
for (entity, cluster_config, extracted_clusters) in views.iter() {
1204-
let mut view_clusters_bindings = ViewClusterBindings::new(use_storage_buffers);
1211+
let mut view_clusters_bindings = ViewClusterBindings::new(supported_binding_types);
12051212
view_clusters_bindings.reserve_and_clear();
12061213

12071214
let mut indices_full = false;
@@ -1219,9 +1226,9 @@ pub fn prepare_clusters(
12191226
for entity in cluster_lights.iter() {
12201227
if let Some(light_index) = global_light_meta.entity_to_index.get(entity)
12211228
{
1222-
if !use_storage_buffers
1223-
&& view_clusters_bindings.n_indices()
1224-
>= ViewClusterBindings::MAX_INDICES
1229+
if view_clusters_bindings.n_indices()
1230+
>= ViewClusterBindings::MAX_INDICES
1231+
&& !supports_storage_buffers
12251232
{
12261233
warn!("Cluster light index lists is full! The PointLights in the view are affecting too many clusters.");
12271234
indices_full = true;
@@ -1237,7 +1244,7 @@ pub fn prepare_clusters(
12371244
}
12381245
}
12391246

1240-
view_clusters_bindings.write_buffers(&render_device, &render_queue);
1247+
view_clusters_bindings.write_buffers(render_device, &render_queue);
12411248

12421249
commands.get_or_spawn(entity).insert(view_clusters_bindings);
12431250
}

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
GlobalLightMeta, GpuLights, LightMeta, NotShadowCaster, NotShadowReceiver, ShadowPipeline,
33
ViewClusterBindings, ViewLightsUniformOffset, ViewShadowBindings,
4+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
45
};
56
use bevy_app::Plugin;
67
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
@@ -167,7 +168,12 @@ impl FromWorld for MeshPipeline {
167168
fn from_world(world: &mut World) -> Self {
168169
let render_device = world.resource::<RenderDevice>();
169170
let (cluster_buffer_binding_type, cluster_min_binding_size) =
170-
if render_device.limits().max_storage_buffers_per_shader_stage >= 3 {
171+
if SupportedBindingTypes::from_device(
172+
render_device,
173+
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
174+
)
175+
.contains(SupportedBindingTypes::STORAGE)
176+
{
171177
(BufferBindingType::Storage { read_only: true }, None)
172178
} else {
173179
(BufferBindingType::Uniform, BufferSize::new(16384))

crates/bevy_render/src/render_resource/storage_buffer.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,31 @@ use crate::renderer::{RenderDevice, RenderQueue};
88

99
use super::Buffer;
1010

11+
bitflags::bitflags! {
12+
#[repr(transparent)]
13+
pub struct SupportedBindingTypes: u32 {
14+
const UNIFORM = (1 << 0);
15+
const STORAGE = (1 << 1);
16+
const NONE = 0;
17+
const UNINITIALIZED = 0xFFFF;
18+
}
19+
}
20+
21+
impl SupportedBindingTypes {
22+
pub fn from_device(
23+
render_device: &RenderDevice,
24+
required_binding_count_per_stage: u32,
25+
) -> SupportedBindingTypes {
26+
let mut supported_binding_types = SupportedBindingTypes::UNIFORM;
27+
if render_device.limits().max_storage_buffers_per_shader_stage
28+
>= required_binding_count_per_stage
29+
{
30+
supported_binding_types |= SupportedBindingTypes::STORAGE;
31+
}
32+
supported_binding_types
33+
}
34+
}
35+
1136
/// A helper for a storage buffer binding with a body, or a variable-sized array, or both.
1237
pub struct StorageBuffer<T: AsStd430, U: AsStd430 = ()> {
1338
body: U,

0 commit comments

Comments
 (0)