KINGDOM HEARTS HD 1.5+2.5 ReMIX

Cutscenes run with sound and a solid green picture: the luma and chroma planes never reach the game's own textures. The same DLL also swallows the shutdown fault that makes Wine open a crash dialog when a launcher or a title closes, so one install fixes both.

GPL-3.0-or-laterThis fix in MacGameFix

What you see

Cutscene runs with sound, picture solid green

Why it happens

The same as Dream Drop Distance: the game copies the two planes of a shared NV12 texture into its own textures, which D3DMetal cannot hand it, so the picture is solid green.

What the fix changes

Software decode, and the luma and chroma planes written straight into the game's own plane textures

The code

The game asks for decode into D3D video textures; the reader gets a copy of its attributes without the two that ask for it, so it decodes in software.

fixes/dwo-video-bridge.c · strip_d3d_attributes, lines 1508–1524
c
static IMFAttributes *strip_d3d_attributes(IMFAttributes *attrs)
{
    IMFAttributes *plain = NULL;
    UINT32 count = 0;

    if (!attrs || !real_MFCreateAttributes) return NULL;
    IMFAttributes_GetCount(attrs, &count);
    if (SUCCEEDED(real_MFCreateAttributes(&plain, count + 2)) && plain
        && SUCCEEDED(IMFAttributes_CopyAllItems(attrs, plain)))
    {
        IMFAttributes_DeleteItem(plain, &MF_SOURCE_READER_D3D_MANAGER);
        IMFAttributes_DeleteItem(plain, &MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS);
        return plain;
    }
    if (plain) IMFAttributes_Release(plain);
    return NULL;
}

The decoded NV12 frame is written straight into the luma and chroma textures the game created, so its own shader has planes to convert.

fixes/dwo-video-bridge.c · plane_write, lines 2112–2161
c
static void plane_write(const BYTE *nv12, UINT stride, UINT width, UINT height)
{
    D3D12_TEXTURE_COPY_LOCATION dst = { 0 }, src = { 0 };
    const BYTE *uv = nv12 + (size_t)stride * height;
    BYTE *mapped = NULL;
    UINT y;

    if (!plane_ready || !bridge_list || !bridge_queue) return;
    /*
     * Copy the planes' geometry, not the frame's.
     *
     * The footprints were computed from the descriptors captured when the pair
     * was created. If a later clip is larger and the game has not yet made a
     * new pair, writing the frame's rows into those footprints runs off the end
     * of the upload buffer. Refusing is the right answer: the next pair the
     * game creates re-arms this.
     */
    if (width != plane_y_desc.Width || height != plane_y_desc.Height) return;
    if (FAILED(ID3D12Resource_Map(plane_upload, 0, NULL, (void **)&mapped)) || !mapped)
        return;
    for (y = 0; y < height; ++y)
        memcpy(mapped + plane_y_fp.Offset + (size_t)y * plane_y_fp.Footprint.RowPitch,
               nv12 + (size_t)y * stride, width);
    for (y = 0; y < height / 2; ++y)
        memcpy(mapped + plane_uv_fp.Offset + (size_t)y * plane_uv_fp.Footprint.RowPitch,
               uv + (size_t)y * stride, width);
    ID3D12Resource_Unmap(plane_upload, 0, NULL);

    ID3D12CommandAllocator_Reset(bridge_alloc);
    ID3D12GraphicsCommandList_Reset(bridge_list, bridge_alloc, NULL);
    src.pResource = plane_upload;
    src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
    dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
    dst.pResource = plane_y;  src.PlacedFootprint = plane_y_fp;
    ID3D12GraphicsCommandList_CopyTextureRegion(bridge_list, &dst, 0, 0, 0, &src, NULL);
    dst.pResource = plane_uv; src.PlacedFootprint = plane_uv_fp;
    ID3D12GraphicsCommandList_CopyTextureRegion(bridge_list, &dst, 0, 0, 0, &src, NULL);
    ID3D12GraphicsCommandList_Close(bridge_list);
    ID3D12CommandQueue_ExecuteCommandLists(bridge_queue, 1,
            (ID3D12CommandList *const *)&bridge_list);

    ++bridge_fence_value;
    if (SUCCEEDED(ID3D12CommandQueue_Signal(bridge_queue, bridge_fence, bridge_fence_value))
        && ID3D12Fence_GetCompletedValue(bridge_fence) < bridge_fence_value
        && bridge_event)
    {
        ID3D12Fence_SetEventOnCompletion(bridge_fence, bridge_fence_value, bridge_event);
        WaitForSingleObject(bridge_event, 1000);
    }
}

Details

Needs
D3DMetal, D3D11 and D3D12
Installer
install-kh-bridge.sh
Executable
KINGDOM HEARTS HD 1.5+2.5 Launcher.exe
Built from
dwo-video-bridge.c
Verified on
Stable 26.3, on a copy of it carrying this project's winegstreamer (2026-08-31)

The full story, with the measurements and the wrong turns