From a1aa73fd8a8569edcc83378804f94dfbdcfcea10 Mon Sep 17 00:00:00 2001 From: Marc-Aurel Zent Date: Wed, 3 Jun 2026 11:47:25 +0200 Subject: [PATCH] feat(d3d11): implement getting Metal layer from HWND via ExtEscape --- src/d3d11/d3d11_swapchain.cpp | 50 +++++++++++++++++++++++++++-------- src/util/util_win32_compat.h | 17 ++++++++++++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 5e9404d3f..4a7e4b1a6 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -26,6 +26,15 @@ #include #include +#define MACDRV_ESCAPE_GET_SURFACE 6790 +#define MACDRV_ESCAPE_RELEASE_SURFACE 6791 + +struct macdrv_escape_surface +{ + UINT64 surface; /* Opaque pointer to struct macdrv_client_surface */ + UINT64 layer; /* Opaque pointer to CAMetalLayer */ +}; + /** Ref: https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-idxgiswapchain2-setmaximumframelatency This value is 1 by default. @@ -131,10 +140,26 @@ class MTLD3D11SwapChain final : public MTLDXGISubObjectGetMTLDevice(), layer_weak_); + HDC hdc = GetDC(hWnd); + int escapeCode = MACDRV_ESCAPE_GET_SURFACE; + int supported = ExtEscape(hdc, QUERYESCSUPPORT, sizeof(int), (LPCSTR)&escapeCode, 0, NULL); + if (supported > 0) { + struct macdrv_escape_surface surfaceInfo = {0}; + int result = ExtEscape(hdc, MACDRV_ESCAPE_GET_SURFACE, 0, NULL, sizeof(surfaceInfo), (LPSTR)&surfaceInfo); + if (result > 0 && surfaceInfo.layer) { + client_surface_.handle = surfaceInfo.surface; + layer_weak_.handle = surfaceInfo.layer; + } + } + ReleaseDC(hWnd, hdc); + + if (!layer_weak_) { + ERR("Failed to get metal layer via MACDRV_ESCAPE_GET_SURFACE."); + native_view_ = WMT::CreateMetalViewFromHWND((intptr_t)hWnd, pDevice->GetMTLDevice(), layer_weak_); + } - if (!native_view_) { - ERR("Failed to create metal view, it seems like your Wine has no exported symbols needed by DXMT."); + if (!layer_weak_) { + ERR("Failed to get metal layer, it seems like your Wine has not the needed functionality for DXMT."); abort(); } @@ -206,7 +231,16 @@ class MTLD3D11SwapChain final : public MTLDXGISubObjectWaitUntilGPUIdle(); - WMT::ReleaseMetalView(native_view_); + if (client_surface_ != nullptr) { + HDC hdc = GetDC(hWnd); + struct macdrv_escape_surface surfaceInfo = {0}; + surfaceInfo.surface = client_surface_.handle; + ExtEscape(hdc, MACDRV_ESCAPE_RELEASE_SURFACE, sizeof(surfaceInfo), (LPCSTR)&surfaceInfo, 0, NULL); + ReleaseDC(hWnd, hdc); + } else { + WMT::ReleaseMetalView(native_view_); + } + client_surface_ = {}; native_view_ = {}; CloseHandle(present_semaphore_); }; @@ -1056,6 +1090,7 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject factory_; Com dxgi_device_; WMT::Object native_view_; + WMT::Object client_surface_; WMT::MetalLayer layer_weak_; ULONG presentation_count_; DXGI_SWAP_CHAIN_DESC1 desc_; @@ -1096,13 +1131,6 @@ CreateSwapChain( return DXGI_ERROR_INVALID_CALL; InitReturnPtr(ppSwapChain); - DWORD window_process_id; - GetWindowThreadProcessId(hWnd, &window_process_id); - if (GetProcessId(GetCurrentProcess()) != window_process_id) { - ERR("CreateSwapChain: cross-process swapchain not supported yet"); - return E_FAIL; - } - Com layer_factory; if (FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&layer_factory)))) { ERR("CreateSwapChain: failed to get IMTLDXGIDevice"); diff --git a/src/util/util_win32_compat.h b/src/util/util_win32_compat.h index e4a556a06..235b74503 100644 --- a/src/util/util_win32_compat.h +++ b/src/util/util_win32_compat.h @@ -99,6 +99,23 @@ inline BOOL DuplicateHandle(HANDLE hSourceProcessHandle, return FALSE; } +#define QUERYESCSUPPORT 8 + +inline HDC GetDC(HWND hWnd) { + dxmt::Logger::warn("GetDC not implemented."); + return nullptr; +} + +inline int ReleaseDC(HWND hWnd, HDC hDC) { + dxmt::Logger::warn("ReleaseDC not implemented."); + return 0; +} + +inline int ExtEscape(HDC hdc, int nEscape, int cbInput, LPCSTR lpszInData, int cbOutput, LPSTR lpszOutData) { + dxmt::Logger::warn("ExtEscape not implemented."); + return 0; +} + #define ARRAYSIZE(a) (sizeof(a)/sizeof(*(a)))