Commit 362c9d06 authored by reveman@chromium.org's avatar reveman@chromium.org

Re-land: cc: Cancel and re-prioritize worker pool tasks.

This adds a task graph interface to the worker pool and
implements a simple queue instance of this interface for
use by the tile manager.

The task graph interface can be used describe more
complicated task dependencies in the future and
provides the immediate benefit of seamlessly being
able to cancel and re-prioritize tasks.

BUG=178974,244642
TEST=cc_unittests --gtest_filter=WorkerPoolTest.Dependencies

Review URL: https://chromiumcodereview.appspot.com/14689004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203041 0039d316-1c4b-4281-b951-d872f2087c98
parent 3d82df66
......@@ -31,7 +31,7 @@ class ScopedPtrHashMap {
~ScopedPtrHashMap() { clear(); }
void swap(ScopedPtrHashMap<Key, Value*>& other) {
void swap(ScopedPtrHashMap<Key, Value>& other) {
data_.swap(other.data_);
}
......
This diff is collapsed.
......@@ -5,31 +5,52 @@
#ifndef CC_BASE_WORKER_POOL_H_
#define CC_BASE_WORKER_POOL_H_
#include <deque>
#include <string>
#include <vector>
#include "base/cancelable_callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_deque.h"
namespace cc {
namespace internal {
class WorkerPoolTask {
class CC_EXPORT WorkerPoolTask
: public base::RefCountedThreadSafe<WorkerPoolTask> {
public:
virtual ~WorkerPoolTask();
typedef std::vector<scoped_refptr<WorkerPoolTask> > TaskVector;
virtual void RunOnThread(unsigned thread_index) = 0;
virtual void DispatchCompletionCallback() = 0;
void DidSchedule();
void WillRun();
void DidRun();
void DidComplete();
bool IsReadyToRun() const;
bool HasFinishedRunning() const;
bool HasCompleted() const;
TaskVector& dependencies() { return dependencies_; }
protected:
explicit WorkerPoolTask(const base::Closure& reply);
friend class base::RefCountedThreadSafe<WorkerPoolTask>;
WorkerPoolTask();
explicit WorkerPoolTask(TaskVector* dependencies);
virtual ~WorkerPoolTask();
const base::Closure reply_;
private:
bool did_schedule_;
bool did_run_;
bool did_complete_;
TaskVector dependencies_;
};
} // namespace internal
......@@ -42,67 +63,50 @@ class CC_EXPORT WorkerPoolClient {
virtual ~WorkerPoolClient() {}
};
// A worker thread pool that runs rendering tasks and guarantees completion
// of all pending tasks at shutdown.
// A worker thread pool that runs tasks provided by task graph and
// guarantees completion of all pending tasks at shutdown.
class CC_EXPORT WorkerPool {
public:
typedef base::Callback<void()> Callback;
virtual ~WorkerPool();
static scoped_ptr<WorkerPool> Create(
size_t num_threads,
base::TimeDelta check_for_completed_tasks_delay,
const std::string& thread_name_prefix) {
return make_scoped_ptr(new WorkerPool(num_threads,
check_for_completed_tasks_delay,
thread_name_prefix));
}
// Tells the worker pool to shutdown and returns once all pending tasks have
// completed.
void Shutdown();
// Posts |task| to worker pool. On completion, |reply|
// is posted to the thread that called PostTaskAndReply().
void PostTaskAndReply(const Callback& task, const base::Closure& reply);
virtual void Shutdown();
// Set a new client.
void SetClient(WorkerPoolClient* client) {
client_ = client;
}
// Force a check for completed tasks.
void CheckForCompletedTasks();
protected:
WorkerPool(size_t num_threads,
base::TimeDelta check_for_completed_tasks_delay,
const std::string& thread_name_prefix);
void PostTask(scoped_ptr<internal::WorkerPoolTask> task);
void ScheduleTasks(internal::WorkerPoolTask* root);
private:
class Inner;
friend class Inner;
void OnTaskCompleted();
void OnIdle();
typedef std::deque<scoped_refptr<internal::WorkerPoolTask> > TaskDeque;
void OnIdle(TaskDeque* completed_tasks);
void ScheduleCheckForCompletedTasks();
void CheckForCompletedTasks();
void DispatchCompletionCallbacks();
void DispatchCompletionCallbacks(TaskDeque* completed_tasks);
WorkerPoolClient* client_;
scoped_refptr<base::MessageLoopProxy> origin_loop_;
base::WeakPtrFactory<WorkerPool> weak_ptr_factory_;
base::CancelableClosure check_for_completed_tasks_callback_;
base::TimeDelta check_for_completed_tasks_delay_;
bool check_for_completed_tasks_pending_;
// Holds all completed tasks for which we have not yet dispatched
// reply callbacks.
ScopedPtrDeque<internal::WorkerPoolTask> completed_tasks_;
bool in_dispatch_completion_callbacks_;
// Hide the gory details of the worker pool in |inner_|.
const scoped_ptr<Inner> inner_;
DISALLOW_COPY_AND_ASSIGN(WorkerPool);
};
} // namespace cc
......
// Copyright 2013 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 "cc/base/worker_pool.h"
#include "base/time.h"
#include "cc/base/completion_event.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
class PerfTaskImpl : public internal::WorkerPoolTask {
public:
explicit PerfTaskImpl(internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies) {}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
virtual void DispatchCompletionCallback() OVERRIDE {}
private:
virtual ~PerfTaskImpl() {}
};
class PerfControlTaskImpl : public internal::WorkerPoolTask {
public:
explicit PerfControlTaskImpl(
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
did_start_(new CompletionEvent),
can_finish_(new CompletionEvent) {}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
did_start_->Signal();
can_finish_->Wait();
}
virtual void DispatchCompletionCallback() OVERRIDE {}
void WaitForTaskToStartRunning() {
did_start_->Wait();
}
void AllowTaskToFinish() {
can_finish_->Signal();
}
private:
virtual ~PerfControlTaskImpl() {}
scoped_ptr<CompletionEvent> did_start_;
scoped_ptr<CompletionEvent> can_finish_;
};
class PerfWorkerPool : public WorkerPool {
public:
PerfWorkerPool() : WorkerPool(1, base::TimeDelta::FromDays(1024), "test") {}
virtual ~PerfWorkerPool() {}
static scoped_ptr<PerfWorkerPool> Create() {
return make_scoped_ptr(new PerfWorkerPool);
}
void ScheduleTasks(internal::WorkerPoolTask* root) {
WorkerPool::ScheduleTasks(root);
}
};
class WorkerPoolPerfTest : public testing::Test,
public WorkerPoolClient {
public:
WorkerPoolPerfTest() : num_runs_(0) {}
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
worker_pool_ = PerfWorkerPool::Create();
worker_pool_->SetClient(this);
}
virtual void TearDown() OVERRIDE {
worker_pool_->Shutdown();
}
// Overridden from WorkerPoolClient:
virtual void DidFinishDispatchingWorkerPoolCompletionCallbacks() OVERRIDE {}
void EndTest() {
elapsed_ = base::TimeTicks::HighResNow() - start_time_;
}
void AfterTest(const std::string test_name) {
// Format matches chrome/test/perf/perf_test.h:PrintResult
printf("*RESULT %s: %.2f runs/s\n",
test_name.c_str(),
num_runs_ / elapsed_.InSecondsF());
}
void BuildTaskGraph(internal::WorkerPoolTask::TaskVector* dependencies,
unsigned current_depth,
unsigned max_depth,
unsigned num_children_per_node) {
internal::WorkerPoolTask::TaskVector children;
if (current_depth < max_depth) {
for (unsigned i = 0; i < num_children_per_node; ++i) {
BuildTaskGraph(&children,
current_depth + 1,
max_depth,
num_children_per_node);
}
} else if (leaf_task_) {
children.push_back(leaf_task_);
}
dependencies->push_back(make_scoped_refptr(new PerfTaskImpl(&children)));
}
bool DidRun() {
++num_runs_;
if (num_runs_ == kWarmupRuns)
start_time_ = base::TimeTicks::HighResNow();
if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
elapsed_ = elapsed;
return false;
}
}
return true;
}
void RunBuildTaskGraphTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
} while (DidRun());
AfterTest(test_name);
}
void RunScheduleTasksTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector empty;
leaf_task_ = make_scoped_refptr(new PerfControlTaskImpl(&empty));
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
scoped_refptr<PerfTaskImpl> root_task(
make_scoped_refptr(new PerfTaskImpl(&children)));
worker_pool_->ScheduleTasks(root_task);
leaf_task_->WaitForTaskToStartRunning();
worker_pool_->ScheduleTasks(NULL);
worker_pool_->CheckForCompletedTasks();
leaf_task_->AllowTaskToFinish();
} while (DidRun());
AfterTest(test_name);
}
void RunExecuteTasksTest(const std::string test_name,
unsigned max_depth,
unsigned num_children_per_node) {
start_time_ = base::TimeTicks();
num_runs_ = 0;
do {
internal::WorkerPoolTask::TaskVector children;
BuildTaskGraph(&children, 0, max_depth, num_children_per_node);
scoped_refptr<PerfControlTaskImpl> root_task(
make_scoped_refptr(new PerfControlTaskImpl(&children)));
worker_pool_->ScheduleTasks(root_task);
root_task->WaitForTaskToStartRunning();
root_task->AllowTaskToFinish();
worker_pool_->CheckForCompletedTasks();
} while (DidRun());
AfterTest(test_name);
}
protected:
scoped_ptr<PerfWorkerPool> worker_pool_;
scoped_refptr<PerfControlTaskImpl> leaf_task_;
base::TimeTicks start_time_;
base::TimeDelta elapsed_;
int num_runs_;
};
TEST_F(WorkerPoolPerfTest, BuildTaskGraph) {
RunBuildTaskGraphTest("build_task_graph_1_10", 1, 10);
RunBuildTaskGraphTest("build_task_graph_1_1000", 1, 1000);
RunBuildTaskGraphTest("build_task_graph_2_10", 2, 10);
RunBuildTaskGraphTest("build_task_graph_5_5", 5, 5);
RunBuildTaskGraphTest("build_task_graph_10_2", 10, 2);
RunBuildTaskGraphTest("build_task_graph_1000_1", 1000, 1);
RunBuildTaskGraphTest("build_task_graph_10_1", 10, 1);
}
TEST_F(WorkerPoolPerfTest, ScheduleTasks) {
RunScheduleTasksTest("schedule_tasks_1_10", 1, 10);
RunScheduleTasksTest("schedule_tasks_1_1000", 1, 1000);
RunScheduleTasksTest("schedule_tasks_2_10", 2, 10);
RunScheduleTasksTest("schedule_tasks_5_5", 5, 5);
RunScheduleTasksTest("schedule_tasks_10_2", 10, 2);
RunScheduleTasksTest("schedule_tasks_1000_1", 1000, 1);
RunScheduleTasksTest("schedule_tasks_10_1", 10, 1);
}
TEST_F(WorkerPoolPerfTest, ExecuteTasks) {
RunExecuteTasksTest("execute_tasks_1_10", 1, 10);
RunExecuteTasksTest("execute_tasks_1_1000", 1, 1000);
RunExecuteTasksTest("execute_tasks_2_10", 2, 10);
RunExecuteTasksTest("execute_tasks_5_5", 5, 5);
RunExecuteTasksTest("execute_tasks_10_2", 10, 2);
RunExecuteTasksTest("execute_tasks_1000_1", 1000, 1);
RunExecuteTasksTest("execute_tasks_10_1", 10, 1);
}
} // namespace
} // namespace cc
......@@ -4,27 +4,101 @@
#include "cc/base/worker_pool.h"
#include <vector>
#include "cc/base/completion_event.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
class WorkerPoolTest : public testing::Test,
public WorkerPoolClient {
class FakeTaskImpl : public internal::WorkerPoolTask {
public:
WorkerPoolTest()
: run_task_count_(0),
on_task_completed_count_(0),
finish_dispatching_completion_callbacks_count_(0) {
FakeTaskImpl(const base::Closure& callback,
const base::Closure& reply,
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
callback_(callback),
reply_(reply) {
}
FakeTaskImpl(const base::Closure& callback, const base::Closure& reply)
: callback_(callback),
reply_(reply) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
if (!callback_.is_null())
callback_.Run();
}
virtual void DispatchCompletionCallback() OVERRIDE {
if (!reply_.is_null())
reply_.Run();
}
private:
virtual ~FakeTaskImpl() {}
const base::Closure callback_;
const base::Closure reply_;
};
class FakeWorkerPool : public WorkerPool {
public:
FakeWorkerPool() : WorkerPool(1, base::TimeDelta::FromDays(1024), "test") {}
virtual ~FakeWorkerPool() {}
static scoped_ptr<FakeWorkerPool> Create() {
return make_scoped_ptr(new FakeWorkerPool);
}
void ScheduleTasks(const base::Closure& callback,
const base::Closure& reply,
const base::Closure& dependency,
int count) {
scoped_refptr<FakeTaskImpl> dependency_task(
new FakeTaskImpl(dependency, base::Closure()));
internal::WorkerPoolTask::TaskVector tasks;
for (int i = 0; i < count; ++i) {
internal::WorkerPoolTask::TaskVector dependencies(1, dependency_task);
tasks.push_back(new FakeTaskImpl(callback, reply, &dependencies));
}
scoped_refptr<FakeTaskImpl> completion_task(
new FakeTaskImpl(base::Bind(&FakeWorkerPool::OnTasksCompleted,
base::Unretained(this)),
base::Closure(),
&tasks));
scheduled_tasks_completion_.reset(new CompletionEvent);
WorkerPool::ScheduleTasks(completion_task);
}
virtual ~WorkerPoolTest() {
void WaitForTasksToComplete() {
DCHECK(scheduled_tasks_completion_);
scheduled_tasks_completion_->Wait();
}
private:
void OnTasksCompleted() {
DCHECK(scheduled_tasks_completion_);
scheduled_tasks_completion_->Signal();
}
scoped_ptr<CompletionEvent> scheduled_tasks_completion_;
};
class WorkerPoolTest : public testing::Test,
public WorkerPoolClient {
public:
WorkerPoolTest() : finish_dispatching_completion_callbacks_count_(0) {}
virtual ~WorkerPoolTest() {}
// Overridden from testing::Test:
virtual void SetUp() OVERRIDE {
Reset();
}
virtual void TearDown() OVERRIDE {
worker_pool_->Shutdown();
}
......@@ -35,35 +109,34 @@ class WorkerPoolTest : public testing::Test,
}
void Reset() {
worker_pool_ = WorkerPool::Create(1,
base::TimeDelta::FromDays(1024),
"test");
worker_pool_ = FakeWorkerPool::Create();
worker_pool_->SetClient(this);
}
void RunAllTasksAndReset() {
worker_pool_->WaitForTasksToComplete();
worker_pool_->Shutdown();
Reset();
}
WorkerPool* worker_pool() {
FakeWorkerPool* worker_pool() {
return worker_pool_.get();
}
void RunTask() {
++run_task_count_;
void RunTask(unsigned id) {
run_task_ids_.push_back(id);
}
void OnTaskCompleted() {
++on_task_completed_count_;
void OnTaskCompleted(unsigned id) {
on_task_completed_ids_.push_back(id);
}
unsigned run_task_count() {
return run_task_count_;
const std::vector<unsigned>& run_task_ids() {
return run_task_ids_;
}
unsigned on_task_completed_count() {
return on_task_completed_count_;
const std::vector<unsigned>& on_task_completed_ids() {
return on_task_completed_ids_;
}
unsigned finish_dispatching_completion_callbacks_count() {
......@@ -71,39 +144,72 @@ class WorkerPoolTest : public testing::Test,
}
private:
scoped_ptr<WorkerPool> worker_pool_;
unsigned run_task_count_;
unsigned on_task_completed_count_;
scoped_ptr<FakeWorkerPool> worker_pool_;
std::vector<unsigned> run_task_ids_;
std::vector<unsigned> on_task_completed_ids_;
unsigned finish_dispatching_completion_callbacks_count_;
};
TEST_F(WorkerPoolTest, Basic) {
EXPECT_EQ(0u, run_task_count());
EXPECT_EQ(0u, on_task_completed_count());
EXPECT_EQ(0u, run_task_ids().size());
EXPECT_EQ(0u, on_task_completed_ids().size());
EXPECT_EQ(0u, finish_dispatching_completion_callbacks_count());
worker_pool()->PostTaskAndReply(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this)));
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
base::Closure(),
1);
RunAllTasksAndReset();
EXPECT_EQ(1u, run_task_count());
EXPECT_EQ(1u, on_task_completed_count());
EXPECT_EQ(1u, run_task_ids().size());
EXPECT_EQ(1u, on_task_completed_ids().size());
EXPECT_EQ(1u, finish_dispatching_completion_callbacks_count());
worker_pool()->PostTaskAndReply(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this)));
worker_pool()->PostTaskAndReply(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this)),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this)));
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 0u),
base::Closure(),
2);
RunAllTasksAndReset();
EXPECT_EQ(3u, run_task_count());
EXPECT_EQ(3u, on_task_completed_count());
EXPECT_EQ(3u, run_task_ids().size());
EXPECT_EQ(3u, on_task_completed_ids().size());
EXPECT_EQ(2u, finish_dispatching_completion_callbacks_count());
}
TEST_F(WorkerPoolTest, Dependencies) {
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
1);
RunAllTasksAndReset();
// Check if dependency ran before task.
ASSERT_EQ(2u, run_task_ids().size());
EXPECT_EQ(0u, run_task_ids()[0]);
EXPECT_EQ(1u, run_task_ids()[1]);
ASSERT_EQ(1u, on_task_completed_ids().size());
EXPECT_EQ(1u, on_task_completed_ids()[0]);
worker_pool()->ScheduleTasks(
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::OnTaskCompleted, base::Unretained(this), 1u),
base::Bind(&WorkerPoolTest::RunTask, base::Unretained(this), 0u),
2);
RunAllTasksAndReset();
// Dependency should only run once.
ASSERT_EQ(5u, run_task_ids().size());
EXPECT_EQ(0u, run_task_ids()[2]);
EXPECT_EQ(1u, run_task_ids()[3]);
EXPECT_EQ(1u, run_task_ids()[4]);
ASSERT_EQ(3u, on_task_completed_ids().size());
EXPECT_EQ(1u, on_task_completed_ids()[1]);
EXPECT_EQ(1u, on_task_completed_ids()[2]);
}
} // namespace
} // namespace cc
......@@ -225,9 +225,10 @@
'cc_test_support',
],
'sources': [
'trees/layer_tree_host_perftest.cc',
'test/run_all_unittests.cc',
'base/worker_pool_perftest.cc',
'test/cc_test_suite.cc',
'test/run_all_unittests.cc',
'trees/layer_tree_host_perftest.cc',
],
'include_dirs': [
'test',
......
......@@ -5,9 +5,9 @@
#ifndef CC_RESOURCES_MANAGED_TILE_STATE_H_
#define CC_RESOURCES_MANAGED_TILE_STATE_H_
#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "cc/resources/platform_color.h"
#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/tile_manager.h"
......@@ -113,11 +113,10 @@ class CC_EXPORT ManagedTileState {
scoped_ptr<base::Value> AsValue() const;
// Persisted state: valid all the time.
typedef base::hash_set<uint32_t> PixelRefSet;
PixelRefSet decoded_pixel_refs;
TileVersion tile_version;
PicturePileImpl::Analysis picture_pile_analysis;
bool picture_pile_analyzed;
PicturePileImpl::Analysis picture_pile_analysis;
RasterWorkerPool::Task raster_task;
// Ephemeral state, valid only during TileManager::ManageTiles.
bool is_in_never_bin_on_both_trees() const {
......
......@@ -10,24 +10,72 @@ namespace cc {
namespace {
class RasterWorkerPoolContainerTaskImpl : public internal::WorkerPoolTask {
public:
RasterWorkerPoolContainerTaskImpl(
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
virtual void DispatchCompletionCallback() OVERRIDE {}
private:
virtual ~RasterWorkerPoolContainerTaskImpl() {}
};
class RasterWorkerPoolTaskImpl : public internal::WorkerPoolTask {
public:
RasterWorkerPoolTaskImpl(PicturePileImpl* picture_pile,
const RasterWorkerPool::RasterCallback& task,
const base::Closure& reply)
: internal::WorkerPoolTask(reply),
RasterWorkerPoolTaskImpl(const base::Closure& callback,
const RasterWorkerPool::Task::Reply& reply)
: callback_(callback),
reply_(reply) {
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
callback_.Run();
}
virtual void DispatchCompletionCallback() OVERRIDE {
reply_.Run(!HasFinishedRunning());
}
private:
virtual ~RasterWorkerPoolTaskImpl() {}
const base::Closure callback_;
const RasterWorkerPool::Task::Reply reply_;
};
class RasterWorkerPoolPictureTaskImpl : public internal::WorkerPoolTask {
public:
RasterWorkerPoolPictureTaskImpl(
PicturePileImpl* picture_pile,
const RasterWorkerPool::PictureTask::Callback& callback,
const RasterWorkerPool::Task::Reply& reply,
internal::WorkerPoolTask::TaskVector* dependencies)
: internal::WorkerPoolTask(dependencies),
picture_pile_(picture_pile),
task_(task) {
callback_(callback),
reply_(reply) {
DCHECK(picture_pile_);
}
// Overridden from internal::WorkerPoolTask:
virtual void RunOnThread(unsigned thread_index) OVERRIDE {
task_.Run(picture_pile_->GetCloneForDrawingOnThread(thread_index));
callback_.Run(picture_pile_->GetCloneForDrawingOnThread(thread_index));
}
virtual void DispatchCompletionCallback() OVERRIDE {
reply_.Run(!HasFinishedRunning());
}
private:
virtual ~RasterWorkerPoolPictureTaskImpl() {}
scoped_refptr<PicturePileImpl> picture_pile_;
RasterWorkerPool::RasterCallback task_;
const RasterWorkerPool::PictureTask::Callback callback_;
const RasterWorkerPool::Task::Reply reply_;
};
const char* kWorkerThreadNamePrefix = "CompositorRaster";
......@@ -36,23 +84,69 @@ const int kCheckForCompletedTasksDelayMs = 6;
} // namespace
RasterWorkerPool::RasterWorkerPool(size_t num_threads)
: WorkerPool(
num_threads,
base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs),
kWorkerThreadNamePrefix) {
RasterWorkerPool::Task::Queue::Queue() {
}
RasterWorkerPool::Task::Queue::~Queue() {
}
void RasterWorkerPool::Task::Queue::Append(const Task& task) {
DCHECK(!task.is_null());
tasks_.push_back(task.internal_);
}
RasterWorkerPool::Task::Task() {
}
RasterWorkerPool::Task::Task(const base::Closure& callback,
const Reply& reply)
: internal_(new RasterWorkerPoolTaskImpl(callback, reply)) {
}
RasterWorkerPool::Task::Task(Queue* dependencies)
: internal_(new RasterWorkerPoolContainerTaskImpl(&dependencies->tasks_)) {
}
RasterWorkerPool::Task::Task(scoped_refptr<internal::WorkerPoolTask> internal)
: internal_(internal) {
}
RasterWorkerPool::Task::~Task() {
}
void RasterWorkerPool::Task::Reset() {
internal_ = NULL;
}
RasterWorkerPool::PictureTask::PictureTask(PicturePileImpl* picture_pile,
const Callback& callback,
const Reply& reply,
Task::Queue* dependencies)
: RasterWorkerPool::Task(
new RasterWorkerPoolPictureTaskImpl(picture_pile,
callback,
reply,
&dependencies->tasks_)) {
}
RasterWorkerPool::RasterWorkerPool(size_t num_threads) : WorkerPool(
num_threads,
base::TimeDelta::FromMilliseconds(kCheckForCompletedTasksDelayMs),
kWorkerThreadNamePrefix) {
}
RasterWorkerPool::~RasterWorkerPool() {
}
void RasterWorkerPool::PostRasterTaskAndReply(PicturePileImpl* picture_pile,
const RasterCallback& task,
const base::Closure& reply) {
PostTask(make_scoped_ptr(new RasterWorkerPoolTaskImpl(
picture_pile,
task,
reply)).PassAs<internal::WorkerPoolTask>());
void RasterWorkerPool::Shutdown() {
// Cancel all previously scheduled tasks.
WorkerPool::ScheduleTasks(NULL);
WorkerPool::Shutdown();
}
void RasterWorkerPool::ScheduleTasks(Task* task) {
WorkerPool::ScheduleTasks(task ? task->internal_ : NULL);
}
} // namespace cc
......@@ -5,8 +5,6 @@
#ifndef CC_RESOURCES_RASTER_WORKER_POOL_H_
#define CC_RESOURCES_RASTER_WORKER_POOL_H_
#include <string>
#include "cc/base/worker_pool.h"
namespace cc {
......@@ -15,7 +13,55 @@ class PicturePileImpl;
// A worker thread pool that runs raster tasks.
class CC_EXPORT RasterWorkerPool : public WorkerPool {
public:
typedef base::Callback<void(PicturePileImpl* picture_pile)> RasterCallback;
class Task {
public:
typedef base::Callback<void(bool)> Reply;
// Highest priority task first. Order of execution is not guaranteed.
class Queue {
public:
Queue();
~Queue();
bool empty() const { return tasks_.empty(); }
// Add task to the back of the queue.
void Append(const Task& task);
private:
friend class RasterWorkerPool;
internal::WorkerPoolTask::TaskVector tasks_;
};
Task();
Task(const base::Closure& callback, const Reply& reply);
explicit Task(Queue* dependencies);
~Task();
// Returns true if Task is null (doesn't refer to anything).
bool is_null() const { return !internal_; }
// Returns the Task into an uninitialized state.
void Reset();
protected:
friend class RasterWorkerPool;
explicit Task(scoped_refptr<internal::WorkerPoolTask> internal);
scoped_refptr<internal::WorkerPoolTask> internal_;
};
class PictureTask : public Task {
public:
typedef base::Callback<void(PicturePileImpl*)> Callback;
PictureTask(PicturePileImpl* picture_pile,
const Callback& callback,
const Reply& reply,
Queue* dependencies);
};
virtual ~RasterWorkerPool();
......@@ -23,9 +69,16 @@ class CC_EXPORT RasterWorkerPool : public WorkerPool {
return make_scoped_ptr(new RasterWorkerPool(num_threads));
}
void PostRasterTaskAndReply(PicturePileImpl* picture_pile,
const RasterCallback& task,
const base::Closure& reply);
// Tells the worker pool to shutdown after canceling all previously
// scheduled tasks. Reply callbacks are still guaranteed to run.
virtual void Shutdown() OVERRIDE;
// Schedule running of |root| task and all its dependencies. Tasks
// previously scheduled but no longer needed to run |root| will be
// canceled unless already running. Once scheduled, reply callbacks
// are guaranteed to run for all tasks even if they later get
// canceled by another call to ScheduleTasks().
void ScheduleTasks(Task* root);
private:
explicit RasterWorkerPool(size_t num_threads);
......
......@@ -981,6 +981,8 @@ uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) {
context3d->mapBufferCHROMIUM(
GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
// Buffer is required to be 4-byte aligned.
CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
return image;
}
......
This diff is collapsed.
......@@ -62,6 +62,8 @@ scoped_ptr<base::Value> TileManagerBinPriorityAsValue(
// created, and unregister from the manager when they are deleted.
class CC_EXPORT TileManager : public WorkerPoolClient {
public:
typedef base::hash_set<uint32_t> PixelRefSet;
static scoped_ptr<TileManager> Create(
TileManagerClient* client,
ResourceProvider* resource_provider,
......@@ -116,7 +118,7 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
void UnregisterTile(Tile* tile);
// Virtual for test
virtual void DispatchMoreTasks();
virtual void ScheduleTasks();
private:
// Data that is passed to raster tasks.
......@@ -129,8 +131,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
int source_frame_number;
};
RasterTaskMetadata GetRasterTaskMetadata(const Tile& tile) const;
void AssignBinsToTiles();
void SortTiles();
void AssignGpuMemoryToTiles();
......@@ -142,20 +142,19 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
client_->ScheduleManageTiles();
manage_tiles_pending_ = true;
}
bool DispatchImageDecodeTasksForTile(Tile* tile);
void DispatchOneImageDecodeTask(
scoped_refptr<Tile> tile, skia::LazyPixelRef* pixel_ref);
RasterWorkerPool::Task CreateImageDecodeTask(
Tile* tile, skia::LazyPixelRef* pixel_ref);
void OnImageDecodeTaskCompleted(
scoped_refptr<Tile> tile,
uint32_t pixel_ref_id);
bool CanDispatchRasterTask(Tile* tile) const;
scoped_ptr<ResourcePool::Resource> PrepareTileForRaster(Tile* tile);
void DispatchOneRasterTask(scoped_refptr<Tile> tile);
uint32_t pixel_ref_id,
bool was_canceled);
RasterTaskMetadata GetRasterTaskMetadata(const Tile& tile) const;
RasterWorkerPool::Task CreateRasterTask(Tile* tile);
void OnRasterTaskCompleted(
scoped_refptr<Tile> tile,
scoped_ptr<ResourcePool::Resource> resource,
PicturePileImpl::Analysis* analysis,
int manage_tiles_call_count_when_dispatched);
bool was_canceled);
void DidFinishTileInitialization(Tile* tile);
void DidTileTreeBinChange(Tile* tile,
TileManagerBin new_tree_bin,
......@@ -163,9 +162,13 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
scoped_ptr<Value> GetMemoryRequirementsAsValue() const;
void AddRequiredTileForActivation(Tile* tile);
static void RunImageDecodeTask(
skia::LazyPixelRef* pixel_ref,
int layer_id,
RenderingStatsInstrumentation* stats_instrumentation);
static void RunAnalyzeAndRasterTask(
const RasterWorkerPool::RasterCallback& analyze_task,
const RasterWorkerPool::RasterCallback& raster_task,
const RasterWorkerPool::PictureTask::Callback& analyze_task,
const RasterWorkerPool::PictureTask::Callback& raster_task,
PicturePileImpl* picture_pile);
static void RunAnalyzeTask(
PicturePileImpl::Analysis* analysis,
......@@ -183,16 +186,11 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
const RasterTaskMetadata& metadata,
RenderingStatsInstrumentation* stats_instrumentation,
PicturePileImpl* picture_pile);
static void RunImageDecodeTask(
skia::LazyPixelRef* pixel_ref,
int layer_id,
RenderingStatsInstrumentation* stats_instrumentation);
TileManagerClient* client_;
scoped_ptr<ResourcePool> resource_pool_;
scoped_ptr<RasterWorkerPool> raster_worker_pool_;
bool manage_tiles_pending_;
int manage_tiles_call_count_;
GlobalStateThatImpactsTilePriority global_state_;
......@@ -202,8 +200,8 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
typedef std::set<Tile*> TileSet;
TileSet tiles_that_need_to_be_initialized_for_activation_;
typedef base::hash_set<uint32_t> PixelRefSet;
PixelRefSet pending_decode_tasks_;
typedef base::hash_map<uint32_t, RasterWorkerPool::Task> PixelRefMap;
PixelRefMap pending_decode_tasks_;
typedef std::queue<scoped_refptr<Tile> > TileQueue;
TileQueue tiles_with_pending_upload_;
......@@ -217,7 +215,6 @@ class CC_EXPORT TileManager : public WorkerPoolClient {
bool use_color_estimator_;
bool did_initialize_visible_tile_;
size_t pending_tasks_;
size_t max_pending_tasks_;
DISALLOW_COPY_AND_ASSIGN(TileManager);
......
......@@ -17,7 +17,7 @@ class FakeTileManager : public TileManager {
protected:
// Do nothing
virtual void DispatchMoreTasks() OVERRIDE { }
virtual void ScheduleTasks() OVERRIDE { }
};
} // namespace cc
......
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