gl_graphics_pipeline: Improve shader builder synchronization using fences (#7969)

* gl_graphics_pipeline: Improve shader builder synchronization

Make use of GLsync objects to ensure better synchronization between shader builder threads and the main context

* gl_graphics_pipeline: Make built_fence access threadsafe

* gl_graphics_pipeline: Use GLsync objects only when building in parallel

* gl_graphics_pipeline: Replace GetSync calls with non-blocking waits

The spec states that a ClientWait on a Fence object ensures the changes propagate to the calling context
This commit is contained in:
Ameer J 2022-03-06 10:46:49 -05:00 committed by GitHub
parent 5192c64991
commit 370e480c8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 21 deletions

View file

@ -243,10 +243,6 @@ GraphicsPipeline::GraphicsPipeline(
case Settings::ShaderBackend::GLASM: case Settings::ShaderBackend::GLASM:
if (!sources[stage].empty()) { if (!sources[stage].empty()) {
assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage)); assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage));
if (in_parallel) {
// Make sure program is built before continuing when building in parallel
glGetString(GL_PROGRAM_ERROR_STRING_NV);
}
} }
break; break;
case Settings::ShaderBackend::SPIRV: case Settings::ShaderBackend::SPIRV:
@ -256,20 +252,18 @@ GraphicsPipeline::GraphicsPipeline(
break; break;
} }
} }
if (in_parallel && backend != Settings::ShaderBackend::GLASM) { if (in_parallel) {
// Make sure programs have built if we are building shaders in parallel std::lock_guard lock{built_mutex};
for (OGLProgram& program : source_programs) { built_fence.Create();
if (program.handle != 0) { // Flush this context to ensure compilation commands and fence are in the GPU pipe.
GLint status{}; glFlush();
glGetProgramiv(program.handle, GL_LINK_STATUS, &status); built_condvar.notify_one();
} } else {
} is_built = true;
} }
if (shader_notify) { if (shader_notify) {
shader_notify->MarkShaderComplete(); shader_notify->MarkShaderComplete();
} }
is_built = true;
built_condvar.notify_one();
}}; }};
if (thread_worker) { if (thread_worker) {
thread_worker->QueueWork(std::move(func)); thread_worker->QueueWork(std::move(func));
@ -440,7 +434,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
buffer_cache.UpdateGraphicsBuffers(is_indexed); buffer_cache.UpdateGraphicsBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed); buffer_cache.BindHostGeometryBuffers(is_indexed);
if (!is_built.load(std::memory_order::relaxed)) { if (!IsBuilt()) {
WaitForBuild(); WaitForBuild();
} }
const bool use_assembly{assembly_programs[0].handle != 0}; const bool use_assembly{assembly_programs[0].handle != 0};
@ -585,8 +579,26 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
} }
void GraphicsPipeline::WaitForBuild() { void GraphicsPipeline::WaitForBuild() {
if (built_fence.handle == 0) {
std::unique_lock lock{built_mutex}; std::unique_lock lock{built_mutex};
built_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); }); built_condvar.wait(lock, [this] { return built_fence.handle != 0; });
}
ASSERT(glClientWaitSync(built_fence.handle, 0, GL_TIMEOUT_IGNORED) != GL_WAIT_FAILED);
is_built = true;
}
bool GraphicsPipeline::IsBuilt() noexcept {
if (is_built) {
return true;
}
if (built_fence.handle == 0) {
return false;
}
// Timeout of zero means this is non-blocking
const auto sync_status = glClientWaitSync(built_fence.handle, 0, 0);
ASSERT(sync_status != GL_WAIT_FAILED);
is_built = sync_status != GL_TIMEOUT_EXPIRED;
return is_built;
} }
} // namespace OpenGL } // namespace OpenGL

View file

@ -100,9 +100,7 @@ public:
return writes_global_memory; return writes_global_memory;
} }
[[nodiscard]] bool IsBuilt() const noexcept { [[nodiscard]] bool IsBuilt() noexcept;
return is_built.load(std::memory_order::relaxed);
}
template <typename Spec> template <typename Spec>
static auto MakeConfigureSpecFunc() { static auto MakeConfigureSpecFunc() {
@ -154,7 +152,8 @@ private:
std::mutex built_mutex; std::mutex built_mutex;
std::condition_variable built_condvar; std::condition_variable built_condvar;
std::atomic_bool is_built{false}; OGLSync built_fence{};
bool is_built{false};
}; };
} // namespace OpenGL } // namespace OpenGL