Bevy version and features
- Bevy 0.19.0 and bevy 0.20 dev
- wgpu 29.0.3 (from Cargo.lock)
- rustc 1.96.0 / cargo 1.96.0
default-features = false with the rendering, PBR, glTF, animation, windowing, asset and Android native activity features enabled. The attached minimal repro contains the exact feature list.
- Also reproduced on Bevy
main (0.20.0-dev, commit 49642fb5b247ccd9d0eeb982a29fabdbaff7b7cb, tested 2026-07-09).
Relevant system information
-
Android 13 / API 33, arm64
-
Device: ZTE A2023P
-
SoC: Snapdragon 8 Gen 1
-
GPU: Adreno (TM) 730
-
Backend: Vulkan through wgpu-hal
-
Adreno Vulkan driver: 0615.0 (build date 2022-07-19)
-
The GLB was exported from Mixamo
Relevant adapter/driver output:
AdapterInfo { name: "Adreno (TM) 730", driver: "Qualcomm Technologies Inc. Adreno Vulkan Driver", backend: Vulkan, ... }
Driver Path : /vendor/lib64/hw/vulkan.adreno.so
Driver Version : 0615.0
Application Name : wgpu
Engine Name : wgpu-hal
What you did
I reduced this from a game to a small Bevy app with no custom shaders or game systems. It loads one skinned GLB scene, creates an animation graph from the first clip, and plays it repeatedly:
commands.spawn((
WorldAssetRoot(asset_server.load(
GltfAssetLabel::Scene(0).from_asset("running.glb"),
)),
Transform::from_scale(Vec3::splat(1.0)),
));
let clip = asset_server.load(
GltfAssetLabel::Animation(0).from_asset("running.glb"),
);
let (graph, node) = AnimationGraph::from_clip(clip);
The same GLB renders and animates correctly in a desktop build.
Reproduction project: [bevy_android_skinning_repro.zip](https://github.com/user-attachments/files/29846990/bevy_android_skinning_repro.zip)
Android reproduction steps:
rustup target add aarch64-linux-android
cargo apk build --release --lib --target aarch64-linux-android
adb install -r target\release\apk\bevy-android-skinning-repro.apk
adb shell am start -n com.neonoverkill.skinrepro/android.app.NativeActivity
So far I have reproduced this on one Android device: ZTE A2023P / Snapdragon 8 Gen 1 / Adreno 730.
What went wrong
Expected: the Android/Vulkan output should match the desktop output for the same skinned GLB.
Actual: the character is corrupted into large stretched fragments. The fragments move between frames, so the animation is advancing, but the skinned vertex output is wrong. The material colors are present on the fragments.
Static GLBs render correctly on the same device. Baked non-skinned frames generated from this character also render correctly, which made this look specific to the skinned mesh render path rather than asset packaging or general GLB loading.
Broken Android screenshot:
Additional information
I tested a local change in bevy_pbr/src/render/skin.rs that forces Android to use the uniform-buffer skinning path:
pub fn skins_use_uniform_buffers(limits: &WgpuLimits) -> bool {
cfg!(target_os = "android")
|| bevy_render::storage_buffers_are_unsupported(limits)
}
With that change, the same APK, GLB and phone render the complete character correctly and the animation advances normally. I also tested five separate instances of the same animated scene at once; all five rendered correctly with the uniform-buffer path.
I repeated the test against the current Bevy main commit listed above. The unmodified storage-buffer build still failed: the character was not visible apart from a few corrupted pixels near the bottom of the screen. Rebuilding that same commit after applying the uniform-buffer change restored the complete animated character. So the issue is still present on current main; it is not specific to the 0.19.0 release.
Patched screenshots:
The minimal repro defaults to unmodified Bevy 0.19.0, so it shows the failure. The small Bevy patch is included separately as bevy_pbr_android_uniform_skinning.patch.
My best guess is that the storage-buffer skinning path is producing or reading incorrect joint matrix data on this Android/Vulkan/Adreno combination. I am not sure yet whether the underlying fault is in Bevy's shader/buffer handling, wgpu, or the Adreno driver, but selecting Bevy's uniform-buffer path avoids the corruption consistently on this device.
I do not think forcing uniform buffers on all Android devices is necessarily the right fix; I included it only because it isolates the failing path.
Bevy version and features
default-features = falsewith the rendering, PBR, glTF, animation, windowing, asset and Android native activity features enabled. The attached minimal repro contains the exact feature list.main(0.20.0-dev, commit49642fb5b247ccd9d0eeb982a29fabdbaff7b7cb, tested 2026-07-09).Relevant system information
Android 13 / API 33, arm64
Device: ZTE A2023P
SoC: Snapdragon 8 Gen 1
GPU: Adreno (TM) 730
Backend: Vulkan through wgpu-hal
Adreno Vulkan driver: 0615.0 (build date 2022-07-19)
The GLB was exported from Mixamo
Relevant adapter/driver output:
What you did
I reduced this from a game to a small Bevy app with no custom shaders or game systems. It loads one skinned GLB scene, creates an animation graph from the first clip, and plays it repeatedly:
The same GLB renders and animates correctly in a desktop build.
Reproduction project: [bevy_android_skinning_repro.zip](https://github.com/user-attachments/files/29846990/bevy_android_skinning_repro.zip)
Android reproduction steps:
So far I have reproduced this on one Android device: ZTE A2023P / Snapdragon 8 Gen 1 / Adreno 730.
What went wrong
Expected: the Android/Vulkan output should match the desktop output for the same skinned GLB.
Actual: the character is corrupted into large stretched fragments. The fragments move between frames, so the animation is advancing, but the skinned vertex output is wrong. The material colors are present on the fragments.
Static GLBs render correctly on the same device. Baked non-skinned frames generated from this character also render correctly, which made this look specific to the skinned mesh render path rather than asset packaging or general GLB loading.
Broken Android screenshot:
Additional information
I tested a local change in
bevy_pbr/src/render/skin.rsthat forces Android to use the uniform-buffer skinning path:With that change, the same APK, GLB and phone render the complete character correctly and the animation advances normally. I also tested five separate instances of the same animated scene at once; all five rendered correctly with the uniform-buffer path.
I repeated the test against the current Bevy
maincommit listed above. The unmodified storage-buffer build still failed: the character was not visible apart from a few corrupted pixels near the bottom of the screen. Rebuilding that same commit after applying the uniform-buffer change restored the complete animated character. So the issue is still present on currentmain; it is not specific to the 0.19.0 release.Patched screenshots:
The minimal repro defaults to unmodified Bevy 0.19.0, so it shows the failure. The small Bevy patch is included separately as
bevy_pbr_android_uniform_skinning.patch.My best guess is that the storage-buffer skinning path is producing or reading incorrect joint matrix data on this Android/Vulkan/Adreno combination. I am not sure yet whether the underlying fault is in Bevy's shader/buffer handling, wgpu, or the Adreno driver, but selecting Bevy's uniform-buffer path avoids the corruption consistently on this device.
I do not think forcing uniform buffers on all Android devices is necessarily the right fix; I included it only because it isolates the failing path.