Extract mesh view layouts logic (#13266)
Copied almost verbatim from the volumetric fog PR # Objective - Managing mesh view layouts is complicated ## Solution - Extract it to it's own struct - This was done as part of #13057 and is copied almost verbatim. I wanted to keep this part of the PR it's own atomic commit in case we ever have to revert fog or run a bisect. This change is good whether or not we have volumetric fog. Co-Authored-By: @pcwalton
This commit is contained in:
parent
1126b5a3d6
commit
4737106bdd
@ -33,15 +33,13 @@ use bevy_render::{
|
|||||||
texture::{BevyDefault, DefaultImageSampler, ImageSampler, TextureFormatPixelInfo},
|
texture::{BevyDefault, DefaultImageSampler, ImageSampler, TextureFormatPixelInfo},
|
||||||
view::{
|
view::{
|
||||||
prepare_view_targets, GpuCulling, RenderVisibilityRanges, ViewTarget, ViewUniformOffset,
|
prepare_view_targets, GpuCulling, RenderVisibilityRanges, ViewTarget, ViewUniformOffset,
|
||||||
ViewVisibility, VisibilityRange, VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
|
ViewVisibility, VisibilityRange,
|
||||||
},
|
},
|
||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::{tracing::error, tracing::warn, Entry, HashMap, Parallel};
|
use bevy_utils::{tracing::error, tracing::warn, Entry, HashMap, Parallel};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
use bevy_utils::warn_once;
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use nonmax::{NonMaxU16, NonMaxU32};
|
use nonmax::{NonMaxU16, NonMaxU32};
|
||||||
use static_assertions::const_assert_eq;
|
use static_assertions::const_assert_eq;
|
||||||
@ -234,6 +232,7 @@ impl Plugin for MeshRenderPlugin {
|
|||||||
|
|
||||||
render_app
|
render_app
|
||||||
.insert_resource(indirect_parameters_buffer)
|
.insert_resource(indirect_parameters_buffer)
|
||||||
|
.init_resource::<MeshPipelineViewLayouts>()
|
||||||
.init_resource::<MeshPipeline>();
|
.init_resource::<MeshPipeline>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1034,7 +1033,8 @@ fn collect_meshes_for_gpu_building(
|
|||||||
|
|
||||||
#[derive(Resource, Clone)]
|
#[derive(Resource, Clone)]
|
||||||
pub struct MeshPipeline {
|
pub struct MeshPipeline {
|
||||||
view_layouts: [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT],
|
/// A reference to all the mesh pipeline view layouts.
|
||||||
|
pub view_layouts: MeshPipelineViewLayouts,
|
||||||
// This dummy white texture is to be used in place of optional StandardMaterial textures
|
// This dummy white texture is to be used in place of optional StandardMaterial textures
|
||||||
pub dummy_white_gpu_image: GpuImage,
|
pub dummy_white_gpu_image: GpuImage,
|
||||||
pub clustered_forward_buffer_binding_type: BufferBindingType,
|
pub clustered_forward_buffer_binding_type: BufferBindingType,
|
||||||
@ -1065,18 +1065,12 @@ impl FromWorld for MeshPipeline {
|
|||||||
Res<RenderDevice>,
|
Res<RenderDevice>,
|
||||||
Res<DefaultImageSampler>,
|
Res<DefaultImageSampler>,
|
||||||
Res<RenderQueue>,
|
Res<RenderQueue>,
|
||||||
|
Res<MeshPipelineViewLayouts>,
|
||||||
)> = SystemState::new(world);
|
)> = SystemState::new(world);
|
||||||
let (render_device, default_sampler, render_queue) = system_state.get_mut(world);
|
let (render_device, default_sampler, render_queue, view_layouts) =
|
||||||
|
system_state.get_mut(world);
|
||||||
let clustered_forward_buffer_binding_type = render_device
|
let clustered_forward_buffer_binding_type = render_device
|
||||||
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
|
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
|
||||||
let visibility_ranges_buffer_binding_type = render_device
|
|
||||||
.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
|
|
||||||
|
|
||||||
let view_layouts = generate_view_layouts(
|
|
||||||
&render_device,
|
|
||||||
clustered_forward_buffer_binding_type,
|
|
||||||
visibility_ranges_buffer_binding_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
// A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
|
// A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
|
||||||
let dummy_white_gpu_image = {
|
let dummy_white_gpu_image = {
|
||||||
@ -1113,7 +1107,7 @@ impl FromWorld for MeshPipeline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MeshPipeline {
|
MeshPipeline {
|
||||||
view_layouts,
|
view_layouts: view_layouts.clone(),
|
||||||
clustered_forward_buffer_binding_type,
|
clustered_forward_buffer_binding_type,
|
||||||
dummy_white_gpu_image,
|
dummy_white_gpu_image,
|
||||||
mesh_layouts: MeshLayouts::new(&render_device),
|
mesh_layouts: MeshLayouts::new(&render_device),
|
||||||
@ -1141,16 +1135,7 @@ impl MeshPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout {
|
pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout {
|
||||||
let index = layout_key.bits() as usize;
|
self.view_layouts.get_view_layout(layout_key)
|
||||||
let layout = &self.view_layouts[index];
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {
|
|
||||||
// Issue our own warning here because Naga's error message is a bit cryptic in this situation
|
|
||||||
warn_once!("Too many textures in mesh pipeline view layout, this might cause us to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments.");
|
|
||||||
}
|
|
||||||
|
|
||||||
&layout.bind_group_layout
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{array, num::NonZeroU64};
|
use std::{array, num::NonZeroU64, sync::Arc};
|
||||||
|
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_3d::ViewTransmissionTexture,
|
core_3d::ViewTransmissionTexture,
|
||||||
@ -7,10 +7,12 @@ use bevy_core_pipeline::{
|
|||||||
get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,
|
get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
system::{Commands, Query, Res},
|
system::{Commands, Query, Res, Resource},
|
||||||
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use bevy_math::Vec4;
|
use bevy_math::Vec4;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
@ -19,13 +21,19 @@ use bevy_render::{
|
|||||||
render_resource::{binding_types::*, *},
|
render_resource::{binding_types::*, *},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::{BevyDefault, FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage},
|
texture::{BevyDefault, FallbackImage, FallbackImageMsaa, FallbackImageZero, GpuImage},
|
||||||
view::{Msaa, RenderVisibilityRanges, ViewUniform, ViewUniforms},
|
view::{
|
||||||
|
Msaa, RenderVisibilityRanges, ViewUniform, ViewUniforms,
|
||||||
|
VISIBILITY_RANGES_STORAGE_BUFFER_COUNT,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]
|
||||||
use bevy_render::render_resource::binding_types::texture_cube;
|
use bevy_render::render_resource::binding_types::texture_cube;
|
||||||
|
use bevy_utils::warn_once;
|
||||||
use environment_map::EnvironmentMapLight;
|
use environment_map::EnvironmentMapLight;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES;
|
||||||
use crate::{
|
use crate::{
|
||||||
environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},
|
environment_map::{self, RenderViewEnvironmentMapBindGroupEntries},
|
||||||
irradiance_volume::{
|
irradiance_volume::{
|
||||||
@ -35,6 +43,7 @@ use crate::{
|
|||||||
prepass, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta,
|
prepass, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta,
|
||||||
LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes,
|
LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes,
|
||||||
ScreenSpaceAmbientOcclusionTextures, ShadowSamplers, ViewClusterBindings, ViewShadowBindings,
|
ScreenSpaceAmbientOcclusionTextures, ShadowSamplers, ViewClusterBindings, ViewShadowBindings,
|
||||||
|
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -330,6 +339,65 @@ fn layout_entries(
|
|||||||
entries.to_vec()
|
entries.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stores the view layouts for every combination of pipeline keys.
|
||||||
|
///
|
||||||
|
/// This is wrapped in an [`Arc`] so that it can be efficiently cloned and
|
||||||
|
/// placed inside specializable pipeline types.
|
||||||
|
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||||
|
pub struct MeshPipelineViewLayouts(
|
||||||
|
pub Arc<[MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT]>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl FromWorld for MeshPipelineViewLayouts {
|
||||||
|
fn from_world(world: &mut World) -> Self {
|
||||||
|
// Generates all possible view layouts for the mesh pipeline, based on all combinations of
|
||||||
|
// [`MeshPipelineViewLayoutKey`] flags.
|
||||||
|
|
||||||
|
let render_device = world.resource::<RenderDevice>();
|
||||||
|
|
||||||
|
let clustered_forward_buffer_binding_type = render_device
|
||||||
|
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
|
||||||
|
let visibility_ranges_buffer_binding_type = render_device
|
||||||
|
.get_supported_read_only_binding_type(VISIBILITY_RANGES_STORAGE_BUFFER_COUNT);
|
||||||
|
|
||||||
|
Self(Arc::new(array::from_fn(|i| {
|
||||||
|
let key = MeshPipelineViewLayoutKey::from_bits_truncate(i as u32);
|
||||||
|
let entries = layout_entries(
|
||||||
|
clustered_forward_buffer_binding_type,
|
||||||
|
visibility_ranges_buffer_binding_type,
|
||||||
|
key,
|
||||||
|
render_device,
|
||||||
|
);
|
||||||
|
let texture_count: usize = entries
|
||||||
|
.iter()
|
||||||
|
.filter(|entry| matches!(entry.ty, BindingType::Texture { .. }))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
MeshPipelineViewLayout {
|
||||||
|
bind_group_layout: render_device
|
||||||
|
.create_bind_group_layout(key.label().as_str(), &entries),
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
texture_count,
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeshPipelineViewLayouts {
|
||||||
|
pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout {
|
||||||
|
let index = layout_key.bits() as usize;
|
||||||
|
let layout = &self[index];
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if layout.texture_count > MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES {
|
||||||
|
// Issue our own warning here because Naga's error message is a bit cryptic in this situation
|
||||||
|
warn_once!("Too many textures in mesh pipeline view layout, this might cause us to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments.");
|
||||||
|
}
|
||||||
|
|
||||||
|
&layout.bind_group_layout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates all possible view layouts for the mesh pipeline, based on all combinations of
|
/// Generates all possible view layouts for the mesh pipeline, based on all combinations of
|
||||||
/// [`MeshPipelineViewLayoutKey`] flags.
|
/// [`MeshPipelineViewLayoutKey`] flags.
|
||||||
pub fn generate_view_layouts(
|
pub fn generate_view_layouts(
|
||||||
|
Loading…
Reference in New Issue
Block a user