910e62b5创建于 1月15日历史提交
// 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