From dd8c2d1993b5dc5c3ffd29095dc9e3071ed3b28d Mon Sep 17 00:00:00 2001 From: WIndFate Date: Fri, 19 Jun 2026 05:38:43 +0900 Subject: [PATCH] feat(d3d11): implement SwapDeviceContextState SwapDeviceContextState was UNIMPLEMENTED. Callers such as Direct2D interop use it to swap their own pipeline state in and the application's state out around a render pass, so any such render loop aborted at the first call. MTLD3D11DeviceContextState gains a D3D11ContextState saved_state slot. The swap saves the current state_ into the returned previous-state token, activates the incoming token's saved state, then resets encoding state and invalidates the render pipeline so the Metal side follows the new state. With this, a Direct2D render loop (BeginDraw/Clear/draw/EndDraw) runs cleanly with EndDraw returning S_OK. --- src/d3d11/d3d11_context_impl.cpp | 21 ++++++++++++++++++++- src/d3d11/d3d11_context_state.hpp | 5 +++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/d3d11/d3d11_context_impl.cpp b/src/d3d11/d3d11_context_impl.cpp index 6d3595207..795cbbe43 100644 --- a/src/d3d11/d3d11_context_impl.cpp +++ b/src/d3d11/d3d11_context_impl.cpp @@ -1884,7 +1884,26 @@ template class MTLD3D11DeviceContextImplBase : p void STDMETHODCALLTYPE SwapDeviceContextState(ID3DDeviceContextState *pState, ID3DDeviceContextState **ppPreviousState) override { - UNIMPLEMENTED("SwapDeviceContextState"); + // Callers (e.g. Direct2D interop) swap their own pipeline state in and the + // application's state out around a render pass. Save the current pipeline + // state into the returned previous-state token, then activate the incoming + // token's saved state. + if (!pState) { + if (ppPreviousState) + *ppPreviousState = nullptr; + return; + } + std::lock_guard lock(mutex); + auto incoming = static_cast(pState); + if (ppPreviousState) { + auto previous = new MTLD3D11DeviceContextState(device); + previous->saved_state = std::move(state_); + *ppPreviousState = ref(previous); + } + state_ = std::move(incoming->saved_state); + incoming->saved_state = {}; + ResetEncodingContextState(); + InvalidateRenderPipeline(); } void diff --git a/src/d3d11/d3d11_context_state.hpp b/src/d3d11/d3d11_context_state.hpp index 3484bda07..cb1bcb9bb 100644 --- a/src/d3d11/d3d11_context_state.hpp +++ b/src/d3d11/d3d11_context_state.hpp @@ -211,6 +211,11 @@ class MTLD3D11DeviceContextState return E_NOINTERFACE; } + + // Saved pipeline state for SwapDeviceContextState. A newly created token + // carries default (empty) state, giving the caller a clean context to render + // into; swapping back restores the previously saved state. + D3D11ContextState saved_state = {}; }; } // namespace dxmt \ No newline at end of file