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/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(
     91         content_rect_, contents_scale_, &analysis_, rendering_stats_);
     92 
     93     // Record the solid color prediction.
     94     UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
     95                           analysis_.is_solid_color);
     96 
     97     // Clear the flag if we're not using the estimator.
     98     analysis_.is_solid_color &= kUseColorEstimator;
     99   }
    100 
    101   bool RunRasterOnThread(unsigned thread_index,
    102                          void* buffer,
    103                          gfx::Size size,
    104                          int stride) {
    105     TRACE_EVENT2(
    106         "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread",
    107         "data",
    108         TracedValue::FromValue(DataAsValue().release()),
    109         "raster_mode",
    110         TracedValue::FromValue(RasterModeAsValue(raster_mode_).release()));
    111 
    112     devtools_instrumentation::ScopedLayerTask raster_task(
    113         devtools_instrumentation::kRasterTask, layer_id_);
    114 
    115     DCHECK(picture_pile_.get());
    116     DCHECK(buffer);
    117 
    118     if (analysis_.is_solid_color)
    119       return false;
    120 
    121     PicturePileImpl* picture_clone =
    122         picture_pile_->GetCloneForDrawingOnThread(thread_index);
    123 
    124     SkBitmap bitmap;
    125     switch (resource()->format()) {
    126       case RGBA_4444:
    127         // Use the default stride if we will eventually convert this
    128         // bitmap to 4444.
    129         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
    130                          size.width(),
    131                          size.height());
    132         bitmap.allocPixels();
    133         break;
    134       case RGBA_8888:
    135       case BGRA_8888:
    136         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
    137                          size.width(),
    138                          size.height(),
    139                          stride);
    140         bitmap.setPixels(buffer);
    141         break;
    142       case LUMINANCE_8:
    143       case RGB_565:
    144       case ETC1:
    145         NOTREACHED();
    146         break;
    147     }
    148 
    149     SkBitmapDevice device(bitmap);
    150     SkCanvas canvas(&device);
    151     skia::RefPtr<SkDrawFilter> draw_filter;
    152     switch (raster_mode_) {
    153       case LOW_QUALITY_RASTER_MODE:
    154         draw_filter = skia::AdoptRef(new skia::PaintSimplifier);
    155         break;
    156       case HIGH_QUALITY_NO_LCD_RASTER_MODE:
    157         draw_filter = skia::AdoptRef(new DisableLCDTextFilter);
    158         break;
    159       case HIGH_QUALITY_RASTER_MODE:
    160         break;
    161       case NUM_RASTER_MODES:
    162       default:
    163         NOTREACHED();
    164     }
    165 
    166     canvas.setDrawFilter(draw_filter.get());
    167 
    168     base::TimeDelta prev_rasterize_time =
    169         rendering_stats_->impl_thread_rendering_stats().rasterize_time;
    170 
    171     // Only record rasterization time for highres tiles, because
    172     // lowres tiles are not required for activation and therefore
    173     // introduce noise in the measurement (sometimes they get rasterized
    174     // before we draw and sometimes they aren't)
    175     if (tile_resolution_ == HIGH_RESOLUTION) {
    176       picture_clone->RasterToBitmap(
    177           &canvas, content_rect_, contents_scale_, rendering_stats_);
    178     } else {
    179       picture_clone->RasterToBitmap(
    180           &canvas, content_rect_, contents_scale_, NULL);
    181     }
    182 
    183     if (rendering_stats_->record_rendering_stats()) {
    184       base::TimeDelta current_rasterize_time =
    185           rendering_stats_->impl_thread_rendering_stats().rasterize_time;
    186       HISTOGRAM_CUSTOM_COUNTS(
    187           "Renderer4.PictureRasterTimeUS",
    188           (current_rasterize_time - prev_rasterize_time).InMicroseconds(),
    189           0,
    190           100000,
    191           100);
    192     }
    193 
    194     ChangeBitmapConfigIfNeeded(bitmap, buffer);
    195 
    196     return true;
    197   }
    198 
    199   // Overridden from internal::RasterWorkerPoolTask:
    200   virtual bool RunOnWorkerThread(unsigned thread_index,
    201                                  void* buffer,
    202                                  gfx::Size size,
    203                                  int stride)
    204       OVERRIDE {
    205     RunAnalysisOnThread(thread_index);
    206     return RunRasterOnThread(thread_index, buffer, size, stride);
    207   }
    208   virtual void CompleteOnOriginThread() OVERRIDE {
    209     reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled());
    210   }
    211 
    212  protected:
    213   virtual ~RasterWorkerPoolTaskImpl() {}
    214 
    215  private:
    216   scoped_ptr<base::Value> DataAsValue() const {
    217     scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
    218     res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release());
    219     res->Set("resolution", TileResolutionAsValue(tile_resolution_).release());
    220     res->SetInteger("source_frame_number", source_frame_number_);
    221     res->SetInteger("layer_id", layer_id_);
    222     return res.PassAs<base::Value>();
    223   }
    224 
    225   void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap,
    226                                   void* buffer) {
    227     TRACE_EVENT0("cc", "RasterWorkerPoolTaskImpl::ChangeBitmapConfigIfNeeded");
    228     SkBitmap::Config config = SkBitmapConfig(resource()->format());
    229     if (bitmap.getConfig() != config) {
    230       SkBitmap bitmap_dest;
    231       IdentityAllocator allocator(buffer);
    232       bitmap.copyTo(&bitmap_dest, config, &allocator);
    233       // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
    234       // bitmap data. This check will be removed once crbug.com/293728 is fixed.
    235       CHECK_EQ(0u, bitmap_dest.rowBytes() % 4);
    236     }
    237   }
    238 
    239   PicturePileImpl::Analysis analysis_;
    240   scoped_refptr<PicturePileImpl> picture_pile_;
    241   gfx::Rect content_rect_;
    242   float contents_scale_;
    243   RasterMode raster_mode_;
    244   TileResolution tile_resolution_;
    245   int layer_id_;
    246   const void* tile_id_;
    247   int source_frame_number_;
    248   RenderingStatsInstrumentation* rendering_stats_;
    249   const RasterWorkerPool::RasterTask::Reply reply_;
    250 
    251   DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl);
    252 };
    253 
    254 class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
    255  public:
    256   ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref,
    257                                 int layer_id,
    258                                 RenderingStatsInstrumentation* rendering_stats,
    259                                 const RasterWorkerPool::Task::Reply& reply)
    260       : pixel_ref_(skia::SharePtr(pixel_ref)),
    261         layer_id_(layer_id),
    262         rendering_stats_(rendering_stats),
    263         reply_(reply) {}
    264 
    265   // Overridden from internal::WorkerPoolTask:
    266   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
    267     TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread");
    268     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
    269         pixel_ref_.get());
    270     pixel_ref_->Decode();
    271   }
    272   virtual void CompleteOnOriginThread() OVERRIDE {
    273     reply_.Run(!HasFinishedRunning());
    274   }
    275 
    276  protected:
    277   virtual ~ImageDecodeWorkerPoolTaskImpl() {}
    278 
    279  private:
    280   skia::RefPtr<skia::LazyPixelRef> pixel_ref_;
    281   int layer_id_;
    282   RenderingStatsInstrumentation* rendering_stats_;
    283   const RasterWorkerPool::Task::Reply reply_;
    284 
    285   DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl);
    286 };
    287 
    288 class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
    289  public:
    290   typedef base::Callback<void(const internal::WorkerPoolTask* source)>
    291       Callback;
    292 
    293   RasterFinishedWorkerPoolTaskImpl(
    294       const Callback& on_raster_finished_callback)
    295       : origin_loop_(base::MessageLoopProxy::current().get()),
    296         on_raster_finished_callback_(on_raster_finished_callback) {
    297   }
    298 
    299   // Overridden from internal::WorkerPoolTask:
    300   virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
    301     TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
    302     origin_loop_->PostTask(
    303         FROM_HERE,
    304         base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread,
    305                    this));
    306   }
    307   virtual void CompleteOnOriginThread() OVERRIDE {}
    308 
    309  private:
    310   virtual ~RasterFinishedWorkerPoolTaskImpl() {}
    311 
    312   void RunOnOriginThread() const {
    313     on_raster_finished_callback_.Run(this);
    314   }
    315 
    316   scoped_refptr<base::MessageLoopProxy> origin_loop_;
    317   const Callback on_raster_finished_callback_;
    318 
    319   DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
    320 };
    321 
    322 const char* kWorkerThreadNamePrefix = "CompositorRaster";
    323 
    324 }  // namespace
    325 
    326 namespace internal {
    327 
    328 RasterWorkerPoolTask::RasterWorkerPoolTask(
    329     const Resource* resource, TaskVector* dependencies)
    330     : did_run_(false),
    331       did_complete_(false),
    332       was_canceled_(false),
    333       resource_(resource) {
    334   dependencies_.swap(*dependencies);
    335 }
    336 
    337 RasterWorkerPoolTask::~RasterWorkerPoolTask() {
    338 }
    339 
    340 void RasterWorkerPoolTask::DidRun(bool was_canceled) {
    341   DCHECK(!did_run_);
    342   did_run_ = true;
    343   was_canceled_ = was_canceled;
    344 }
    345 
    346 bool RasterWorkerPoolTask::HasFinishedRunning() const {
    347   return did_run_;
    348 }
    349 
    350 bool RasterWorkerPoolTask::WasCanceled() const {
    351   return was_canceled_;
    352 }
    353 
    354 void RasterWorkerPoolTask::WillComplete() {
    355   DCHECK(!did_complete_);
    356 }
    357 
    358 void RasterWorkerPoolTask::DidComplete() {
    359   DCHECK(!did_complete_);
    360   did_complete_ = true;
    361 }
    362 
    363 bool RasterWorkerPoolTask::HasCompleted() const {
    364   return did_complete_;
    365 }
    366 
    367 }  // namespace internal
    368 
    369 RasterWorkerPool::Task::Set::Set() {
    370 }
    371 
    372 RasterWorkerPool::Task::Set::~Set() {
    373 }
    374 
    375 void RasterWorkerPool::Task::Set::Insert(const Task& task) {
    376   DCHECK(!task.is_null());
    377   tasks_.push_back(task.internal_);
    378 }
    379 
    380 RasterWorkerPool::Task::Task() {
    381 }
    382 
    383 RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal)
    384     : internal_(internal) {
    385 }
    386 
    387 RasterWorkerPool::Task::~Task() {
    388 }
    389 
    390 void RasterWorkerPool::Task::Reset() {
    391   internal_ = NULL;
    392 }
    393 
    394 RasterWorkerPool::RasterTask::Queue::Queue() {
    395 }
    396 
    397 RasterWorkerPool::RasterTask::Queue::~Queue() {
    398 }
    399 
    400 void RasterWorkerPool::RasterTask::Queue::Append(
    401     const RasterTask& task, bool required_for_activation) {
    402   DCHECK(!task.is_null());
    403   tasks_.push_back(task.internal_);
    404   if (required_for_activation)
    405     tasks_required_for_activation_.insert(task.internal_.get());
    406 }
    407 
    408 RasterWorkerPool::RasterTask::RasterTask() {
    409 }
    410 
    411 RasterWorkerPool::RasterTask::RasterTask(
    412     internal::RasterWorkerPoolTask* internal)
    413     : internal_(internal) {
    414 }
    415 
    416 void RasterWorkerPool::RasterTask::Reset() {
    417   internal_ = NULL;
    418 }
    419 
    420 RasterWorkerPool::RasterTask::~RasterTask() {
    421 }
    422 
    423 // static
    424 RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask(
    425     const Resource* resource,
    426     PicturePileImpl* picture_pile,
    427     gfx::Rect content_rect,
    428     float contents_scale,
    429     RasterMode raster_mode,
    430     TileResolution tile_resolution,
    431     int layer_id,
    432     const void* tile_id,
    433     int source_frame_number,
    434     RenderingStatsInstrumentation* rendering_stats,
    435     const RasterTask::Reply& reply,
    436     Task::Set* dependencies) {
    437   return RasterTask(
    438       new RasterWorkerPoolTaskImpl(resource,
    439                                    picture_pile,
    440                                    content_rect,
    441                                    contents_scale,
    442                                    raster_mode,
    443                                    tile_resolution,
    444                                    layer_id,
    445                                    tile_id,
    446                                    source_frame_number,
    447                                    rendering_stats,
    448                                    reply,
    449                                    &dependencies->tasks_));
    450 }
    451 
    452 // static
    453 RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask(
    454     skia::LazyPixelRef* pixel_ref,
    455     int layer_id,
    456     RenderingStatsInstrumentation* stats_instrumentation,
    457     const Task::Reply& reply) {
    458   return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref,
    459                                                 layer_id,
    460                                                 stats_instrumentation,
    461                                                 reply));
    462 }
    463 
    464 RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider,
    465                                    size_t num_threads)
    466     : WorkerPool(num_threads, kWorkerThreadNamePrefix),
    467       client_(NULL),
    468       resource_provider_(resource_provider),
    469       weak_ptr_factory_(this) {
    470 }
    471 
    472 RasterWorkerPool::~RasterWorkerPool() {
    473 }
    474 
    475 void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
    476   client_ = client;
    477 }
    478 
    479 void RasterWorkerPool::Shutdown() {
    480   raster_tasks_.clear();
    481   TaskGraph empty;
    482   SetTaskGraph(&empty);
    483   WorkerPool::Shutdown();
    484   weak_ptr_factory_.InvalidateWeakPtrs();
    485 }
    486 
    487 void RasterWorkerPool::SetRasterTasks(RasterTask::Queue* queue) {
    488   raster_tasks_.swap(queue->tasks_);
    489   raster_tasks_required_for_activation_.swap(
    490       queue->tasks_required_for_activation_);
    491 }
    492 
    493 bool RasterWorkerPool::IsRasterTaskRequiredForActivation(
    494     internal::RasterWorkerPoolTask* task) const {
    495   return
    496       raster_tasks_required_for_activation_.find(task) !=
    497       raster_tasks_required_for_activation_.end();
    498 }
    499 
    500 scoped_refptr<internal::WorkerPoolTask>
    501     RasterWorkerPool::CreateRasterFinishedTask() {
    502   return make_scoped_refptr(
    503       new RasterFinishedWorkerPoolTaskImpl(
    504           base::Bind(&RasterWorkerPool::OnRasterFinished,
    505                      weak_ptr_factory_.GetWeakPtr())));
    506 }
    507 
    508 scoped_refptr<internal::WorkerPoolTask>
    509     RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask() {
    510   return make_scoped_refptr(
    511       new RasterFinishedWorkerPoolTaskImpl(
    512           base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished,
    513                      weak_ptr_factory_.GetWeakPtr())));
    514 }
    515 
    516 void RasterWorkerPool::OnRasterFinished(
    517     const internal::WorkerPoolTask* source) {
    518   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");
    519 
    520   // Early out if current |raster_finished_task_| is not the source.
    521   if (source != raster_finished_task_.get())
    522     return;
    523 
    524   OnRasterTasksFinished();
    525 }
    526 
    527 void RasterWorkerPool::OnRasterRequiredForActivationFinished(
    528     const internal::WorkerPoolTask* source) {
    529   TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");
    530 
    531   // Early out if current |raster_required_for_activation_finished_task_|
    532   // is not the source.
    533   if (source != raster_required_for_activation_finished_task_.get())
    534     return;
    535 
    536   OnRasterTasksRequiredForActivationFinished();
    537 }
    538 
    539 scoped_ptr<base::Value> RasterWorkerPool::ScheduledStateAsValue() const {
    540   scoped_ptr<base::DictionaryValue> scheduled_state(new base::DictionaryValue);
    541   scheduled_state->SetInteger("task_count", raster_tasks_.size());
    542   scheduled_state->SetInteger("task_required_for_activation_count",
    543                               raster_tasks_required_for_activation_.size());
    544   return scheduled_state.PassAs<base::Value>();
    545 }
    546 
    547 // static
    548 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask(
    549     internal::WorkerPoolTask* task,
    550     unsigned priority,
    551     TaskGraph* graph) {
    552   internal::GraphNode* node = new internal::GraphNode(task, priority);
    553   DCHECK(graph->find(task) == graph->end());
    554   graph->set(task, make_scoped_ptr(node));
    555   return node;
    556 }
    557 
    558 // static
    559 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask(
    560     internal::WorkerPoolTask* raster_task,
    561     const TaskVector& decode_tasks,
    562     unsigned priority,
    563     TaskGraph* graph) {
    564   DCHECK(!raster_task->HasCompleted());
    565 
    566   internal::GraphNode* raster_node = CreateGraphNodeForTask(
    567       raster_task, priority, graph);
    568 
    569   // Insert image decode tasks.
    570   for (TaskVector::const_iterator it = decode_tasks.begin();
    571        it != decode_tasks.end(); ++it) {
    572     internal::WorkerPoolTask* decode_task = it->get();
    573 
    574     // Skip if already decoded.
    575     if (decode_task->HasCompleted())
    576       continue;
    577 
    578     raster_node->add_dependency();
    579 
    580     // Check if decode task already exists in graph.
    581     GraphNodeMap::iterator decode_it = graph->find(decode_task);
    582     if (decode_it != graph->end()) {
    583       internal::GraphNode* decode_node = decode_it->second;
    584       decode_node->add_dependent(raster_node);
    585       continue;
    586     }
    587 
    588     internal::GraphNode* decode_node = CreateGraphNodeForTask(
    589         decode_task, priority, graph);
    590     decode_node->add_dependent(raster_node);
    591   }
    592 
    593   return raster_node;
    594 }
    595 
    596 }  // namespace cc
    597