|
| 1 | +#include <stdatomic.h> |
1 | 2 | #include <dlfcn.h> |
2 | 3 | #import <Cocoa/Cocoa.h> |
3 | 4 | #import <ColorSync/ColorSync.h> |
| 5 | +#import <CoreFoundation/CFRunLoop.h> |
4 | 6 | #import <Metal/Metal.h> |
5 | 7 | #import <MetalFX/MetalFX.h> |
6 | 8 | #import <QuartzCore/QuartzCore.h> |
@@ -2269,31 +2271,102 @@ _MTLSharedEvent_signalValue(void *obj) { |
2269 | 2271 | } |
2270 | 2272 |
|
2271 | 2273 | #ifndef DXMT_NATIVE |
| 2274 | + |
| 2275 | +typedef struct { |
| 2276 | + _Atomic(CFRunLoopRef) runloop_ref; |
| 2277 | + MTLSharedEventListener *shared_listener; |
| 2278 | +} *shared_event_listener_t; |
| 2279 | + |
2272 | 2280 | extern NTSTATUS NtSetEvent(void *handle, void *prev_state); |
2273 | 2281 |
|
2274 | 2282 | static NTSTATUS |
2275 | 2283 | _MTLSharedEvent_setWin32EventAtValue(void *obj) { |
2276 | | - static MTLSharedEventListener *shared_listener = nil; |
2277 | | - static dispatch_once_t pred; |
2278 | | - dispatch_once(&pred, ^{ |
2279 | | - shared_listener = [[MTLSharedEventListener alloc] init]; |
2280 | | - }); |
| 2284 | + struct unixcall_mtlsharedevent_setevent *params = obj; |
| 2285 | + void *nt_event_handle = (shared_event_listener_t)params->event_handle; |
| 2286 | + shared_event_listener_t q = (shared_event_listener_t)params->shared_event_listener; |
| 2287 | + [(id<MTLSharedEvent>)params->shared_event |
| 2288 | + notifyListener:q->shared_listener |
| 2289 | + atValue:params->value |
| 2290 | + block:^(id<MTLSharedEvent> _e, uint64_t _v) { |
| 2291 | + // NOTE: must ensure no more notification comes after listener been destroyed. |
| 2292 | + while (!atomic_load_explicit(&q->runloop_ref, memory_order_acquire)) { |
| 2293 | +#if defined(__x86_64__) |
| 2294 | + _mm_pause(); |
| 2295 | +#elif defined(__aarch64__) |
| 2296 | + __asm__ __volatile__("yield"); |
| 2297 | +#endif |
| 2298 | + } |
| 2299 | + CFRunLoopPerformBlock(q->runloop_ref, kCFRunLoopCommonModes, ^{ |
| 2300 | + NtSetEvent(nt_event_handle, NULL); |
| 2301 | + }); |
| 2302 | + CFRunLoopWakeUp(q->runloop_ref); |
| 2303 | + }]; |
| 2304 | + return STATUS_SUCCESS; |
| 2305 | +} |
2281 | 2306 |
|
2282 | | - struct unixcall_generic_obj_obj_uint64_noret *params = obj; |
2283 | | - void *nt_event_handle = (void *)params->arg0; |
2284 | | - [(id<MTLSharedEvent>)params->handle notifyListener:shared_listener |
2285 | | - atValue:params->arg1 |
2286 | | - block:^(id<MTLSharedEvent> _e, uint64_t _v) { |
2287 | | - NtSetEvent(nt_event_handle, NULL); |
2288 | | - }]; |
| 2307 | +static NTSTATUS |
| 2308 | +_SharedEventListener_start(void *obj) { |
| 2309 | + struct unixcall_generic_obj_noret *params = obj; |
| 2310 | + shared_event_listener_t q = (shared_event_listener_t)params->handle; |
| 2311 | + CFRunLoopRef uninited = NULL; |
| 2312 | + if (q && atomic_compare_exchange_strong(&q->runloop_ref, &uninited, CFRunLoopGetCurrent())) { |
| 2313 | + /* Add a dummy source so the runloop stays running */ |
| 2314 | + CFRunLoopSourceContext source_context = {0}; |
| 2315 | + CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &source_context); |
| 2316 | + CFRunLoopAddSource(q->runloop_ref, source, kCFRunLoopCommonModes); |
| 2317 | + CFRunLoopRun(); |
| 2318 | + } |
| 2319 | + return STATUS_SUCCESS; |
| 2320 | +} |
| 2321 | + |
| 2322 | +static NTSTATUS |
| 2323 | +_SharedEventListener_create(void *obj) { |
| 2324 | + struct unixcall_generic_obj_ret *params = obj; |
| 2325 | + shared_event_listener_t q = malloc(sizeof(*q)); |
| 2326 | + if (q) { |
| 2327 | + q->runloop_ref = NULL; |
| 2328 | + q->shared_listener = [[MTLSharedEventListener alloc] init]; |
| 2329 | + } |
| 2330 | + params->ret = (obj_handle_t)q; |
| 2331 | + return STATUS_SUCCESS; |
| 2332 | +} |
| 2333 | + |
| 2334 | +static NTSTATUS |
| 2335 | +_SharedEventListener_destroy(void *obj) { |
| 2336 | + struct unixcall_generic_obj_noret *params = obj; |
| 2337 | + shared_event_listener_t q = (shared_event_listener_t)params->handle; |
| 2338 | + if (q && q->runloop_ref) { |
| 2339 | + CFRunLoopStop(q->runloop_ref); |
| 2340 | + q->runloop_ref = NULL; |
| 2341 | + [q->shared_listener release]; |
| 2342 | + q->shared_listener = nil; |
| 2343 | + free(q); |
| 2344 | + } |
2289 | 2345 | return STATUS_SUCCESS; |
2290 | 2346 | } |
| 2347 | + |
2291 | 2348 | #else |
2292 | 2349 | static NTSTATUS |
2293 | 2350 | _MTLSharedEvent_setWin32EventAtValue(void *obj) { |
2294 | 2351 | // nop |
2295 | 2352 | return STATUS_SUCCESS; |
2296 | 2353 | } |
| 2354 | + |
| 2355 | +static NTSTATUS |
| 2356 | +_SharedEventListener_start(void *obj) { |
| 2357 | + return STATUS_SUCCESS; |
| 2358 | +} |
| 2359 | + |
| 2360 | +static NTSTATUS |
| 2361 | +_SharedEventListener_create(void *obj) { |
| 2362 | + return STATUS_SUCCESS; |
| 2363 | +} |
| 2364 | + |
| 2365 | +static NTSTATUS |
| 2366 | +_SharedEventListener_destroy(void *obj) { |
| 2367 | + return STATUS_SUCCESS; |
| 2368 | +} |
| 2369 | + |
2297 | 2370 | #endif |
2298 | 2371 |
|
2299 | 2372 | static NTSTATUS |
@@ -2426,6 +2499,9 @@ const void *__wine_unix_call_funcs[] = { |
2426 | 2499 | &_MTLDevice_newFence, |
2427 | 2500 | &_MTLDevice_newEvent, |
2428 | 2501 | &_MTLBuffer_updateContents, |
| 2502 | + &_SharedEventListener_create, |
| 2503 | + &_SharedEventListener_start, |
| 2504 | + &_SharedEventListener_destroy, |
2429 | 2505 | }; |
2430 | 2506 |
|
2431 | 2507 | #ifndef DXMT_NATIVE |
@@ -2538,5 +2614,8 @@ const void *__wine_unix_call_wow64_funcs[] = { |
2538 | 2614 | &_MTLDevice_newFence, |
2539 | 2615 | &_MTLDevice_newEvent, |
2540 | 2616 | &_MTLBuffer_updateContents, |
| 2617 | + &_SharedEventListener_create, |
| 2618 | + &_SharedEventListener_start, |
| 2619 | + &_SharedEventListener_destroy, |
2541 | 2620 | }; |
2542 | 2621 | #endif |
0 commit comments