[PATCH 0/1] MR11058: winemac: Implement ExtEscape queries for Metal layer creation and release.
This exposes similar functionality to `vkCreateWin32SurfaceKHR`, just for projects that implement some sort of graphics backend directly on top of Metal that do not use Vulkan as an in-between layer, like DXMT. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058
From: Marc-Aurel Zent <mzent@codeweavers.com> --- dlls/winemac.drv/gdi.c | 60 +++++++++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv.h | 14 +++++++++ 2 files changed, 74 insertions(+) diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index a0f314234b9..a7d9b4b1294 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -231,11 +231,71 @@ static INT macdrv_GetDeviceCaps(PHYSDEV dev, INT cap) } +/*********************************************************************** + * ExtEscape (MACDRV.@) + */ +static INT macdrv_ExtEscape(PHYSDEV dev, INT escape, INT in_count, LPCVOID in_data, + INT out_count, LPVOID out_data) +{ + switch (escape) + { + case QUERYESCSUPPORT: + if (in_data && in_count >= sizeof(DWORD)) + { + switch (*(const INT *)in_data) + { + case MACDRV_ESCAPE_GET_SURFACE: + case MACDRV_ESCAPE_RELEASE_SURFACE: + return TRUE; + } + } + break; + + case MACDRV_ESCAPE_GET_SURFACE: + { + struct macdrv_escape_surface *data = out_data; + struct macdrv_client_surface *surface; + HWND hwnd = NtUserWindowFromDC(dev->hdc); + + if (out_count < sizeof(*data)) return FALSE; + + if (!hwnd || !(surface = macdrv_client_surface_create(hwnd))) return FALSE; + + if (!macdrv_client_surface_acquire_metal_swapchain(surface)) + { + client_surface_release(&surface->client); + return FALSE; + } + + data->surface = (UINT_PTR)surface; + data->layer = (UINT_PTR)macdrv_swapchain_get_layer(surface->metal_swapchain); + return TRUE; + } + case MACDRV_ESCAPE_RELEASE_SURFACE: + { + const struct macdrv_escape_surface *data = in_data; + struct macdrv_client_surface *surface; + + if (in_count < sizeof(*data)) return FALSE; + + if (!data) return FALSE; + + surface = (struct macdrv_client_surface *)(UINT_PTR)data->surface; + if (surface) client_surface_release(&surface->client); + return TRUE; + } + } + + return FALSE; +} + + static const struct user_driver_funcs macdrv_funcs = { .dc_funcs.pCreateCompatibleDC = macdrv_CreateCompatibleDC, .dc_funcs.pCreateDC = macdrv_CreateDC, .dc_funcs.pDeleteDC = macdrv_DeleteDC, + .dc_funcs.pExtEscape = macdrv_ExtEscape, .dc_funcs.pGetDeviceCaps = macdrv_GetDeviceCaps, .dc_funcs.pGetDeviceGammaRamp = macdrv_GetDeviceGammaRamp, .dc_funcs.pSetDeviceGammaRamp = macdrv_SetDeviceGammaRamp, diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 4f7107baf68..46d6a990a78 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -347,4 +347,18 @@ static inline UINT asciiz_to_unicode(WCHAR *dst, const char *src) return (p - dst) * sizeof(WCHAR); } +/* ExtEscape definitions */ + +enum macdrv_escape_codes +{ + MACDRV_ESCAPE_GET_SURFACE = 6790, + MACDRV_ESCAPE_RELEASE_SURFACE, +}; + +struct macdrv_escape_surface +{ + UINT64 surface; + UINT64 layer; +}; + #endif /* __WINE_MACDRV_H */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11058
Here is the corresponding DXMT PR that would make use of this: https://github.com/3Shain/dxmt/pull/166 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058#note_142087
This kind of interop with third-party projects has proven to be quite annoying when refactoring Wine internals and I expect this area to require a lot more of it in the future. It would be nicer to find a more standard way, or that depends less on internal implementation and especially not on internal structures. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058#note_142089
On Wed Jun 3 10:14:46 2026 +0000, Rémi Bernon wrote:
This kind of interop with third-party projects has proven to be quite annoying when refactoring Wine internals and I expect this area to require a lot more of it in the future. It would be nicer to find a more standard way, or that depends less on internal implementation and especially not on internal structures. But we are not depending on any internals structures here, no?
The consumer of the API just needs to get a metal layer for its HWND, and this is much better than the usage of get_win_data, create_metal_device, create_metal_view, get_metal_layer, release_win_data, that is currently done by downstream projects (for more recent versions even through a compatibility shim, since Wine internals did change there). The surface pointer is just something opaque the consumer needs to release after it is done with the Metal layer, not something that is used in any other way... -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058#note_142090
On Wed Jun 3 10:14:46 2026 +0000, Marc-Aurel Zent wrote:
But we are not depending on any internals structures here, no? The consumer of the API just needs to get a metal layer for its HWND, and this is much better than the usage of get_win_data, create_metal_device, create_metal_view, get_metal_layer, release_win_data, that is currently done by downstream projects (for more recent versions even through a compatibility shim, since Wine internals did change there). The surface pointer is just something opaque the consumer needs to release after it is done with the Metal layer, not something that is used in any other way...
/* ExtEscape definitions */
enum macdrv_escape_codes
{
MACDRV_ESCAPE_GET_SURFACE = 6790,
MACDRV_ESCAPE_RELEASE_SURFACE,
};
struct macdrv_escape_surface
{
UINT64 surface;
UINT64 layer;
};
The above would be the "public" API we can't change, and I can't believe this can be made much simpler... Theoretically, we could store a Metal layer to window surface mapping internally, and the consumer only gets the layer, and then later releases the layer, but I am not too sure a 1:1 mapping is always a given there, since the layer is a weak reference... -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058#note_142091
On Wed Jun 3 10:18:48 2026 +0000, Marc-Aurel Zent wrote:
``` /* ExtEscape definitions */ enum macdrv_escape_codes { MACDRV_ESCAPE_GET_SURFACE = 6790, MACDRV_ESCAPE_RELEASE_SURFACE, }; struct macdrv_escape_surface { UINT64 surface; UINT64 layer; }; ``` The above would be the "public" API we can't change, and I can't believe this can be made much simpler... Theoretically, we could store a Metal layer to window surface mapping internally, and the consumer only gets the layer, and then later releases the layer, but I am not too sure a 1:1 mapping is always a given there, since the layer is a weak reference...
I see, it's indeed better if doesn't depend on some internal struct, but it still feels quite brittle and difficult to maintain as there's no code user for this API in Wine source. It's then probably up to @julliard if we want to support such private interface. Fwiw I believe there's a precedent in winex11 with some escape codes being used by Gallium Nine, as IIUC it has been broken a couple times and I'm not sure how well we can maintain it in the future either. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11058#note_142092
participants (3)
-
Marc-Aurel Zent -
Marc-Aurel Zent (@mzent) -
Rémi Bernon (@rbernon)