1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192

cc / tiles / image_controller.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_TILES_IMAGE_CONTROLLER_H_
#define CC_TILES_IMAGE_CONTROLLER_H_

#include <map>
#include <memory>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "base/thread_annotations.h"
#include "cc/base/unique_notifier.h"
#include "cc/cc_export.h"
#include "cc/paint/draw_image.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/image_decode_cache.h"

namespace cc {

class CC_EXPORT ImageController {
 public:
  enum class ImageDecodeResult { SUCCESS, DECODE_NOT_REQUIRED, FAILURE };

  using ImageDecodeRequestId = uint64_t;
  using ImageDecodedCallback =
      base::OnceCallback<void(ImageDecodeRequestId, ImageDecodeResult)>;
  explicit ImageController(
      scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
      scoped_refptr<base::SequencedTaskRunner> worker_task_runner,
      base::RepeatingCallback<void(scoped_refptr<TileTask>)>
          notify_external_dependent);
  ImageController(const ImageController&) = delete;
  virtual ~ImageController();

  ImageController& operator=(const ImageController&) = delete;

  void SetImageDecodeCache(ImageDecodeCache* cache);
  // Build tile tasks for synchronously decoded images.
  // |sync_decoded_images| is the input. These are the images from a particular
  // tile, retrieved by the DiscardableImageMap. Images can be removed from the
  // vector under certain conditions.
  // |tasks| is an output, which are the built tile tasks.
  // |has_at_raster_images| is an output parameter.
  // |has_hardware_accelerated_jpeg_candidates| and
  // |has_hardware_accelerated_webp_candidates| are output parameters that
  // indicate if there are images in |sync_decoded_images| that could be decoded
  // using hardware decode acceleration.
  // |tracing_info| is used in tracing or UMA only.
  void ConvertImagesToTasks(std::vector<DrawImage>* sync_decoded_images,
                            std::vector<scoped_refptr<TileTask>>* tasks,
                            bool* has_at_raster_images,
                            bool* has_hardware_accelerated_jpeg_candidates,
                            bool* has_hardware_accelerated_webp_candidates,
                            const ImageDecodeCache::TracingInfo& tracing_info);
  void UnrefImages(const std::vector<DrawImage>& images);
  void ReduceMemoryUsage();
  std::vector<scoped_refptr<TileTask>> SetPredecodeImages(
      std::vector<DrawImage> predecode_images,
      const ImageDecodeCache::TracingInfo& tracing_info);

  // Virtual for testing.
  virtual void UnlockImageDecode(ImageDecodeRequestId id);

  // This function requests that the given image be decoded and locked. Once the
  // callback has been issued, it is passed an ID, which should be used to
  // unlock this image. It is up to the caller to ensure that the image is later
  // unlocked using UnlockImageDecode.
  // Virtual for testing.
  virtual ImageDecodeRequestId QueueImageDecode(const DrawImage& draw_image,
                                                ImageDecodedCallback callback);

  // Signals that an external dependency of `task` has completed.
  void ExternalDependencyCompletedForTask(scoped_refptr<TileTask> task);

  size_t image_cache_max_limit_bytes() const {
    return image_cache_max_limit_bytes_;
  }

  void SetMaxImageCacheLimitBytesForTesting(size_t bytes) {
    image_cache_max_limit_bytes_ = bytes;
  }

  bool HasReadyToRunTaskForTesting() const;

  void FlushDecodeTasksForTesting();

  ImageDecodeCache* cache() const { return cache_; }

 protected:
  scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;

 private:
  struct ImageDecodeRequest {
    ImageDecodeRequest();
    ImageDecodeRequest(ImageDecodeRequestId id,
                       const DrawImage& draw_image,
                       ImageDecodedCallback callback,
                       scoped_refptr<TileTask> task,
                       bool need_unref,
                       bool has_external_dependency);
    ImageDecodeRequest(ImageDecodeRequest&& other);
    ~ImageDecodeRequest();

    ImageDecodeRequest& operator=(ImageDecodeRequest&& other);

    ImageDecodeRequestId id;
    DrawImage draw_image;
    ImageDecodedCallback callback;
    scoped_refptr<TileTask> task;
    bool need_unref;
    bool has_external_dependency;
  };

  enum class WorkerTaskState {
    kNoTask,
    kQueuedTask,
    kRunningTask,
  };

  // State accessible from the worker thread. Held in a isolated struct so it
  // can be deleted asynchronously on the worker thread after the
  // ImageController is deleted.
  struct WorkerState {
    WorkerState(scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
                base::WeakPtr<ImageController> weak_ptr);
    ~WorkerState();

    base::Lock lock;
    std::map<ImageDecodeRequestId, ImageDecodeRequest> image_decode_queue
        GUARDED_BY(lock);
    std::map<ImageDecodeRequestId, ImageDecodeRequest>
        requests_needing_completion GUARDED_BY(lock);
    WorkerTaskState task_state GUARDED_BY(lock) = WorkerTaskState::kNoTask;

    const scoped_refptr<base::SequencedTaskRunner> origin_task_runner;
    const base::WeakPtr<ImageController> weak_ptr;
  };

  void StopWorkerTasks();

  bool HasReadyToRunTask() const;

  static void ProcessNextImageDecodeOnWorkerThread(WorkerState* worker_state);
  static void ProcessNextImageDecodeWithLock(WorkerState* worker_state);

  void ImageDecodeCompleted(ImageDecodeRequestId id);
  ImageDecodeResult CompleteTaskForRequest(ImageDecodeRequest& request);
  void GenerateTasksForOrphanedRequests();

  void ScheduleImageDecodeOnWorkerIfNeeded()
      EXCLUSIVE_LOCKS_REQUIRED(worker_state_->lock);

  // RAW_PTR_EXCLUSION: ImageDecodeCache is marked as not supported by raw_ptr.
  // See raw_ptr.h for more information.
  RAW_PTR_EXCLUSION ImageDecodeCache* cache_ = nullptr;
  std::vector<DrawImage> predecode_locked_images_;

  static ImageDecodeRequestId s_next_image_decode_queue_id_;
  base::flat_map<ImageDecodeRequestId, DrawImage> requested_locked_images_;
  size_t image_cache_max_limit_bytes_ = 0u;

  std::unique_ptr<WorkerState> worker_state_;
  base::RepeatingClosure worker_task_;

  const base::RepeatingCallback<void(scoped_refptr<TileTask>)>
      notify_external_dependent_;

  // Orphaned requests are requests that were either in queue or needed a
  // completion callback when we set the decode cache to be nullptr. When a new
  // decode cache is set, these requests are re-enqueued again with tasks
  // generated by the new cache. Note that when the cache is set, then aside
  // from generating new tasks, this vector should be empty.
  std::vector<ImageDecodeRequest> orphaned_decode_requests_;

  // The id generated by ImageDecodeCache instance to identify this client
  // instance when requesting image tasks.
  ImageDecodeCache::ClientId image_cache_client_id_ = 0;

  base::WeakPtrFactory<ImageController> weak_ptr_factory_{this};
};

}  // namespace cc

#endif  // CC_TILES_IMAGE_CONTROLLER_H_