mem: implicit-Context platform fixes — chess green on macOS/iOS/Android
Verify-step uncovered three categories of regressions where sx code
calls into the platform's C ABI through fn-pointer types or as a
registered callback. Every site now declares the right convention.
C-side calls INTO sx → callconv(.c) on the sx function:
- platform/android.sx: sx_android_render_thread_entry is the start
routine pthread_create invokes — pthread treats it as a C function.
Also annotate the pthread_create signature so the start-routine fn-
pointer field rejects mismatching sx fns at compile time.
sx code calling typed fn-pointers cast from C symbols → callconv(.c)
on the fn-pointer type:
- opengl.sx: 55 GL fn-ptr globals + load_gl's proc-loader param. GL
trampolines are macOS/iOS/Android system code.
- std/objc.sx: the two typed `objc_msgSend` casts.
- gpu/metal.sx: ~40 typed `objc_msgSend` casts across Metal command
encoder / device / pipeline construction.
The block invoke trampolines (objc_block.sx) call back INTO sx (the
closure trampoline). The typed fn-ptr there stays default-conv so
ctx prepends correctly. Compiler change: a callconv(.c) sx function
now binds `current_ctx_ref` to `&__sx_default_context` at entry (used
to be gated by `isExportedEntryName`). C-callable sx callbacks like
the block invokes don't get their own __sx_ctx param but their bodies
still need a real Context to forward to the closure they delegate to.
Tests: 152/152 example suite + chess green on all 3 platforms.
Screenshots at /tmp/sx-game-{macos,iossim,android}.png.
This commit is contained in:
@@ -250,11 +250,11 @@ metal_init_ios :: (self: *MetalGPU) -> bool {
|
||||
if self.device == null { return false; }
|
||||
}
|
||||
|
||||
msg_oo : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void = xx objc_msgSend;
|
||||
msg_ob : (*void, *void, u8) -> void = xx objc_msgSend;
|
||||
msg_osize : (*void, *void, CGSize) -> void = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ob : (*void, *void, u8) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_osize : (*void, *void, CGSize) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
|
||||
if self.queue == null {
|
||||
self.queue = msg_o(self.device, sel_registerName("newCommandQueue".ptr));
|
||||
@@ -283,7 +283,7 @@ metal_resize_ios :: (self: *MetalGPU) {
|
||||
inline if OS != .ios { return; }
|
||||
if self.layer == null { return; }
|
||||
|
||||
msg_osize : (*void, *void, CGSize) -> void = xx objc_msgSend;
|
||||
msg_osize : (*void, *void, CGSize) -> void callconv(.c) = xx objc_msgSend;
|
||||
size := CGSize.{ width = xx self.pixel_w, height = xx self.pixel_h };
|
||||
msg_osize(self.layer, sel_registerName("setDrawableSize:".ptr), size);
|
||||
}
|
||||
@@ -294,12 +294,12 @@ metal_begin_frame_ios :: (self: *MetalGPU, clear: ClearColor) -> bool {
|
||||
if self.queue == null { return false; }
|
||||
if self.pixel_w <= 0 or self.pixel_h <= 0 { return false; }
|
||||
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg_oo_ret : (*void, *void, *void) -> *void = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void = xx objc_msgSend;
|
||||
msg_ouret : (*void, *void, u64) -> *void = xx objc_msgSend;
|
||||
msg_oclear : (*void, *void, MTLClearColor) -> void = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_oo_ret : (*void, *void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ouret : (*void, *void, u64) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_oclear : (*void, *void, MTLClearColor) -> void callconv(.c) = xx objc_msgSend;
|
||||
|
||||
// drawable = [layer nextDrawable]
|
||||
self.drawable = msg_o(self.layer, sel_registerName("nextDrawable".ptr));
|
||||
@@ -346,9 +346,9 @@ metal_end_frame_ios :: (self: *MetalGPU, target_time: f64) {
|
||||
if self.cmd_buffer == null { return; }
|
||||
if self.drawable == null { return; }
|
||||
|
||||
msg_v : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg_ood : (*void, *void, *void, f64) -> void = xx objc_msgSend;
|
||||
msg_v : (*void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ood : (*void, *void, *void, f64) -> void callconv(.c) = xx objc_msgSend;
|
||||
|
||||
msg_v(self.encoder, sel_registerName("endEncoding".ptr));
|
||||
|
||||
@@ -379,15 +379,15 @@ metal_create_shader_ios :: (self: *MetalGPU, src: string) -> u32 {
|
||||
inline if OS != .ios { return 0; }
|
||||
if self.device == null { return 0; }
|
||||
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg_oo_r : (*void, *void, *void) -> *void = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void = xx objc_msgSend;
|
||||
msg_ouret: (*void, *void, u64) -> *void = xx objc_msgSend;
|
||||
msg_ob : (*void, *void, u8) -> void = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_oo_r : (*void, *void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_ou : (*void, *void, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ouret: (*void, *void, u64) -> *void callconv(.c) = xx objc_msgSend;
|
||||
msg_ob : (*void, *void, u8) -> void callconv(.c) = xx objc_msgSend;
|
||||
|
||||
// [device newLibraryWithSource:src options:nil error:&err]
|
||||
msg_lib : (*void, *void, *void, *void, **void) -> *void = xx objc_msgSend;
|
||||
msg_lib : (*void, *void, *void, *void, **void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
src_ns := ns_string(src.ptr);
|
||||
err : *void = null;
|
||||
library := msg_lib(self.device,
|
||||
@@ -422,7 +422,7 @@ metal_create_shader_ios :: (self: *MetalGPU, src: string) -> u32 {
|
||||
msg_ou(att0, sel_registerName("setSourceAlphaBlendFactor:".ptr), MTL_BLEND_FACTOR_SRC_ALPHA);
|
||||
msg_ou(att0, sel_registerName("setDestinationAlphaBlendFactor:".ptr), MTL_BLEND_FACTOR_ONE_MINUS_SRC_A);
|
||||
|
||||
msg_pipe : (*void, *void, *void, **void) -> *void = xx objc_msgSend;
|
||||
msg_pipe : (*void, *void, *void, **void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
err2 : *void = null;
|
||||
state := msg_pipe(self.device,
|
||||
sel_registerName("newRenderPipelineStateWithDescriptor:error:".ptr),
|
||||
@@ -446,7 +446,7 @@ metal_create_buffer_ios :: (self: *MetalGPU, size_bytes: s64) -> u32 {
|
||||
if size_bytes <= 0 { return 0; }
|
||||
|
||||
// MTLResourceStorageModeShared is the default (option value 0).
|
||||
msg_buf : (*void, *void, u64, u64) -> *void = xx objc_msgSend;
|
||||
msg_buf : (*void, *void, u64, u64) -> *void callconv(.c) = xx objc_msgSend;
|
||||
buf := msg_buf(self.device,
|
||||
sel_registerName("newBufferWithLength:options:".ptr),
|
||||
xx size_bytes, 0);
|
||||
@@ -463,7 +463,7 @@ metal_update_buffer_ios :: (self: *MetalGPU, handle: u32, data: *void, size_byte
|
||||
if data == null { return; }
|
||||
if size_bytes <= 0 { return; }
|
||||
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
dst := msg_o(buf, sel_registerName("contents".ptr));
|
||||
if dst == null { return; }
|
||||
memcpy(dst, data, size_bytes);
|
||||
@@ -477,7 +477,7 @@ metal_update_buffer_at_ios :: (self: *MetalGPU, handle: u32, data: *void, size_b
|
||||
if size_bytes <= 0 { return; }
|
||||
if byte_offset < 0 { return; }
|
||||
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_o : (*void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
base := msg_o(buf, sel_registerName("contents".ptr));
|
||||
if base == null { return; }
|
||||
// Add byte_offset via integer arithmetic — `@dst[i]` on `[*]u8`
|
||||
@@ -524,7 +524,7 @@ metal_create_texture_ios :: (self: *MetalGPU, w: s32, h: s32, format: TextureFor
|
||||
|
||||
// [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:width:height:mipmapped:]
|
||||
MTLTextureDescriptor := objc_getClass("MTLTextureDescriptor".ptr);
|
||||
msg_desc : (*void, *void, u64, u64, u64, u8) -> *void = xx objc_msgSend;
|
||||
msg_desc : (*void, *void, u64, u64, u64, u8) -> *void callconv(.c) = xx objc_msgSend;
|
||||
desc := msg_desc(MTLTextureDescriptor,
|
||||
sel_registerName("texture2DDescriptorWithPixelFormat:width:height:mipmapped:".ptr),
|
||||
pixel_format, xx w, xx h, 0);
|
||||
@@ -533,10 +533,10 @@ metal_create_texture_ios :: (self: *MetalGPU, w: s32, h: s32, format: TextureFor
|
||||
// Force shared storage so the CPU can keep writing pixels (atlas updates,
|
||||
// sprite uploads). On iOS-sim under Apple Silicon the convenience class
|
||||
// method's default storage isn't reliably shared for every format.
|
||||
msg_ou_void : (*void, *void, u64) -> void = xx objc_msgSend;
|
||||
msg_ou_void : (*void, *void, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg_ou_void(desc, sel_registerName("setStorageMode:".ptr), MTL_STORAGE_MODE_SHARED);
|
||||
|
||||
msg_oo : (*void, *void, *void) -> *void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> *void callconv(.c) = xx objc_msgSend;
|
||||
tex := msg_oo(self.device, sel_registerName("newTextureWithDescriptor:".ptr), desc);
|
||||
if tex == null { return 0; }
|
||||
|
||||
@@ -590,7 +590,7 @@ metal_destroy_shader_ios :: (self: *MetalGPU, handle: u32) {
|
||||
if h64 > self.shaders.len { return; }
|
||||
obj := self.shaders.items[handle - 1];
|
||||
if obj == null { return; }
|
||||
msg : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(obj, sel_registerName("release".ptr));
|
||||
self.shaders.items[handle - 1] = null;
|
||||
}
|
||||
@@ -602,7 +602,7 @@ metal_destroy_buffer_ios :: (self: *MetalGPU, handle: u32) {
|
||||
if h64 > self.buffers.len { return; }
|
||||
obj := self.buffers.items[handle - 1];
|
||||
if obj == null { return; }
|
||||
msg : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(obj, sel_registerName("release".ptr));
|
||||
self.buffers.items[handle - 1] = null;
|
||||
}
|
||||
@@ -614,7 +614,7 @@ metal_destroy_texture_ios :: (self: *MetalGPU, handle: u32) {
|
||||
if h64 > self.textures.len { return; }
|
||||
obj := self.textures.items[handle - 1].tex;
|
||||
if obj == null { return; }
|
||||
msg : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(obj, sel_registerName("release".ptr));
|
||||
self.textures.items[handle - 1].tex = null;
|
||||
self.textures.items[handle - 1].bytes_per_pixel = 0;
|
||||
@@ -627,7 +627,7 @@ metal_set_shader_ios :: (self: *MetalGPU, sh: u32) {
|
||||
if self.encoder == null { return; }
|
||||
state := metal_lookup_shader(self, sh);
|
||||
if state == null { return; }
|
||||
msg : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void, *void) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(self.encoder, sel_registerName("setRenderPipelineState:".ptr), state);
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ metal_set_vertex_buffer_ios :: (self: *MetalGPU, h: u32) {
|
||||
buf := metal_lookup_buffer(self, h);
|
||||
if buf == null { return; }
|
||||
// [encoder setVertexBuffer:buf offset:0 atIndex:0]
|
||||
msg : (*void, *void, *void, u64, u64) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void, *void, u64, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(self.encoder, sel_registerName("setVertexBuffer:offset:atIndex:".ptr), buf, 0, 0);
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ metal_set_texture_ios :: (self: *MetalGPU, slot: u32, h: u32) {
|
||||
tex := self.textures.items[h - 1].tex;
|
||||
if tex == null { return; }
|
||||
// [encoder setFragmentTexture:tex atIndex:slot]
|
||||
msg : (*void, *void, *void, u64) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void, *void, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(self.encoder, sel_registerName("setFragmentTexture:atIndex:".ptr), tex, xx slot);
|
||||
}
|
||||
|
||||
@@ -660,7 +660,7 @@ metal_set_vertex_constants_ios :: (self: *MetalGPU, slot: u32, data: *void, size
|
||||
if data == null { return; }
|
||||
if size_bytes <= 0 { return; }
|
||||
// [encoder setVertexBytes:data length:size_bytes atIndex:slot]
|
||||
msg : (*void, *void, *void, u64, u64) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void, *void, u64, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(self.encoder, sel_registerName("setVertexBytes:length:atIndex:".ptr),
|
||||
data, xx size_bytes, xx slot);
|
||||
}
|
||||
@@ -689,7 +689,7 @@ metal_draw_triangles_ios :: (self: *MetalGPU, vertex_offset: s32, vertex_count:
|
||||
if self.encoder == null { return; }
|
||||
if vertex_count <= 0 { return; }
|
||||
// [encoder drawPrimitives:.triangle vertexStart:offset vertexCount:count]
|
||||
msg : (*void, *void, u64, u64, u64) -> void = xx objc_msgSend;
|
||||
msg : (*void, *void, u64, u64, u64) -> void callconv(.c) = xx objc_msgSend;
|
||||
msg(self.encoder, sel_registerName("drawPrimitives:vertexStart:vertexCount:".ptr),
|
||||
MTL_PRIMITIVE_TYPE_TRIANGLE, xx vertex_offset, xx vertex_count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user