Commit 1d91e2b4 authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

aw: Implement task queue for viz

Make TaskQueueWebView an abstract interface. The old implementation
becomes TaskQueueSingleThread, with some cleanups. Add new TaskQueueViz
which implements code required for viz thread scheduling tasks to render
thread without ability to block on it at any time.

Add a kVizForWebView to switch between the two implementations, and use
to distinguish the code paths in the future.

Nothing uses TaskQueueViz in this CL yet, but the viz prototype has been
rebased onto this and works.

Bug: 805739
Change-Id: I0fe6c935fa7b1536700bd84950397ac756c4209e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1729473
Commit-Queue: Bo <boliu@chromium.org>
Reviewed-by: default avatarEric Karl <ericrk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683530}
parent dac741fb
......@@ -42,6 +42,10 @@ namespace features {
// Alphabetical:
// Viz for WebView architecture.
const base::Feature kVizForWebView{"VizForWebView",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enable brotli compression support in WebView.
const base::Feature kWebViewBrotliSupport{"WebViewBrotliSupport",
base::FEATURE_DISABLED_BY_DEFAULT};
......
......@@ -14,6 +14,7 @@ namespace features {
// alongside the definition of their values in the .cc file.
// Alphabetical:
extern const base::Feature kVizForWebView;
extern const base::Feature kWebViewBrotliSupport;
extern const base::Feature kWebViewConnectionlessSafeBrowsing;
extern const base::Feature kWebViewSniffMimeType;
......
......@@ -3,6 +3,7 @@ include_rules = [
"-android_webview/browser",
"+android_webview/browser/gfx",
"+android_webview/native_jni",
"+android_webview/browser/aw_feature_list.h",
"+android_webview/common/aw_switches.h",
"+android_webview/public/browser",
]
......
......@@ -50,7 +50,12 @@ void TaskForwardingSequence::ScheduleTask(
void TaskForwardingSequence::ScheduleOrRetainTask(
base::OnceClosure task,
std::vector<gpu::SyncToken> sync_token_fences) {
ScheduleTask(std::move(task), std::move(sync_token_fences));
uint32_t order_num = sync_point_order_data_->GenerateUnprocessedOrderNumber();
// Use a weak ptr because the task executor holds the tasks, and the
// sequence will be destroyed before the task executor.
task_queue_->ScheduleOrRetainTask(base::BindOnce(
&TaskForwardingSequence::RunTask, weak_ptr_factory_.GetWeakPtr(),
std::move(task), std::move(sync_token_fences), order_num));
}
// Should not be called because tasks aren't reposted to wait for sync tokens,
......
......@@ -4,58 +4,73 @@
#include "android_webview/browser/gfx/task_queue_web_view.h"
#include <memory>
#include <utility>
#include "android_webview/browser/aw_feature_list.h"
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/containers/queue.h"
#include "base/no_destructor.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"
namespace android_webview {
base::LazyInstance<base::ThreadLocalBoolean>::DestructorAtExit
ScopedAllowGL::allow_gl;
// static
bool ScopedAllowGL::IsAllowed() {
return allow_gl.Get().Get();
namespace {
base::ThreadLocalBoolean* GetAllowGL() {
static base::NoDestructor<base::ThreadLocalBoolean> allow_gl;
return allow_gl.get();
}
ScopedAllowGL::ScopedAllowGL() {
DCHECK(!allow_gl.Get().Get());
allow_gl.Get().Set(true);
// This task queue is used when the client and gpu service runs on the same
// thread (render thread). It has some simple logic to avoid reentrancy; in most
// cases calling schedule will actually run the task immediately.
class TaskQueueSingleThread : public TaskQueueWebView {
public:
TaskQueueSingleThread();
~TaskQueueSingleThread() override = default;
TaskQueueWebView* service = TaskQueueWebView::GetInstance();
DCHECK(service);
}
// TaskQueueWebView overrides.
void ScheduleTask(base::OnceClosure task, bool out_of_order) override;
void ScheduleOrRetainTask(base::OnceClosure task) override;
void ScheduleIdleTask(base::OnceClosure task) override;
void ScheduleClientTask(base::OnceClosure task) override;
void RunAllTasks() override;
void InitializeVizThread(const scoped_refptr<base::SingleThreadTaskRunner>&
viz_task_runner) override;
void ScheduleOnVizAndBlock(VizTask viz_task) override;
ScopedAllowGL::~ScopedAllowGL() {
TaskQueueWebView* service = TaskQueueWebView::GetInstance();
DCHECK(service);
service->RunAllTasks();
allow_gl.Get().Set(false);
}
private:
// Flush the idle queue until it is empty.
void PerformAllIdleWork();
void RunTasks();
// static
TaskQueueWebView* TaskQueueWebView::GetInstance() {
static TaskQueueWebView* task_queue =
TaskQueueWebView::CreateTaskQueueWebView();
return task_queue;
}
// All access to task queue should happen on a single thread.
THREAD_CHECKER(task_queue_thread_checker_);
base::circular_deque<base::OnceClosure> tasks_;
base::queue<base::OnceClosure> idle_tasks_;
base::queue<base::OnceClosure> client_tasks_;
// static
TaskQueueWebView* TaskQueueWebView::CreateTaskQueueWebView() {
return new TaskQueueWebView();
}
bool inside_run_tasks_ = false;
bool inside_run_idle_tasks_ = false;
TaskQueueWebView::TaskQueueWebView() {
DETACH_FROM_THREAD(task_queue_thread_checker_);
}
DISALLOW_COPY_AND_ASSIGN(TaskQueueSingleThread);
};
TaskQueueWebView::~TaskQueueWebView() {
DCHECK(tasks_.empty());
TaskQueueSingleThread::TaskQueueSingleThread() {
DETACH_FROM_THREAD(task_queue_thread_checker_);
}
void TaskQueueWebView::ScheduleTask(base::OnceClosure task, bool out_of_order) {
void TaskQueueSingleThread::ScheduleTask(base::OnceClosure task,
bool out_of_order) {
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
LOG_IF(FATAL, !ScopedAllowGL::IsAllowed())
LOG_IF(FATAL, !GetAllowGL()->Get())
<< "ScheduleTask outside of ScopedAllowGL";
if (out_of_order)
tasks_.emplace_front(std::move(task));
......@@ -64,20 +79,24 @@ void TaskQueueWebView::ScheduleTask(base::OnceClosure task, bool out_of_order) {
RunTasks();
}
void TaskQueueWebView::ScheduleIdleTask(base::OnceClosure task) {
LOG_IF(FATAL, !ScopedAllowGL::IsAllowed())
void TaskQueueSingleThread::ScheduleOrRetainTask(base::OnceClosure task) {
ScheduleTask(std::move(task), false);
}
void TaskQueueSingleThread::ScheduleIdleTask(base::OnceClosure task) {
LOG_IF(FATAL, !GetAllowGL()->Get())
<< "ScheduleDelayedWork outside of ScopedAllowGL";
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
idle_tasks_.push(std::make_pair(base::Time::Now(), std::move(task)));
idle_tasks_.push(std::move(task));
}
void TaskQueueWebView::ScheduleClientTask(base::OnceClosure task) {
void TaskQueueSingleThread::ScheduleClientTask(base::OnceClosure task) {
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
client_tasks_.emplace(std::move(task));
}
void TaskQueueWebView::RunTasks() {
TRACE_EVENT0("android_webview", "TaskQueueWebView::RunTasks");
void TaskQueueSingleThread::RunTasks() {
TRACE_EVENT0("android_webview", "TaskQueueSingleThread::RunTasks");
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
if (inside_run_tasks_)
return;
......@@ -88,7 +107,7 @@ void TaskQueueWebView::RunTasks() {
}
}
void TaskQueueWebView::RunAllTasks() {
void TaskQueueSingleThread::RunAllTasks() {
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
RunTasks();
PerformAllIdleWork();
......@@ -112,17 +131,208 @@ void TaskQueueWebView::RunAllTasks() {
}
}
void TaskQueueWebView::PerformAllIdleWork() {
TRACE_EVENT0("android_webview", "TaskQueuewebview::PerformAllIdleWork");
void TaskQueueSingleThread::PerformAllIdleWork() {
TRACE_EVENT0("android_webview", "TaskQueueWebview::PerformAllIdleWork");
DCHECK_CALLED_ON_VALID_THREAD(task_queue_thread_checker_);
if (inside_run_idle_tasks_)
return;
base::AutoReset<bool> inside(&inside_run_idle_tasks_, true);
while (idle_tasks_.size() > 0) {
base::OnceClosure task = std::move(idle_tasks_.front().second);
base::OnceClosure task = std::move(idle_tasks_.front());
idle_tasks_.pop();
std::move(task).Run();
}
}
void TaskQueueSingleThread::InitializeVizThread(
const scoped_refptr<base::SingleThreadTaskRunner>& viz_task_runner) {
NOTREACHED();
}
void TaskQueueSingleThread::ScheduleOnVizAndBlock(VizTask viz_task) {
NOTREACHED();
}
// This class is used with kVizForWebView. 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.
//
// This class does not implement methods only needed by command buffer.
// It does not reply on ScopedAllowGL either.
class TaskQueueViz : public TaskQueueWebView {
public:
TaskQueueViz();
~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;
void ScheduleClientTask(base::OnceClosure task) override;
void RunAllTasks() 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_;
// Only accessed on viz thread.
bool allow_schedule_task_ = false;
base::Lock lock_;
base::ConditionVariable condvar_{&lock_};
bool done_ GUARDED_BY(lock_) = true;
base::circular_deque<base::OnceClosure> tasks_ GUARDED_BY(lock_);
DISALLOW_COPY_AND_ASSIGN(TaskQueueViz);
};
TaskQueueViz::TaskQueueViz() = default;
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) {
NOTREACHED();
}
void TaskQueueViz::ScheduleClientTask(base::OnceClosure task) {
DCHECK(viz_task_runner_);
viz_task_runner_->PostTask(FROM_HERE, std::move(task));
}
void TaskQueueViz::RunAllTasks() {
// Intentional no-op.
}
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");
// 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)));
{
base::AutoLock lock(lock_);
while (!done_ || !tasks_.empty()) {
if (tasks_.empty())
condvar_.Wait();
base::circular_deque<base::OnceClosure> tasks;
tasks.swap(tasks_);
{
base::AutoUnlock unlock(lock_);
if (!tasks.empty()) {
TRACE_EVENT0("android_webview", "RunTasks");
while (tasks.size()) {
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
ScopedAllowGL::ScopedAllowGL() {
DCHECK(!GetAllowGL()->Get());
GetAllowGL()->Set(true);
}
ScopedAllowGL::~ScopedAllowGL() {
TaskQueueWebView* service = TaskQueueWebView::GetInstance();
DCHECK(service);
service->RunAllTasks();
GetAllowGL()->Set(false);
}
// static
TaskQueueWebView* TaskQueueWebView::GetInstance() {
static TaskQueueWebView* task_queue =
base::FeatureList::IsEnabled(features::kVizForWebView)
? static_cast<TaskQueueWebView*>(new TaskQueueViz)
: static_cast<TaskQueueWebView*>(new TaskQueueSingleThread);
return task_queue;
}
} // namespace android_webview
......@@ -5,17 +5,10 @@
#ifndef ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEB_VIEW_H_
#define ANDROID_WEBVIEW_BROWSER_GFX_TASK_QUEUE_WEB_VIEW_H_
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/containers/queue.h"
#include "base/lazy_instance.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_local.h"
#include "base/time/time.h"
#include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h"
namespace android_webview {
......@@ -25,12 +18,7 @@ class ScopedAllowGL {
ScopedAllowGL();
~ScopedAllowGL();
static bool IsAllowed();
private:
static base::LazyInstance<base::ThreadLocalBoolean>::DestructorAtExit
allow_gl;
DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
};
......@@ -41,40 +29,38 @@ class TaskQueueWebView {
public:
// Static method that makes sure this is only one copy of this class.
static TaskQueueWebView* GetInstance();
~TaskQueueWebView();
// Methods only used when kVizForWebView is enabled, ie client is the viz
// thread.
virtual void InitializeVizThread(
const scoped_refptr<base::SingleThreadTaskRunner>& viz_task_runner) = 0;
// The calling OnceClosure unblocks the render thread, and disallows further
// calls to ScheduleTask.
using VizTask = base::OnceCallback<void(base::OnceClosure)>;
virtual void ScheduleOnVizAndBlock(VizTask viz_task) = 0;
// Called by TaskForwardingSequence. |out_of_order| indicates if task should
// be run ahead of already enqueued tasks.
void ScheduleTask(base::OnceClosure task, bool out_of_order);
virtual void ScheduleTask(base::OnceClosure task, bool out_of_order) = 0;
// Called by TaskForwardingSequence.
virtual void ScheduleOrRetainTask(base::OnceClosure task) = 0;
// Called by DeferredGpuCommandService to schedule delayed tasks.
void ScheduleIdleTask(base::OnceClosure task);
// This should not be called when kVizForWebView is enabled.
virtual void ScheduleIdleTask(base::OnceClosure task) = 0;
// Called by both DeferredGpuCommandService and
// SkiaOutputSurfaceDisplayContext to post task to client thread.
void ScheduleClientTask(base::OnceClosure task);
// Called by ScopedAllowGL and ScheduleTask().
void RunAllTasks();
void RunTasks();
private:
static TaskQueueWebView* CreateTaskQueueWebView();
TaskQueueWebView();
// Flush the idle queue until it is empty.
void PerformAllIdleWork();
virtual void ScheduleClientTask(base::OnceClosure task) = 0;
// All access to task queue should happen on a single thread.
THREAD_CHECKER(task_queue_thread_checker_);
base::circular_deque<base::OnceClosure> tasks_;
base::queue<std::pair<base::Time, base::OnceClosure>> idle_tasks_;
base::queue<base::OnceClosure> client_tasks_;
protected:
friend ScopedAllowGL;
bool inside_run_tasks_ = false;
bool inside_run_idle_tasks_ = false;
virtual ~TaskQueueWebView() = default;
DISALLOW_COPY_AND_ASSIGN(TaskQueueWebView);
// Called by ScopedAllowGL.
virtual void RunAllTasks() = 0;
};
} // namespace android_webview
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment