diff --git a/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.cpp b/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.cpp index afea108853..d6971eb87a 100644 --- a/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.cpp +++ b/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.cpp @@ -38,17 +38,18 @@ namespace juce struct Direct2DHwndContext::HwndPimpl : public Direct2DGraphicsContext::Pimpl { private: - struct SwapChainThread : private AsyncUpdater + struct SwapChainThread { SwapChainThread (Direct2DHwndContext::HwndPimpl& ownerIn, HANDLE swapHandle) : owner (ownerIn), swapChainEventHandle (swapHandle) { + SetWindowSubclass (owner.hwnd, subclassWindowProc, (UINT_PTR) this, (DWORD_PTR) this); } - ~SwapChainThread() override + ~SwapChainThread() { - cancelPendingUpdate(); + RemoveWindowSubclass (owner.hwnd, subclassWindowProc, (UINT_PTR) this); SetEvent (quitEvent.getHandle()); thread.join(); } @@ -62,10 +63,32 @@ private: WindowsScopedEvent quitEvent; std::thread thread { [&] { threadLoop(); } }; - void handleAsyncUpdate() override + static constexpr uint32_t swapchainReadyMessageID = WM_USER + 124; + + bool handleWindowProcMessage (UINT message) { - owner.swapEventReceived = true; - owner.present(); + if (message == swapchainReadyMessageID) + { + owner.onSwapchainEvent(); + return true; + } + + return false; + } + + static LRESULT CALLBACK subclassWindowProc (HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam, + UINT_PTR, + DWORD_PTR referenceData) + { + auto* that = reinterpret_cast (referenceData); + + if (that != nullptr && that->handleWindowProcMessage (message)) + return 0; + + return DefSubclassProc (hwnd, message, wParam, lParam); } void threadLoop() @@ -82,7 +105,7 @@ private: { case WAIT_OBJECT_0: { - triggerAsyncUpdate(); + PostMessage (owner.hwnd, swapchainReadyMessageID, 0, 0); break; } @@ -98,10 +121,12 @@ private: } }; + HWND hwnd; SwapChain swap; ComSmartPtr deviceContext; std::unique_ptr swapChainThread; std::optional compositionTree; + SwapchainDelegate& delegate; // Areas that must be repainted during the next paint call, between startFrame/endFrame RectangleList deferredRepaints; @@ -111,12 +136,17 @@ private: std::vector dirtyRectangles; int64 lastFinishFrameTicks = 0; - HWND hwnd = nullptr; // Set to true after the swap event is signalled, indicating that we're allowed to try presenting // a new frame. bool swapEventReceived = false; + void onSwapchainEvent() + { + swapEventReceived = true; + delegate.onSwapchainEvent(); + } + bool prepare() override { const auto adapter = directX->adapters.getAdapterForHwnd (hwnd); @@ -182,6 +212,7 @@ private: bool ready = Pimpl::checkPaintReady(); ready &= swap.canPaint(); ready &= compositionTree.has_value(); + ready &= swapEventReceived; return ready; } @@ -189,9 +220,10 @@ private: JUCE_DECLARE_WEAK_REFERENCEABLE (HwndPimpl) public: - HwndPimpl (Direct2DHwndContext& ownerIn, HWND hwndIn) + HwndPimpl (Direct2DHwndContext& ownerIn, HWND hwndIn, SwapchainDelegate& swapDelegate) : Pimpl (ownerIn), - hwnd (hwndIn) + hwnd (hwndIn), + delegate (swapDelegate) { } @@ -375,7 +407,7 @@ public: }; //============================================================================== -Direct2DHwndContext::Direct2DHwndContext (HWND windowHandle) +Direct2DHwndContext::Direct2DHwndContext (HWND windowHandle, SwapchainDelegate& swapDelegate) { #if JUCE_DIRECT2D_METRICS metrics = new Direct2DMetrics { Direct2DMetricsHub::getInstance()->lock, @@ -384,7 +416,7 @@ Direct2DHwndContext::Direct2DHwndContext (HWND windowHandle) Direct2DMetricsHub::getInstance()->add (metrics); #endif - pimpl = std::make_unique (*this, windowHandle); + pimpl = std::make_unique (*this, windowHandle, swapDelegate); } Direct2DHwndContext::~Direct2DHwndContext() diff --git a/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.h b/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.h index 70ac6196a5..78161eb244 100644 --- a/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.h +++ b/modules/juce_gui_basics/native/juce_Direct2DHwndContext_windows.h @@ -38,7 +38,13 @@ namespace juce class Direct2DHwndContext : public Direct2DGraphicsContext { public: - explicit Direct2DHwndContext (HWND windowHandle); + struct SwapchainDelegate + { + virtual ~SwapchainDelegate() = default; + virtual void onSwapchainEvent() = 0; + }; + + Direct2DHwndContext (HWND windowHandle, SwapchainDelegate& swapDelegate); ~Direct2DHwndContext() override; void handleShowWindow(); diff --git a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp index a77d914892..cdfc4936c9 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp @@ -5061,7 +5061,8 @@ private: RectangleList deferredRepaints; }; -class D2DRenderContext : public RenderContext +class D2DRenderContext : public RenderContext, + private Direct2DHwndContext::SwapchainDelegate { public: static constexpr auto name = "Direct2D"; @@ -5080,7 +5081,7 @@ public: if (transparent != direct2DContext->supportsTransparency()) { direct2DContext.reset(); - direct2DContext = getContextForPeer (peer); + direct2DContext = getContextForPeer (peer, *this); } if (direct2DContext->supportsTransparency()) @@ -5129,6 +5130,11 @@ public: } private: + void onSwapchainEvent() override + { + handleDirect2DPaint(); + } + struct WrappedD2DHwndContextBase { virtual ~WrappedD2DHwndContextBase() = default; @@ -5159,7 +5165,8 @@ private: class WrappedD2DHwndContext : public WrappedD2DHwndContextBase { public: - explicit WrappedD2DHwndContext (HWND hwnd) : ctx (hwnd) {} + WrappedD2DHwndContext (HWND hwnd, SwapchainDelegate& swapDelegate) + : ctx (hwnd, swapDelegate) {} void addDeferredRepaint (Rectangle area) override { @@ -5475,17 +5482,18 @@ private: #endif } - static std::unique_ptr getContextForPeer (HWNDComponentPeer& peer) + static std::unique_ptr getContextForPeer (HWNDComponentPeer& peer, + SwapchainDelegate& delegate) { if (peer.getTransparencyKind() != HWNDComponentPeer::TransparencyKind::opaque) return std::make_unique (peer); - return std::make_unique (peer.getHWND()); + return std::make_unique (peer.getHWND(), delegate); } HWNDComponentPeer& peer; - std::unique_ptr direct2DContext = getContextForPeer (peer); + std::unique_ptr direct2DContext = getContextForPeer (peer, *this); UpdateRegion updateRegion; #if JUCE_ETW_TRACELOGGING