Pixel 11 Pro XL (PowerVR C-Series) aborts before the first frame: get_pixel10_driver_version matches one literal adapter name
Bevy version
0.19.1 (wgpu 29.0.4)
Relevant system information
Google Pixel 11 Pro XL (kodiak), Android 17.
Build fingerprint: google/kodiak/kodiak:17/CD1A.260905.001.B1/16238327:user/release-keys
AdapterInfo {
name: "PowerVR C-Series CXTP-48-1536 MC1",
vendor: 4112, device: 1879445570, device_type: IntegratedGpu,
driver: "PowerVR C-Series Vulkan Driver",
driver_info: "25.3@6908880",
backend: Vulkan,
subgroup_min_size: 32, subgroup_max_size: 128,
transient_saves_memory: true,
}
Built with cargo-apk / #[bevy_main], aarch64-linux-android, dev profile,
NativeActivity.
What you did
Started a DefaultPlugins app on the device. Nothing exotic: a 2D camera and a
bevy_ui tree.
What went wrong
The process aborts before the first frame is presented, inside the PowerVR
SPIR-V compiler, while IMG_vkCreateComputePipelines compiles a compute shader:
E spvcompiler: Unhandled sampler flag combo
F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 18432 (Async Compute T), pid 18390 (l.baylee.client)
Tombstone (top of a 56-frame backtrace):
#00 abort+160 /apex/com.android.runtime/lib64/bionic/libc.so
#01 spvcompiler::getMangledImageTypeString(spvcompiler::SpvTypeImage const*)+716 /vendor/lib64/libufwriter.so
#02 spvcompiler::LLVMWriter::getMangledSampledImageOpaqueName(...)+480 /vendor/lib64/libufwriter.so
#03 spvcompiler::LLVMWriter::getLLVMSamplerOrImageType(...)+596 /vendor/lib64/libufwriter.so
#04 spvcompiler::LLVMWriter::getLLVMType(...)+768 /vendor/lib64/libufwriter.so
#05 spvcompiler::LLVMWriter::generateLLVM(char const*, bool)+1516 /vendor/lib64/libufwriter.so
#06 spvcompiler::VulkanSpvCompilerIF::compileToUniflex(...)+3360 /vendor/lib64/libufwriter.so
#07 (anonymous namespace)::BILParseStreamsWithFlags(...)+96 /vendor/lib64/libufwriter.so
#08 BILParseStream+96 /vendor/lib64/libufwriter.so
#09 ComputeShaderCompileState::CompileUF()+100 /vendor/lib64/hw/vulkan.powervr.so
#10 CompileShaders+480 /vendor/lib64/hw/vulkan.powervr.so
#11 IMG_vkCreateComputePipelines+476 /vendor/lib64/hw/vulkan.powervr.so
#12.. libbaylee_client_android.so (wgpu / bevy)
getMangledImageTypeString + getMangledSampledImageOpaqueName inside
vkCreateComputePipelines means the driver is choking on a sampled-image
type in a compute shader. In 0.19.1 the compute shader that has one is
mesh_preprocess.wgsl (depth_pyramid: texture_2d<f32>), and that shader only
exists under GpuPreprocessingMode::Culling.
Why bevy's existing carve-out does not catch it
Bevy already knows this GPU family cannot do culling.
GpuPreprocessingSupport::from_world
(bevy_render/src/batching/gpu_preprocessing.rs:1336) has:
fn is_preprocessing_only_android_device(adapter_info: &RenderAdapterInfo) -> bool {
crate::get_pixel10_driver_version(adapter_info).is_some()
}
and get_pixel10_driver_version (bevy_render/src/lib.rs:571) begins:
if adapter_info.name != "PowerVR D-Series DXT-48-1536 MC1" {
return None;
}
That is exact string equality against one device's adapter name. The Pixel 11
Pro XL reports "PowerVR C-Series CXTP-48-1536 MC1" — same vendor
(4112 = Imagination Technologies), one generation newer, different string. It
falls through, is granted GpuPreprocessingMode::Culling, and aborts on the
first frame.
The two sibling checks in the same function are deliberately not exact:
fn is_non_supported_android_device(adapter_info: &RenderAdapterInfo) -> bool {
crate::get_adreno_model(adapter_info).is_some_and(|model| model != 720 && model <= 730)
|| crate::get_mali_driver_version(adapter_info).is_some_and(|version| version < 48)
}
get_adreno_model and get_mali_driver_version both parse a family out of
the name (contains("Mali"), a number out of v1.rNNp…). The Pixel 10 check is
the odd one out, and it is the one that aged out after a single hardware
generation.
Suggested fix
Recognise the family, the way the Adreno and Mali checks do — for example
if !adapter_info.name.starts_with("PowerVR") {
return None;
}
(or gate on vendor == 0x1010, Imagination Technologies). That still covers the
D-Series it was written for, and it would have covered this device on the day
it shipped. If a future PowerVR part is known good, an allow-list is cheaper
to maintain than a deny-list that has to be extended for every new SoC before
bevy will start on it at all.
Workaround, for anyone who lands here before that
Features::INDIRECT_FIRST_INSTANCE is read in exactly one place in bevy 0.19.1
— culling_feature_support in that same function:
bevy_render/src/batching/gpu_preprocessing.rs:1342: .contains(Features::INDIRECT_FIRST_INSTANCE | Features::IMMEDIATES)
(the only other hits in the tree are doc comments in
render_phase/draw_state.rs). So removing that one bit from the device asks
for PreprocessingOnly through the public API and clamps nothing else:
app.add_plugins(DefaultPlugins.set(RenderPlugin {
render_creation: WgpuSettings {
disabled_features: Some(WgpuFeatures::INDIRECT_FIRST_INSTANCE),
..default()
}
.into(),
..default()
}));
Confirm it took effect by bevy's own log line rather than by "it did not crash":
INFO bevy_render::batching::gpu_preprocessing: Some GPU preprocessing are limited on this device.
With that, the app starts and runs on this device.
Additional information
A second, unrelated-looking problem shows up on the same device once it starts:
bevy_ui renders a different random subset of its batch on every frame. That
is almost certainly the already-open #14710, and I have put the details there
rather than here.
One note in case it saves someone an hour: on this phone adb install -r
streams the APK incrementally, and the dynamic linker then faults with
SIGBUS / BUS_ADRERR in __dl_load_library on launch. It looks exactly like an
engine crash and is not one — adb install -r --no-incremental fixes it.
Source: bevyengine/bevy