Summary
On Samsung Galaxy S26 (Exynos 2600 / Xclipse 960), Engine.initialize() fails for any LiteRT-LM model when backend = Backend.GPU(). The native LITERT_CL delegate is selected, then its kernel build step fails: Clspv (the OpenCL → SPIR-V compiler used by Samsung's ANGLE-CL implementation of libOpenCL.so) rejects an MLDrift-generated kernel that initializes a __constant pointer with a __global value. Engine creation throws LiteRtLmJniException: Failed to create engine: INTERNAL: ERROR .... Since Backend.GPU() has no automatic CPU fallback, the app surfaces the error to the user.
The same failure reproduces in the official AI Edge Gallery app (v1.0.12 generic APK) on the same device, with both Gemma-4-E2B-it and Gemma3-1B-IT — i.e. with the team's own reference Kotlin code (LlmChatModelHelper.kt).
Device fingerprint
- Device: Samsung Galaxy S26 (Exynos variant), 12 GB RAM
- GPU / driver: Samsung Xclipse 960 on Vulkan 1.4.304
- OpenCL runtime:
libOpenCL.so is ANGLE-CL (no native vendor CL driver on this SoC)
- ANGLE Version:
25.2.13 (git 4d70502cade5)
- Clspv revision:
43805b00de5b
- OCL revision:
95b8efdb36c2
- Vendor-supplied ANGLE-CL — system property
vendor.angle-cl.max_command_count is present.
- Android API 35, target / compile SDK 35.
Reproduction matrix — all fail identically
litertlm-android versions tried
Models tried (both fail at engine init, before any inference)
litert-community/gemma-4-E2B-it-litert-lm/gemma-4-E2B-it.litertlm (multimodal, ~2.4 GB)
litert-community/Gemma3-1B-IT/Gemma3-1B-IT_multi-prefill-seq_q4_ekv4096.litertlm (text-only, 557 MB)
EngineConfig variants tried
- Minimal (per
docs/api/kotlin/getting_started.md):
EngineConfig(modelPath = path, backend = Backend.GPU())
- With
cacheDir = context.cacheDir.absolutePath.
- Mirroring
LlmChatModelHelper.kt in google-ai-edge/gallery exactly:
EngineConfig(
modelPath = path,
backend = Backend.GPU(),
visionBackend = null,
audioBackend = null,
maxNumTokens = 4096,
cacheDir = context.cacheDir.absolutePath,
)
All three variants fail at engine.initialize() with the same LiteRtLmJniException.
AndroidManifest.xml declares the recommended native libs:
<uses-native-library android:name="libvndksupport.so" android:required="false"/>
<uses-native-library android:name="libOpenCL.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false"/>
Cross-check: AI Edge Gallery reproduces the same failure
To rule out anything app-side, I installed the official ai-edge-gallery.apk v1.0.12 (the non-Snapdragon-NPU "generic" APK from the v1.0.12 release) on the same physical device.
- AI Chat → Gemma-4-E2B-it (Best overall recommended) → Error dialog:
Failed to create engine: INTERNAL: ERROR: [third_party/odml/litert_lm/runtime/executor/llm_litert_compiled_model_executor.cc:1952] └ ERROR: [./third_party/odml/litert/litert/cc/litert_compiled_model.h:1140]
- AI Chat → Gemma3-1B-IT → identical error dialog at the same source lines.
The Gallery uses litertlm = "0.10.0" per its Android/src/gradle/libs.versions.toml, and the engine setup in LlmChatModelHelper.kt is exactly the EngineConfig variant 3 above.
I'm happy to attach screenshots; let me know if useful.
Native error excerpt (from adb logcat -v threadtime, our app, but identical pattern in the Gallery)
ANGLE-CL: OCL version revision number = 95b8efdb36c2
ANGLE-CL: CLSPV version revision number = 43805b00de5b
ANGLE : Version (25.2.13 git hash: 4d70502cade5),
Renderer ((Samsung Xclipse 960) on Vulkan 1.4.304)
tflite : Replacing 1330 out of 1330 node(s) with delegate (LITERT_CL) node, yielding 1 partitions for subgraph 0.
native : I delegate_kernel.cc:716 Initializing OpenCL-based API from serialized data.
tflite : Replacing 1373 out of 1373 node(s) with delegate (LITERT_CL) node, yielding 1 partitions for subgraph 1.
native : I delegate_kernel.cc:716 Initializing OpenCL-based API from serialized data.
ANGLE : ERR: CLProgramVk.cpp:960 (buildInternal): OpenCL build failed with: ClspvError(3)!
ANGLE : ERR: CLProgramVk.cpp:961 (buildInternal): Clspv option: -cl-std=CL3.0 -arch=spir
-cl-arm-non-uniform-work-group-size --spv-version=1.4 --long-vector --global-offset
--enable-printf --cl-kernel-arg-info --int8 --rewrite-packed-structs
--no-16bit-storage=pushconstant --std430-ubo-layout --fp16 --fp64=0
--rounding-mode-rte=32,16
--enable-feature-macros=__opencl_c_atomic_order_acq_rel,
__opencl_c_atomic_order_seq_cst,__opencl_c_atomic_scope_device,
__opencl_c_images,__opencl_c_3d_image_writes,__opencl_c_read_write_images,
__opencl_c_int64,__opencl_c_integer_dot_product_input_4x8bit,
__opencl_c_integer_dot_product_input_4x8bit_packed,__opencl_c_subgroups
--use-native-builtins=fma,half_exp2,exp2, -vectorize-loops=false
ANGLE : ERR: cl_stubs.cpp:488 (BuildProgram): failed with error code: -11
native : E delegate_opencl.cc:330 Failed to create litert::ml_drift::DelegateKernelLiteRt:
UNKNOWN: Failed to build program executable - Build program failure
native : source:42:21: error: initializing '__constant uint4 *__private' with an
expression of type '__global uint4 *' changes address space of pointer
native : 42 | __constant uint4* weights_offset =
weights_buffer + DST_S * 4 * shared_int4_1.w / 4;
native : third_party/odml/litert/ml_drift/delegate/gpu_backend_opencl_litert.cc:334
native : third_party/odml/litert/ml_drift/delegate/delegate_kernel.cc:725
native : third_party/odml/litert/ml_drift/delegate/delegate_kernel.cc:652
native : third_party/odml/litert/ml_drift/delegate/delegate_kernel.cc:744
native : third_party/odml/litert/ml_drift/delegate/delegate_kernel.cc:287
native : third_party/odml/litert/ml_drift/delegate/delegate_kernel_litert.cc:159
tflite : Failed to initialize kernel.
tflite : Restored original execution plan after delegate application failure.
Root cause (best read)
In third_party/odml/litert/ml_drift/delegate/gpu_backend_opencl_litert.cc:334, the generated kernel does:
__constant uint4* weights_offset = weights_buffer + DST_S * 4 * shared_int4_1.w / 4;
weights_buffer is __global uint4*. Native vendor OpenCL drivers (Adreno, Mali) typically accept this implicit address-space conversion; Clspv rejects it as a hard error ("changes address space of pointer"). Since LITERT_CL is the only delegate registered for Backend.GPU() and the kernel build is part of the engine-init critical path, the entire Engine construction fails and no inference is possible.
This isn't model-specific — both a 1.5B-param text-only Gemma 3 and the multimodal 2B Gemma 4 E2B fail at the same source line.
Expected behavior
Backend.GPU() succeeds on a current Samsung flagship that ships ANGLE-CL as libOpenCL.so (which is the direction Pixel and Samsung have both moved on recent generations). The Kotlin API surface is documented as Stable for Android in docs/api/kotlin/getting_started.md, with no chipset caveats; the Gallery's "Best overall" recommendation is precisely Gemma-4-E2B-it, so this combo is the intended primary path.
Suggested fix directions
- MLDrift codegen fix — declare
weights_offset (and any similar derived helper pointers) as __global* instead of __constant* when their initializer is a __global value. The __constant qualifier only saves anything if the address is actually constant memory; for a weights_buffer + DST_S * ... expression it's __global-derived anyway.
- Clspv-aware kernel variant — detect ANGLE-CL (
vendor.angle-cl.* properties, or query CL platform vendor string) at runtime and emit a Clspv-compatible kernel template.
- Document the LITERT_CL device support matrix — at minimum, list which CL runtimes the GPU backend is tested on (Adreno native, Mali native, ANGLE-CL on Pixel, etc.) so app authors targeting ANGLE-CL-only devices can pick a non-GPU backend up-front rather than hitting this at engine init.
Workarounds for app authors hitting this today
Backend.CPU() works fine on the same device (untested for tok/s, but engine init succeeds).
- Targeting Snapdragon-only is the de facto current state — Edge Gallery's per-SoC NPU APKs are all
sm**** (Qualcomm).
Happy to provide more logcat, attach screenshots of the Gallery error dialogs, or test patches.
Summary
On Samsung Galaxy S26 (Exynos 2600 / Xclipse 960),
Engine.initialize()fails for any LiteRT-LM model whenbackend = Backend.GPU(). The native LITERT_CL delegate is selected, then its kernel build step fails: Clspv (the OpenCL → SPIR-V compiler used by Samsung's ANGLE-CL implementation oflibOpenCL.so) rejects an MLDrift-generated kernel that initializes a__constantpointer with a__globalvalue. Engine creation throwsLiteRtLmJniException: Failed to create engine: INTERNAL: ERROR .... SinceBackend.GPU()has no automatic CPU fallback, the app surfaces the error to the user.The same failure reproduces in the official AI Edge Gallery app (v1.0.12 generic APK) on the same device, with both Gemma-4-E2B-it and Gemma3-1B-IT — i.e. with the team's own reference Kotlin code (
LlmChatModelHelper.kt).Device fingerprint
libOpenCL.sois ANGLE-CL (no native vendor CL driver on this SoC)25.2.13(git4d70502cade5)43805b00de5b95b8efdb36c2vendor.angle-cl.max_command_countis present.Reproduction matrix — all fail identically
litertlm-androidversions tried0.10.00.10.2Models tried (both fail at engine init, before any inference)
litert-community/gemma-4-E2B-it-litert-lm/gemma-4-E2B-it.litertlm(multimodal, ~2.4 GB)litert-community/Gemma3-1B-IT/Gemma3-1B-IT_multi-prefill-seq_q4_ekv4096.litertlm(text-only, 557 MB)EngineConfigvariants trieddocs/api/kotlin/getting_started.md):cacheDir = context.cacheDir.absolutePath.LlmChatModelHelper.ktingoogle-ai-edge/galleryexactly:All three variants fail at
engine.initialize()with the sameLiteRtLmJniException.AndroidManifest.xmldeclares the recommended native libs:Cross-check: AI Edge Gallery reproduces the same failure
To rule out anything app-side, I installed the official
ai-edge-gallery.apkv1.0.12 (the non-Snapdragon-NPU "generic" APK from the v1.0.12 release) on the same physical device.Failed to create engine: INTERNAL: ERROR: [third_party/odml/litert_lm/runtime/executor/llm_litert_compiled_model_executor.cc:1952] └ ERROR: [./third_party/odml/litert/litert/cc/litert_compiled_model.h:1140]The Gallery uses
litertlm = "0.10.0"per itsAndroid/src/gradle/libs.versions.toml, and the engine setup inLlmChatModelHelper.ktis exactly the EngineConfig variant 3 above.I'm happy to attach screenshots; let me know if useful.
Native error excerpt (from
adb logcat -v threadtime, our app, but identical pattern in the Gallery)Root cause (best read)
In
third_party/odml/litert/ml_drift/delegate/gpu_backend_opencl_litert.cc:334, the generated kernel does:weights_bufferis__global uint4*. Native vendor OpenCL drivers (Adreno, Mali) typically accept this implicit address-space conversion; Clspv rejects it as a hard error ("changes address space of pointer"). Since LITERT_CL is the only delegate registered forBackend.GPU()and the kernel build is part of the engine-init critical path, the entireEngineconstruction fails and no inference is possible.This isn't model-specific — both a 1.5B-param text-only Gemma 3 and the multimodal 2B Gemma 4 E2B fail at the same source line.
Expected behavior
Backend.GPU()succeeds on a current Samsung flagship that ships ANGLE-CL aslibOpenCL.so(which is the direction Pixel and Samsung have both moved on recent generations). The Kotlin API surface is documented as Stable for Android indocs/api/kotlin/getting_started.md, with no chipset caveats; the Gallery's "Best overall" recommendation is precisely Gemma-4-E2B-it, so this combo is the intended primary path.Suggested fix directions
weights_offset(and any similar derived helper pointers) as__global*instead of__constant*when their initializer is a__globalvalue. The__constantqualifier only saves anything if the address is actually constant memory; for aweights_buffer + DST_S * ...expression it's__global-derived anyway.vendor.angle-cl.*properties, or query CL platform vendor string) at runtime and emit a Clspv-compatible kernel template.Workarounds for app authors hitting this today
Backend.CPU()works fine on the same device (untested for tok/s, but engine init succeeds).sm****(Qualcomm).Happy to provide more logcat, attach screenshots of the Gallery error dialogs, or test patches.