Skip to content

Commit 991ac55

Browse files
Fix multi-threaded creation of PipelineStates in PipelineStateCache (o3de#18091)
Signed-off-by: Martin Winter <[email protected]>
1 parent 4a3ee11 commit 991ac55

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

Gems/Atom/RHI/Code/Include/Atom/RHI/PipelineState.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ namespace AZ::RHI
4444
const PipelineStateDescriptor& descriptor,
4545
PipelineLibrary* pipelineLibrary = nullptr);
4646

47+
//! Preinitializes a pipeline state to allow for safe usage with multi-threaded DrawPacket creation
48+
void PreInitialize(MultiDevice::DeviceMask deviceMask);
49+
4750
PipelineStateType GetType() const;
4851

4952
private:

Gems/Atom/RHI/Code/Source/RHI/PipelineState.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ namespace AZ::RHI
2929
return true;
3030
}
3131

32+
void PipelineState::PreInitialize(MultiDevice::DeviceMask deviceMask)
33+
{
34+
const int deviceCount = RHI::RHISystemInterface::Get()->GetDeviceCount();
35+
36+
for (int deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex)
37+
{
38+
if ((AZStd::to_underlying(deviceMask) >> deviceIndex) & 1)
39+
{
40+
m_deviceObjects[deviceIndex] = Factory::Get().CreatePipelineState();
41+
}
42+
}
43+
}
44+
3245
ResultCode PipelineState::Init(
3346
MultiDevice::DeviceMask deviceMask, const PipelineStateDescriptor& descriptor, PipelineLibrary* pipelineLibrary)
3447
{
@@ -51,7 +64,11 @@ namespace AZ::RHI
5164
{
5265
auto* device = RHISystemInterface::Get()->GetDevice(deviceIndex);
5366

54-
m_deviceObjects[deviceIndex] = Factory::Get().CreatePipelineState();
67+
if(!m_deviceObjects.contains(deviceIndex))
68+
{
69+
m_deviceObjects[deviceIndex] = Factory::Get().CreatePipelineState();
70+
}
71+
5572
switch (descriptor.GetType())
5673
{
5774
case PipelineStateType::Draw:
@@ -106,8 +123,8 @@ namespace AZ::RHI
106123

107124
if (resultCode != ResultCode::Success)
108125
{
109-
// Reset already initialized device-specific PipelineStates and set deviceMask to 0
110-
m_deviceObjects.clear();
126+
// Only reset the device mask but the the device-specific PipelineStates, as other
127+
// threads might be using them already
111128
MultiDeviceObject::Init(static_cast<MultiDevice::DeviceMask>(0u));
112129
}
113130

@@ -116,9 +133,9 @@ namespace AZ::RHI
116133

117134
void PipelineState::Shutdown()
118135
{
136+
m_deviceObjects.clear();
119137
if (IsInitialized())
120138
{
121-
m_deviceObjects.clear();
122139
MultiDeviceObject::Shutdown();
123140
}
124141
}

Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ namespace AZ::RHI
376376
// but don't initialize it yet. We can safely allocate the 'empty' instance and cache it.
377377
pipelineState = aznew PipelineState;
378378

379+
pipelineState->PreInitialize(m_deviceMask);
380+
379381
[[maybe_unused]] bool success =
380382
InsertPipelineState(pendingCache, PipelineStateEntry(pipelineStateHash, pipelineState, descriptor));
381383
AZ_Assert(success, "PipelineStateEntry already exists in the pending cache.");

0 commit comments

Comments
 (0)