I've managed to narrow down the problem, although I don't have an isolated test case; the bug seems to be fairly brittle. The issue appears to be memory corruption related to captures in an async closure (where I'm capturing a number of variables by value which were vars in the enclosing scope). Concretely, on x86_64 and not ARM, this crashes at the next await call that suspends the current task:
renderGraph.addDrawCallbackPass(renderTarget: renderTarget,
reflection: ResolveAccumulatedTargetPassReflection.self,
{ [uvToNDC, imageUVToSceneUV, filmicToneMapUniforms, vignetteUniforms, colorGradedSceneRegionBackgroundColor] encoder in
...
await Task.yield() // crash
...
}
Moving the imageUVToSceneUV to a tuple works around it (doesn't crash):
let arguments = (uvToNDC, imageUVToSceneUV)
renderGraph.addDrawCallbackPass(renderTarget: renderTarget,
reflection: ResolveAccumulatedTargetPassReflection.self,
{ [arguments, filmicToneMapUniforms, vignetteUniforms, colorGradedSceneRegionBackgroundColor] encoder in
let (uvToNDC, imageUVToSceneUV) = arguments
await Task.yield() // no crash
}
as does inserting a print statement for imageUVToSceneUV specifically:
renderGraph.addDrawCallbackPass(renderTarget: renderTarget,
reflection: ResolveAccumulatedTargetPassReflection.self,
{ [uvToNDC, imageUVToSceneUV, filmicToneMapUniforms, vignetteUniforms, colorGradedSceneRegionBackgroundColor] encoder in
print(imageUVToSceneUV)
await Task.yield() // no crash
...
}
but moving the print statement to after the first use of imageUVToSceneUV in the function does crash:
renderGraph.addDrawCallbackPass(renderTarget: renderTarget,
reflection: ResolveAccumulatedTargetPassReflection.self,
{ [uvToNDC, imageUVToSceneUV, filmicToneMapUniforms, vignetteUniforms, colorGradedSceneRegionBackgroundColor] encoder in
...
encoder.set1.uniforms = .init(clearColor: SIMD4(SIMD3(clearColor), 0.0),
backgroundColor: SIMD4(colorGradedSceneRegionBackgroundColor),
uvToSceneUVScale: SIMD2(imageUVToSceneUV.scale),
uvToSceneUVOffset: SIMD2(imageUVToSceneUV.offset),
uvToBlitTexture0UV: multiFrameAccumulationWeight < 1.0 ? previewBufferUVScale : .one,
highlightColorMultiply: SIMD3(highlightColorMult),
highlightColorAdditive: SIMD3(highlightColorAdd),
toneMapParams: filmicToneMapUniforms,
vignetteParams: vignetteUniforms)
print(imageUVToSceneUV)
await Task.yield() // crash
...
}
uvToNDC and imageUVToSceneUV are RectTransform<Float>s, which are composed of two SIMD2<Float>s each; addDrawCallbackPass is defined at Substrate/RenderGraph.swift at 6f25f5b6606278e705144b3664a4fdfe111b3a53 · troughton/Substrate · GitHub.
I can’t provide source but isolated SIL/LLVM IR may be possible.
I’ve also added this information to the GitHub issue, and can shift discussion there if that’s best.