Home | History | Annotate | Download | only in resources
      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/benchmark_instrumentation.h"
     11 #include "cc/debug/devtools_instrumentation.h"
     12 #include "cc/debug/traced_value.h"
     13 #include "cc/resources/picture_pile_impl.h"
     14 #include "skia/ext/lazy_pixel_ref.h"
     15 #include "skia/ext/paint_simplifier.h"
     16 
     17 namespace cc {
     18 
     19 namespace {
     20 
     21 // Flag to indicate whether we should try and detect that
     22 // a tile is of solid color.
     23 const bool kUseColorEstimator = true;
     24 
     25 class DisableLCDTextFilter : public SkDrawFilter {
     26  public:
     27   // SkDrawFilter interface.
     28   virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE {
     29     if (type != SkDrawFilter::kText_Type)
     30       return true;
     31 
     32     paint->setLCDRenderText(false);
     33     return true;
     34   }
     35 };
     36 
     37 class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask {
     38  public:
     39   RasterWorkerPoolTaskImpl(const Resource* resource,
     40                            PicturePileImpl* picture_pile,
     41                            gfx::Rect content_rect,
     42                            float contents_scale,
     43                            RasterMode raster_mode,
     44                            bool is_tile_in_pending_tree_now_bin,
     45                            TileResolution tile_resolution,
     46                            int layer_id,
     47                            const void* tile_id,
     48                            int source_frame_number,
     49                            RenderingStatsInstrumentation* rendering_stats,
     50                            const RasterWorkerPool::RasterTask::Reply& reply,
     51                            TaskVector* dependencies)
     52       : internal::RasterWorkerPoolTask(resource, dependencies),
     53         picture_pile_(picture_pile),
     54         content_rect_(content_rect),
     55         contents_scale_(contents_scale),
     56         raster_mode_(raster_mode),
     57         is_tile_in_pending_tree_now_bin_(is_tile_in_pending_tree_now_bin),
     58         tile_resolution_(tile_resolution),
     59         layer_id_(layer_id),
     60         tile_id_(tile_id),
     61         source_frame_number_(source_frame_number),
     62         rendering_stats_(rendering_stats),
     63         reply_(reply) {}
     64 
     65   void RunAnalysisOnThread(unsigned thread_index) {
     66     TRACE_EVENT1("cc",
     67                  "RasterWorkerPoolTaskImpl::RunAnalysisOnThread",
     68                  "data",
     69                  TracedValue::FromValue(DataAsValue().release()));
     70 
     71     DCHECK(picture_pile_.get());
     72     DCHECK(rendering_stats_);
     73 
     74     PicturePileImpl* picture_clone =
     75         picture_pile_->GetCloneForDrawingOnThread(thread_index);
     76 
     77     DCHECK(picture_clone);
     78 
     79     base::TimeTicks start_time = rendering_stats_->StartRecording();
     80     picture_clone->AnalyzeInRect(content_rect_, contents_scale_, &analysis_);
     81     base::TimeDelta duration = rendering_stats_->EndRecording(start_time);
     82 
     83     // Record the solid color prediction.
     84     UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
     85                           analysis_.is_solid_color);
     86     rendering_stats_->AddAnalysisResult(duration, analysis_.is_solid_color);
     87 
     88     // Clear the flag if we're not using the estimator.
     89     analysis_.is_solid_color &= kUseColorEstimator;
     90   }
     91 
     92   bool RunRasterOnThread(SkDevice* device, unsigned thread_index) {
     93     TRACE_EVENT2(
     94         benchmark_instrumentation::kCategory,
     95         benchmark_instrumentation::kRunRasterOnThread,
     96         benchmark_instrumentation::kData,
     97         TracedValue::FromValue(DataAsValue().release()),
     98         "raster_mode",
     99         TracedValue::FromValue(RasterModeAsValue(raster_mode_).release()));
    100 
    101     devtools_instrumentation::ScopedLayerTask raster_task(
    102         devtools_instrumentation::kRasterTask, layer_id_);
    103 
    104     DCHECK(picture_pile_.get());
    105     DCHECK(device);
    106 
    107     if (analysis_.is_solid_color)
    108       return false;
    109 
    110     PicturePileImpl* picture_clone =
    111         picture_pile_->GetCloneForDrawingOnThread(thread_index);
    112 
    113     SkCanvas canvas(device);
    114 
    115     skia::RefPtr<SkDrawFilter> draw_filter;
    116     switch (raster_mode_) {
    117       case LOW_QUALITY_RASTER_MODE:
    118         draw_filter = skia::AdoptRef(new skia::PaintSimplifier);
    119         break;
    120       case HIGH_QUALITY_NO_LCD_RASTER_MODE:
    121         draw_filter = skia::AdoptRef(new DisableLCDTextFilter);
    122         break;
    123       case HIGH_QUALITY_RASTER_MODE:
    124         break;
    125       case NUM_RASTER_MODES:
    126       default:
    127         NOTREACHED();
    128     }
    129 
    130     canvas.setDrawFilter(draw_filter.get());
    131 
    132     if (rendering_stats_->record_rendering_stats()) {
    133       PicturePileImpl::RasterStats raster_stats;
    134       picture_clone->RasterToBitmap(
    135           &canvas, content_rect_, contents_scale_, &raster_stats);
    136       rendering_stats_->AddRaster(
    137           raster_stats.total_rasterize_time,
    138           raster_stats.best_rasterize_time,
    139           raster_stats.total_pixels_rasterized,
    140           is_tile_in_pending_tree_now_bin_);
    141 
    142       HISTOGRAM_CUSTOM_COUNTS(
    143           "Renderer4.PictureRasterTimeUS",
    144           raster_stats.total_rasterize_time.InMicroseconds(),
    145           0,
    146           100000,
    147           100);
    148     } else {
    149       picture_clone->RasterToBitmap(
    150           &canvas, content_rect_, contents_scale_, NULL);
    151     }
    152     return true;
    153   }
    154 
    155   // Overridden from internal::RasterWorkerPoolTask:
    156   virtual bool RunOnWorkerThread(SkDevice* device, unsigned thread_index)
    157       OVERRIDE {
    158     RunAnalysisOnThread(thread_index);
    159     return RunRasterOnThread(device, thread_index);
    160   }
    161   virtual void CompleteOnOriginThread() OVERRIDE {
    162     reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled());
    163   }
    164 
    165  protected:
    166   virtual ~RasterWorkerPoolTaskImpl() {}
    167 
    168  private:
    169   scoped_ptr<base::Value> DataAsValue() const {
    170     scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
    171     res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release());
    172     res->SetBoolean("is_tile_in_pending_tree_now_bin",
    173                     is_tile_in_pending_tree_now_bin_);
    174     res->Set("resolution", TileResolutionAsValue(tile_resolution_).release());
    175     res->SetInteger("source_frame_number", source_frame_number_);
    176     res->SetInteger("layer_id", layer_id_);
    177     return res.PassAs<base::Value>();
    178   }
    179 
    180   PicturePileImpl::Analysis analysis_;
    181   scoped_refptr<PicturePileImpl> picture_pile_;
    182   gfx::Rect content_rect_;
    183   float contents_scale_;
    184   RasterMode raster_mode_;
    185   bool is_tile_in_pending_tree_now_bin_;
    186   TileResolution tile_resolution_;
    187   int layer_id_;
    188   const void* tile_id_;
    189   int source_frame_number_;
    190   RenderingStatsInstrumentation* rendering_stats_;
    191   const RasterWorkerPool::RasterTask::Reply reply_;
    192 
    193   DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl);
    194 };
    195 
    196 class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
    197  public:
    198   ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref,
    199                                 int layer_id,
    200                                 RenderingStatsInstrumentation* rendering_stats,
    201                                 const RasterWorkerPool::Task::Reply& reply)
    202       : pixel_ref_(pixel_ref),
    203         layer_id_(layer_id),
    204         rendering_stats_(rendering_stats),
    205         reply_(reply) {}
    206 
    207   // Overridden from internal::WorkerPoolTask:
    208   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
    209     TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread");
    210     devtools_instrumentation::ScopedLayerTask image_decode_task(
    211         devtools_instrumentation::kImageDecodeTask, layer_id_);
    212     base::TimeTicks start_time = rendering_stats_->StartRecording();
    213     pixel_ref_->Decode();
    214     base::TimeDelta duration = rendering_stats_->EndRecording(start_time);
    215     rendering_stats_->AddDeferredImageDecode(duration);
    216   }
    217   virtual void CompleteOnOriginThread() OVERRIDE {
    218     reply_.Run(!HasFinishedRunning());
    219   }
    220 
    221  protected:
    222   virtual ~ImageDecodeWorkerPoolTaskImpl() {}
    223 
    224  private:
    225   skia::LazyPixelRef* pixel_ref_;
    226   int layer_id_;
    227   RenderingStatsInstrumentation* rendering_stats_;
    228   const RasterWorkerPool::Task::Reply reply_;
    229 
    230   DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl);
    231 };
    232 
    233 class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
    234  public:
    235   typedef base::Callback<void(const internal::WorkerPoolTask* source)>
    236       Callback;
    237 
    238   RasterFinishedWorkerPoolTaskImpl(
    239       const Callback& on_raster_finished_callback)
    240       : origin_loop_(base::MessageLoopProxy::current().get()),
    241         on_raster_finished_callback_(on_raster_finished_callback) {
    242   }
    243 
    244   // Overridden from internal::WorkerPoolTask:
    245   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
    246     TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
    247     origin_loop_->PostTask(
    248         FROM_HERE,
    249         base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread,
    250                    this));
    251   }
    252   virtual void CompleteOnOriginThread() OVERRIDE {}
    253 
    254  private:
    255   virtual ~RasterFinishedWorkerPoolTaskImpl() {}
    256 
    257   void RunOnOriginThread() const {
    258     on_raster_finished_callback_.Run(this);
    259   }
    260 
    261   scoped_refptr<base::MessageLoopProxy> origin_loop_;
    262   const Callback on_raster_finished_callback_;
    263 
    264   DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
    265 };
    266 
    267 const char* kWorkerThreadNamePrefix = "CompositorRaster";
    268 
    269 }  // namespace
    270 
    271 namespace internal {
    272 
    273 RasterWorkerPoolTask::RasterWorkerPoolTask(
    274     const Resource* resource, TaskVector* dependencies)
    275     : did_run_(false),
    276       did_complete_(false),
    277       was_canceled_(false),
    278       resource_(resource) {
    279   dependencies_.swap(*dependencies);
    280 }
    281 
    282 RasterWorkerPoolTask::~RasterWorkerPoolTask() {
    283 }
    284 
    285 void RasterWorkerPoolTask::DidRun(bool was_canceled) {
    286   DCHECK(!did_run_);
    287   did_run_ = true;
    288   was_canceled_ = was_canceled;
    289 }
    290 
    291 bool RasterWorkerPoolTask::HasFinishedRunning() const {
    292   return did_run_;
    293 }
    294 
    295 bool RasterWorkerPoolTask::WasCanceled() const {
    296   return was_canceled_;
    297 }
    298 
    299 void RasterWorkerPoolTask::WillComplete() {
    300   DCHECK(!did_complete_);
    301 }
    302 
    303 void RasterWorkerPoolTask::DidComplete() {
    304   DCHECK(!did_complete_);
    305   did_complete_ = true;
    306 }
    307 
    308 bool RasterWorkerPoolTask::HasCompleted() const {
    309   return did_complete_;
    310 }
    311 
    312 }  // namespace internal
    313 
    314 RasterWorkerPool::Task::Set::Set() {
    315 }
    316 
    317 RasterWorkerPool::Task::Set::~Set() {
    318 }
    319 
    320 void RasterWorkerPool::Task::Set::Insert(const Task& task) {
    321   DCHECK(!task.is_null());
    322   tasks_.push_back(task.internal_);
    323 }
    324 
    325 RasterWorkerPool::Task::Task() {
    326 }
    327 
    328 RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal)
    329     : internal_(internal) {
    330 }
    331 
    332 RasterWorkerPool::Task::~Task() {
    333 }
    334 
    335 void RasterWorkerPool::Task::Reset() {
    336   internal_ = NULL;
    337 }
    338 
    339 RasterWorkerPool::RasterTask::Queue::Queue() {
    340 }
    341 
    342 RasterWorkerPool::RasterTask::Queue::~Queue() {
    343 }
    344 
    345 void RasterWorkerPool::RasterTask::Queue::Append(
    346     const RasterTask& task, bool required_for_activation) {
    347   DCHECK(!task.is_null());
    348   tasks_.push_back(task.internal_);
    349   if (required_for_activation)
    350     tasks_required_for_activation_.insert(task.internal_.get());
    351 }
    352 
    353 RasterWorkerPool::RasterTask::RasterTask() {
    354 }
    355 
    356 RasterWorkerPool::RasterTask::RasterTask(
    357     internal::RasterWorkerPoolTask* internal)
    358     : internal_(internal) {
    359 }
    360 
    361 void RasterWorkerPool::RasterTask::Reset() {
    362   internal_ = NULL;
    363 }
    364 
    365 RasterWorkerPool::RasterTask::~RasterTask() {
    366 }
    367 
    368 // static
    369 RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask(
    370     const Resource* resource,
    371     PicturePileImpl* picture_pile,
    372     gfx::Rect content_rect,
    373     float contents_scale,
    374     RasterMode raster_mode,
    375     bool is_tile_in_pending_tree_now_bin,
    376     TileResolution tile_resolution,
    377     int layer_id,
    378     const void* tile_id,
    379     int source_frame_number,
    380     RenderingStatsInstrumentation* rendering_stats,
    381     const RasterTask::Reply& reply,
    382     Task::Set* dependencies) {
    383   return RasterTask(
    384       new RasterWorkerPoolTaskImpl(resource,
    385                                    picture_pile,
    386                                    content_rect,
    387                                    contents_scale,
    388                                    raster_mode,
    389                                    is_tile_in_pending_tree_now_bin,
    390                                    tile_resolution,
    391                                    layer_id,
    392                                    tile_id,
    393                                    source_frame_number,
    394                                    rendering_stats,
    395                                    reply,
    396                                    &dependencies->tasks_));
    397 }
    398 
    399 // static
    400 RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask(
    401     skia::LazyPixelRef* pixel_ref,
    402     int layer_id,
    403     RenderingStatsInstrumentation* stats_instrumentation,
    404     const Task::Reply& reply) {
    405   return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref,
    406                                                 layer_id,
    407                                                 stats_instrumentation,
    408                                                 reply));
    409 }
    410 
    411 RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider,
    412                                    size_t num_threads)
    413     : WorkerPool(num_threads, kWorkerThreadNamePrefix),
    414       client_(NULL),
    415       resource_provider_(resource_provider),
    416       weak_ptr_factory_(this) {
    417 }
    418 
    419 RasterWorkerPool::~RasterWorkerPool() {
    420 }
    421 
    422 void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
    423   client_ = client;
    424 }
    425 
    426 void RasterWorkerPool::Shutdown() {
    427   raster_tasks_.clear();
    428   TaskGraph empty;
    429   SetTaskGraph(&empty);
    430   WorkerPool::Shutdown();
    431   weak_ptr_factory_.InvalidateWeakPtrs();
    432 }
    433 
    434 void RasterWorkerPool::SetRasterTasks(RasterTask::Queue* queue) {
    435   raster_tasks_.swap(queue->tasks_);
    436   raster_tasks_required_for_activation_.swap(
    437       queue->tasks_required_for_activation_);
    438 }
    439 
    440 bool RasterWorkerPool::IsRasterTaskRequiredForActivation(
    441     internal::RasterWorkerPoolTask* task) const {
    442   return
    443       raster_tasks_required_for_activation_.find(task) !=
    444       raster_tasks_required_for_activation_.end();
    445 }
    446 
    447 scoped_refptr<internal::WorkerPoolTask>
    448     RasterWorkerPool::CreateRasterFinishedTask() {
    449   return make_scoped_refptr(
    450       new RasterFinishedWorkerPoolTaskImpl(
    451           base::Bind(&RasterWorkerPool::OnRasterFinished,
    452                      weak_ptr_factory_.GetWeakPtr())));
    453 }
    454 
    455 scoped_refptr<internal::WorkerPoolTask>
    456     RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask() {
    457   return make_scoped_refptr(
    458       new RasterFinishedWorkerPoolTaskImpl(
    459           base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished,
    460                      weak_ptr_factory_.GetWeakPtr())));
    461 }
    462 
    463 void RasterWorkerPool::OnRasterFinished(
    464     const internal::WorkerPoolTask* source) {
    465   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");
    466 
    467   // Early out if current |raster_finished_task_| is not the source.
    468   if (source != raster_finished_task_.get())
    469     return;
    470 
    471   OnRasterTasksFinished();
    472 }
    473 
    474 void RasterWorkerPool::OnRasterRequiredForActivationFinished(
    475     const internal::WorkerPoolTask* source) {
    476   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");
    477 
    478   // Early out if current |raster_required_for_activation_finished_task_|
    479   // is not the source.
    480   if (source != raster_required_for_activation_finished_task_.get())
    481     return;
    482 
    483   OnRasterTasksRequiredForActivationFinished();
    484 }
    485 
    486 scoped_ptr<base::Value> RasterWorkerPool::ScheduledStateAsValue() const {
    487   scoped_ptr<base::DictionaryValue> scheduled_state(new base::DictionaryValue);
    488   scheduled_state->SetInteger("task_count", raster_tasks_.size());
    489   scheduled_state->SetInteger("task_required_for_activation_count",
    490                               raster_tasks_required_for_activation_.size());
    491   return scheduled_state.PassAs<base::Value>();
    492 }
    493 
    494 // static
    495 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask(
    496     internal::WorkerPoolTask* task,
    497     unsigned priority,
    498     TaskGraph* graph) {
    499   internal::GraphNode* node = new internal::GraphNode(task, priority);
    500   DCHECK(graph->find(task) == graph->end());
    501   graph->set(task, make_scoped_ptr(node));
    502   return node;
    503 }
    504 
    505 // static
    506 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask(
    507     internal::WorkerPoolTask* raster_task,
    508     const TaskVector& decode_tasks,
    509     unsigned priority,
    510     TaskGraph* graph) {
    511   DCHECK(!raster_task->HasCompleted());
    512 
    513   internal::GraphNode* raster_node = CreateGraphNodeForTask(
    514       raster_task, priority, graph);
    515 
    516   // Insert image decode tasks.
    517   for (TaskVector::const_iterator it = decode_tasks.begin();
    518        it != decode_tasks.end(); ++it) {
    519     internal::WorkerPoolTask* decode_task = it->get();
    520 
    521     // Skip if already decoded.
    522     if (decode_task->HasCompleted())
    523       continue;
    524 
    525     raster_node->add_dependency();
    526 
    527     // Check if decode task already exists in graph.
    528     GraphNodeMap::iterator decode_it = graph->find(decode_task);
    529     if (decode_it != graph->end()) {
    530       internal::GraphNode* decode_node = decode_it->second;
    531       decode_node->add_dependent(raster_node);
    532       continue;
    533     }
    534 
    535     internal::GraphNode* decode_node = CreateGraphNodeForTask(
    536         decode_task, priority, graph);
    537     decode_node->add_dependent(raster_node);
    538   }
    539 
    540   return raster_node;
    541 }
    542 
    543 }  // namespace cc
    544