1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Direct2D: Use PostMessage for swapchain events

Co-authored-by: Matt Gonzalez <matt@echoaudio.com>
This commit is contained in:
Oli 2025-04-15 11:11:00 +01:00
parent 16326d13d3
commit 44d304b468
3 changed files with 65 additions and 19 deletions

View file

@ -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<SwapChainThread*> (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<ID2D1DeviceContext1> deviceContext;
std::unique_ptr<SwapChainThread> swapChainThread;
std::optional<CompositionTree> compositionTree;
SwapchainDelegate& delegate;
// Areas that must be repainted during the next paint call, between startFrame/endFrame
RectangleList<int> deferredRepaints;
@ -111,12 +136,17 @@ private:
std::vector<RECT> 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<HwndPimpl> (*this, windowHandle);
pimpl = std::make_unique<HwndPimpl> (*this, windowHandle, swapDelegate);
}
Direct2DHwndContext::~Direct2DHwndContext()

View file

@ -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();

View file

@ -5061,7 +5061,8 @@ private:
RectangleList<int> 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<int> area) override
{
@ -5475,17 +5482,18 @@ private:
#endif
}
static std::unique_ptr<WrappedD2DHwndContextBase> getContextForPeer (HWNDComponentPeer& peer)
static std::unique_ptr<WrappedD2DHwndContextBase> getContextForPeer (HWNDComponentPeer& peer,
SwapchainDelegate& delegate)
{
if (peer.getTransparencyKind() != HWNDComponentPeer::TransparencyKind::opaque)
return std::make_unique<WrappedD2DHwndContextTransparent> (peer);
return std::make_unique<WrappedD2DHwndContext> (peer.getHWND());
return std::make_unique<WrappedD2DHwndContext> (peer.getHWND(), delegate);
}
HWNDComponentPeer& peer;
std::unique_ptr<WrappedD2DHwndContextBase> direct2DContext = getContextForPeer (peer);
std::unique_ptr<WrappedD2DHwndContextBase> direct2DContext = getContextForPeer (peer, *this);
UpdateRegion updateRegion;
#if JUCE_ETW_TRACELOGGING