Skip to content

Fix Adreno GPU crashes from symbol UBO dynamic indexing#13653

Closed
navidemad wants to merge 5 commits intomapbox:mainfrom
navidemad:fix/adreno-symbol-ubo-crash-v2
Closed

Fix Adreno GPU crashes from symbol UBO dynamic indexing#13653
navidemad wants to merge 5 commits intomapbox:mainfrom
navidemad:fix/adreno-symbol-ubo-crash-v2

Conversation

@navidemad
Copy link
Copy Markdown

@navidemad navidemad commented Apr 4, 2026

Summary

Fixes #13651 — v3.21.0 crashes on Android Pixel devices (Pixel 7, 8, 8A, 9a) during zoom/pan due to Adreno GPU incompatibility with the new symbol UBO feature.

Root cause: Adreno GPUs (like PowerVR, already disabled in 9880b06b) do not correctly handle dynamic (non-uniform) indexing into UBO arrays — this is technically undefined behavior in GLSL ES 3.00. The symbol shader also had inconsistent Adreno workarounds: uvec4At/vec4At used safe explicit swizzles, but readFloat/readUint used direct bracket indexing that fails on affected Adreno drivers.

Changes

  • src/gl/context.ts — Disable symbol UBO batching on Adreno GPUs, matching the existing PowerVR treatment.
  • src/shaders/symbol.vertex.glsl — Replace direct slot[index] bracket indexing in readFloat/readUint with the existing Adreno-safe vec4At/uvec4At helpers.
  • src/data/bucket/symbol_properties_ubo.ts — Fix stale default parameter in getMaxFeatureCount (was 4096 - 12 = 4084, should be 4096 after the sizing fix in e56c5673).
  • src/render/cutoff.ts — Guard zRange division against near-zero values on mobile viewports.
  • CHANGELOG.md — Added changelog entry per contributing guidelines.
  • test/unit/gl/context_gpu_flags.test.ts — New: regression tests for the disableSymbolUBO flag (default behavior and forceDisableSymbolUBO override).
  • test/unit/render/cutoff.test.ts — New: regression tests for getCutoffParams covering the zero/negative zRange guard and all early-exit paths.
  • test/unit/data/symbol_property_binder_ubo.test.ts — Updated expected value for getMaxFeatureCount default parameter fix.

Test plan

  • TypeScript type checking passes (npm run tsc)
  • symbol_property_binder_ubo.test.ts — all 35 tests pass
  • context_gpu_flags.test.ts — 2 new tests pass
  • cutoff.test.ts — 6 new tests pass
  • ESLint passes on all changed/new files
  • Verify on Pixel 7/8/8A/9a that zoom/pan no longer crashes
  • Verify on desktop that symbol rendering is unchanged (UBO still active on non-Adreno/non-PowerVR GPUs)
  • Verify on PowerVR devices that existing disable still works

🤖 Generated with Claude Code

Disable symbol UBO batching on Adreno GPUs (Qualcomm, used in Pixel 7/8/8A/9a)
where GLSL ES 3.00 dynamic indexing into UBO arrays causes GPU faults and page
crashes during zoom/pan. Also fix readFloat/readUint in the symbol shader to use
the existing Adreno-safe swizzle helpers, correct a stale getMaxFeatureCount
default, and guard against zero-division in the cutoff formula.

Fixes mapbox#13651

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@navidemad navidemad requested a review from a team as a code owner April 4, 2026 02:55
@navidemad navidemad requested review from ibesora and removed request for a team April 4, 2026 02:55
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

Hey, @navidemad 👋 Thanks for your contribution to Mapbox GL JS!

Important: This repository does not accept direct merges. All changes go through our internal review process.

What happens next:

  1. A team member will review your PR here first
  2. If it looks good, they will import it to our internal repository for further review
  3. If approved, changes will be synced back here via our release process

Please respond to any review comments on this PR. For more details, see CONTRIBUTING.md.

navidemad and others added 4 commits April 4, 2026 05:08
Add unit tests for the two code paths that lacked coverage:

- context_gpu_flags.test.ts: verify disableSymbolUBO is false by default and
  true when forceDisableSymbolUBO option is set.
- cutoff.test.ts: verify getCutoffParams returns finite values when zRange is
  zero or negative, and exercises early-exit paths (zero fade range, terrain
  active, low pitch).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
context_gpu_flags.test.ts:
- Add renderer-based detection tests: Adreno → disabled, PowerVR → disabled,
  Apple M2 → enabled. Uses getExtension/getParameter interception to inject
  fake WEBGL_debug_renderer_info strings deterministically.
- Guard createContext() with explicit null check on getContext('webgl2').

cutoff.test.ts:
- Add invariant assertions for active cutoff: all 4 params finite,
  relativeCutoffFadeDistance <= relativeCutoffDistance, both non-negative.
- Keep existing zero/negative zRange and early-exit coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove host-dependent "disabled by default on standard GPUs" test that
  would fail on Adreno/PowerVR machines. All four remaining tests use
  createGLWithRenderer() to inject a controlled renderer string.

- Wire forceDisableSymbolUBO through the render test infrastructure
  (one-line addition in utils.ts, matching the existing
  forceManualRenderingForInstanceIDShaders pattern).

- Add text-color/property-function-no-symbol-ubo render test: exercises
  data-driven symbol rendering with UBO disabled, verifying the pragma
  fallback path renders correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- context_gpu_flags.test.ts: add createGLWithoutRendererInfo() helper
  that makes WEBGL_debug_renderer_info return null.  Two new tests
  verify disableSymbolUBO is falsy without the extension and that
  forceDisableSymbolUBO still overrides it.

- text-halo-color/property-function-no-symbol-ubo: new render fixture
  exercising data-driven text-halo-color with UBO disabled.  Covers
  halo_np_color (UBO property index 1), complementing the existing
  text-color fixture (fill_np_color, index 0).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ibesora
Copy link
Copy Markdown
Contributor

ibesora commented Apr 7, 2026

Hey @navidemad, thanks for the PR!
Since the Adreno GPUs are not the only ones exhibiting issues, I'll close this PR.
We are working internally on a fix and we'll publish a patch version once it's ready.

@ibesora ibesora closed this Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Map crashes in v3.21.0 with many Pixel devices

2 participants