ffi 3.2 C5: migrate uikit.sx view tree + GL drawables cluster

Final Phase 3.2 cluster. CALayer / CAEAGLLayer / EAGLContext declared
as `#foreign #objc_class` blocks, plus `setContentScaleFactor` added
to UIView and `-layer` now returns `*CALayer` (was opaque `*void`).

Classes declared:

- CALayer      → setOpaque (instance)
- CAEAGLLayer  → setDrawableProperties (instance)
- EAGLContext  → alloc (class), initWithAPI (instance),
                 setCurrentContext (class — takes EAGLContext arg),
                 renderbufferStorage_fromDrawable (instance),
                 presentRenderbuffer (instance)
- UIView       → +setContentScaleFactor (existing decl extended)

The C5 group sits above UIView in the file so the `-layer` return type
`*CALayer` forward-resolves cleanly.

Migration sites in uikit.sx:

- `uikit_create_gl_context` → `EAGLContext.alloc().initWithAPI(api)`
  + `EAGLContext.setCurrentContext(ctx)`.
- `uikit_setup_renderbuffer` → cast `*EAGLContext` and
  `gl_ctx.renderbufferStorage_fromDrawable(target, layer)`.
- `uikit_present_renderbuffer` → same cast + `presentRenderbuffer(target)`.
- Scene-connect bring-up: `gl_layer.setOpaque(1)`,
  `eagl_layer.setDrawableProperties(...)`,
  `gl_view.setContentScaleFactor(scale)`.

One more `objc_getClass(...)` lookup (EAGLContext) retired — the class
slot comes from the declarative binding via `__sx_objc_class_init`.

**Phase 3.2 complete.** Five clusters migrated (C1: Foundation
utility; C2: Notifications + Bundle; C3: RunLoop + display timing;
C4: UIKit chrome; C5: view tree + GL drawables). 8 foreign Cocoa
classes declared; ~30 `#objc_call(T)(...)` sites rewritten to
`recv.method(args)` / `Cls.method(args)`; 6 `objc_getClass`
lookups retired. Sx-defined classes (SxAppDelegate, SxSceneDelegate,
SxGLView, SxMetalView) and a handful of foreign sites that exercise
delegate/protocol surfaces stay on the explicit `#objc_call` form
pending Phase 3.7's class synthesis.

167/167 example tests; chess clean on macOS / iOS sim / Android via
`tools/verify-step.sh`.
This commit is contained in:
agra
2026-05-25 17:58:55 +03:00
parent 5b4969f9be
commit bd3033dc5a
2 changed files with 74 additions and 36 deletions

View File

