Initialize pre-processing pipelines only when culling is enabled. (#18759)

Better fix for #18463 that still allows enabling mesh preprocessing on
webgpu.

Fixes #18463
This commit is contained in:
charlotte 2025-04-09 14:31:29 -07:00 committed by GitHub
parent 065a95e0a1
commit f75078676b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 42 deletions

View File

@ -27,7 +27,7 @@ use bevy_ecs::{
world::{FromWorld, World}, world::{FromWorld, World},
}; };
use bevy_render::batching::gpu_preprocessing::{ use bevy_render::batching::gpu_preprocessing::{
IndirectParametersGpuMetadata, UntypedPhaseIndirectParametersBuffers, GpuPreprocessingMode, IndirectParametersGpuMetadata, UntypedPhaseIndirectParametersBuffers,
}; };
use bevy_render::{ use bevy_render::{
batching::gpu_preprocessing::{ batching::gpu_preprocessing::{
@ -1173,26 +1173,41 @@ fn run_build_indirect_parameters_node(
impl PreprocessPipelines { impl PreprocessPipelines {
/// Returns true if the preprocessing and indirect parameters pipelines have /// Returns true if the preprocessing and indirect parameters pipelines have
/// been loaded or false otherwise. /// been loaded or false otherwise.
pub(crate) fn pipelines_are_loaded(&self, pipeline_cache: &PipelineCache) -> bool { pub(crate) fn pipelines_are_loaded(
self.direct_preprocess.is_loaded(pipeline_cache) &self,
&& self pipeline_cache: &PipelineCache,
.gpu_frustum_culling_preprocess preprocessing_support: &GpuPreprocessingSupport,
.is_loaded(pipeline_cache) ) -> bool {
&& self match preprocessing_support.max_supported_mode {
.early_gpu_occlusion_culling_preprocess GpuPreprocessingMode::None => false,
.is_loaded(pipeline_cache) GpuPreprocessingMode::PreprocessingOnly => {
&& self self.direct_preprocess.is_loaded(pipeline_cache)
.late_gpu_occlusion_culling_preprocess && self
.is_loaded(pipeline_cache) .gpu_frustum_culling_preprocess
&& self .is_loaded(pipeline_cache)
.gpu_frustum_culling_build_indexed_indirect_params }
.is_loaded(pipeline_cache) GpuPreprocessingMode::Culling => {
&& self self.direct_preprocess.is_loaded(pipeline_cache)
.gpu_frustum_culling_build_non_indexed_indirect_params && self
.is_loaded(pipeline_cache) .gpu_frustum_culling_preprocess
&& self.early_phase.is_loaded(pipeline_cache) .is_loaded(pipeline_cache)
&& self.late_phase.is_loaded(pipeline_cache) && self
&& self.main_phase.is_loaded(pipeline_cache) .early_gpu_occlusion_culling_preprocess
.is_loaded(pipeline_cache)
&& self
.late_gpu_occlusion_culling_preprocess
.is_loaded(pipeline_cache)
&& self
.gpu_frustum_culling_build_indexed_indirect_params
.is_loaded(pipeline_cache)
&& self
.gpu_frustum_culling_build_non_indexed_indirect_params
.is_loaded(pipeline_cache)
&& self.early_phase.is_loaded(pipeline_cache)
&& self.late_phase.is_loaded(pipeline_cache)
&& self.main_phase.is_loaded(pipeline_cache)
}
}
} }
} }
@ -1495,6 +1510,7 @@ pub fn prepare_preprocess_pipelines(
SpecializedComputePipelines<BuildIndirectParametersPipeline>, SpecializedComputePipelines<BuildIndirectParametersPipeline>,
>, >,
preprocess_pipelines: ResMut<PreprocessPipelines>, preprocess_pipelines: ResMut<PreprocessPipelines>,
gpu_preprocessing_support: Res<GpuPreprocessingSupport>,
) { ) {
let preprocess_pipelines = preprocess_pipelines.into_inner(); let preprocess_pipelines = preprocess_pipelines.into_inner();
@ -1508,22 +1524,25 @@ pub fn prepare_preprocess_pipelines(
&mut specialized_preprocess_pipelines, &mut specialized_preprocess_pipelines,
PreprocessPipelineKey::FRUSTUM_CULLING, PreprocessPipelineKey::FRUSTUM_CULLING,
); );
preprocess_pipelines
.early_gpu_occlusion_culling_preprocess if gpu_preprocessing_support.is_culling_supported() {
.prepare( preprocess_pipelines
&pipeline_cache, .early_gpu_occlusion_culling_preprocess
&mut specialized_preprocess_pipelines, .prepare(
PreprocessPipelineKey::FRUSTUM_CULLING &pipeline_cache,
| PreprocessPipelineKey::OCCLUSION_CULLING &mut specialized_preprocess_pipelines,
| PreprocessPipelineKey::EARLY_PHASE, PreprocessPipelineKey::FRUSTUM_CULLING
); | PreprocessPipelineKey::OCCLUSION_CULLING
preprocess_pipelines | PreprocessPipelineKey::EARLY_PHASE,
.late_gpu_occlusion_culling_preprocess );
.prepare( preprocess_pipelines
&pipeline_cache, .late_gpu_occlusion_culling_preprocess
&mut specialized_preprocess_pipelines, .prepare(
PreprocessPipelineKey::FRUSTUM_CULLING | PreprocessPipelineKey::OCCLUSION_CULLING, &pipeline_cache,
); &mut specialized_preprocess_pipelines,
PreprocessPipelineKey::FRUSTUM_CULLING | PreprocessPipelineKey::OCCLUSION_CULLING,
);
}
let mut build_indirect_parameters_pipeline_key = BuildIndirectParametersPipelineKey::empty(); let mut build_indirect_parameters_pipeline_key = BuildIndirectParametersPipelineKey::empty();
@ -1553,6 +1572,10 @@ pub fn prepare_preprocess_pipelines(
build_indirect_parameters_pipeline_key, build_indirect_parameters_pipeline_key,
); );
if !gpu_preprocessing_support.is_culling_supported() {
return;
}
for (preprocess_phase_pipelines, build_indirect_parameters_phase_pipeline_key) in [ for (preprocess_phase_pipelines, build_indirect_parameters_phase_pipeline_key) in [
( (
&mut preprocess_pipelines.early_phase, &mut preprocess_pipelines.early_phase,

View File

@ -3057,6 +3057,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
SRes<PipelineCache>, SRes<PipelineCache>,
SRes<MeshAllocator>, SRes<MeshAllocator>,
Option<SRes<PreprocessPipelines>>, Option<SRes<PreprocessPipelines>>,
SRes<GpuPreprocessingSupport>,
); );
type ViewQuery = Has<PreprocessBindGroups>; type ViewQuery = Has<PreprocessBindGroups>;
type ItemQuery = (); type ItemQuery = ();
@ -3072,6 +3073,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
pipeline_cache, pipeline_cache,
mesh_allocator, mesh_allocator,
preprocess_pipelines, preprocess_pipelines,
preprocessing_support,
): SystemParamItem<'w, '_, Self::Param>, ): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>, pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult { ) -> RenderCommandResult {
@ -3080,7 +3082,8 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
// it's compiled. Otherwise, our mesh instance data won't be present. // it's compiled. Otherwise, our mesh instance data won't be present.
if let Some(preprocess_pipelines) = preprocess_pipelines { if let Some(preprocess_pipelines) = preprocess_pipelines {
if !has_preprocess_bind_group if !has_preprocess_bind_group
|| !preprocess_pipelines.pipelines_are_loaded(&pipeline_cache) || !preprocess_pipelines
.pipelines_are_loaded(&pipeline_cache, &preprocessing_support)
{ {
return RenderCommandResult::Skip; return RenderCommandResult::Skip;
} }

View File

@ -111,6 +111,11 @@ impl GpuPreprocessingSupport {
} }
} }
} }
/// Returns true if GPU culling is supported on this platform.
pub fn is_culling_supported(&self) -> bool {
self.max_supported_mode == GpuPreprocessingMode::Culling
}
} }
/// The amount of GPU preprocessing (compute and indirect draw) that we do. /// The amount of GPU preprocessing (compute and indirect draw) that we do.
@ -1096,7 +1101,7 @@ impl FromWorld for GpuPreprocessingSupport {
crate::get_adreno_model(adapter).is_some_and(|model| model != 720 && model <= 730) crate::get_adreno_model(adapter).is_some_and(|model| model != 720 && model <= 730)
} }
let feature_support = device.features().contains( let culling_feature_support = device.features().contains(
Features::INDIRECT_FIRST_INSTANCE Features::INDIRECT_FIRST_INSTANCE
| Features::MULTI_DRAW_INDIRECT | Features::MULTI_DRAW_INDIRECT
| Features::PUSH_CONSTANTS, | Features::PUSH_CONSTANTS,
@ -1107,12 +1112,11 @@ impl FromWorld for GpuPreprocessingSupport {
DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW
); );
let max_supported_mode = if !feature_support let max_supported_mode = if device.limits().max_compute_workgroup_size_x == 0
|| device.limits().max_compute_workgroup_size_x == 0
|| is_non_supported_android_device(adapter) || is_non_supported_android_device(adapter)
{ {
GpuPreprocessingMode::None GpuPreprocessingMode::None
} else if !(feature_support && limit_support && downlevel_support) { } else if !(culling_feature_support && limit_support && downlevel_support) {
GpuPreprocessingMode::PreprocessingOnly GpuPreprocessingMode::PreprocessingOnly
} else { } else {
GpuPreprocessingMode::Culling GpuPreprocessingMode::Culling