Skip to content

Commit 74020b4

Browse files
Fixed issue with synchronous pipelines not waiting for asynchronous shaders
1 parent 986c9d6 commit 74020b4

File tree

4 files changed

+72
-25
lines changed

4 files changed

+72
-25
lines changed

Common/interface/AsyncInitializer.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828

2929
#include <atomic>
3030
#include <memory>
31+
#include <vector>
3132

3233
#include "SpinLock.hpp"
3334
#include "ThreadPool.hpp"
35+
#include "RefCntAutoPtr.hpp"
3436

3537
namespace Diligent
3638
{
@@ -107,6 +109,15 @@ class AsyncInitializer
107109
};
108110
}
109111

112+
template <typename HanlderType>
113+
static std::unique_ptr<AsyncInitializer> Start(IThreadPool* pThreadPool,
114+
const std::vector<RefCntAutoPtr<IAsyncTask>>& Prerequisites,
115+
HanlderType&& Handler)
116+
{
117+
std::vector<IAsyncTask*> PrerequisitePtrs{Prerequisites.begin(), Prerequisites.end()};
118+
return Start(pThreadPool, PrerequisitePtrs.data(), static_cast<Uint32>(PrerequisitePtrs.size()), std::forward<HanlderType>(Handler));
119+
}
120+
110121
template <typename HanlderType>
111122
static std::unique_ptr<AsyncInitializer> Start(IThreadPool* pThreadPool,
112123
HanlderType&& Handler)

