gfx: Limit # of synchronous pipelines per frame

Allows OpenGL(+ES) to run smoothly even when
building initial pipeline cache.
This commit is contained in:
Luke Street 2022-08-29 17:05:34 -04:00
parent ff0b43137c
commit ea6e49e000
1 changed files with 36 additions and 9 deletions

View File

@ -109,6 +109,12 @@ namespace aurora::gfx {
using NewPipelineCallback = std::function<wgpu::RenderPipeline()>; using NewPipelineCallback = std::function<wgpu::RenderPipeline()>;
std::mutex g_pipelineMutex; std::mutex g_pipelineMutex;
static bool g_hasPipelineThread = false; static bool g_hasPipelineThread = false;
static size_t g_pipelinesPerFrame = 0;
#ifdef NDEBUG
constexpr size_t BuildPipelinesPerFrame = 5;
#else
constexpr size_t BuildPipelinesPerFrame = 1;
#endif
static std::thread g_pipelineThread; static std::thread g_pipelineThread;
static std::atomic_bool g_pipelineThreadEnd; static std::atomic_bool g_pipelineThreadEnd;
static std::condition_variable g_pipelineCv; static std::condition_variable g_pipelineCv;
@ -176,18 +182,24 @@ static PipelineRef find_pipeline(ShaderType type, const PipelineConfig& config,
std::scoped_lock guard{g_pipelineMutex}; std::scoped_lock guard{g_pipelineMutex};
found = g_pipelines.contains(hash); found = g_pipelines.contains(hash);
if (!found) { if (!found) {
const auto ref =
std::find_if(g_queuedPipelines.begin(), g_queuedPipelines.end(), [=](auto v) { return v.first == hash; });
if (g_hasPipelineThread) { if (g_hasPipelineThread) {
const auto ref =
std::find_if(g_queuedPipelines.begin(), g_queuedPipelines.end(), [=](auto v) { return v.first == hash; });
if (ref != g_queuedPipelines.end()) { if (ref != g_queuedPipelines.end()) {
found = true; found = true;
} }
} else { } else {
g_pipelines.try_emplace(hash, cb()); if (ref != g_queuedPipelines.end()) {
if (serialize) { found = true;
serialize_pipeline_config(type, config); } else if (g_pipelinesPerFrame < BuildPipelinesPerFrame) {
g_pipelines.try_emplace(hash, cb());
if (serialize) {
serialize_pipeline_config(type, config);
}
++g_pipelinesPerFrame;
createdPipelines++;
found = true;
} }
found = true;
} }
} }
if (!found) { if (!found) {
@ -298,12 +310,16 @@ PipelineRef pipeline_ref(model::PipelineConfig config) {
static void pipeline_worker() { static void pipeline_worker() {
bool hasMore = false; bool hasMore = false;
while (true) { while (g_hasPipelineThread || g_pipelinesPerFrame < BuildPipelinesPerFrame) {
std::pair<PipelineRef, NewPipelineCallback> cb; std::pair<PipelineRef, NewPipelineCallback> cb;
{ {
std::unique_lock lock{g_pipelineMutex}; std::unique_lock lock{g_pipelineMutex};
if (!hasMore) { if (g_hasPipelineThread) {
g_pipelineCv.wait(lock, [] { return !g_queuedPipelines.empty() || g_pipelineThreadEnd; }); if (!hasMore) {
g_pipelineCv.wait(lock, [] { return !g_queuedPipelines.empty() || g_pipelineThreadEnd; });
}
} else if (g_queuedPipelines.empty()) {
return;
} }
if (g_pipelineThreadEnd) { if (g_pipelineThreadEnd) {
break; break;
@ -318,6 +334,9 @@ static void pipeline_worker() {
g_queuedPipelines.pop_front(); g_queuedPipelines.pop_front();
hasMore = !g_queuedPipelines.empty(); hasMore = !g_queuedPipelines.empty();
} }
if (!g_hasPipelineThread) {
++g_pipelinesPerFrame;
}
createdPipelines++; createdPipelines++;
queuedPipelines--; queuedPipelines--;
} }
@ -507,6 +526,10 @@ void begin_frame() {
g_currentRenderPass = 0; g_currentRenderPass = 0;
// push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport}); // push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport});
// push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor}); // push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor});
if (!g_hasPipelineThread) {
g_pipelinesPerFrame = 0;
}
} }
void end_frame(const wgpu::CommandEncoder& cmd) { void end_frame(const wgpu::CommandEncoder& cmd) {
@ -545,6 +568,10 @@ void end_frame(const wgpu::CommandEncoder& cmd) {
currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size(); currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size();
map_staging_buffer(); map_staging_buffer();
g_currentRenderPass = UINT32_MAX; g_currentRenderPass = UINT32_MAX;
if (!g_hasPipelineThread) {
pipeline_worker();
}
} }
void render(wgpu::CommandEncoder& cmd) { void render(wgpu::CommandEncoder& cmd) {