bevyengine / bevyengine/bevy

OcclusionCulling crashes without DepthPrepass

Open
#22,747 3 comments 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug C-Code-Quality D-Modest S-Ready-For-Implementation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

[Documentation](https://docs.rs/bevy/latest/bevy/render/experimental/occlusion_culling/struct.OcclusionCulling.html) says that
> Occlusion culling currently requires a DepthPrepass. If no depth prepass is present on the view, the OcclusionCulling component will be ignored.

However the actual behavior is a crash during the preparation for mipmap generation of the depth texture:

```
ERROR wgpu::backend::wgpu_core: Handling wgpu errors as fatal by default

thread 'Compute Task Pool (12)' (383983) panicked at ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wgpu-28.0.0/src/backend/wgpu_core.rs:1254:26:
wgpu error: Validation Error

Caused by:
In Device::create_bind_group, label = 'downsample multisample depth bind group'
Usage flags TextureUsages(RENDER_ATTACHMENT) of TextureView with '' label do not contain required usage flags TextureUsages(TEXTURE_BINDING)

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_core_pipeline::mip_generation::experimental::depth::prepare_downsample_depth_view_bind_groups`!
```

The `MipGenerationPlugin` is a dependent plugin of `CorePipelinePlugin`, and system `prepare_downsample_depth_view_bind_groups` constructs the bind groups referencing the source depth textures corresponding to either a camera view or a view used for shadow mapping. For the former case, the depth texture is not setup with `TEXTURE_BINDING` usage in general (in the absence of `DepthPrepass`).

So the requirement `OcclusionCulling => DepthPrepass` is somewhat indirectly enforced via `MipGenerationPlugin` (of course used for the implementation of `OcclusionCulling`, but also available for general purpose mipmap generation). As a side note, this plugin might be a little too eager to do work even when it is not actually used.

It also seems that this requirement can be lifted by adding the `TEXTURE_BINDING` usage when necessary, as suggested by the error, and adding this [here](https://github.com/bevyengine/bevy/blob/44ae8e2416e5ae3f97cad0e66b73ccd987bb0f3e/crates/bevy_core_pipeline/src/core_3d/mod.rs#L613)
```
pub fn prepare_core_3d_depth_textures(
mut commands: Commands,
mut texture_cache: ResMut,
render_device: Res,
views_3d: Query<(
Entity,
&ExtractedCamera,
Option<&DepthPrepass>,
&Camera3d,
Option<&OcclusionCulling>,
&Msaa,
)>,
)
...

if depth_prepass.is_some() {
// Required to read the output of the prepass
usage |= TextureUsages::COPY_SRC;
} else {
if occlusion_culling.is_some() {
usage |= TextureUsages::TEXTURE_BINDING;
}
}

...
```

I don't claim this is a correct solution, it just confirms the issue. Adding these lines fixes the crash and the `occclusion_culling` example then works even without `DepthPrepass`.

### Reproduction
To reproduce the error mentioned above, either
1. Add `OcclusionCulling` to a one of the 3d examples, e.g. [`3d_shapes`](https://github.com/bevyengine/bevy/blob/44ae8e2416e5ae3f97cad0e66b73ccd987bb0f3e/examples/3d/3d_shapes.rs#L191):
```
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 7., 14.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y),
bevy_render::occlusion_culling::OcclusionCulling,
));
```
or
2. Comment out ```DepthPrepass``` insertion in [`examples/3d/occlusion_culling.rs`](https://github.com/bevyengine/bevy/blob/44ae8e2416e5ae3f97cad0e66b73ccd987bb0f3e/examples/3d/occlusion_culling.rs#L371)

https://github.com/bevyengine/bevy/blob/44ae8e2416e5ae3f97cad0e66b73ccd987bb0f3e/examples/3d/occlusion_culling.rs#L371

Contributor guide

Open the contributing guide

Research direction

Start in crates/bevy_core_pipeline/src/core_3d/mod.rs, especially prepare_core_3d_depth_textures, and inspect how MipGenerationPlugin invokes prepare_downsample_depth_view_bind_groups. Reproduce with the 3d_shapes or examples/3d/occlusion_culling.rs cases after removing DepthPrepass. Done means OcclusionCulling without DepthPrepass no longer crashes and the relevant example runs successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.