[PATCH v2 0/3] MR10935: winemac: Add cross-process MetalViewSwapChain.
-- v2: winemac: Implement cross-process MetalViewSwapChain via CALayerHost. winemac: Factor out Metal device and view logic into MetalViewSwapChain. https://gitlab.winehq.org/wine/wine/-/merge_requests/10935
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/winemac.drv/vulkan.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index b9b042bd85d..02c6a20a03c 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -27,8 +27,6 @@ #include "config.h" -#include <stdarg.h> -#include <stdio.h> #include <dlfcn.h> #include "ntstatus.h" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10935
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/winemac.drv/cocoa_window.m | 68 +++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv.h | 8 ++-- dlls/winemac.drv/macdrv_cocoa.h | 4 ++ dlls/winemac.drv/vulkan.c | 8 ++-- dlls/winemac.drv/window.c | 18 ++++++++- 5 files changed, 96 insertions(+), 10 deletions(-) diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 4c1ac93524f..2e62c471eba 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -3972,6 +3972,74 @@ void macdrv_view_release_metal_view(macdrv_metal_view v) }); } +@protocol WineMetalSwapChain <NSObject> + +- (CAMetalLayer*) layer; + +@end + +@interface MetalViewSwapChain : NSObject <WineMetalSwapChain> +{ + macdrv_metal_device device; + macdrv_metal_view metal_view; +} + +- (instancetype) initWithView:(macdrv_view)view; + +@end + +@implementation MetalViewSwapChain + +- (instancetype) initWithView:(macdrv_view)view +{ + self = [super init]; + if (!self) return nil; + + if (!(device = macdrv_create_metal_device())) + { + [self release]; + return nil; + } + if (!(metal_view = macdrv_view_create_metal_view(view, device))) + { + macdrv_release_metal_device(device); + device = NULL; + [self release]; + return nil; + } + return self; +} + +- (CAMetalLayer*) layer +{ + return (CAMetalLayer*)macdrv_view_get_metal_layer(metal_view); +} + +- (void) dealloc +{ + if (metal_view) macdrv_view_release_metal_view(metal_view); + if (device) macdrv_release_metal_device(device); + [super dealloc]; +} + +@end + +macdrv_metal_swapchain macdrv_create_view_swapchain(macdrv_view v) +{ + return (macdrv_metal_swapchain)[[MetalViewSwapChain alloc] initWithView:v]; +} + +macdrv_metal_layer macdrv_swapchain_get_layer(macdrv_metal_swapchain swapchain) +{ + return (macdrv_metal_layer)[(id<WineMetalSwapChain>)swapchain layer]; +} + + +void macdrv_destroy_swapchain(macdrv_metal_swapchain swapchain) +{ + [(id<WineMetalSwapChain>)swapchain release]; +} + bool macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]) { WineContentView* view = (WineContentView*)v; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 6316a096365..4462ef99b73 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -193,10 +193,9 @@ extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_p struct macdrv_client_surface { - struct client_surface client; - macdrv_view cocoa_view; - macdrv_metal_device metal_device; - macdrv_metal_view metal_view; + struct client_surface client; + macdrv_view cocoa_view; + macdrv_metal_swapchain metal_swapchain; }; static inline struct macdrv_client_surface *impl_from_client_surface(struct client_surface *client) @@ -205,6 +204,7 @@ extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_p } extern struct macdrv_client_surface *macdrv_client_surface_create(HWND hwnd); +extern BOOL macdrv_client_surface_acquire_metal_swapchain(struct macdrv_client_surface *surface); extern struct macdrv_win_data *get_win_data(HWND hwnd); extern void release_win_data(struct macdrv_win_data *data); diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 381808479ce..fdc4222d296 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -106,6 +106,7 @@ typedef struct macdrv_opaque_metal_device* macdrv_metal_device; typedef struct macdrv_opaque_metal_view* macdrv_metal_view; typedef struct macdrv_opaque_metal_layer* macdrv_metal_layer; +typedef struct macdrv_opaque_metal_swapchain* macdrv_metal_swapchain; typedef struct macdrv_opaque_status_item* macdrv_status_item; struct macdrv_event; struct macdrv_query; @@ -527,6 +528,9 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern macdrv_metal_view macdrv_view_create_metal_view(macdrv_view v, macdrv_metal_device d); extern macdrv_metal_layer macdrv_view_get_metal_layer(macdrv_metal_view v); extern void macdrv_view_release_metal_view(macdrv_metal_view v); +extern macdrv_metal_swapchain macdrv_create_view_swapchain(macdrv_view v); +extern macdrv_metal_layer macdrv_swapchain_get_layer(macdrv_metal_swapchain swapchain); +extern void macdrv_destroy_swapchain(macdrv_metal_swapchain swapchain); extern bool macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]); extern void macdrv_set_view_backing_size(macdrv_view v, const int backing_size[2]); extern uint32_t macdrv_window_background_color(void); diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index 02c6a20a03c..f1643e3e5c4 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -49,8 +49,8 @@ static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_inst TRACE("%p %p %p %p\n", hwnd, instance, handle, client); if (!(surface = macdrv_client_surface_create(hwnd))) return VK_ERROR_OUT_OF_HOST_MEMORY; - if (!(surface->metal_device = macdrv_create_metal_device())) goto err; - if (!(surface->metal_view = macdrv_view_create_metal_view(surface->cocoa_view, surface->metal_device))) goto err; + + if (!macdrv_client_surface_acquire_metal_swapchain(surface)) goto err; if (instance->p_vkCreateMetalSurfaceEXT) { @@ -58,7 +58,7 @@ static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_inst create_info_host.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ - create_info_host.pLayer = macdrv_view_get_metal_layer(surface->metal_view); + create_info_host.pLayer = macdrv_swapchain_get_layer(surface->metal_swapchain); res = instance->p_vkCreateMetalSurfaceEXT(instance->host.instance, &create_info_host, NULL /* allocator */, handle); } @@ -68,7 +68,7 @@ static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_inst create_info_host.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ - create_info_host.pView = macdrv_view_get_metal_layer(surface->metal_view); + create_info_host.pView = macdrv_swapchain_get_layer(surface->metal_swapchain); res = instance->p_vkCreateMacOSSurfaceMVK(instance->host.instance, &create_info_host, NULL /* allocator */, handle); } diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 2cc11b7dc1e..47c08e87e89 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1076,8 +1076,7 @@ static void macdrv_client_surface_destroy(struct client_surface *client) TRACE("%s\n", debugstr_client_surface(client)); - if (surface->metal_view) macdrv_view_release_metal_view(surface->metal_view); - if (surface->metal_device) macdrv_release_metal_device(surface->metal_device); + if (surface->metal_swapchain) macdrv_destroy_swapchain(surface->metal_swapchain); } static void macdrv_client_surface_detach(struct client_surface *client) @@ -1167,6 +1166,21 @@ struct macdrv_client_surface *macdrv_client_surface_create(HWND hwnd) return surface; } +BOOL macdrv_client_surface_acquire_metal_swapchain(struct macdrv_client_surface *surface) +{ + HWND hwnd = surface->client.hwnd; + struct macdrv_win_data *data; + + if (surface->metal_swapchain) return TRUE; + + if ((data = get_win_data(hwnd))) + { + release_win_data(data); + surface->metal_swapchain = macdrv_create_view_swapchain(surface->cocoa_view); + } + return surface->metal_swapchain != NULL; +} + /********************************************************************** * SetDesktopWindow (MACDRV.@) */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10935
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/winemac.drv/cocoa_window.m | 175 ++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv.h | 2 + dlls/winemac.drv/macdrv_cocoa.h | 5 + dlls/winemac.drv/window.c | 42 ++++++++ 4 files changed, 224 insertions(+) diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 2e62c471eba..6b0ab117cd1 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -45,6 +45,25 @@ - (void)_setPreventsActivation:(BOOL)flag; @end +typedef uint32_t CGSConnectionID; +extern CGSConnectionID CGSMainConnectionID(void); + +typedef uint32_t CAContextID; + +@interface CAContext : NSObject + ++ (id) contextWithCGSConnection:(CGSConnectionID)connection options:(NSDictionary*)options; +@property(readonly) CAContextID contextId; +@property(retain) CALayer* layer; + +@end + +@interface CALayerHost : CALayer + +- (void) setContextId:(CAContextID)contextId; + +@end + static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf) { @@ -374,6 +393,7 @@ @interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContent int backingSize[2]; WineMetalView *_metalView; + NSMutableDictionary<NSNumber*, CALayerHost*>* _caLayerHosts; } @property (readonly, nonatomic) BOOL everHadGLContext; @@ -386,6 +406,8 @@ - (void) wine_getBackingSize:(int*)outBackingSize; - (void) wine_setBackingSize:(const int*)newBackingSize; - (WineMetalView*) newMetalViewWithDevice:(id<MTLDevice>)device; + - (void) addCALayerHostViewWithContextId:(CAContextID)contextId; + - (void) removeCALayerHostView:(CAContextID)contextId; @end @@ -496,6 +518,7 @@ - (void) dealloc [markedText release]; [glContexts release]; [pendingGlContexts release]; + [_caLayerHosts release]; CGImageRelease(colorImage); CGImageRelease(shapeImage); [super dealloc]; @@ -699,6 +722,33 @@ - (WineMetalView*) newMetalViewWithDevice:(id<MTLDevice>)device return _metalView; } + - (void) addCALayerHostViewWithContextId:(CAContextID)contextId + { + if (!_caLayerHosts) + _caLayerHosts = [[NSMutableDictionary alloc] init]; + + [self removeCALayerHostView:contextId]; + + CALayerHost* host = [CALayerHost layer]; + [host setContextId:contextId]; + host.magnificationFilter = kCAFilterNearest; + host.contentsScale = retina_on ? 2.0 : 1.0; + host.frame = self.layer.bounds; + host.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + + [self.layer addSublayer:host]; + [_caLayerHosts setObject:host forKey:@(contextId)]; + + [(WineWindow*)self.window windowDidDrawContent]; + } + + - (void) removeCALayerHostView:(CAContextID)contextId + { + NSNumber* key = @(contextId); + [[_caLayerHosts objectForKey:key] removeFromSuperlayer]; + [_caLayerHosts removeObjectForKey:key]; + } + - (void) setLayerRetinaProperties:(BOOL)mode { [self layer].contentsScale = mode ? 2.0 : 1.0; @@ -738,6 +788,9 @@ - (void) setRetinaMode:(BOOL)mode [self updateGLContexts]; [self setLayerRetinaProperties:mode]; + for (CALayerHost* host in [_caLayerHosts allValues]) + host.contentsScale = mode ? 2.0 : 1.0; + [super setRetinaMode:mode]; } @@ -4024,11 +4077,103 @@ - (void) dealloc @end +@interface CAContextSwapChain : NSObject <WineMetalSwapChain> +{ + void* hwnd; + macdrv_metal_device device; + CAMetalLayer* offscreen_layer; + CAContext* remote_context; + CAContextID context_id; +} + +- (instancetype) initWithHwnd:(void*)hwnd bounds:(CGRect)bounds; + +@end + +@implementation CAContextSwapChain + +- (instancetype) initWithHwnd:(void*)newHwnd bounds:(CGRect)bounds +{ + self = [super init]; + if (!self) return nil; + + hwnd = newHwnd; + if (!(device = macdrv_create_metal_device())) + { + [self release]; + return nil; + } + + offscreen_layer = [[CAMetalLayer alloc] init]; + if (!offscreen_layer) + { + macdrv_release_metal_device(device); + device = NULL; + [self release]; + return nil; + } + + offscreen_layer.device = (id<MTLDevice>)device; + offscreen_layer.framebufferOnly = YES; + offscreen_layer.magnificationFilter = kCAFilterNearest; + offscreen_layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); + offscreen_layer.contentsScale = retina_on ? 2.0 : 1.0; + [offscreen_layer setBounds:cgrect_mac_from_win(bounds)]; + [offscreen_layer setAnchorPoint:CGPointMake(0, 0)]; + + /* Export the CAMetalLayer from the rendering process, then have the + * target HWND's owner host it using CALayerHost. */ + OnMainThread(^{ + remote_context = [[CAContext contextWithCGSConnection:CGSMainConnectionID() + options:[NSDictionary dictionary]] retain]; + [remote_context setLayer:offscreen_layer]; + context_id = [remote_context contextId]; + }); + + if (!remote_context || !context_id) + { + [self release]; + return nil; + } + + macdrv_create_remote_layer(hwnd, context_id); + return self; +} + +- (CAMetalLayer*) layer +{ + return offscreen_layer; +} + +- (void) dealloc +{ + if (context_id) macdrv_release_remote_layer(hwnd, context_id); + CAContext *context = remote_context; + CAMetalLayer *layer = offscreen_layer; + macdrv_metal_device dev = device; + + OnMainThreadAsync(^{ + [context setLayer:nil]; + [context release]; + [layer release]; + if (dev) macdrv_release_metal_device(dev); + }); + + [super dealloc]; +} + +@end + macdrv_metal_swapchain macdrv_create_view_swapchain(macdrv_view v) { return (macdrv_metal_swapchain)[[MetalViewSwapChain alloc] initWithView:v]; } +macdrv_metal_swapchain macdrv_create_offscreen_swapchain(void* hwnd, CGRect bounds) +{ + return (macdrv_metal_swapchain)[[CAContextSwapChain alloc] initWithHwnd:hwnd bounds:bounds]; +} + macdrv_metal_layer macdrv_swapchain_get_layer(macdrv_metal_swapchain swapchain) { return (macdrv_metal_layer)[(id<WineMetalSwapChain>)swapchain layer]; @@ -4040,6 +4185,36 @@ void macdrv_destroy_swapchain(macdrv_metal_swapchain swapchain) [(id<WineMetalSwapChain>)swapchain release]; } +void macdrv_window_create_ca_layer_host_view(macdrv_window w, unsigned int context_id) +{ +@autoreleasepool +{ + WineWindow* window = (WineWindow*)w; + + OnMainThread(^{ + NSView* content_view = [window contentView]; + + if ([content_view isKindOfClass:[WineContentView class]]) + [(WineContentView*)content_view addCALayerHostViewWithContextId:context_id]; + }); +} +} + +void macdrv_window_release_ca_layer_host_view(macdrv_window w, unsigned int context_id) +{ +@autoreleasepool +{ + WineWindow* window = (WineWindow*)w; + + OnMainThread(^{ + NSView* content_view = [window contentView]; + + if ([content_view isKindOfClass:[WineContentView class]]) + [(WineContentView*)content_view removeCALayerHostView:context_id]; + }); +} +} + bool macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]) { WineContentView* view = (WineContentView*)v; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 4462ef99b73..4f7107baf68 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -96,6 +96,8 @@ static inline RECT rect_from_cgrect(CGRect cgrect) { WM_MACDRV_SET_WIN_REGION = WM_WINE_FIRST_DRIVER_MSG, WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS, + WM_MACDRV_CREATE_REMOTE_LAYER, + WM_MACDRV_RELEASE_REMOTE_LAYER, }; struct macdrv_thread_data diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index fdc4222d296..9a91edbe8e3 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -529,8 +529,13 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern macdrv_metal_layer macdrv_view_get_metal_layer(macdrv_metal_view v); extern void macdrv_view_release_metal_view(macdrv_metal_view v); extern macdrv_metal_swapchain macdrv_create_view_swapchain(macdrv_view v); +extern macdrv_metal_swapchain macdrv_create_offscreen_swapchain(void* hwnd, CGRect bounds); extern macdrv_metal_layer macdrv_swapchain_get_layer(macdrv_metal_swapchain swapchain); extern void macdrv_destroy_swapchain(macdrv_metal_swapchain swapchain); +extern void macdrv_window_create_ca_layer_host_view(macdrv_window w, unsigned int context_id); +extern void macdrv_window_release_ca_layer_host_view(macdrv_window w, unsigned int context_id); +extern void macdrv_create_remote_layer(void* hwnd, unsigned int context_id); +extern void macdrv_release_remote_layer(void* hwnd, unsigned int context_id); extern bool macdrv_get_view_backing_size(macdrv_view v, int backing_size[2]); extern void macdrv_set_view_backing_size(macdrv_view v, const int backing_size[2]); extern uint32_t macdrv_window_background_color(void); diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 47c08e87e89..ceb90119330 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1178,6 +1178,20 @@ BOOL macdrv_client_surface_acquire_metal_swapchain(struct macdrv_client_surface release_win_data(data); surface->metal_swapchain = macdrv_create_view_swapchain(surface->cocoa_view); } + else + { + RECT rect; + + if (NtUserGetAncestor(hwnd, GA_ROOT) != hwnd) + { + FIXME("Cross-process child window Metal swapchains are not implemented\n"); + return FALSE; + } + + if (!NtUserGetClientRect(hwnd, &rect, NtUserGetWinMonitorDpi(hwnd, MDT_RAW_DPI))) return FALSE; + surface->metal_swapchain = macdrv_create_offscreen_swapchain(hwnd, cgrect_from_rect(rect)); + } + return surface->metal_swapchain != NULL; } @@ -1545,6 +1559,22 @@ LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) activate_on_following_focus(); TRACE("WM_MACDRV_ACTIVATE_ON_FOLLOWING_FOCUS time %u\n", activate_on_focus_time); return 0; + case WM_MACDRV_CREATE_REMOTE_LAYER: + if ((data = get_win_data(hwnd))) + { + TRACE("WM_MACDRV_CREATE_REMOTE_LAYER context_id %u\n", (unsigned int)lp); + if (data->cocoa_window) macdrv_window_create_ca_layer_host_view(data->cocoa_window, (unsigned int)lp); + release_win_data(data); + } + return 0; + case WM_MACDRV_RELEASE_REMOTE_LAYER: + if ((data = get_win_data(hwnd))) + { + TRACE("WM_MACDRV_RELEASE_REMOTE_LAYER context_id %u\n", (unsigned int)lp); + if (data->cocoa_window) macdrv_window_release_ca_layer_host_view(data->cocoa_window, (unsigned int)lp); + release_win_data(data); + } + return 0; } FIXME("unrecognized window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (unsigned long)wp, lp); @@ -1552,6 +1582,18 @@ LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) } +void macdrv_create_remote_layer(void* hwnd_ptr, unsigned int context_id) +{ + NtUserPostMessage((HWND)hwnd_ptr, WM_MACDRV_CREATE_REMOTE_LAYER, 0, context_id); +} + + +void macdrv_release_remote_layer(void* hwnd_ptr, unsigned int context_id) +{ + NtUserPostMessage((HWND)hwnd_ptr, WM_MACDRV_RELEASE_REMOTE_LAYER, 0, context_id); +} + + /*********************************************************************** * WindowPosChanging (MACDRV.@) */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10935
On Wed May 20 14:21:48 2026 +0000, Chip Davis wrote:
```suggestion:-0+0 + (instancetype) contextWithCGSConnection:(CGSConnectionID)connection options:(NSDictionary*)options; ```
Thanks, this is already resolved. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935#note_140808
On Wed May 20 14:13:08 2026 +0000, Marc-Aurel Zent wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/10935/diffs?diff_id=269054&start_sha=66b4356b19acec6b37d63f8979c729b306dd0374#ec9dfe2bf80e5cdb35cb0f13c9f06da8984c9a00_4046_4046) Should be fixed now.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935#note_140809
On Wed May 20 11:27:13 2026 +0000, Chip Davis wrote:
Why not use the public `CARemoteLayer` API? It is a bit more clunky with requiring to passing around mach ports (at which point IOSurfaces are equally as attractive) and also deprecated by Apple in favor of those.
Both [Chromium](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/cocoa/remot...) and [WebKit](https://github.com/WebKit/webkit/blob/main/Source/WebCore/PAL/pal/spi/cocoa/...) use this API over `CARemoteLayer`, so it seems to be the preferred/de-facto standard for cross-process layer hosting on macOS. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935#note_140816
On Wed May 20 15:04:51 2026 +0000, Brendan Shanks wrote:
One thing that comes to mind is that OpenGL/Vulkan content calls `macdrv_client_surface_present()` on presentation, how does that work if rendering and display are happening in different processes? Also, is there an application that can be used to test this? `macdrv_client_surface_present()` only handles making the right client_surface view visible. It doesn’t do the actual buffer transfer/presentation itself.
For the cross-process Metal/Vulkan path, presentation happens via the exported CAMetalLayer/CALayerHost pair. A later `macdrv_client_surface_present()` from the rendering process doesn’t need to do anything special and just becomes a no-op. There are a bunch of intricacies with child windows, which would need extra consideration still. This simple approach here works well for top-level windows at least...
Also, is there an application that can be used to test this?
Either this MR with DXVK/MVK with Battle.net, or with the two attached patches DXMT can also be tested: [dxmt-ExtEscape.patch](/uploads/34ac670abe29df3a5e8e710f1ee8f244/dxmt-ExtEscape.patch)[wine-ExtEscape.patch](/uploads/781960199979e3fa81ec479addbaba6f/wine-ExtEscape.patch) Current steam requires child window support, so con't be tested with this MR as it is. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935#note_140822
This merge request was approved by Brendan Shanks. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935
On Mon Jun 1 03:40:54 2026 +0000, Marc-Aurel Zent wrote:
It is a bit more clunky with requiring to passing around mach ports (at which point IOSurfaces are equally as attractive) and also deprecated by Apple in favor of those. Both [Chromium](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/cocoa/remot...) and [WebKit](https://github.com/WebKit/webkit/blob/main/Source/WebCore/PAL/pal/spi/cocoa/...) use this API over `CARemoteLayer`, so it seems to be the preferred/de-facto standard for cross-process layer hosting on macOS. OK. I'm sure you're aware of Apple's infamously strict stance towards use of "private" SPIs, but since we _already_ do that (e.g. using the underlying `__pthread_kill(2)` syscall to signal arbitrary threads), I suppose that's less of a concern.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10935#note_141805
participants (4)
-
Brendan Shanks (@bshanks) -
Chip Davis (@cdavis5e) -
Marc-Aurel Zent -
Marc-Aurel Zent (@mzent)