Graphics/Archiver/src/SerializedPipelineStateImpl.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -382,26 +382,36 @@ SerializedPipelineStateImpl::SerializedPipelineStateImpl(IReferenceCounters*
382382
constexpr bool WaitUntilShadersReady = false;
383383
PipelineStateUtils::ExtractShaders<SerializedShaderImpl>(CreateInfo, ShaderStages, WaitUntilShadersReady, ActiveShaderStages);
384384

385-
std::vector<RefCntAutoPtr<IAsyncTask>> ShaderCompileTasks;
385+
std::vector<const SerializedShaderImpl*> Shaders;
386386
for (const SerializedShaderStageInfo& Stage : ShaderStages)
387387
{
388-
for (const SerializedShaderImpl* pShader : Stage.Shaders)
389-
{
390-
for (RefCntAutoPtr<IAsyncTask> pCompileTask : pShader->GetCompileTasks())
391-
ShaderCompileTasks.emplace_back(std::move(pCompileTask));
392-
}
388+
Shaders.insert(Shaders.end(), Stage.Shaders.begin(), Stage.Shaders.end());
393389
}
394390

395-
std::vector<IAsyncTask*> Prerequisites{ShaderCompileTasks.begin(), ShaderCompileTasks.end()};
391+
std::vector<RefCntAutoPtr<IAsyncTask>> ShaderCompileTasks;
392+
for (const SerializedShaderImpl* pShader : Shaders)
393+
{
394+
for (RefCntAutoPtr<IAsyncTask> pCompileTask : pShader->GetCompileTasks())
395+
ShaderCompileTasks.emplace_back(std::move(pCompileTask));
396+
}
396397

397398
m_AsyncInitializer = AsyncInitializer::Start(
398399
pDevice->GetShaderCompilationThreadPool(),
399-
Prerequisites.data(), // Make sure that all asynchronous shader compile tasks are
400-
static_cast<Uint32>(Prerequisites.size()), // completed before the pipeline initialization task starts
400+
ShaderCompileTasks, // Make sure that all asynchronous shader compile tasks are completed first
401401
[this,
402+
#ifdef DILIGENT_DEBUG
403+
Shaders,
404+
#endif
402405
CreateInfo = typename PipelineStateCreateInfoXTraits<PSOCreateInfoType>::CreateInfoXType{CreateInfo},
403406
ArchiveInfo](Uint32 ThreadId) mutable //
404407
{
408+
#ifdef DILIGENT_DEBUG
409+
for (const SerializedShaderImpl* pShader : Shaders)
410+
{
411+
VERIFY(!pShader->IsCompiling(), "All shader compile tasks must have been completed since we used them as "
412+
"prerequisites for the pipeline initialization task. This appears to be a bug.");
413+
}
414+
#endif
405415
try
406416
{
407417
Initialize(static_cast<const PSOCreateInfoType&>(CreateInfo), ArchiveInfo);

Graphics/GraphicsEngine/include/PipelineStateBase.hpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ void WaitUntilShaderReadyIfRequested(RefCntAutoPtr<ShaderImplType>& pShader, boo
181181
{
182182
if (WaitForCompletion)
183183
{
184-
VERIFY(!pShader->IsCompiling(), "All shader compile tasks must have been completed since we used them as prerequisites for the pipeline initialization task. This appears to be a bug.");
185184
const SHADER_STATUS ShaderStatus = pShader->GetStatus(/*WaitForCompletion = */ true);
186185
if (ShaderStatus != SHADER_STATUS_READY)
187186
{
@@ -864,28 +863,40 @@ class PipelineStateBase : public DeviceObjectBase<typename EngineImplTraits::Pip
864863
{
865864
// Collect all asynchronous shader compile tasks
866865
typename PipelineStateImplType::TShaderStages ShaderStages;
867-
ExtractShaders<ShaderImplType>(CreateInfo, ShaderStages);
866+
SHADER_TYPE ActiveShaderStages = SHADER_TYPE_UNKNOWN;
867+
constexpr bool WaitUntilShadersReady = false;
868+
PipelineStateUtils::ExtractShaders<ShaderImplType>(CreateInfo, ShaderStages, WaitUntilShadersReady, ActiveShaderStages);
868869

869-
std::vector<RefCntAutoPtr<IAsyncTask>> ShaderCompileTasks;
870+
std::vector<const ShaderImplType*> Shaders;
870871
for (const auto& Stage : ShaderStages)
871872
{
872-
std::vector<const ShaderImplType*> Shaders = GetStageShaders(Stage);
873-
for (const ShaderImplType* pShader : Shaders)
874-
{
875-
if (RefCntAutoPtr<IAsyncTask> pCompileTask = pShader->GetCompileTask())
876-
ShaderCompileTasks.emplace_back(std::move(pCompileTask));
877-
}
873+
std::vector<const ShaderImplType*> StageShaders = GetStageShaders(Stage);
874+
Shaders.insert(Shaders.end(), StageShaders.begin(), StageShaders.end());
878875
}
879876

880-
std::vector<IAsyncTask*> Prerequisites{ShaderCompileTasks.begin(), ShaderCompileTasks.end()};
877+
std::vector<RefCntAutoPtr<IAsyncTask>> ShaderCompileTasks;
878+
for (const ShaderImplType* pShader : Shaders)
879+
{
880+
if (RefCntAutoPtr<IAsyncTask> pCompileTask = pShader->GetCompileTask())
881+
ShaderCompileTasks.emplace_back(std::move(pCompileTask));
882+
}
881883

882884
m_AsyncInitializer = AsyncInitializer::Start(
883885
this->m_pDevice->GetShaderCompilationThreadPool(),
884-
Prerequisites.data(), // Make sure that all asynchronous shader compile tasks are
885-
static_cast<Uint32>(Prerequisites.size()), // completed before the pipeline initialization task starts
886+
ShaderCompileTasks, // Make sure that all asynchronous shader compile tasks are completed first
886887
[pThisImpl,
888+
#ifdef DILIGENT_DEBUG
889+
Shaders,
890+
#endif
887891
CreateInfo = typename PipelineStateCreateInfoXTraits<PSOCreateInfoType>::CreateInfoXType{CreateInfo}](Uint32 ThreadId) mutable //
888892
{
893+
#ifdef DILIGENT_DEBUG
894+
for (const ShaderImplType* pShader : Shaders)
895+
{
896+
VERIFY(!pShader->IsCompiling(), "All shader compile tasks must have been completed since we used them as "
897+
"prerequisites for the pipeline initialization task. This appears to be a bug.");
898+
}
899+
#endif
889900
try
890901
{
891902
pThisImpl->InitializePipeline(CreateInfo);

Tests/DiligentCoreAPITest/src/AsyncShaderCompilationTest.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ TEST(Shader, ReleaseWhileCompiling)
143143
pShader.Release();
144144
}
145145

146-
TEST(Shader, AsyncPipeline)
146+
void TestAsyncPipeline(SHADER_COMPILE_FLAGS ShaderFlags, PSO_CREATE_FLAGS PSOFlags)
147147
{
148148
GPUTestingEnvironment::ScopedReset EnvironmentAutoReset;
149149

@@ -158,12 +158,12 @@ TEST(Shader, AsyncPipeline)
158158
{
159159
constexpr bool SimplifiedShader = true;
160160

161-
auto pVS = CreateShader("AsyncShaderCompilationTest.vsh", "Async pipeline test VS", SHADER_TYPE_VERTEX, SHADER_COMPILE_FLAG_ASYNCHRONOUS, SimplifiedShader);
161+
auto pVS = CreateShader("AsyncShaderCompilationTest.vsh", "Async pipeline test VS", SHADER_TYPE_VERTEX, ShaderFlags, SimplifiedShader);
162162
ASSERT_NE(pVS, nullptr);
163163

164164
for (size_t i = 0; i < 16; ++i)
165165
{
166-
auto pPS = CreateShader("AsyncShaderCompilationTest.psh", "Async pipeline test PS", SHADER_TYPE_PIXEL, SHADER_COMPILE_FLAG_ASYNCHRONOUS, SimplifiedShader);
166+
auto pPS = CreateShader("AsyncShaderCompilationTest.psh", "Async pipeline test PS", SHADER_TYPE_PIXEL, ShaderFlags, SimplifiedShader);
167167
ASSERT_NE(pPS, nullptr);
168168

169169
// Allocate pipeline CI on the heap to check that all data is copied correctly
@@ -183,7 +183,7 @@ TEST(Shader, AsyncPipeline)
183183
.AddRenderTarget(TEX_FORMAT_RGBA8_UNORM)
184184
.SetInputLayout(InputLayout)
185185
.SetResourceLayout(ResourceLayout)
186-
.SetFlags(PSO_CREATE_FLAG_ASYNCHRONOUS);
186+
.SetFlags(PSOFlags);
187187

188188
// Create multiple pipelines that use the same shaders.
189189
// In particular this reproduces the problem with the non-thread-safe ID3DBlob in D3D12.
@@ -217,4 +217,19 @@ TEST(Shader, AsyncPipeline)
217217
LOG_INFO_MESSAGE(pPSOs.size(), " PSOs were compiled after ", Iter, " iterations (", (T.GetElapsedTime() - StartTime) * 1000, " ms)");
218218
}
219219

220+
TEST(Shader, AsyncPipeline_SyncShaders)
221+
{
222+
TestAsyncPipeline(SHADER_COMPILE_FLAG_NONE, PSO_CREATE_FLAG_ASYNCHRONOUS);
223+
}
224+
225+
TEST(Shader, SyncPipeline_AsyncShaders)
226+
{
227+
TestAsyncPipeline(SHADER_COMPILE_FLAG_ASYNCHRONOUS, PSO_CREATE_FLAG_NONE);
228+
}
229+
230+
TEST(Shader, AsyncPipeline_AsyncShaders)
231+
{
232+
TestAsyncPipeline(SHADER_COMPILE_FLAG_ASYNCHRONOUS, PSO_CREATE_FLAG_ASYNCHRONOUS);
233+
}
234+
220235
} // namespace

0 commit comments

Comments
 (0)