Skip to content

metal: pass API validation with 3D terrain on and off - #4556

Open
AndrewN81 wants to merge 2 commits into
maplibre:feature/terrain-3dfrom
AndrewN81:pr/metal-api-validation
Open

metal: pass API validation with 3D terrain on and off#4556
AndrewN81 wants to merge 2 commits into
maplibre:feature/terrain-3dfrom
AndrewN81:pr/metal-api-validation

Conversation

@AndrewN81

Copy link
Copy Markdown

What

Two Metal API validation failures with the terrain-3d branch, one with terrain off and one with it on. Xcode's Run scheme enables Metal API Validation by default, so with this branch any app hits one of them on launch (terrain off) or on the first draped frame (terrain on).

  1. Missing sampler bindings with terrain off. The symbol, circle and fill-extrusion shaders declare the DEM and depth samplers unconditionally, but their tweakers only bind textures when a terrain is present, so validation aborts with missing sampler binding at index N for demSampler/depthSampler. gfx::Context::getPlaceholderTexture2D() now provides a 1x1 texture that the tweakers bind when parameters.terrain is null (the shaders never sample it, dem_enabled / depth_enabled are 0).
  2. Pipeline state reuse across attachment formats with terrain on. mtl::ShaderProgram::getRenderPipelineState cached states keyed only on the colour mode and vertex layout, so a state created for the BGRA8 screen was reused for the RGBA8 drape and hillshade render targets (Set Render Pipeline State Validation ... BGRA8Unorm vs RGBA8Unorm, and a stencil format mismatch). The cache key now folds in the colour, depth and stencil attachment formats.

How it was verified

  • Reproduced both aborts on the iOS simulator with SIMCTL_CHILD_MTL_DEBUG_LAYER=1 xcrun simctl launch <udid> <bundle>; both are gone with this change, with terrain on and off.
  • Running in a shipped iOS app (Metal, iPhone 16 Pro and simulator) since 2026-09-05.

Notes

Written with AI assistance (Claude), reviewed and tested by me before opening this PR, per MapLibre's AI policy.

Two validation aborts under Xcode's Metal API Validation (the default for a
Run scheme), both invisible without validation because nothing is sampled or
the mismatch happens to work:

1. The symbol, circle and fill-extrusion shaders declare a DEM sampler (and
   the symbol shader a terrain-depth sampler) unconditionally, but the layer
   tweakers only bind them when a RenderTerrain exists. On a flat map every
   symbol draw hit "missing sampler binding". Vulkan already binds a dummy
   texture in that gap; add gfx::Context::getPlaceholderTexture2D (a 1x1 zero
   texture) and bind it in the three tweakers when terrain is off.

2. ShaderProgram::getRenderPipelineState cached pipeline states by the
   caller's hash of colour mode + vertex layout only, so a state built for the
   BGRA8 + stencil screen was reused for RGBA8 offscreen targets without a
   stencil (terrain drape targets, hillshade prepare targets): "pipeline's
   pixelFormat does not match the framebuffer's". Fold the renderable's colour,
   depth and stencil formats into the cache key.

Verified on the iOS simulator with MTL_DEBUG_LAYER=1: flat map and draped
terrain both run with zero validation messages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added the core Changes that affect the C++ core of MapLibre Native label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Changes that affect the C++ core of MapLibre Native

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant