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

D2D: Refactor SwapChainThread and attempt to ensure correct alignment of slist entries

This commit is contained in:
reuk 2024-04-24 13:31:27 +01:00
parent 56d5445f8a
commit 06903573d2
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
2 changed files with 75 additions and 48 deletions

View file

@ -36,10 +36,13 @@ namespace juce
{
//==============================================================================
class Presentation
class alignas (MEMORY_ALLOCATION_ALIGNMENT) Presentation
{
public:
SLIST_ENTRY& getListEntry() { return listEntry; }
SLIST_ENTRY& getListEntry()
{
return listEntry;
}
auto getPresentationBitmap() const
{
@ -90,13 +93,47 @@ public:
}
private:
JUCE_ALIGN (MEMORY_ALLOCATION_ALIGNMENT)
SLIST_ENTRY listEntry;
ComSmartPtr<ID2D1Bitmap> presentationBitmap;
RectangleList<int> paintAreas;
HRESULT hr = S_OK;
};
class SList
{
public:
void push (SLIST_ENTRY& item)
{
jassert ((reinterpret_cast<uintptr_t> (&item) % MEMORY_ALLOCATION_ALIGNMENT) == 0);
InterlockedPushEntrySList (head.get(), &item);
}
auto* pop()
{
return InterlockedPopEntrySList (head.get());
}
private:
struct Destructor
{
void operator() (void* ptr) const
{
_aligned_free (ptr);
}
};
std::unique_ptr<SLIST_HEADER, Destructor> head { []() -> SLIST_HEADER*
{
auto* result = static_cast<SLIST_HEADER*> (_aligned_malloc (sizeof (SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT));
if (result == nullptr)
return nullptr;
InitializeSListHead (result);
return result;
}() };
};
struct Direct2DHwndContext::HwndPimpl : public Direct2DGraphicsContext::Pimpl
{
private:
@ -108,39 +145,33 @@ private:
multithread (multithreadIn),
swapChainEventHandle (ownerIn.swap.swapChainEvent->getHandle())
{
InitializeSListHead (&paintedPresentations);
InitializeSListHead (&retiredPresentations);
for (auto& p : presentations)
InterlockedPushEntrySList (&retiredPresentations, &p.getListEntry());
retired.push (p.getListEntry());
}
~SwapChainThread()
{
SetEvent (quitEvent.getHandle());
thread.join();
InterlockedFlushSList (&paintedPresentations);
InterlockedFlushSList (&retiredPresentations);
}
Presentation* getFreshPresentation()
{
if (auto listEntry = InterlockedPopEntrySList (&retiredPresentations))
return reinterpret_cast<Presentation*> (listEntry);
if (auto* listEntry = reinterpret_cast<Presentation*> (retired.pop()))
return listEntry;
return nullptr;
}
void pushPaintedPresentation (Presentation* presentationIn)
{
InterlockedPushEntrySList (&paintedPresentations, &presentationIn->getListEntry());
painted.push (presentationIn->getListEntry());
SetEvent (wakeEvent.getHandle());
}
void retirePresentation (Presentation* presentationIn)
{
InterlockedPushEntrySList (&retiredPresentations, &presentationIn->getListEntry());
retired.push (presentationIn->getListEntry());
}
void notify()
@ -149,35 +180,10 @@ private:
}
private:
void serviceSwapChain()
{
if (swapChainReady)
{
if (auto listEntry = InterlockedPopEntrySList (&paintedPresentations))
{
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (owner.owner.metrics, swapChainThreadTime);
auto filledPresentation = reinterpret_cast<Presentation*> (listEntry);
{
ScopedMultithread scopedMultithread { multithread };
owner.present (filledPresentation, 0);
}
swapChainReady = false;
InterlockedPushEntrySList (&retiredPresentations, listEntry);
}
}
}
JUCE_ALIGN (MEMORY_ALLOCATION_ALIGNMENT)
SLIST_HEADER paintedPresentations;
JUCE_ALIGN (MEMORY_ALLOCATION_ALIGNMENT)
SLIST_HEADER retiredPresentations;
SList painted, retired;
Direct2DHwndContext::HwndPimpl& owner;
ComSmartPtr<ID2D1Multithread> multithread;
HANDLE swapChainEventHandle = nullptr;
bool swapChainReady = false;
std::vector<Presentation> presentations = std::vector<Presentation> (2);
WindowsScopedEvent wakeEvent;
@ -186,7 +192,30 @@ private:
void threadLoop()
{
Thread::setCurrentThreadName ("swapChainThread");
Thread::setCurrentThreadName ("JUCE D2D swap chain thread");
bool swapChainReady = false;
const auto serviceSwapChain = [&]
{
if (! swapChainReady)
return;
auto* listEntry = reinterpret_cast<Presentation*> (painted.pop());
if (listEntry == nullptr)
return;
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (owner.owner.metrics, swapChainThreadTime);
{
ScopedMultithread scopedMultithread { multithread };
owner.present (listEntry, 0);
}
retired.push (listEntry->getListEntry());
swapChainReady = false;
};
for (;;)
{

View file

@ -482,8 +482,8 @@ public:
swapChainDescription.Height = (UINT) size.getHeight();
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.BufferCount = bufferCount;
swapChainDescription.SwapEffect = swapEffect;
swapChainDescription.BufferCount = 2;
swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDescription.Flags = swapChainFlags;
swapChainDescription.Scaling = DXGI_SCALING_STRETCH;
@ -587,11 +587,9 @@ public:
return { (int) size.width, (int) size.height };
}
DXGI_SWAP_EFFECT const swapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
UINT const bufferCount = 2;
uint32 const swapChainFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
uint32 const presentSyncInterval = 1;
uint32 const presentFlags = 0;
static constexpr uint32 swapChainFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
static constexpr uint32 presentSyncInterval = 1;
static constexpr uint32 presentFlags = 0;
ComSmartPtr<IDXGISwapChain1> chain;
ComSmartPtr<ID2D1Bitmap1> buffer;
std::optional<WindowsScopedEvent> swapChainEvent;