@@ -113,6 +113,25 @@ CADisplayLink :: #foreign #objc_class("CADisplayLink") {
duration :: (self: *Self) -> f64;
}
// ── View tree + GL drawables (Phase 3.2 C5) ────────────────────────────
// (Declared before UIView so `layer :: (...) -> *CALayer` can reference it.)
CALayer :: #foreign #objc_class("CALayer") {
setOpaque :: (self: *Self, opaque: s8);
}
CAEAGLLayer :: #foreign #objc_class("CAEAGLLayer") {
setDrawableProperties :: (self: *Self, props: *void);
}
EAGLContext :: #foreign #objc_class("EAGLContext") {
alloc :: () -> *EAGLContext;
initWithAPI :: (self: *Self, api: s32) -> *EAGLContext;
setCurrentContext :: (ctx: *EAGLContext);
renderbufferStorage_fromDrawable :: (self: *Self, target: u32, drawable: *void) -> s8;
presentRenderbuffer :: (self: *Self, target: u32) -> s8;
}
// ── UIKit chrome (Phase 3.2 C4) ────────────────────────────────────────
UIScreen :: #foreign #objc_class("UIScreen") {
@@ -122,11 +141,10 @@ UIScreen :: #foreign #objc_class("UIScreen") {
}
UIView :: #foreign #objc_class("UIView") {
safeAreaInsets :: (self: *Self) -> UIEdgeInsets;
addSubview :: (self: *Self, view: *void);
// `-layer` returns a CALayer*; declared as opaque pointer for now
// (CALayer's own declarative binding is in the C5 cluster).
layer :: (self: *Self) -> *void;
safeAreaInsets :: (self: *Self) -> UIEdgeInsets;
addSubview :: (self: *Self, view: *void);
layer :: (self: *Self) -> *CALayer;
setContentScaleFactor :: (self: *Self, scale: f64);
}
UIWindow :: #foreign #objc_class("UIWindow") {
@@ -526,17 +544,14 @@ uikit_keyboard_will_change_frame :: (self: *void, _cmd: *void, notification: *vo
uikit_create_gl_context :: (plat: *UIKitPlatform) {
inline if OS != .ios { return; }
EAGLContext := objc_getClass("EAGLContext".ptr);
// UIScreen class slot comes from the declarative #objc_class binding.
// Read the screen scale up-front so callers can size font caches and
// textures with the right DPI before the window even exists.
screen := UIScreen.mainScreen();
plat.dpi_scale = xx screen.nativeScale();
ctx_raw := #objc_call(*void)(EAGLContext, "alloc");
plat.gl_ctx = #objc_call(*void)(ctx_raw, "initWithAPI:", EAGL_API_GLES3);
#objc_call(void)(EAGLContext, "setCurrentContext:", plat.gl_ctx);
ctx := EAGLContext.alloc().initWithAPI(EAGL_API_GLES3);
plat.gl_ctx = xx ctx;
EAGLContext.setCurrentContext(ctx);
load_gl(@ios_gl_proc);
}
@@ -611,12 +626,13 @@ uikit_scene_will_connect_ios :: (delegate: *void, scene: *void) {
win.setRootViewController(plat.root_vc);
gl_view : *UIView = xx plat.gl_view;
plat.gl_layer = gl_view.layer();
gl_layer := gl_view.layer();
plat.gl_layer = xx gl_layer;
// Mark the layer opaque (no compositor blend). Required for EAGL +
// recommended for Metal (CAMetalLayer.opaque defaults to YES but doesn't
// hurt to be explicit).
#objc_call(void)(plat.gl_layer, "setOpaque:", xx 1);
gl_layer.setOpaque(1);
if plat.gpu_mode == .gles {
// EAGL drawable properties dict required by
@@ -634,7 +650,8 @@ uikit_scene_will_connect_ios :: (delegate: *void, scene: *void) {
dict := NSMutableDictionary.dictionary();
dict.setObject_forKey(xx ns_no, retained_key);
dict.setObject_forKey(rgba8_value, colorformat_key);
#objc_call(void)(plat.gl_layer, "setDrawableProperties:", xx dict);
eagl_layer : *CAEAGLLayer = xx gl_layer;
eagl_layer.setDrawableProperties(xx dict);
}
// EAGLContext + load_gl were already done in uikit_create_gl_context()
@@ -647,7 +664,7 @@ uikit_scene_will_connect_ios :: (delegate: *void, scene: *void) {
screen2 := win.screen();
scale := screen2.nativeScale();
plat.dpi_scale = xx scale;
#objc_call(void)(plat.gl_view, "setContentScaleFactor:", scale);
gl_view.setContentScaleFactor(scale);
// Renderbuffer is allocated lazily in -[SxGLView layoutSubviews] once
// the layer has its real on-screen bounds. makeKeyAndVisible triggers
@@ -691,7 +708,8 @@ uikit_setup_renderbuffer :: (plat: *UIKitPlatform) {
glBindRenderbuffer(GL_RENDERBUFFER, plat.color_renderbuffer);
#objc_call(bool)(plat.gl_ctx, "renderbufferStorage:fromDrawable:", GL_RENDERBUFFER, plat.gl_layer);
gl_ctx : *EAGLContext = xx plat.gl_ctx;
gl_ctx.renderbufferStorage_fromDrawable(GL_RENDERBUFFER, plat.gl_layer);
glBindFramebuffer(GL_FRAMEBUFFER, plat.framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, plat.color_renderbuffer);
@@ -723,7 +741,8 @@ uikit_setup_renderbuffer :: (plat: *UIKitPlatform) {
uikit_present_renderbuffer :: (self: *UIKitPlatform) {
inline if OS != .ios { return; }
glBindRenderbuffer(GL_RENDERBUFFER, self.color_renderbuffer);
#objc_call(bool)(self.gl_ctx, "presentRenderbuffer:", GL_RENDERBUFFER);
gl_ctx : *EAGLContext = xx self.gl_ctx;
gl_ctx.presentRenderbuffer(GL_RENDERBUFFER);
}
// ── SxGLView class ─────────────────────────────────────────────────────────