- add sources.
[platform/framework/web/crosswalk.git] / src / cc / resources / raster_worker_pool.cc
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.
4
5 #include "cc/resources/raster_worker_pool.h"
6
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"
16
17 namespace cc {
18
19 namespace {
20
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 {
24  public:
25   explicit IdentityAllocator(void* buffer) : buffer_(buffer) {}
26   virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE {
27     dst->setPixels(buffer_);
28     return true;
29   }
30  private:
31   void* buffer_;
32 };
33
34 // Flag to indicate whether we should try and detect that
35 // a tile is of solid color.
36 const bool kUseColorEstimator = true;
37
38 class DisableLCDTextFilter : public SkDrawFilter {
39  public:
40   // SkDrawFilter interface.
41   virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE {
42     if (type != SkDrawFilter::kText_Type)
43       return true;
44
45     paint->setLCDRenderText(false);
46     return true;
47   }
48 };
49
50 class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask {
51  public:
52   RasterWorkerPoolTaskImpl(const Resource* resource,
53                            PicturePileImpl* picture_pile,
54                            gfx::Rect content_rect,
55                            float contents_scale,
56                            RasterMode raster_mode,
57                            TileResolution tile_resolution,
58                            int layer_id,
59                            const void* tile_id,
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),
70         layer_id_(layer_id),
71         tile_id_(tile_id),
72         source_frame_number_(source_frame_number),
73         rendering_stats_(rendering_stats),
74         reply_(reply) {}
75
76   void RunAnalysisOnThread(unsigned thread_index) {
77     TRACE_EVENT1("cc",
78                  "RasterWorkerPoolTaskImpl::RunAnalysisOnThread",
79                  "data",
80                  TracedValue::FromValue(DataAsValue().release()));
81
82     DCHECK(picture_pile_.get());
83     DCHECK(rendering_stats_);
84
85     PicturePileImpl* picture_clone =
86         picture_pile_->GetCloneForDrawingOnThread(thread_index);
87
88     DCHECK(picture_clone);
89
90     picture_clone->AnalyzeInRect(content_rect_, contents_scale_, &analysis_);
91
92     // Record the solid color prediction.
93     UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
94                           analysis_.is_solid_color);
95
96     // Clear the flag if we're not using the estimator.
97     analysis_.is_solid_color &= kUseColorEstimator;
98   }
99
100   bool RunRasterOnThread(unsigned thread_index,
101                          void* buffer,
102                          gfx::Size size,
103                          int stride) {
104     TRACE_EVENT2(
105         "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread",
106         "data",
107         TracedValue::FromValue(DataAsValue().release()),
108         "raster_mode",
109         TracedValue::FromValue(RasterModeAsValue(raster_mode_).release()));
110
111     devtools_instrumentation::ScopedLayerTask raster_task(
112         devtools_instrumentation::kRasterTask, layer_id_);
113
114     DCHECK(picture_pile_.get());
115     DCHECK(buffer);
116
117     if (analysis_.is_solid_color)
118       return false;
119
120     PicturePileImpl* picture_clone =
121         picture_pile_->GetCloneForDrawingOnThread(thread_index);
122
123     SkBitmap bitmap;
124     switch (resource()->format()) {
125       case RGBA_4444:
126         // Use the default stride if we will eventually convert this
127         // bitmap to 4444.
128         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
129                          size.width(),
130                          size.height());
131         bitmap.allocPixels();
132         break;
133       case RGBA_8888:
134       case BGRA_8888:
135         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
136                          size.width(),
137                          size.height(),
138                          stride);
139         bitmap.setPixels(buffer);
140         break;
141       case LUMINANCE_8:
142       case RGB_565:
143       case ETC1:
144         NOTREACHED();
145         break;
146     }
147
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);
154         break;
155       case HIGH_QUALITY_NO_LCD_RASTER_MODE:
156         draw_filter = skia::AdoptRef(new DisableLCDTextFilter);
157         break;
158       case HIGH_QUALITY_RASTER_MODE:
159         break;
160       case NUM_RASTER_MODES:
161       default:
162         NOTREACHED();
163     }
164
165     canvas.setDrawFilter(draw_filter.get());
166
167     base::TimeDelta prev_rasterize_time =
168         rendering_stats_->impl_thread_rendering_stats().rasterize_time;
169
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_);
177     } else {
178       picture_clone->RasterToBitmap(
179           &canvas, content_rect_, contents_scale_, NULL);
180     }
181
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(),
188           0,
189           100000,
190           100);
191     }
192
193     ChangeBitmapConfigIfNeeded(bitmap, buffer);
194
195     return true;
196   }
197
198   // Overridden from internal::RasterWorkerPoolTask:
199   virtual bool RunOnWorkerThread(unsigned thread_index,
200                                  void* buffer,
201                                  gfx::Size size,
202                                  int stride)
203       OVERRIDE {
204     RunAnalysisOnThread(thread_index);
205     return RunRasterOnThread(thread_index, buffer, size, stride);
206   }
207   virtual void CompleteOnOriginThread() OVERRIDE {
208     reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled());
209   }
210
211  protected:
212   virtual ~RasterWorkerPoolTaskImpl() {}
213
214  private:
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>();
222   }
223
224   void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap,
225                                   void* buffer) {
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);
235     }
236   }
237
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_;
244   int layer_id_;
245   const void* tile_id_;
246   int source_frame_number_;
247   RenderingStatsInstrumentation* rendering_stats_;
248   const RasterWorkerPool::RasterTask::Reply reply_;
249
250   DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl);
251 };
252
253 class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
254  public:
255   ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref,
256                                 int layer_id,
257                                 RenderingStatsInstrumentation* rendering_stats,
258                                 const RasterWorkerPool::Task::Reply& reply)
259       : pixel_ref_(skia::SharePtr(pixel_ref)),
260         layer_id_(layer_id),
261         rendering_stats_(rendering_stats),
262         reply_(reply) {}
263
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(
268         pixel_ref_.get());
269     pixel_ref_->Decode();
270   }
271   virtual void CompleteOnOriginThread() OVERRIDE {
272     reply_.Run(!HasFinishedRunning());
273   }
274
275  protected:
276   virtual ~ImageDecodeWorkerPoolTaskImpl() {}
277
278  private:
279   skia::RefPtr<skia::LazyPixelRef> pixel_ref_;
280   int layer_id_;
281   RenderingStatsInstrumentation* rendering_stats_;
282   const RasterWorkerPool::Task::Reply reply_;
283
284   DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl);
285 };
286
287 class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
288  public:
289   typedef base::Callback<void(const internal::WorkerPoolTask* source)>
290       Callback;
291
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) {
296   }
297
298   // Overridden from internal::WorkerPoolTask:
299   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
300     TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
301     origin_loop_->PostTask(
302         FROM_HERE,
303         base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread,
304                    this));
305   }
306   virtual void CompleteOnOriginThread() OVERRIDE {}
307
308  private:
309   virtual ~RasterFinishedWorkerPoolTaskImpl() {}
310
311   void RunOnOriginThread() const {
312     on_raster_finished_callback_.Run(this);
313   }
314
315   scoped_refptr<base::MessageLoopProxy> origin_loop_;
316   const Callback on_raster_finished_callback_;
317
318   DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
319 };
320
321 const char* kWorkerThreadNamePrefix = "CompositorRaster";
322
323 }  // namespace
324
325 namespace internal {
326
327 RasterWorkerPoolTask::RasterWorkerPoolTask(
328     const Resource* resource, TaskVector* dependencies)
329     : did_run_(false),
330       did_complete_(false),
331       was_canceled_(false),
332       resource_(resource) {
333   dependencies_.swap(*dependencies);
334 }
335
336 RasterWorkerPoolTask::~RasterWorkerPoolTask() {
337 }
338
339 void RasterWorkerPoolTask::DidRun(bool was_canceled) {
340   DCHECK(!did_run_);
341   did_run_ = true;
342   was_canceled_ = was_canceled;
343 }
344
345 bool RasterWorkerPoolTask::HasFinishedRunning() const {
346   return did_run_;
347 }
348
349 bool RasterWorkerPoolTask::WasCanceled() const {
350   return was_canceled_;
351 }
352
353 void RasterWorkerPoolTask::WillComplete() {
354   DCHECK(!did_complete_);
355 }
356
357 void RasterWorkerPoolTask::DidComplete() {
358   DCHECK(!did_complete_);
359   did_complete_ = true;
360 }
361
362 bool RasterWorkerPoolTask::HasCompleted() const {
363   return did_complete_;
364 }
365
366 }  // namespace internal
367
368 RasterWorkerPool::Task::Set::Set() {
369 }
370
371 RasterWorkerPool::Task::Set::~Set() {
372 }
373
374 void RasterWorkerPool::Task::Set::Insert(const Task& task) {
375   DCHECK(!task.is_null());
376   tasks_.push_back(task.internal_);
377 }
378
379 RasterWorkerPool::Task::Task() {
380 }
381
382 RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal)
383     : internal_(internal) {
384 }
385
386 RasterWorkerPool::Task::~Task() {
387 }
388
389 void RasterWorkerPool::Task::Reset() {
390   internal_ = NULL;
391 }
392
393 RasterWorkerPool::RasterTask::Queue::Queue() {
394 }
395
396 RasterWorkerPool::RasterTask::Queue::~Queue() {
397 }
398
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());
405 }
406
407 RasterWorkerPool::RasterTask::RasterTask() {
408 }
409
410 RasterWorkerPool::RasterTask::RasterTask(
411     internal::RasterWorkerPoolTask* internal)
412     : internal_(internal) {
413 }
414
415 void RasterWorkerPool::RasterTask::Reset() {
416   internal_ = NULL;
417 }
418
419 RasterWorkerPool::RasterTask::~RasterTask() {
420 }
421
422 // static
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,
430     int layer_id,
431     const void* tile_id,
432     int source_frame_number,
433     RenderingStatsInstrumentation* rendering_stats,
434     const RasterTask::Reply& reply,
435     Task::Set* dependencies) {
436   return RasterTask(
437       new RasterWorkerPoolTaskImpl(resource,
438                                    picture_pile,
439                                    content_rect,
440                                    contents_scale,
441                                    raster_mode,
442                                    tile_resolution,
443                                    layer_id,
444                                    tile_id,
445                                    source_frame_number,
446                                    rendering_stats,
447                                    reply,
448                                    &dependencies->tasks_));
449 }
450
451 // static
452 RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask(
453     skia::LazyPixelRef* pixel_ref,
454     int layer_id,
455     RenderingStatsInstrumentation* stats_instrumentation,
456     const Task::Reply& reply) {
457   return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref,
458                                                 layer_id,
459                                                 stats_instrumentation,
460                                                 reply));
461 }
462
463 RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider,
464                                    size_t num_threads)
465     : WorkerPool(num_threads, kWorkerThreadNamePrefix),
466       client_(NULL),
467       resource_provider_(resource_provider),
468       weak_ptr_factory_(this) {
469 }
470
471 RasterWorkerPool::~RasterWorkerPool() {
472 }
473
474 void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
475   client_ = client;
476 }
477
478 void RasterWorkerPool::Shutdown() {
479   raster_tasks_.clear();
480   TaskGraph empty;
481   SetTaskGraph(&empty);
482   WorkerPool::Shutdown();
483   weak_ptr_factory_.InvalidateWeakPtrs();
484 }
485
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_);
490 }
491
492 bool RasterWorkerPool::IsRasterTaskRequiredForActivation(
493     internal::RasterWorkerPoolTask* task) const {
494   return
495       raster_tasks_required_for_activation_.find(task) !=
496       raster_tasks_required_for_activation_.end();
497 }
498
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())));
505 }
506
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())));
513 }
514
515 void RasterWorkerPool::OnRasterFinished(
516     const internal::WorkerPoolTask* source) {
517   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");
518
519   // Early out if current |raster_finished_task_| is not the source.
520   if (source != raster_finished_task_.get())
521     return;
522
523   OnRasterTasksFinished();
524 }
525
526 void RasterWorkerPool::OnRasterRequiredForActivationFinished(
527     const internal::WorkerPoolTask* source) {
528   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");
529
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())
533     return;
534
535   OnRasterTasksRequiredForActivationFinished();
536 }
537
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>();
544 }
545
546 // static
547 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask(
548     internal::WorkerPoolTask* task,
549     unsigned priority,
550     TaskGraph* graph) {
551   internal::GraphNode* node = new internal::GraphNode(task, priority);
552   DCHECK(graph->find(task) == graph->end());
553   graph->set(task, make_scoped_ptr(node));
554   return node;
555 }
556
557 // static
558 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask(
559     internal::WorkerPoolTask* raster_task,
560     const TaskVector& decode_tasks,
561     unsigned priority,
562     TaskGraph* graph) {
563   DCHECK(!raster_task->HasCompleted());
564
565   internal::GraphNode* raster_node = CreateGraphNodeForTask(
566       raster_task, priority, graph);
567
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();
572
573     // Skip if already decoded.
574     if (decode_task->HasCompleted())
575       continue;
576
577     raster_node->add_dependency();
578
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);
584       continue;
585     }
586
587     internal::GraphNode* decode_node = CreateGraphNodeForTask(
588         decode_task, priority, graph);
589     decode_node->add_dependent(raster_node);
590   }
591
592   return raster_node;
593 }
594
595 }  // namespace cc