From 34aab167bed5c99246ec42f4d48f5a4c03350126 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Tue, 5 Apr 2022 14:14:22 -0700 Subject: [PATCH] Move storage buffer detection to RenderDevice --- crates/bevy_pbr/src/lib.rs | 10 +--- crates/bevy_pbr/src/light.rs | 13 ++--- crates/bevy_pbr/src/pbr_material.rs | 10 ++-- crates/bevy_pbr/src/render/light.rs | 47 ++++++++++++------- crates/bevy_pbr/src/render/mesh.rs | 25 +++++----- .../src/render_resource/storage_buffer.rs | 34 ++------------ .../bevy_render/src/renderer/render_device.rs | 13 ++++- 7 files changed, 69 insertions(+), 83 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index e1998cfbd1b19..3659a88c088ac 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -40,8 +40,7 @@ use bevy_render::{ prelude::Color, render_graph::RenderGraph, render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions}, - render_resource::{Shader, SpecializedMeshPipelines, SupportedBindingTypes}, - renderer::RenderDevice, + render_resource::{Shader, SpecializedMeshPipelines}, view::VisibilitySystems, RenderApp, RenderStage, }; @@ -127,11 +126,6 @@ impl Plugin for PbrPlugin { }, ); - let supported_binding_types = SupportedBindingTypes::from_device( - app.world.resource::(), - CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - ); - let render_app = match app.get_sub_app_mut(RenderApp) { Ok(render_app) => render_app, Err(_) => return, @@ -170,7 +164,7 @@ impl Plugin for PbrPlugin { .init_resource::() .init_resource::>() .init_resource::() - .insert_resource(GlobalLightMeta::new(supported_binding_types)) + .init_resource::() .init_resource::>(); let shadow_pass_node = ShadowPassNode::new(&mut render_app.world); diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index ca2d8ce6863a2..d7678df12255b 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -9,7 +9,7 @@ use bevy_render::{ color::Color, prelude::Image, primitives::{Aabb, CubemapFrusta, Frustum, Sphere}, - render_resource::SupportedBindingTypes, + render_resource::BufferBindingType, renderer::RenderDevice, view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities}, }; @@ -730,11 +730,12 @@ pub(crate) fn assign_lights_to_clusters( ), ); - let supports_storage_buffers = SupportedBindingTypes::from_device( - render_device.into_inner(), - CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - ) - .contains(SupportedBindingTypes::STORAGE); + 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 { .. } + ); if lights.len() > MAX_POINT_LIGHTS && !supports_storage_buffers { lights.sort_by(|light_1, light_2| { point_light_order( diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index dd5bed2650a2b..35a53bca506c7 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -373,11 +373,11 @@ impl SpecializedMaterial for StandardMaterial { StandardMaterialKey { normal_map: render_asset.has_normal_map, cull_mode: render_asset.cull_mode, - use_storage_buffers: SupportedBindingTypes::from_device( - render_device, - CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - ) - .contains(SupportedBindingTypes::STORAGE), + use_storage_buffers: matches!( + render_device + .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT), + BufferBindingType::Storage { .. } + ), } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e6fb2a5359d17..45a686361a13c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -102,11 +102,10 @@ pub enum GpuPointLights { } impl GpuPointLights { - fn new(supported_binding_types: SupportedBindingTypes) -> Self { - if supported_binding_types.contains(SupportedBindingTypes::STORAGE) { - Self::storage() - } else { - Self::uniform() + fn new(buffer_binding_type: BufferBindingType) -> Self { + match buffer_binding_type { + BufferBindingType::Storage { .. } => Self::storage(), + BufferBindingType::Uniform => Self::uniform(), } } @@ -602,10 +601,20 @@ pub struct GlobalLightMeta { pub entity_to_index: HashMap, } +impl FromWorld for GlobalLightMeta { + fn from_world(world: &mut World) -> Self { + Self::new( + world + .resource::() + .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT), + ) + } +} + impl GlobalLightMeta { - pub fn new(supported_binding_types: SupportedBindingTypes) -> Self { + pub fn new(buffer_binding_type: BufferBindingType) -> Self { Self { - gpu_point_lights: GpuPointLights::new(supported_binding_types), + gpu_point_lights: GpuPointLights::new(buffer_binding_type), entity_to_index: HashMap::default(), } } @@ -1020,11 +1029,10 @@ enum ViewClusterBuffers { } impl ViewClusterBuffers { - fn new(supported_binding_types: SupportedBindingTypes) -> Self { - if supported_binding_types.contains(SupportedBindingTypes::STORAGE) { - Self::storage() - } else { - Self::uniform() + fn new(buffer_binding_type: BufferBindingType) -> Self { + match buffer_binding_type { + BufferBindingType::Storage { .. } => Self::storage(), + BufferBindingType::Uniform => Self::uniform(), } } @@ -1055,11 +1063,11 @@ impl ViewClusterBindings { const MAX_UNIFORM_ITEMS: usize = Self::MAX_OFFSETS / 4; pub const MAX_INDICES: usize = 16384; - pub fn new(supported_binding_types: SupportedBindingTypes) -> Self { + pub fn new(buffer_binding_type: BufferBindingType) -> Self { Self { n_indices: 0, n_offsets: 0, - buffers: ViewClusterBuffers::new(supported_binding_types), + buffers: ViewClusterBuffers::new(buffer_binding_type), } } @@ -1191,6 +1199,7 @@ pub fn prepare_clusters( mut commands: Commands, render_device: Res, render_queue: Res, + mesh_pipeline: Res, global_light_meta: Res, views: Query< ( @@ -1202,11 +1211,13 @@ pub fn prepare_clusters( >, ) { let render_device = render_device.into_inner(); - let supported_binding_types = - SupportedBindingTypes::from_device(render_device, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); - let supports_storage_buffers = supported_binding_types.contains(SupportedBindingTypes::STORAGE); + let supports_storage_buffers = matches!( + mesh_pipeline.clustered_forward_buffer_binding_type, + BufferBindingType::Storage { .. } + ); for (entity, cluster_config, extracted_clusters) in views.iter() { - let mut view_clusters_bindings = ViewClusterBindings::new(supported_binding_types); + let mut view_clusters_bindings = + ViewClusterBindings::new(mesh_pipeline.clustered_forward_buffer_binding_type); view_clusters_bindings.reserve_and_clear(); let mut indices_full = false; diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index d14e4ed5c6e62..9edbd59196af6 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -162,22 +162,18 @@ pub struct MeshPipeline { pub mesh_layout: BindGroupLayout, // This dummy white texture is to be used in place of optional StandardMaterial textures pub dummy_white_gpu_image: GpuImage, + pub clustered_forward_buffer_binding_type: BufferBindingType, } impl FromWorld for MeshPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); - let (cluster_buffer_binding_type, cluster_min_binding_size) = - if SupportedBindingTypes::from_device( - render_device, - CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, - ) - .contains(SupportedBindingTypes::STORAGE) - { - (BufferBindingType::Storage { read_only: true }, None) - } else { - (BufferBindingType::Uniform, BufferSize::new(16384)) - }; + let clustered_forward_buffer_binding_type = render_device + .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); + let cluster_min_binding_size = match clustered_forward_buffer_binding_type { + BufferBindingType::Storage { .. } => None, + BufferBindingType::Uniform => BufferSize::new(16384), + }; let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { entries: &[ // View @@ -249,7 +245,7 @@ impl FromWorld for MeshPipeline { binding: 6, visibility: ShaderStages::FRAGMENT, ty: BindingType::Buffer { - ty: cluster_buffer_binding_type, + ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, // NOTE (when no storage buffers): Static size for uniform buffers. // GpuPointLight has a padded size of 64 bytes, so 16384 / 64 = 256 @@ -263,7 +259,7 @@ impl FromWorld for MeshPipeline { binding: 7, visibility: ShaderStages::FRAGMENT, ty: BindingType::Buffer { - ty: cluster_buffer_binding_type, + ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, // NOTE (when no storage buffers): With 256 point lights max, indices // need 8 bits so use u8 @@ -276,7 +272,7 @@ impl FromWorld for MeshPipeline { binding: 8, visibility: ShaderStages::FRAGMENT, ty: BindingType::Buffer { - ty: cluster_buffer_binding_type, + ty: clustered_forward_buffer_binding_type, has_dynamic_offset: false, // NOTE (when no storage buffers): The offset needs to address 16384 // indices, which needs 14 bits. The count can be at most all 256 lights @@ -353,6 +349,7 @@ impl FromWorld for MeshPipeline { MeshPipeline { view_layout, mesh_layout, + clustered_forward_buffer_binding_type, dummy_white_gpu_image, } } diff --git a/crates/bevy_render/src/render_resource/storage_buffer.rs b/crates/bevy_render/src/render_resource/storage_buffer.rs index cda0585d79ddf..b0015f1c3d941 100644 --- a/crates/bevy_render/src/render_resource/storage_buffer.rs +++ b/crates/bevy_render/src/render_resource/storage_buffer.rs @@ -1,38 +1,10 @@ -use std::num::NonZeroU64; - +use super::Buffer; +use crate::renderer::{RenderDevice, RenderQueue}; use bevy_crevice::std430::{self, AsStd430, Std430}; use bevy_utils::tracing::warn; +use std::num::NonZeroU64; use wgpu::{BindingResource, BufferBinding, BufferDescriptor, BufferUsages}; -use crate::renderer::{RenderDevice, RenderQueue}; - -use super::Buffer; - -bitflags::bitflags! { - #[repr(transparent)] - pub struct SupportedBindingTypes: u32 { - const UNIFORM = (1 << 0); - const STORAGE = (1 << 1); - const NONE = 0; - const UNINITIALIZED = 0xFFFF; - } -} - -impl SupportedBindingTypes { - pub fn from_device( - render_device: &RenderDevice, - required_binding_count_per_stage: u32, - ) -> SupportedBindingTypes { - let mut supported_binding_types = SupportedBindingTypes::UNIFORM; - if render_device.limits().max_storage_buffers_per_shader_stage - >= required_binding_count_per_stage - { - supported_binding_types |= SupportedBindingTypes::STORAGE; - } - supported_binding_types - } -} - /// A helper for a storage buffer binding with a body, or a variable-sized array, or both. pub struct StorageBuffer { body: U, diff --git a/crates/bevy_render/src/renderer/render_device.rs b/crates/bevy_render/src/renderer/render_device.rs index 7ff9e88ef6dd0..4430e7001273f 100644 --- a/crates/bevy_render/src/renderer/render_device.rs +++ b/crates/bevy_render/src/renderer/render_device.rs @@ -4,7 +4,7 @@ use crate::render_resource::{ }; use futures_lite::future; use std::sync::Arc; -use wgpu::util::DeviceExt; +use wgpu::{util::DeviceExt, BufferBindingType}; use super::RenderQueue; @@ -184,4 +184,15 @@ impl RenderDevice { let padded_bytes_per_row_padding = (align - row_bytes % align) % align; row_bytes + padded_bytes_per_row_padding } + + pub fn get_supported_read_only_binding_type( + &self, + buffers_per_shader_stage: u32, + ) -> BufferBindingType { + if self.limits().max_storage_buffers_per_shader_stage >= buffers_per_shader_stage { + BufferBindingType::Storage { read_only: true } + } else { + BufferBindingType::Uniform + } + } }