Summary
On macOS 27 beta, every CesiumJS scene fails to render in Safari. linkProgram fails on the very first frame with an MSL compilation error coming from ANGLE’s Metal backend. This isn’t a Cesium-specific shader bug — it’s a regression in how the system Metal compiler now handles the ANGLE_Out/ANGLE_InOut helper templates ANGLE generates for any GLSL function that takes an out or inout parameter. Since Cesium’s atmosphere and 3D Tiles styling stages both rely on out parameters, the globe never renders at all: black canvas, console full of link errors.
Given how much of the Cesium user base is on Mac, this is worth flagging loudly before macOS 27 ships. Filing here so other Mac users can pile on with +1 / their own environment, and so this thread can be linked from the WebKit/Apple bug report.
Environment
- macOS 27.0 beta 2
- Safari Version 27.0 (22625.1.24.11.2)
- CesiumJS (all versions)
- Reproduces on every scene tested so far, both
Scene3DOnlyglobe (atmosphere) and 3D Tiles (CPU styling)
Two separate Cesium shaders confirmed broken
- Ground/sky atmosphere scattering (
czm_computeGroundAtmosphereScattering) — the first error I hit. - 3D Tiles CPU styling stage (
cpuStylingStage,inouton position + feature struct) — fails identically even with the atmosphere disabled.
Because both failures are in the same linked program in practice (a normal 3D Tiles scene draws atmosphere and styled tiles together), there’s no scene-level workaround. Turning off globe.showGroundAtmosphere / scene.skyAtmosphere.show removes error #1 but not #2, since #2 fires for any styled/batched glTF regardless of atmosphere settings.
Error output (atmosphere shader)
RuntimeError: Program failed to link. Link log: Internal error while linking shader. MSL compilation error:
program_source:94:36: error: reference to type 'thread float3' (vector of 3 'float' values) could not bind to an lvalue of type '__metal_generic float3' (vector of 3 'float' values)
operator thread T &() { return mTemp; }
^~~~~
program_source:483:89: note: in instantiation of member function 'ANGLE_Out::operator float thread & __attribute__((ext_vector_type(3)))' requested here
_ucomputeAtmosphereScattering(ANGLE_userUniforms, _upositionWC.xyz, _ulightDirection, ANGLE_out(ANGLE_vertexOut._uv_rayleighColor), ANGLE_out(ANGLE_vertexOut._uv_mieColor), ANGLE_out(ANGLE_vertexOut._uv_opacity), ANGLE_out(ANGLE_vertexOut._uv_translucent));
Same pattern for float and for the tiles-styling inout struct case, with ANGLE_InOut instead of ANGLE_Out. Full translated MSL for both cases available on request — long, happy to paste or link a gist.
Root cause (as far as I can tell from the outside)
ANGLE’s MSL translator emits an RAII wrapper for every GLSL out/inout parameter, because MSL has no native equivalent:
template <typename T>
struct ANGLE_Out
{
T mTemp;
thread T &mDest;
~ANGLE_Out() { mDest = mTemp; }
ANGLE_Out(thread T &dest) : mTemp(dest), mDest(dest) {}
operator thread T &() { return mTemp; } // <-- rejected on macOS 27 beta
};
The conversion operator’s implicit object parameter is now apparently deduced as __metal_generic instead of thread by the macOS 27 Metal compiler, so it can’t bind to the thread T& it needs to return. This affects scalars, vectors, and struct instantiations alike — it’s the template itself that’s broken, not any one call site. Since out/inout parameters are ordinary GLSL ES 3.00, this will hit essentially any nontrivial WebGL app on this backend, not just Cesium.
Minimal repro (no Cesium involved)
#version 300 es
out vec3 vColor;
void compute(out vec3 c) { c = vec3(0.5); }
void main() {
compute(vColor);
gl_Position = vec4(vColor, 1.0);
}
Linking a WebGL2 program with this vertex shader fails the same way on macOS 27 beta Safari. Passes everywhere else I’ve tested (macOS 26, Chrome/Firefox on the same beta machine — need more people to confirm the Chrome/Firefox result across different machines, since they ship their own ANGLE build).
Ask
- Anyone else seeing this on macOS 27 beta Safari, please reply with your Safari build, whether the globe renders at all, and whether you see the same
ANGLE_Out/ANGLE_InOutsignature in your console.
