1 // Copyright 2013 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.
5 #include "cc/resources/raster_worker_pool.h"
7 #include "base/json/json_writer.h"
8 #include "base/metrics/histogram.h"
9 #include "base/values.h"
10 #include "cc/debug/devtools_instrumentation.h"
11 #include "cc/debug/traced_value.h"
12 #include "cc/resources/picture_pile_impl.h"
13 #include "skia/ext/lazy_pixel_ref.h"
14 #include "skia/ext/paint_simplifier.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
21 // Subclass of Allocator that takes a suitably allocated pointer and uses
22 // it as the pixel memory for the bitmap.
23 class IdentityAllocator : public SkBitmap::Allocator {
25 explicit IdentityAllocator(void* buffer) : buffer_(buffer) {}
26 virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE {
27 dst->setPixels(buffer_);
34 // Flag to indicate whether we should try and detect that
35 // a tile is of solid color.
36 const bool kUseColorEstimator = true;
38 class DisableLCDTextFilter : public SkDrawFilter {
40 // SkDrawFilter interface.
41 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE {
42 if (type != SkDrawFilter::kText_Type)
45 paint->setLCDRenderText(false);
50 class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask {
52 RasterWorkerPoolTaskImpl(const Resource* resource,
53 PicturePileImpl* picture_pile,
54 gfx::Rect content_rect,
56 RasterMode raster_mode,
57 TileResolution tile_resolution,
60 int source_frame_number,
61 RenderingStatsInstrumentation* rendering_stats,
62 const RasterWorkerPool::RasterTask::Reply& reply,
63 TaskVector* dependencies)
64 : internal::RasterWorkerPoolTask(resource, dependencies),
65 picture_pile_(picture_pile),
66 content_rect_(content_rect),
67 contents_scale_(contents_scale),
68 raster_mode_(raster_mode),
69 tile_resolution_(tile_resolution),
72 source_frame_number_(source_frame_number),
73 rendering_stats_(rendering_stats),
76 void RunAnalysisOnThread(unsigned thread_index) {
78 "RasterWorkerPoolTaskImpl::RunAnalysisOnThread",
80 TracedValue::FromValue(DataAsValue().release()));
82 DCHECK(picture_pile_.get());
83 DCHECK(rendering_stats_);
85 PicturePileImpl* picture_clone =
86 picture_pile_->GetCloneForDrawingOnThread(thread_index);
88 DCHECK(picture_clone);
90 picture_clone->AnalyzeInRect(content_rect_, contents_scale_, &analysis_);
92 // Record the solid color prediction.
93 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
94 analysis_.is_solid_color);
96 // Clear the flag if we're not using the estimator.
97 analysis_.is_solid_color &= kUseColorEstimator;
100 bool RunRasterOnThread(unsigned thread_index,
105 "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread",
107 TracedValue::FromValue(DataAsValue().release()),
109 TracedValue::FromValue(RasterModeAsValue(raster_mode_).release()));
111 devtools_instrumentation::ScopedLayerTask raster_task(
112 devtools_instrumentation::kRasterTask, layer_id_);
114 DCHECK(picture_pile_.get());
117 if (analysis_.is_solid_color)
120 PicturePileImpl* picture_clone =
121 picture_pile_->GetCloneForDrawingOnThread(thread_index);
124 switch (resource()->format()) {
126 // Use the default stride if we will eventually convert this
128 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
131 bitmap.allocPixels();
135 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
139 bitmap.setPixels(buffer);
148 SkBitmapDevice device(bitmap);
149 SkCanvas canvas(&device);
150 skia::RefPtr<SkDrawFilter> draw_filter;
151 switch (raster_mode_) {
152 case LOW_QUALITY_RASTER_MODE:
153 draw_filter = skia::AdoptRef(new skia::PaintSimplifier);
155 case HIGH_QUALITY_NO_LCD_RASTER_MODE:
156 draw_filter = skia::AdoptRef(new DisableLCDTextFilter);
158 case HIGH_QUALITY_RASTER_MODE:
160 case NUM_RASTER_MODES:
165 canvas.setDrawFilter(draw_filter.get());
167 base::TimeDelta prev_rasterize_time =
168 rendering_stats_->impl_thread_rendering_stats().rasterize_time;
170 // Only record rasterization time for highres tiles, because
171 // lowres tiles are not required for activation and therefore
172 // introduce noise in the measurement (sometimes they get rasterized
173 // before we draw and sometimes they aren't)
174 if (tile_resolution_ == HIGH_RESOLUTION) {
175 picture_clone->RasterToBitmap(
176 &canvas, content_rect_, contents_scale_, rendering_stats_);
178 picture_clone->RasterToBitmap(
179 &canvas, content_rect_, contents_scale_, NULL);
182 if (rendering_stats_->record_rendering_stats()) {
183 base::TimeDelta current_rasterize_time =
184 rendering_stats_->impl_thread_rendering_stats().rasterize_time;
185 HISTOGRAM_CUSTOM_COUNTS(
186 "Renderer4.PictureRasterTimeUS",
187 (current_rasterize_time - prev_rasterize_time).InMicroseconds(),
193 ChangeBitmapConfigIfNeeded(bitmap, buffer);
198 // Overridden from internal::RasterWorkerPoolTask:
199 virtual bool RunOnWorkerThread(unsigned thread_index,
204 RunAnalysisOnThread(thread_index);
205 return RunRasterOnThread(thread_index, buffer, size, stride);
207 virtual void CompleteOnOriginThread() OVERRIDE {
208 reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled());
212 virtual ~RasterWorkerPoolTaskImpl() {}
215 scoped_ptr<base::Value> DataAsValue() const {
216 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
217 res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release());
218 res->Set("resolution", TileResolutionAsValue(tile_resolution_).release());
219 res->SetInteger("source_frame_number", source_frame_number_);
220 res->SetInteger("layer_id", layer_id_);
221 return res.PassAs<base::Value>();
224 void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap,
226 TRACE_EVENT0("cc", "RasterWorkerPoolTaskImpl::ChangeBitmapConfigIfNeeded");
227 SkBitmap::Config config = SkBitmapConfig(resource()->format());
228 if (bitmap.getConfig() != config) {
229 SkBitmap bitmap_dest;
230 IdentityAllocator allocator(buffer);
231 bitmap.copyTo(&bitmap_dest, config, &allocator);
232 // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
233 // bitmap data. This check will be removed once crbug.com/293728 is fixed.
234 CHECK_EQ(0u, bitmap_dest.rowBytes() % 4);
238 PicturePileImpl::Analysis analysis_;
239 scoped_refptr<PicturePileImpl> picture_pile_;
240 gfx::Rect content_rect_;
241 float contents_scale_;
242 RasterMode raster_mode_;
243 TileResolution tile_resolution_;
245 const void* tile_id_;
246 int source_frame_number_;
247 RenderingStatsInstrumentation* rendering_stats_;
248 const RasterWorkerPool::RasterTask::Reply reply_;
250 DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl);
253 class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
255 ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref,
257 RenderingStatsInstrumentation* rendering_stats,
258 const RasterWorkerPool::Task::Reply& reply)
259 : pixel_ref_(skia::SharePtr(pixel_ref)),
261 rendering_stats_(rendering_stats),
264 // Overridden from internal::WorkerPoolTask:
265 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
266 TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread");
267 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
269 pixel_ref_->Decode();
271 virtual void CompleteOnOriginThread() OVERRIDE {
272 reply_.Run(!HasFinishedRunning());
276 virtual ~ImageDecodeWorkerPoolTaskImpl() {}
279 skia::RefPtr<skia::LazyPixelRef> pixel_ref_;
281 RenderingStatsInstrumentation* rendering_stats_;
282 const RasterWorkerPool::Task::Reply reply_;
284 DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl);
287 class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
289 typedef base::Callback<void(const internal::WorkerPoolTask* source)>
292 RasterFinishedWorkerPoolTaskImpl(
293 const Callback& on_raster_finished_callback)
294 : origin_loop_(base::MessageLoopProxy::current().get()),
295 on_raster_finished_callback_(on_raster_finished_callback) {
298 // Overridden from internal::WorkerPoolTask:
299 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
300 TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
301 origin_loop_->PostTask(
303 base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread,
306 virtual void CompleteOnOriginThread() OVERRIDE {}
309 virtual ~RasterFinishedWorkerPoolTaskImpl() {}
311 void RunOnOriginThread() const {
312 on_raster_finished_callback_.Run(this);
315 scoped_refptr<base::MessageLoopProxy> origin_loop_;
316 const Callback on_raster_finished_callback_;
318 DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
321 const char* kWorkerThreadNamePrefix = "CompositorRaster";
327 RasterWorkerPoolTask::RasterWorkerPoolTask(
328 const Resource* resource, TaskVector* dependencies)
330 did_complete_(false),
331 was_canceled_(false),
332 resource_(resource) {
333 dependencies_.swap(*dependencies);
336 RasterWorkerPoolTask::~RasterWorkerPoolTask() {
339 void RasterWorkerPoolTask::DidRun(bool was_canceled) {
342 was_canceled_ = was_canceled;
345 bool RasterWorkerPoolTask::HasFinishedRunning() const {
349 bool RasterWorkerPoolTask::WasCanceled() const {
350 return was_canceled_;
353 void RasterWorkerPoolTask::WillComplete() {
354 DCHECK(!did_complete_);
357 void RasterWorkerPoolTask::DidComplete() {
358 DCHECK(!did_complete_);
359 did_complete_ = true;
362 bool RasterWorkerPoolTask::HasCompleted() const {
363 return did_complete_;
366 } // namespace internal
368 RasterWorkerPool::Task::Set::Set() {
371 RasterWorkerPool::Task::Set::~Set() {
374 void RasterWorkerPool::Task::Set::Insert(const Task& task) {
375 DCHECK(!task.is_null());
376 tasks_.push_back(task.internal_);
379 RasterWorkerPool::Task::Task() {
382 RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal)
383 : internal_(internal) {
386 RasterWorkerPool::Task::~Task() {
389 void RasterWorkerPool::Task::Reset() {
393 RasterWorkerPool::RasterTask::Queue::Queue() {
396 RasterWorkerPool::RasterTask::Queue::~Queue() {
399 void RasterWorkerPool::RasterTask::Queue::Append(
400 const RasterTask& task, bool required_for_activation) {
401 DCHECK(!task.is_null());
402 tasks_.push_back(task.internal_);
403 if (required_for_activation)
404 tasks_required_for_activation_.insert(task.internal_.get());
407 RasterWorkerPool::RasterTask::RasterTask() {
410 RasterWorkerPool::RasterTask::RasterTask(
411 internal::RasterWorkerPoolTask* internal)
412 : internal_(internal) {
415 void RasterWorkerPool::RasterTask::Reset() {
419 RasterWorkerPool::RasterTask::~RasterTask() {
423 RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask(
424 const Resource* resource,
425 PicturePileImpl* picture_pile,
426 gfx::Rect content_rect,
427 float contents_scale,
428 RasterMode raster_mode,
429 TileResolution tile_resolution,
432 int source_frame_number,
433 RenderingStatsInstrumentation* rendering_stats,
434 const RasterTask::Reply& reply,
435 Task::Set* dependencies) {
437 new RasterWorkerPoolTaskImpl(resource,
448 &dependencies->tasks_));
452 RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask(
453 skia::LazyPixelRef* pixel_ref,
455 RenderingStatsInstrumentation* stats_instrumentation,
456 const Task::Reply& reply) {
457 return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref,
459 stats_instrumentation,
463 RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider,
465 : WorkerPool(num_threads, kWorkerThreadNamePrefix),
467 resource_provider_(resource_provider),
468 weak_ptr_factory_(this) {
471 RasterWorkerPool::~RasterWorkerPool() {
474 void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
478 void RasterWorkerPool::Shutdown() {
479 raster_tasks_.clear();
481 SetTaskGraph(&empty);
482 WorkerPool::Shutdown();
483 weak_ptr_factory_.InvalidateWeakPtrs();
486 void RasterWorkerPool::SetRasterTasks(RasterTask::Queue* queue) {
487 raster_tasks_.swap(queue->tasks_);
488 raster_tasks_required_for_activation_.swap(
489 queue->tasks_required_for_activation_);
492 bool RasterWorkerPool::IsRasterTaskRequiredForActivation(
493 internal::RasterWorkerPoolTask* task) const {
495 raster_tasks_required_for_activation_.find(task) !=
496 raster_tasks_required_for_activation_.end();
499 scoped_refptr<internal::WorkerPoolTask>
500 RasterWorkerPool::CreateRasterFinishedTask() {
501 return make_scoped_refptr(
502 new RasterFinishedWorkerPoolTaskImpl(
503 base::Bind(&RasterWorkerPool::OnRasterFinished,
504 weak_ptr_factory_.GetWeakPtr())));
507 scoped_refptr<internal::WorkerPoolTask>
508 RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask() {
509 return make_scoped_refptr(
510 new RasterFinishedWorkerPoolTaskImpl(
511 base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished,
512 weak_ptr_factory_.GetWeakPtr())));
515 void RasterWorkerPool::OnRasterFinished(
516 const internal::WorkerPoolTask* source) {
517 TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");
519 // Early out if current |raster_finished_task_| is not the source.
520 if (source != raster_finished_task_.get())
523 OnRasterTasksFinished();
526 void RasterWorkerPool::OnRasterRequiredForActivationFinished(
527 const internal::WorkerPoolTask* source) {
528 TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");
530 // Early out if current |raster_required_for_activation_finished_task_|
531 // is not the source.
532 if (source != raster_required_for_activation_finished_task_.get())
535 OnRasterTasksRequiredForActivationFinished();
538 scoped_ptr<base::Value> RasterWorkerPool::ScheduledStateAsValue() const {
539 scoped_ptr<base::DictionaryValue> scheduled_state(new base::DictionaryValue);
540 scheduled_state->SetInteger("task_count", raster_tasks_.size());
541 scheduled_state->SetInteger("task_required_for_activation_count",
542 raster_tasks_required_for_activation_.size());
543 return scheduled_state.PassAs<base::Value>();
547 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask(
548 internal::WorkerPoolTask* task,
551 internal::GraphNode* node = new internal::GraphNode(task, priority);
552 DCHECK(graph->find(task) == graph->end());
553 graph->set(task, make_scoped_ptr(node));
558 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask(
559 internal::WorkerPoolTask* raster_task,
560 const TaskVector& decode_tasks,
563 DCHECK(!raster_task->HasCompleted());
565 internal::GraphNode* raster_node = CreateGraphNodeForTask(
566 raster_task, priority, graph);
568 // Insert image decode tasks.
569 for (TaskVector::const_iterator it = decode_tasks.begin();
570 it != decode_tasks.end(); ++it) {
571 internal::WorkerPoolTask* decode_task = it->get();
573 // Skip if already decoded.
574 if (decode_task->HasCompleted())
577 raster_node->add_dependency();
579 // Check if decode task already exists in graph.
580 GraphNodeMap::iterator decode_it = graph->find(decode_task);
581 if (decode_it != graph->end()) {
582 internal::GraphNode* decode_node = decode_it->second;
583 decode_node->add_dependent(raster_node);
587 internal::GraphNode* decode_node = CreateGraphNodeForTask(
588 decode_task, priority, graph);
589 decode_node->add_dependent(raster_node);