Skip to content

v1.2.0

Latest

Choose a tag to compare

@gsdali gsdali released this 20 Aug 05:36
· 1 commit to main since this release
6326344

Eight commits since v1.1.27, including a real Swift 6 concurrency bug and the first working test gate this repo has ever had.

The headline fix: Metal completion handlers inherited @MainActor

ViewportRenderer is @MainActor, and Xcode 16.4's SDK does not annotate MTLCommandBufferHandler as Sendable. So an unannotated closure passed to addCompletedHandler inherited that isolation, and Swift 6 asserted it on entry. Metal calls the handler on its own completion queue, so the assertion failed and the process died with SIGTRAP after every test had already reported green.

Both addCompletedHandler closures are now written @Sendable, which keeps them nonisolated on every SDK and makes the compiler verify the captures rather than trusting an annotation in someone else's header. Zero behaviour change: both bodies already decoded off the main actor and hopped back via Task { @MainActor in }. Those two are the only sites in the package handing a closure to an off-main callback, so the class is closed rather than the one instance patched.

This was diagnosed as a hardware problem and was not one. It looked like a paravirtualised GPU faulting where a real one would not. Xcode 26.x adds NS_SWIFT_SENDABLE to that typedef, so no check is emitted locally at all: the local versus CI split was a toolchain difference. Anyone on Xcode 16.4 with a real GPU would hit it.

Proven by A/B on one runner image: fixed 217 pass, fixed GPU-only 42 pass, and a control job that strips the @Sendable back out reproduces the identical backtrace.

SelectionFilter is now PickResultFilter

Renamed because it filters a PickResult, before any topology exists, and collided by name with OCCTSwiftAIS.SelectionFilter, which filters a resolved sub-shape. Different inputs, different jobs; only the name suggested otherwise.

Source-compatible. SelectionFilter remains as a deprecated typealias, as does _SelectionFilter. Every factory and combinator keeps its name and vends the renamed type.

Also in this release

  • Headless / off-screen render mode on ViewportRenderer, with shared Metal setup extracted from ViewportRenderer and OffscreenRenderer.
  • Shadow-casting light frustum now fits world-space bounds.
  • SSAO and silhouette depth-only prepass now applies body.transform.
  • The code-style manifest is swept to zero entries, completing that rollout. Behaviour-neutrality was verified three ways rather than asserted: every string and numeric literal byte-identical after comment stripping, zero residual diff after normalising the five mechanical rewrites, and an unchanged suite.

CI

This repo now runs swift build and swift test on every push and PR, which it never did before. That gate could not be installed until the crash above was fixed, and the crash could not have been found without running the GPU suites in CI. Both landed together.

217 tests in 39 suites, green on main.