123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- // Copyright 2019 The Chromium 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 "android_webview/browser/gfx/task_queue_webview.h"
- #include <memory>
- #include <utility>
- #include "android_webview/common/aw_features.h"
- #include "base/auto_reset.h"
- #include "base/bind.h"
- #include "base/containers/queue.h"
- #include "base/logging.h"
- #include "base/synchronization/condition_variable.h"
- #include "base/synchronization/lock.h"
- #include "base/thread_annotations.h"
- #include "base/threading/thread_checker.h"
- #include "base/threading/thread_local.h"
- #include "base/trace_event/trace_event.h"
- #include "components/viz/common/features.h"
- namespace android_webview {
- namespace {
- // The client is the single viz thread and the gpu service runs on the render
- // thread. Render thread is allowed to block on the viz thread, but not the
- // other way around. This achieves viz scheduling tasks to gpu by first blocking
- // render thread on the viz thread so render thread is ready to receive and run
- // tasks.
- class TaskQueueViz : public TaskQueueWebView {
- public:
- TaskQueueViz();
- TaskQueueViz(const TaskQueueViz&) = delete;
- TaskQueueViz& operator=(const TaskQueueViz&) = delete;
- ~TaskQueueViz() override;
- // TaskQueueWebView overrides.
- void ScheduleTask(base::OnceClosure task, bool out_of_order) override;
- void ScheduleOrRetainTask(base::OnceClosure task) override;
- void ScheduleIdleTask(base::OnceClosure task) override;
- scoped_refptr<base::TaskRunner> GetClientTaskRunner() override;
- void InitializeVizThread(const scoped_refptr<base::SingleThreadTaskRunner>&
- viz_task_runner) override;
- void ScheduleOnVizAndBlock(VizTask viz_task) override;
- private:
- void RunOnViz(VizTask viz_task);
- void SignalDone();
- void EmplaceTask(base::OnceClosure task);
- scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
- THREAD_CHECKER(render_thread_checker_);
- // Only accessed on viz thread.
- bool allow_schedule_task_ = false;
- // Only accessed on render thread.
- bool inside_schedule_on_viz_and_block_ = false;
- base::Lock lock_;
- base::ConditionVariable condvar_{&lock_};
- bool done_ GUARDED_BY(lock_) = true;
- base::circular_deque<base::OnceClosure> tasks_ GUARDED_BY(lock_);
- };
- TaskQueueViz::TaskQueueViz() {
- DETACH_FROM_THREAD(render_thread_checker_);
- }
- TaskQueueViz::~TaskQueueViz() = default;
- void TaskQueueViz::ScheduleTask(base::OnceClosure task, bool out_of_order) {
- TRACE_EVENT0("android_webview", "ScheduleTask");
- DCHECK(viz_task_runner_->BelongsToCurrentThread());
- DCHECK(allow_schedule_task_);
- // |out_of_order| is not needed by TaskForwardingSequence. Not supporting
- // it allows slightly more efficient swapping the task queue in
- // ScheduleOnVizAndBlock .
- DCHECK(!out_of_order);
- EmplaceTask(std::move(task));
- }
- void TaskQueueViz::ScheduleOrRetainTask(base::OnceClosure task) {
- DCHECK(viz_task_runner_->BelongsToCurrentThread());
- // The two branches end up doing the exact same thing only because retain can
- // use the same task queue. The code says the intention which is
- // |ScheduleOrRetainTask| behaves the same as |ScheduleTask| if
- // |allow_schedule_task_| is true.
- // Sharing the queue makes it clear |ScheduleTask| and |ScheduleOrRetainTask|
- // but however has a non-practical risk of live-locking the render thread.
- if (allow_schedule_task_) {
- ScheduleTask(std::move(task), false);
- return;
- }
- EmplaceTask(std::move(task));
- }
- void TaskQueueViz::EmplaceTask(base::OnceClosure task) {
- base::AutoLock lock(lock_);
- tasks_.emplace_back(std::move(task));
- condvar_.Signal();
- }
- void TaskQueueViz::ScheduleIdleTask(base::OnceClosure task) {
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- DCHECK(inside_schedule_on_viz_and_block_);
- EmplaceTask(std::move(task));
- }
- scoped_refptr<base::TaskRunner> TaskQueueViz::GetClientTaskRunner() {
- DCHECK(viz_task_runner_);
- return viz_task_runner_;
- }
- void TaskQueueViz::InitializeVizThread(
- const scoped_refptr<base::SingleThreadTaskRunner>& viz_task_runner) {
- DCHECK(!viz_task_runner_);
- viz_task_runner_ = viz_task_runner;
- }
- void TaskQueueViz::ScheduleOnVizAndBlock(VizTask viz_task) {
- TRACE_EVENT0("android_webview", "ScheduleOnVizAndBlock");
- DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
- // Expected behavior is |viz_task| on the viz thread. From |viz_task| until
- // the done closure is called (which may not be in the viz_task), viz thread
- // is allowed to call ScheduleTask.
- //
- // Implementation is uses a normal run-loop like logic. The done closure
- // marks |done_| true, and run loop exists when |done_| is true *and* the task
- // queue is empty. A condition variable is signaled when |done_| is set or
- // when something is appended to the task queue.
- {
- base::AutoLock lock(lock_);
- DCHECK(done_);
- done_ = false;
- }
- // Unretained safe because this object is never deleted.
- viz_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&TaskQueueViz::RunOnViz, base::Unretained(this),
- std::move(viz_task)));
- {
- DCHECK(!inside_schedule_on_viz_and_block_);
- base::AutoReset<bool> inside_bf(&inside_schedule_on_viz_and_block_, true);
- base::AutoLock lock(lock_);
- while (!done_ || !tasks_.empty()) {
- while (!done_ && tasks_.empty())
- condvar_.Wait();
- if (!tasks_.empty()) {
- base::circular_deque<base::OnceClosure> tasks;
- tasks.swap(tasks_);
- {
- base::AutoUnlock unlock(lock_);
- TRACE_EVENT0("android_webview", "RunTasks");
- while (!tasks.empty()) {
- std::move(tasks.front()).Run();
- tasks.pop_front();
- }
- }
- }
- }
- DCHECK(done_);
- }
- }
- void TaskQueueViz::RunOnViz(VizTask viz_task) {
- DCHECK(viz_task_runner_->BelongsToCurrentThread());
- DCHECK(!allow_schedule_task_);
- allow_schedule_task_ = true;
- // Unretained safe because this object is never deleted.
- std::move(viz_task).Run(
- base::BindOnce(&TaskQueueViz::SignalDone, base::Unretained(this)));
- }
- void TaskQueueViz::SignalDone() {
- DCHECK(viz_task_runner_->BelongsToCurrentThread());
- DCHECK(allow_schedule_task_);
- allow_schedule_task_ = false;
- base::AutoLock lock(lock_);
- DCHECK(!done_);
- done_ = true;
- condvar_.Signal();
- }
- } // namespace
- // static
- TaskQueueWebView* TaskQueueWebView::GetInstance() {
- static TaskQueueWebView* task_queue =
- static_cast<TaskQueueWebView*>(new TaskQueueViz);
- return task_queue;
- }
- } // namespace android_webview
|