Skip to content

Commit

Permalink
Move storage buffer detection to RenderDevice
Browse files Browse the repository at this point in the history
  • Loading branch information
cart committed Apr 5, 2022
1 parent b77c4fc commit 34aab16
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 83 deletions.
10 changes: 2 additions & 8 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -127,11 +126,6 @@ impl Plugin for PbrPlugin {
},
);

let supported_binding_types = SupportedBindingTypes::from_device(
app.world.resource::<RenderDevice>(),
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
);

let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
Expand Down Expand Up @@ -170,7 +164,7 @@ impl Plugin for PbrPlugin {
.init_resource::<ShadowPipeline>()
.init_resource::<DrawFunctions<Shadow>>()
.init_resource::<LightMeta>()
.insert_resource(GlobalLightMeta::new(supported_binding_types))
.init_resource::<GlobalLightMeta>()
.init_resource::<SpecializedMeshPipelines<ShadowPipeline>>();

let shadow_pass_node = ShadowPassNode::new(&mut render_app.world);
Expand Down
13 changes: 7 additions & 6 deletions crates/bevy_pbr/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -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(
Expand Down
10 changes: 5 additions & 5 deletions crates/bevy_pbr/src/pbr_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 { .. }
),
}
}

Expand Down
47 changes: 29 additions & 18 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}

Expand Down Expand Up @@ -602,10 +601,20 @@ pub struct GlobalLightMeta {
pub entity_to_index: HashMap<Entity, usize>,
}

impl FromWorld for GlobalLightMeta {
fn from_world(world: &mut World) -> Self {
Self::new(
world
.resource::<RenderDevice>()
.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(),
}
}
Expand Down Expand Up @@ -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(),
}
}

Expand Down Expand Up @@ -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),
}
}

Expand Down Expand Up @@ -1191,6 +1199,7 @@ pub fn prepare_clusters(
mut commands: Commands,
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mesh_pipeline: Res<MeshPipeline>,
global_light_meta: Res<GlobalLightMeta>,
views: Query<
(
Expand All @@ -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;
Expand Down
25 changes: 11 additions & 14 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<RenderDevice>();
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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -353,6 +349,7 @@ impl FromWorld for MeshPipeline {
MeshPipeline {
view_layout,
mesh_layout,
clustered_forward_buffer_binding_type,
dummy_white_gpu_image,
}
}
Expand Down
34 changes: 3 additions & 31 deletions crates/bevy_render/src/render_resource/storage_buffer.rs
Original file line number Diff line number Diff line change
@@ -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<T: AsStd430, U: AsStd430 = ()> {
body: U,
Expand Down
13 changes: 12 additions & 1 deletion crates/bevy_render/src/renderer/render_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
}
}
}

0 comments on commit 34aab16

Please sign in to comment.