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

View File

@ -3057,6 +3057,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
SRes<PipelineCache>,
SRes<MeshAllocator>,
Option<SRes<PreprocessPipelines>>,
SRes<GpuPreprocessingSupport>,
);
type ViewQuery = Has<PreprocessBindGroups>;
type ItemQuery = ();
@ -3072,6 +3073,7 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
pipeline_cache,
mesh_allocator,
preprocess_pipelines,
preprocessing_support,
): SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
@ -3080,7 +3082,8 @@ impl<P: PhaseItem> RenderCommand<P> for DrawMesh {
// it's compiled. Otherwise, our mesh instance data won't be present.
if let Some(preprocess_pipelines) = preprocess_pipelines {
if !has_preprocess_bind_group
|| !preprocess_pipelines.pipelines_are_loaded(&pipeline_cache)
|| !preprocess_pipelines
.pipelines_are_loaded(&pipeline_cache, &preprocessing_support)
{
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.
@ -1096,7 +1101,7 @@ impl FromWorld for GpuPreprocessingSupport {
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::MULTI_DRAW_INDIRECT
| Features::PUSH_CONSTANTS,
@ -1107,12 +1112,11 @@ impl FromWorld for GpuPreprocessingSupport {
DownlevelFlags::VERTEX_AND_INSTANCE_INDEX_RESPECTS_RESPECTIVE_FIRST_VALUE_IN_INDIRECT_DRAW
);
let max_supported_mode = if !feature_support
|| device.limits().max_compute_workgroup_size_x == 0
let max_supported_mode = if device.limits().max_compute_workgroup_size_x == 0
|| is_non_supported_android_device(adapter)
{
GpuPreprocessingMode::None
} else if !(feature_support && limit_support && downlevel_support) {
} else if !(culling_feature_support && limit_support && downlevel_support) {
GpuPreprocessingMode::PreprocessingOnly
} else {
GpuPreprocessingMode::Culling