task_queue_webview.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "android_webview/browser/gfx/task_queue_webview.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "android_webview/common/aw_features.h"
  8. #include "base/auto_reset.h"
  9. #include "base/bind.h"
  10. #include "base/containers/queue.h"
  11. #include "base/logging.h"
  12. #include "base/synchronization/condition_variable.h"
  13. #include "base/synchronization/lock.h"
  14. #include "base/thread_annotations.h"
  15. #include "base/threading/thread_checker.h"
  16. #include "base/threading/thread_local.h"
  17. #include "base/trace_event/trace_event.h"
  18. #include "components/viz/common/features.h"
  19. namespace android_webview {
  20. namespace {
  21. // The client is the single viz thread and the gpu service runs on the render
  22. // thread. Render thread is allowed to block on the viz thread, but not the
  23. // other way around. This achieves viz scheduling tasks to gpu by first blocking
  24. // render thread on the viz thread so render thread is ready to receive and run
  25. // tasks.
  26. class TaskQueueViz : public TaskQueueWebView {
  27. public:
  28. TaskQueueViz();
  29. TaskQueueViz(const TaskQueueViz&) = delete;
  30. TaskQueueViz& operator=(const TaskQueueViz&) = delete;
  31. ~TaskQueueViz() override;
  32. // TaskQueueWebView overrides.
  33. void ScheduleTask(base::OnceClosure task, bool out_of_order) override;
  34. void ScheduleOrRetainTask(base::OnceClosure task) override;
  35. void ScheduleIdleTask(base::OnceClosure task) override;
  36. scoped_refptr<base::TaskRunner> GetClientTaskRunner() override;
  37. void InitializeVizThread(const scoped_refptr<base::SingleThreadTaskRunner>&
  38. viz_task_runner) override;
  39. void ScheduleOnVizAndBlock(VizTask viz_task) override;
  40. private:
  41. void RunOnViz(VizTask viz_task);
  42. void SignalDone();
  43. void EmplaceTask(base::OnceClosure task);
  44. scoped_refptr<base::SingleThreadTaskRunner> viz_task_runner_;
  45. THREAD_CHECKER(render_thread_checker_);
  46. // Only accessed on viz thread.
  47. bool allow_schedule_task_ = false;
  48. // Only accessed on render thread.
  49. bool inside_schedule_on_viz_and_block_ = false;
  50. base::Lock lock_;
  51. base::ConditionVariable condvar_{&lock_};
  52. bool done_ GUARDED_BY(lock_) = true;
  53. base::circular_deque<base::OnceClosure> tasks_ GUARDED_BY(lock_);
  54. };
  55. TaskQueueViz::TaskQueueViz() {
  56. DETACH_FROM_THREAD(render_thread_checker_);
  57. }
  58. TaskQueueViz::~TaskQueueViz() = default;
  59. void TaskQueueViz::ScheduleTask(base::OnceClosure task, bool out_of_order) {
  60. TRACE_EVENT0("android_webview", "ScheduleTask");
  61. DCHECK(viz_task_runner_->BelongsToCurrentThread());
  62. DCHECK(allow_schedule_task_);
  63. // |out_of_order| is not needed by TaskForwardingSequence. Not supporting
  64. // it allows slightly more efficient swapping the task queue in
  65. // ScheduleOnVizAndBlock .
  66. DCHECK(!out_of_order);
  67. EmplaceTask(std::move(task));
  68. }
  69. void TaskQueueViz::ScheduleOrRetainTask(base::OnceClosure task) {
  70. DCHECK(viz_task_runner_->BelongsToCurrentThread());
  71. // The two branches end up doing the exact same thing only because retain can
  72. // use the same task queue. The code says the intention which is
  73. // |ScheduleOrRetainTask| behaves the same as |ScheduleTask| if
  74. // |allow_schedule_task_| is true.
  75. // Sharing the queue makes it clear |ScheduleTask| and |ScheduleOrRetainTask|
  76. // but however has a non-practical risk of live-locking the render thread.
  77. if (allow_schedule_task_) {
  78. ScheduleTask(std::move(task), false);
  79. return;
  80. }
  81. EmplaceTask(std::move(task));
  82. }
  83. void TaskQueueViz::EmplaceTask(base::OnceClosure task) {
  84. base::AutoLock lock(lock_);
  85. tasks_.emplace_back(std::move(task));
  86. condvar_.Signal();
  87. }
  88. void TaskQueueViz::ScheduleIdleTask(base::OnceClosure task) {
  89. DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
  90. DCHECK(inside_schedule_on_viz_and_block_);
  91. EmplaceTask(std::move(task));
  92. }
  93. scoped_refptr<base::TaskRunner> TaskQueueViz::GetClientTaskRunner() {
  94. DCHECK(viz_task_runner_);
  95. return viz_task_runner_;
  96. }
  97. void TaskQueueViz::InitializeVizThread(
  98. const scoped_refptr<base::SingleThreadTaskRunner>& viz_task_runner) {
  99. DCHECK(!viz_task_runner_);
  100. viz_task_runner_ = viz_task_runner;
  101. }
  102. void TaskQueueViz::ScheduleOnVizAndBlock(VizTask viz_task) {
  103. TRACE_EVENT0("android_webview", "ScheduleOnVizAndBlock");
  104. DCHECK_CALLED_ON_VALID_THREAD(render_thread_checker_);
  105. // Expected behavior is |viz_task| on the viz thread. From |viz_task| until
  106. // the done closure is called (which may not be in the viz_task), viz thread
  107. // is allowed to call ScheduleTask.
  108. //
  109. // Implementation is uses a normal run-loop like logic. The done closure
  110. // marks |done_| true, and run loop exists when |done_| is true *and* the task
  111. // queue is empty. A condition variable is signaled when |done_| is set or
  112. // when something is appended to the task queue.
  113. {
  114. base::AutoLock lock(lock_);
  115. DCHECK(done_);
  116. done_ = false;
  117. }
  118. // Unretained safe because this object is never deleted.
  119. viz_task_runner_->PostTask(
  120. FROM_HERE, base::BindOnce(&TaskQueueViz::RunOnViz, base::Unretained(this),
  121. std::move(viz_task)));
  122. {
  123. DCHECK(!inside_schedule_on_viz_and_block_);
  124. base::AutoReset<bool> inside_bf(&inside_schedule_on_viz_and_block_, true);
  125. base::AutoLock lock(lock_);
  126. while (!done_ || !tasks_.empty()) {
  127. while (!done_ && tasks_.empty())
  128. condvar_.Wait();
  129. if (!tasks_.empty()) {
  130. base::circular_deque<base::OnceClosure> tasks;
  131. tasks.swap(tasks_);
  132. {
  133. base::AutoUnlock unlock(lock_);
  134. TRACE_EVENT0("android_webview", "RunTasks");
  135. while (!tasks.empty()) {
  136. std::move(tasks.front()).Run();
  137. tasks.pop_front();
  138. }
  139. }
  140. }
  141. }
  142. DCHECK(done_);
  143. }
  144. }
  145. void TaskQueueViz::RunOnViz(VizTask viz_task) {
  146. DCHECK(viz_task_runner_->BelongsToCurrentThread());
  147. DCHECK(!allow_schedule_task_);
  148. allow_schedule_task_ = true;
  149. // Unretained safe because this object is never deleted.
  150. std::move(viz_task).Run(
  151. base::BindOnce(&TaskQueueViz::SignalDone, base::Unretained(this)));
  152. }
  153. void TaskQueueViz::SignalDone() {
  154. DCHECK(viz_task_runner_->BelongsToCurrentThread());
  155. DCHECK(allow_schedule_task_);
  156. allow_schedule_task_ = false;
  157. base::AutoLock lock(lock_);
  158. DCHECK(!done_);
  159. done_ = true;
  160. condvar_.Signal();
  161. }
  162. } // namespace
  163. // static
  164. TaskQueueWebView* TaskQueueWebView::GetInstance() {
  165. static TaskQueueWebView* task_queue =
  166. static_cast<TaskQueueWebView*>(new TaskQueueViz);
  167. return task_queue;
  168. }
  169. } // namespace android_webview