DYNASTY WARRIORS: ORIGINS
The player needs D3D11 video interfaces D3DMetal lacks, and the decoded frame carried across to its D3D12 renderer.
What you see
Cutscenes play with sound and subtitles, and a black picture.
Why it happens
The cutscenes are WebM (VP9) decoded by IMFSourceReader on a separate D3D11 device and presented by a D3D12 renderer: the frame never reaches the renderer, and a stock CrossOver 26.3 ships no demuxer that opens a WebM.
What the fix changes
A bridge in libxess.dll answers the shared handle of each decoded frame and carries it across to the D3D12 renderer. On CrossOver Preview 27 that is all it needs.
The code
The D3D12 renderer opens the handle of a frame decoded on the D3D11 device; the bridge answers with a texture on the game's own device that carries the frame across.
fixes/dwo-video-bridge.c · d3d12_open_shared_handle, lines 2163–2215static HRESULT WINAPI d3d12_open_shared_handle(void *self, HANDLE handle,
REFIID iid, void **out)
{
{
static LONG told;
if (InterlockedIncrement(&told) <= 12)
logf_("D3D12 OpenSharedHandle %p %s%s", handle, guid_text_(iid),
handle == BRIDGE_HANDLE ? " << ours" : "");
}
if (handle == BRIDGE_HANDLE)
{
HRESULT hr;
if (!out) return E_INVALIDARG;
*out = NULL;
if (!IsEqualGUID(iid, &IID_ID3D12Resource)) return E_NOINTERFACE;
EnterCriticalSection(&frame_lock);
/* A new clip of another size: the game has made a new texture and is
* opening it now, so this is the one moment the bridge can change size.
* Handing back the old one leaves the game drawing from a texture no
* frame of this clip can be written into. */
if (bridge_texture && frame_width && frame_height &&
(texture_width != frame_width || texture_height != frame_height))
{
logf_("bridge: the game opens a %ux%u clip on a %ux%u bridge; rebuilding",
frame_width, frame_height, texture_width, texture_height);
bridge_destroy();
}
if (!bridge_texture && frame_width && frame_height)
{
/*
* The size the game asked to share, when it said one.
*
* The handle it passes belongs to a texture it created itself, and
* what comes back has to describe that texture -- not the clip.
* Kingdom Hearts shares a 2048x1080 surface to carry a 1920x1080
* frame, so a texture built to the clip's size is the wrong
* resource under the same handle, and what the game copies out of
* it is not a picture.
*/
bridge_create((ID3D12Device *)self, frame_width, frame_height);
}
hr = bridge_texture ? S_OK : E_FAIL;
if (bridge_texture)
{
ID3D12Resource_AddRef(bridge_texture);
*out = bridge_texture;
}
LeaveCriticalSection(&frame_lock);
return hr;
}
return real_open_shared_handle(self, handle, iid, out);
}On the D3D11 side IDXGIResource::GetSharedHandle returns E_NOTIMPL; the bridge hands out a handle of its own that the D3D12 side recognises.
fixes/dwo-video-bridge.c · res_get_shared_handle, lines 1863–1884static HRESULT WINAPI res_get_shared_handle(void *self, HANDLE *handle)
{
HRESULT hr = real_res_get_shared_handle(self, handle);
{
static LONG told;
if (InterlockedIncrement(&told) <= 12)
logf_("GetSharedHandle -> 0x%08lx%s", (unsigned long)hr,
(FAILED(hr) && d3d12_bridge_armed) ? " (answering BRIDGE_HANDLE)" : "");
}
/*
* Only invent a handle if the side that can recognise it is armed.
*
* BRIDGE_HANDLE is meaningful to d3d12_open_shared_handle and to nothing
* else. Handing it out while that hook is missing turns a clean failure --
* the game learns it cannot share, and says so -- into a real D3D12 device
* dereferencing 0xD3D12B21D. Nioh 3 crashed exactly that way, because its
* D3D12 arrives through Streamline and the hook had not been placed there
* yet. Reporting the original failure is the safe answer.
*/
if (FAILED(hr) && handle && d3d12_bridge_armed) { *handle = BRIDGE_HANDLE; return S_OK; }
return hr;
}Details
- Needs
- D3DMetal
- Installer
- install-dwo-bridge.sh
- Executable
- DWORIGINS.exe
- Built from
- dwo-video-bridge.c
- Verified on
- Preview 27 (2026-10-14)