diff --git a/crates/bevy_pbr/src/render/gpu_preprocess.rs b/crates/bevy_pbr/src/render/gpu_preprocess.rs index f54a1d5dd9..912f6192ce 100644 --- a/crates/bevy_pbr/src/render/gpu_preprocess.rs +++ b/crates/bevy_pbr/src/render/gpu_preprocess.rs @@ -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, >, preprocess_pipelines: ResMut, + gpu_preprocessing_support: Res, ) { 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, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 98501955a0..e00153d97b 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -3057,6 +3057,7 @@ impl RenderCommand

for DrawMesh { SRes, SRes, Option>, + SRes, ); type ViewQuery = Has; type ItemQuery = (); @@ -3072,6 +3073,7 @@ impl RenderCommand

for DrawMesh { pipeline_cache, mesh_allocator, preprocess_pipelines, + preprocessing_support, ): SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -3080,7 +3082,8 @@ impl RenderCommand

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; } diff --git a/crates/bevy_render/src/batching/gpu_preprocessing.rs b/crates/bevy_render/src/batching/gpu_preprocessing.rs index b8edb932ed..07694ecd0f 100644 --- a/crates/bevy_render/src/batching/gpu_preprocessing.rs +++ b/crates/bevy_render/src/batching/gpu_preprocessing.rs @@ -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