blob: eda5362e9e8897925b592049981e5b70592a87b2 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/blocking_sequence_runner.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/service/scheduler.h"
namespace gpu {
BlockingSequenceRunner::BlockingSequenceRunner(Scheduler* scheduler)
: task_graph_(scheduler->task_graph()) {
auto sequence = std::make_unique<Sequence>(scheduler);
sequence_ = sequence.get();
task_graph_->AddSequence(std::move(sequence));
}
BlockingSequenceRunner::~BlockingSequenceRunner() {
SequenceId id = GetSequenceId();
sequence_ = nullptr;
task_graph_->DestroySequence(id);
}
SequenceId BlockingSequenceRunner::GetSequenceId() const {
return sequence_->sequence_id();
}
bool BlockingSequenceRunner::HasTasks() const {
base::AutoLock locker(lock());
return sequence_->HasTasks();
}
uint32_t BlockingSequenceRunner::AddTask(TaskCallback task_callback,
std::vector<SyncToken> wait_fences,
const SyncToken& release,
ReportingCallback report_callback) {
base::AutoLock auto_lock(lock());
return sequence_->AddTask(std::move(task_callback), std::move(wait_fences),
release, std::move(report_callback));
}
uint32_t BlockingSequenceRunner::AddTask(base::OnceClosure task_closure,
std::vector<SyncToken> wait_fences,
const SyncToken& release,
ReportingCallback report_callback) {
base::AutoLock auto_lock(lock());
return sequence_->AddTask(std::move(task_closure), std::move(wait_fences),
release, std::move(report_callback));
}
ScopedSyncPointClientState BlockingSequenceRunner::CreateSyncPointClientState(
CommandBufferNamespace namespace_id,
CommandBufferId command_buffer_id) {
base::AutoLock auto_lock(lock());
return sequence_->CreateSyncPointClientState(namespace_id, command_buffer_id);
}
void BlockingSequenceRunner::RunAllTasks() {
base::AutoLock auto_lock(lock());
sequence_->RunAllTasks();
}
BlockingSequenceRunner::Sequence::Sequence(Scheduler* scheduler)
: TaskGraph::Sequence(scheduler->task_graph(),
/*validation_runner=*/{}),
scheduler_(scheduler) {}
void BlockingSequenceRunner::Sequence::RunAllTasks() {
while (!tasks_.empty()) {
// Synchronously wait for the fences of the front task.
while (!IsFrontTaskUnblocked()) {
gpu::SyncToken sync_token = wait_fences_.begin()->sync_token;
uint32_t order_num = wait_fences_.begin()->order_num;
gpu::SequenceId release_sequence_id =
wait_fences_.begin()->release_sequence_id;
// Must unlock the task graph lock, otherwise it will deadlock when
// calling into scheduler to update sequence priority, or when blocking on
// `completion` waiting for other tasks to release fences.
//
// Manually release and re-acquire the lock, because locking annotation
// used on ValidateSequenceTaskFenceDeps() doesn't recognize
// base::AutoUnlock.
lock().Release();
base::WaitableEvent completion;
if (task_graph_->sync_point_manager()->Wait(
sync_token, sequence_id_, order_num,
base::BindOnce(&base::WaitableEvent::Signal,
base::Unretained(&completion)))) {
TRACE_EVENT1(
"gpu",
"BlockingSequenceRunner::Sequence::RunAllTasks::WaitSyncToken",
"sequence_id", release_sequence_id.value());
gpu::Scheduler::ScopedSetSequencePriority waiting(
scheduler_, release_sequence_id, gpu::SchedulingPriority::kHigh);
if (task_graph_->graph_validation_enabled()) {
while (!completion.TimedWait(gpu::TaskGraph::kMinValidationDelay)) {
task_graph_->ValidateSequenceTaskFenceDeps(this);
}
} else {
completion.Wait();
}
}
lock().Acquire();
}
// Run the front task.
base::OnceClosure task_closure;
uint32_t order_num = BeginTask(&task_closure);
gpu::SyncToken release = current_task_release_;
{
base::AutoUnlock auto_unlock(lock());
order_data()->BeginProcessingOrderNumber(order_num);
std::move(task_closure).Run();
if (order_data()->IsProcessingOrderNumber()) {
if (release.HasData()) {
task_graph_->sync_point_manager()->EnsureFenceSyncReleased(
release, gpu::ReleaseCause::kTaskCompletionRelease);
}
order_data()->FinishProcessingOrderNumber(order_num);
}
}
FinishTask();
}
}
} // namespace gpu