Skip to content

Universal (Apple Silicon + Intel) build without Xcode - #9

Open
trackme518 wants to merge 2 commits into
Syphon:masterfrom
trackme518:universal-binary-support
Open

trackme518 wants to merge 2 commits into
Syphon:masterfrom
trackme518:universal-binary-support

Conversation

@trackme518

Copy link
Copy Markdown

Added support for macOS Apple Silicon (arm64), while remaining compatible with Intel macOS

The shipped native_libs binaries are x86_64-only, so they fail to load in arm64 JVMs (e.g. Processing 4 on Apple Silicon). Compiling with the current Xcode project is also impossible on modern macOS: Apple removed the JavaVM / JavaNativeFoundation frameworks and their headers from the SDK.

Changes

  • JSyphon/native_src/build_universal.sh – new script that builds Syphon and libJSyphon.jnilib as universal (x86_64 + arm64) binaries using only the Command Line Tools and a JDK (for jni.h) — no Xcode required. Results are ad-hoc code signed.
  • JSyphon/native_src/jnf/ – vendored JavaNativeFoundation sources (from apple/openjdk, xcodejdk14-release, APSL 2.0), compiled statically into libJSyphon.jnilib to replace the removed system framework.
  • JNI sources – replaced removed <JavaVM/JavaVM.h> / <JavaVM/jni.h> imports with <jni.h>.
  • Syphon built with -DSYPHON_CORE_RESTORE – the upstream state-restore code paths were never enabled in the Xcode build. Without them, Apple's OpenGL driver (which shares VAO/FBO/VBO bindings across share-group contexts) corrupts the host app's GL state when publishing frames from a core-profile context. This caused RuntimeException: Cannot validate shader program: Validation Failed: No vertex array object bound. in Processing P3D. tests/vao_test.m is a regression test for it.
  • Syphon-Framework submodule bumped c404f3c (v5) → f476167 (post-5.0 tip of main, +99 commits): ARC conversion, modern atomics, Explicitly set pixel format type to 32BGRA and other Apple-Silicon-relevant fixes, Metal server/client support.
  • Rebuilt build products: jsyphon.jar (unchanged bytecode, Java 8 target) and universal native_libs/{Syphon,libJSyphon.jnilib}.

Verification

  • lipo -info shows x86_64 arm64 for both native binaries; both are code-signed.
  • Tested on macOS 26 (Tahoe): JNI load, JSyphonServerList, server publish and client receive verified on arm64, and on x86_64 via Rosetta (vao_test.m passes on both: host VAO binding preserved, no GL errors).
  • Used with Processing 4.5.6 (SendFrames, ReceiveFrames, SendScreen examples).

Apple removed JavaNativeFoundation and JavaVM headers from the macOS SDK,
so the Xcode project can no longer link the JNI library, and the shipped
x86_64-only binaries fail to load on arm64 JVMs.

- build_universal.sh: builds Syphon and libJSyphon.jnilib as universal
  (x86_64 + arm64) with the Command Line Tools only; statically links the
  vendored JavaNativeFoundation sources (apple/openjdk xcodejdk14-release,
  APSL 2.0) instead of the removed system framework; ad-hoc code signs.
- Vendored JavaNativeFoundation sources under JSyphon/native_src/jnf.
- Replace removed <JavaVM/...> imports with <jni.h> in JNI sources.
- Build Syphon with -DSYPHON_CORE_RESTORE: restores GL state (VAO etc.)
  around core-profile publishing. Apple's driver shares these bindings
  across share-group contexts, so without it Processing's shader
  validation failed with 'No vertex array object bound'.
- tests/vao_test.m: regression test for the VAO binding restore.
- Rebuilt jsyphon.jar and universal native_libs binaries.
- Bump Syphon-Framework to f476167 (post-5.0 main): adds Apple Silicon
  32BGRA pixel format fix and core-profile improvements.

Tested on macOS 26 (arm64 and x86_64 via Rosetta) with Processing 4.5.6.
@trackme518
trackme518 force-pushed the universal-binary-support branch from d46c515 to 1fe588e Compare September 21, 2026 14:32
On Apple Silicon (and recent Intel macOS) the OpenGL implementation backs
GL with Metal and shares some per-context state (texture unit bindings,
blend, VAO/FBO bindings) between contexts in a share group. Publishing a
frame draws a quad on the server's context, which silently clobbers state
the calling context relies on: after one publish, Processing draws
subsequent image() calls with corrupted vertex attributes (flat color or
wrong size).

- JNI: capture and re-apply the full state set Syphon may touch (active
  texture unit, 2D/rectangle texture bindings on units 0-3, VAO, read/draw
  FBO, renderbuffer, array/element buffers, viewport, scissor, blend,
  current program) around publishFrameTexture. No copies, no sync stalls.
- Syphon-Framework: extend SYPHON_CORE_RESTORE in
  SyphonServerRendererCoreGL drawFrameTexture to also save/restore
  active texture unit, unit-0 texture bindings, viewport and blend
  (previously only the target texture binding was restored, and that from
  the wrong unit when the caller had a unit other than 0 active).
@trackme518

Copy link
Copy Markdown
Author

Update: GL state restore fix (a5ad314)

The universal build worked on Apple Silicon, but any draw on the Processing context after publishFrameTexture rendered with corrupted vertex state (flat color / wrong size). Cause: macOS' GL-over-Metal shares some per-context state (active texture unit, blend, VAO/FBO bindings) between contexts in a share group, and the server's internal quad draw clobbers it.

This commit:

  • jsyphon_JSyphonServer.m – captures the caller's GL state (active texture unit, 2D/rectangle bindings on units 0–3, VAO, read/draw FBO, renderbuffer, array/element buffers, viewport, scissor, blend, current program) before publishFrameTexture and re-applies it after. Element-array binding is rebound after the VAO since it lives inside the VAO. Pure state get/set – no texture copies, no sync stalls, ~40 driver calls per frame.
  • Rebuilt native_libs/Syphon includes the renderer-side completion of the same fix (SYPHON_CORE_RESTORE: preserve state changed by drawFrameTexture Syphon-Framework#107): drawFrameTexture under SYPHON_CORE_RESTORE now also saves/restores the active texture unit, unit-0 texture bindings, viewport and blend — and fixes a latent bug where the previous texture binding was queried on the wrong unit. Until that PR merges, the prebuilt binary here is built against the patch (java/JSyphon/native_src/build_universal.sh).

Verified: minimal repro (offscreen P2D published once, then image() to main canvas) renders pixel-correct on arm64 and x86_64, P2D and P3D main renderers.

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.

1 participant