blob: 124e11e177346d486c490afdeff69e7723319d34 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/pipeline_compile_queue.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
namespace impeller {
std::shared_ptr<PipelineCompileQueue> PipelineCompileQueue::Create(
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner) {
return std::shared_ptr<PipelineCompileQueue>(
new PipelineCompileQueue(std::move(worker_task_runner)));
}
PipelineCompileQueue::PipelineCompileQueue(
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner)
: worker_task_runner_(std::move(worker_task_runner)) {}
PipelineCompileQueue::~PipelineCompileQueue() {
FinishAllJobs();
}
bool PipelineCompileQueue::PostJobForDescriptor(const PipelineDescriptor& desc,
const fml::closure& job) {
if (!job) {
return false;
}
{
Lock lock(pending_jobs_mutex_);
auto insertion_result = pending_jobs_.insert(std::make_pair(desc, job));
if (!insertion_result.second) {
// This bit is being extremely conservative. If insertion did not take
// place, someone gave the compile queue a job for the same description.
// This is highly unusual but technically not impossible. Just run the job
// eagerly.
FML_LOG(ERROR) << "Got multiple compile jobs for the same descriptor. "
"Running eagerly.";
// Don't invoke the job here has there are we have currently acquired a
// mutex.
worker_task_runner_->PostTask(job);
return true;
}
}
worker_task_runner_->PostTask([weak_queue = weak_from_this()]() {
if (auto queue = weak_queue.lock()) {
queue->DoOneJob();
}
});
return true;
}
fml::closure PipelineCompileQueue::TakeNextJob() {
Lock lock(pending_jobs_mutex_);
if (pending_jobs_.empty()) {
return nullptr;
}
auto job_iterator = pending_jobs_.begin();
auto job = job_iterator->second;
pending_jobs_.erase(job_iterator);
return job;
}
fml::closure PipelineCompileQueue::TakeJob(const PipelineDescriptor& desc) {
Lock lock(pending_jobs_mutex_);
auto found = pending_jobs_.find(desc);
if (found == pending_jobs_.end()) {
return nullptr;
}
// The pipeline compile job was somewhere in the task queue. However, a
// rendering operation needed the job to be done ASAP. Instead of waiting for
// the pipeline compile queue to eventually get to finishing job, the thread
// waiting on the job just decided to take the job from the queue and do it
// itself. If there were jobs ahead of this one, it means that they were
// mis-prioritized. This counter dumps the number of job re-prioritizations.
priorities_elevated_++;
FML_TRACE_COUNTER("impeller", "PipelineCompileQueue",
reinterpret_cast<int64_t>(this), // Trace Counter ID
"PrioritiesElevated", priorities_elevated_);
auto job = found->second;
pending_jobs_.erase(found);
return job;
}
void PipelineCompileQueue::DoOneJob() {
if (auto job = TakeNextJob()) {
job();
}
}
void PipelineCompileQueue::FinishAllJobs() {
// This doesn't have to be fast. Just ensures the task queue is flushed when
// the compile queue is shutting down with jobs still in it.
while (true) {
bool has_jobs = false;
{
Lock lock(pending_jobs_mutex_);
has_jobs = !pending_jobs_.empty();
}
if (!has_jobs) {
return;
}
// Allow any remaining worker threads to take jobs from this queue.
DoOneJob();
}
}
void PipelineCompileQueue::PerformJobEagerly(const PipelineDescriptor& desc) {
if (auto job = TakeJob(desc)) {
job();
}
}
} // namespace impeller