[Bug 60263] New: winemac.drv: cross-process child window Metal swapchains not implemented (Steam client renders black); the CAContext/CALayerHost route already exists and is only reached from vulkan.c
http://bugs.winehq.org/show_bug.cgi?id=60263 Bug ID: 60263 Summary: winemac.drv: cross-process child window Metal swapchains not implemented (Steam client renders black); the CAContext/CALayerHost route already exists and is only reached from vulkan.c Product: Wine Version: 11.16 Hardware: x86-64 OS: MacOS Status: UNCONFIRMED Severity: normal Priority: P2 Component: winemac.drv Assignee: wine-bugs@list.winehq.org Reporter: winebugs@protonmail.ch Target Milestone: --- winemac.drv contains this FIXME: Cross-process child window Metal swapchains are not implemented This is the whole reason Steam's client renders as a black window under Wine on macOS, and the route to fix it already exists in the tree — it is simply never reached from the Metal side. ## What happens Steam's CEF GPU process asks for a Metal view for a child window whose root lives in the *browser* process. `get_win_data()` returns NULL by construction for a foreign HWND — `win_datas` is a process-local CFDictionary — and the caller aborts on the null view by design. Chromium restarts the GPU process, it dies identically, and after ~6 attempts it gives up. Black window. Two things make this hard to spot: - The `CreateSwapChain` cross-process guard never fires for this window, because `GetWindowThreadProcessId()` says the *child* belongs to us. The Win32 process check and winemac's realization check disagree, and the path trusts the first. - It is backend-independent: forcing `--use-angle=swiftshader` (no Metal, no GPU driver at all) produces the same crash count and a byte-identical black capture. ## The route already in the tree `macdrv_client_surface_acquire_metal_swapchain()` builds a `CAContext`-backed offscreen swapchain and posts `WM_MACDRV_CREATE_REMOTE_LAYER` to the window's owning process, which hosts it via `CALayerHost`. That is exactly the cross-process case. In stock Wine only `vulkan.c` reaches it. Wiring the Metal side to fall back to that route when `get_win_data()` returns NULL makes Steam's client render completely, out-of-process, with text, no injected switches and 0 GPU crashes. ## Working implementation, for reference A working version of both halves is public here, under MIT: https://github.com/macgameport/cities-skylines-2-macos/blob/main/scripts/win... Notes from getting it working, in case they save someone time: - **Do not add a member to `macdrv_functions_t`** to expose the entry point — that struct is `C_ASSERT`-ed at a fixed size, so a client built against a larger struct would read past the end of an older winemac's and call whatever followed. A standalone exported symbol degrades safely. - **Convert Win32 pixels to Cocoa points at the CALayerHost entry points.** `CALayer.frame` is in points; unconverted frames are 2x too large on retina and the content is pushed down and right. - **Stack the hosted layers by Win32 paint order, not insertion order.** CEF recreates a swapchain on every resize, so insertion order puts whichever browser was recreated last on top. Steam runs two sibling browsers and the client goes black. - **An empty child rect is not "no rect".** CEF keeps an inactive browser in the z-order at 0x0; treating that as "no rect supplied" and stretching the layer over the view blacks the window. - **Retire a superseded layer on CREATE, not on destroy**, or the child is unhosted between the two and the window blinks through during a resize. ## Disclosure This was investigated with heavy AI assistance, so I am filing a report rather than a patch, and the implementation above is offered only as a reference someone may or may not want to look at. I am also aware of the relicensing discussion in 3Shain/dxmt#152 and am not asking for anything to be taken as-is. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60263 Ken Sharp <imwellcushtymelike@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |download URL| |https://cdn.fastly.steamsta | |tic.com/client/installer/St | |eamSetup.exe -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60263 --- Comment #1 from James <winebugs@protonmail.ch> --- Created attachment 82021 --> http://bugs.winehq.org/attachment.cgi?id=82021 Reference implementation (applyable diff against wine 11.16 + the out-of-tree DXMT support patch), regenerated 2026-09-02 Attaching the current, applyable diff. Until 2026-09-02 the file at the linked URL was a prose changelog rather than a patch -- my mistake, now corrected at the same path. Offered as a reference only, per the disclosure in the description. Note it targets a tree that already carries the out-of-tree DXMT support patch (dlls/winemac.drv gains a dxmt_objc.m), so it does not apply to stock wine as-is; the child-window mechanism in window.c / cocoa_window.m is independent of that and is the part worth reading. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60263 marc_aurel@me.com changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |marc_aurel@me.com -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60263 --- Comment #2 from James <winebugs@protonmail.ch> --- Created attachment 82030 --> http://bugs.winehq.org/attachment.cgi?id=82030 Stock-applicable core of the reference implementation (applies to pristine wine 11.16), regenerated 2026-09-03 — obsoletes attachment 82021 Replacing attachment 82021, which needed a tree already carrying the out-of-tree DXMT support patch and, as noted at the time, did not apply to stock wine as-is. This one does. It is the same implementation with the DXMT-specific layer split off, regenerated from git rather than hand-maintained. What it is: the cross-process child window case in window.c's macdrv_client_surface_acquire_metal_swapchain, where the driver currently prints the FIXME and returns FALSE. A child HWND owned by another process gets no cocoa_window of its own; the child's process renders into a CAContext-backed layer and the owner's WineContentView hosts it through a CALayerHost, keyed by the CAContextID, with the owner repositioning and restacking the hosted layer as the child moves. That is the CAContext/CALayerHost route the driver already has for vulkan.c, reached from the Metal side as well. Measured on wine 11.16, 2026-09-03: - Applies to a pristine 11.16 tree with `patch -p1` at fuzz 0. Also applies on top of the DXMT support patch; the insertion points are placed away from its. - Four files: window.c, cocoa_window.m, macdrv.h, macdrv_cocoa.h. +513/-27. - Compiles on pristine 11.16 with no new warnings against the stock build of the driver, and the FIXME string is gone from the built module. - Runtime testing was through the Metal route only: Steam's client, where CEF's GPU process asks for a swapchain on a child window owned by the browser process. That is the black-window case in the description, and it renders. The vulkan.c path compiles and links but I have not exercised it at runtime. - On its own it changes no behaviour for an application that never asks for a cross-process child swapchain. Two fixes since 82021: a child's own move now repositions its hosted layer (previously only a move of the top-level did, which CEF happens to mask by recreating the swapchain), and the paint-order walk no longer has a fixed capacity. Same disclosure as the description: written with heavy AI assistance and offered as a reference for whoever writes the real thing, not as a submission. The header's licensing note is corrected: the modifications are offered under LGPL-2.1-or-later, the licence of the files they touch. The earlier attachment's header carried an MIT sentence, which cannot apply to a diff of LGPL files. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=60263 James <winebugs@protonmail.ch> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #82021|0 |1 is obsolete| | -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla