Skip to content

Vulkan backend incorrectly skips barriers #8853

@AlbinBernhardssonARM

Description

@AlbinBernhardssonARM

wgpu-core contains logic to skip unnecessary barriers if the usage hasn't changed and is "ordered". What uses count as ordered are defined in wgpu-types. This includes Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits().

While this may be true for DX12 when using legacy barriers (no need to transition from RENDER_TARGET to RENDER_TARGET (I am not a DX12 expert)), this is not true in Vulkan. Vulkan makes very few execution ordering guarantees. The only guarantees are: order of primitives in the graphics pipeline, the order of image layout transitions (relative to other image layout transitions) and the order of pipeline stages within one command (ie. fragment shading happens after vertex shading). Everything else can execute out of order / in parallel unless an execution dependency is issued. For instance, on a tiled architecture, two render passes will execute in parallel, regardless of submission order, unless some synchronization primitive is used to ensure the order.

Additionally, for write-after-write and read-after-write hazards, ensuring correct execution order is not enough. Memory dependencies must also be expressed to ensure correct cache flushing/invalidation.

This is the case in Bevy's Android example, which contains two render passes:

  1. Render pass 1 renders the 3D scene.
  2. Render pass 2 renders a 2D overlay.

Both render passes render to the same color attachment. This is a write-after-write hazard, which requires a pipeline barrier from COLOR_ATTACHMENT_OUTPUT_BIT to COLOR_ATTACHMENT_OUTPUT_BIT with the associated image memory barrier. wgpu incorrectly skips the barrier since both uses of the color attachment are COLOR_TARGET, which is considered ordered. This leads to these rendering artifacts on Immortalis-G715:

bevy_rendering_artifacts.mp4

Removing Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() from ORDERED fixes the artifacts (remaining uses aren't "ordered" by Vulkan either but are read-only so ordering doesn't matter). However, removing them may negatively affect other backends (at least DX12). So I believe the proper solution is to move the barrier skipping logic from wgpu-core/wgpu-types to wgpu-hal on a per-backend basis as different backends have different synchronization requirements.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions