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:
@@ -600,27 +600,46 @@ matching the expected output.
|
||||
|
||||
Phase 3.2 C4 landed: UIKit chrome cluster migrated. Six classes
|
||||
declared (UIScreen, UIView, UIWindow, UIViewController, UITextField
|
||||
— plus the existing C1/C2/C3 classes already in place). Migration
|
||||
sites: `show_keyboard` / `hide_keyboard` use `tf.becomeFirstResponder()`
|
||||
/ `tf.resignFirstResponder()`; `uikit_refresh_safe_insets` uses
|
||||
`gl_view.safeAreaInsets()`; `uikit_read_screen_scale` and the GL-
|
||||
context bring-up both use `UIScreen.mainScreen().nativeScale()`;
|
||||
keyboard-frame callback uses `win.screen().bounds()`; the scene-
|
||||
connect bring-up chains `UIWindow.alloc().initWithWindowScene(scene)`
|
||||
and `UIViewController.alloc().init()` then `vc.setView(...)`,
|
||||
`win.setRootViewController(...)`, `gl_view.layer()`,
|
||||
`UITextField.alloc().init()`, `gl_view.addSubview(...)`,
|
||||
`win.makeKeyAndVisible()`. Three `objc_getClass(...)` calls (UIWindow,
|
||||
UIViewController, UITextField) are gone — the class slots come from
|
||||
the declarative bindings via `__sx_objc_class_init`. C4 is the
|
||||
cluster that triggered issue-0043; with the fix in, the chained
|
||||
dispatch resolves correctly under lazy lowering. 167/167 tests +
|
||||
chess clean on macOS / iOS sim / Android.
|
||||
— plus the existing C1/C2/C3 classes already in place). Three
|
||||
`objc_getClass(...)` calls (UIWindow, UIViewController, UITextField)
|
||||
are gone — the class slots come from the declarative bindings via
|
||||
`__sx_objc_class_init`. C4 is the cluster that triggered
|
||||
issue-0043; with the fix in, the chained dispatch resolves
|
||||
correctly under lazy lowering.
|
||||
|
||||
Phase 3.2 C5 landed: view tree + GL drawables cluster migrated.
|
||||
CALayer (`setOpaque`), CAEAGLLayer (`setDrawableProperties`), and
|
||||
EAGLContext (`alloc`, `initWithAPI`, `setCurrentContext`,
|
||||
`renderbufferStorage_fromDrawable`, `presentRenderbuffer`) declared.
|
||||
UIView gained `setContentScaleFactor` and `layer` now returns
|
||||
`*CALayer` (was opaque `*void`). Migration sites:
|
||||
`uikit_create_gl_context` uses `EAGLContext.alloc().initWithAPI(...)`
|
||||
then `EAGLContext.setCurrentContext(ctx)`;
|
||||
`uikit_setup_renderbuffer` uses
|
||||
`gl_ctx.renderbufferStorage_fromDrawable(...)`;
|
||||
`uikit_present_renderbuffer` uses `gl_ctx.presentRenderbuffer(...)`;
|
||||
the scene-connect bring-up uses `gl_layer.setOpaque(1)`,
|
||||
`eagl_layer.setDrawableProperties(...)`, and
|
||||
`gl_view.setContentScaleFactor(scale)`. One more `objc_getClass`
|
||||
(EAGLContext) gone. 167/167 + chess clean on macOS / iOS sim /
|
||||
Android.
|
||||
|
||||
**Phase 3.2 complete.** Surface summary:
|
||||
|
||||
- `#selector("explicit:")` override (parts A1+A2).
|
||||
- Locked-in golden mangling-table test (part B).
|
||||
- Five uikit.sx clusters migrated to declarative `#objc_class`
|
||||
(parts C1..C5) — 8 foreign Cocoa classes declared, 30+
|
||||
`#objc_call` call sites rewritten to `recv.method(args)` /
|
||||
`Cls.method(args)` form. 6 redundant `objc_getClass(...)` lookups
|
||||
retired. Sx-defined classes (SxAppDelegate, SxSceneDelegate,
|
||||
SxGLView, SxMetalView) and a handful of foreign sites that
|
||||
exercise less common paths (e.g. `objc_call(void)(delegate,
|
||||
"setWindow:", ...)` from UIWindowSceneDelegate protocol) stay on
|
||||
the explicit `#objc_call` form pending Phase 3.7's class-synthesis
|
||||
work.
|
||||
|
||||
Open work:
|
||||
- **Phase 3 step 3.2 — C5** — uikit.sx migration (view tree + GL
|
||||
drawables: CAEAGLLayer, EAGLContext, plus any remaining
|
||||
CAMetalLayer / NSTimer sites).
|
||||
- **Phase 3 step 3.3** — `property name: Type` synthesizes
|
||||
`inst.name` → `[inst name]` getter and `inst.name = x` →
|
||||
`[inst setName: x]` setter. `#setter("...")` overrides the setter
|
||||
|
||||
@@ -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 ─────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user