Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: cc/tiles/image_decode_controller.cc

Issue 1385733002: (not for review) nwayover (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/tiles/image_decode_controller.h ('k') | cc/tiles/tile_manager.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/tiles/image_decode_controller.h" 5 #include "cc/tiles/image_decode_controller.h"
6 6
7 #include "cc/debug/devtools_instrumentation.h" 7 #include "cc/debug/devtools_instrumentation.h"
8 #include "third_party/skia/include/core/SkCanvas.h"
9 #include "base/memory/discardable_memory.h"
8 10
9 namespace cc { 11 namespace cc {
10 namespace { 12 namespace {
11 13
12 class ImageDecodeTaskImpl : public ImageDecodeTask { 14 class ImageDecodeTaskImpl : public ImageDecodeTask {
13 public: 15 public:
14 ImageDecodeTaskImpl(ImageDecodeController* controller, 16 ImageDecodeTaskImpl(ImageDecodeController* controller,
15 const SkImage* image, 17 const ImageDecodeController::ImageKey& image_key,
16 int layer_id, 18 const PositionImage& image,
17 uint64_t source_prepare_tiles_id) 19 uint64_t source_prepare_tiles_id)
18 : controller_(controller), 20 : controller_(controller),
19 image_(skia::SharePtr(image)), 21 image_key_(image_key),
20 layer_id_(layer_id), 22 image_(image),
23 image_ref_(skia::SharePtr(image.image)),
21 source_prepare_tiles_id_(source_prepare_tiles_id) {} 24 source_prepare_tiles_id_(source_prepare_tiles_id) {}
22 25
23 // Overridden from Task: 26 // Overridden from Task:
24 void RunOnWorkerThread() override { 27 void RunOnWorkerThread() override {
25 TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", 28 TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread",
26 "source_prepare_tiles_id", source_prepare_tiles_id_); 29 "source_prepare_tiles_id", source_prepare_tiles_id_);
27 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( 30 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
28 image_.get()); 31 image_ref_.get());
29 controller_->DecodeImage(image_.get()); 32 controller_->DecodeImage(image_key_, image_);
30 33
31 // Release the reference after decoding image to ensure that it is not kept 34 // Release the reference after decoding image to ensure that it is not kept
32 // alive unless needed. 35 // alive unless needed.
33 image_.clear(); 36 image_ref_.clear();
34 } 37 }
35 38
36 // Overridden from TileTask: 39 // Overridden from TileTask:
37 void ScheduleOnOriginThread(TileTaskClient* client) override {} 40 void ScheduleOnOriginThread(TileTaskClient* client) override {}
38 void CompleteOnOriginThread(TileTaskClient* client) override { 41 void CompleteOnOriginThread(TileTaskClient* client) override {
39 controller_->OnImageDecodeTaskCompleted(layer_id_, image_.get(), 42 controller_->OnImageDecodeTaskCompleted(image_key_, !HasFinishedRunning());
40 !HasFinishedRunning());
41 } 43 }
42 44
43 protected: 45 protected:
44 ~ImageDecodeTaskImpl() override {} 46 ~ImageDecodeTaskImpl() override {}
45 47
46 private: 48 private:
47 ImageDecodeController* controller_; 49 ImageDecodeController* controller_;
48 skia::RefPtr<const SkImage> image_; 50 ImageDecodeController::ImageKey image_key_;
49 int layer_id_; 51 PositionImage image_;
52 skia::RefPtr<const SkImage> image_ref_;
50 uint64_t source_prepare_tiles_id_; 53 uint64_t source_prepare_tiles_id_;
51 54
52 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); 55 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
53 }; 56 };
54 57
58 // Return the scaled size of the image under the given transformation.
59 gfx::Size ExtractSizeFromImage(const SkImage* image,
60 const SkMatrix& total_matrix) {
61 SkSize scale =
62 SkSize::Make(total_matrix.getScaleX(), total_matrix.getScaleY());
63 if (total_matrix.getType() & SkMatrix::kAffine_Mask) {
64 if (!total_matrix.decomposeScale(&scale))
65 scale.set(1, 1);
66 }
67
68 return gfx::Size(
69 std::abs(SkScalarRoundToInt(image->width() * scale.width())),
70 std::abs(SkScalarRoundToInt(image->height() * scale.height())));
71 }
72
55 } // namespace 73 } // namespace
56 74
57 ImageDecodeController::ImageDecodeController() {} 75 ImageDecodeController::ImageDecodeController() {}
58 76
59 ImageDecodeController::~ImageDecodeController() {} 77 ImageDecodeController::~ImageDecodeController() {}
60 78
61 scoped_refptr<ImageDecodeTask> ImageDecodeController::GetTaskForImage( 79 scoped_refptr<ImageDecodeTask> ImageDecodeController::GetTaskForImage(
62 const PositionImage& image, 80 const PositionImage& image,
63 int layer_id,
64 uint64_t prepare_tiles_id) { 81 uint64_t prepare_tiles_id) {
65 uint32_t generation_id = image.image->uniqueID(); 82 ImageKey key =
66 scoped_refptr<ImageDecodeTask>& decode_task = 83 ImageKey::FromImageData(image.image, image.matrix, image.filter_quality);
67 image_decode_tasks_[layer_id][generation_id]; 84 if (LockDecodedImageIfPossible(key))
68 if (!decode_task) 85 return nullptr;
69 decode_task = CreateTaskForImage(image.image, layer_id, prepare_tiles_id); 86
70 return decode_task; 87 auto decode_task_iterator =
88 std::find_if(pending_image_tasks_.begin(), pending_image_tasks_.end(),
89 [key](const AnnotatedDecodeTask& annotated_task) {
90 return key == annotated_task.first;
91 });
92 // If the task doesn't exist, create it.
93 if (decode_task_iterator == pending_image_tasks_.end()) {
94 pending_image_tasks_.push_back(AnnotatedDecodeTask(
95 key, CreateTaskForImage(key, image, prepare_tiles_id)));
96 return pending_image_tasks_.back().second;
97 }
98 return decode_task_iterator->second;
99 }
100
101 bool ImageDecodeController::LockDecodedImageIfPossible(const ImageKey& key) {
102 base::AutoLock lock(lock_);
103 auto decoded_images_iterator =
104 std::find_if(decoded_images_.begin(), decoded_images_.end(),
105 [key](const AnnotatedDecodedImage& annotated_image) {
106 return key == annotated_image.first;
107 });
108 if (decoded_images_iterator == decoded_images_.end())
109 return false;
110
111 scoped_refptr<DecodedImage>& decoded_image = decoded_images_iterator->second;
112
113 // Figure out if the image is locked or try to lock it.
114 bool locked = decoded_image->is_locked();
115 if (!locked)
116 locked = decoded_image->Lock();
117
118 if (locked)
119 return true;
120
121 // If we couldn't lock the image, then we might as well clean up the entry in
122 // the cache, since for all intents and purposes it is a cache miss.
123 decoded_images_.erase(decoded_images_iterator);
124 return false;
71 } 125 }
72 126
73 scoped_refptr<ImageDecodeTask> ImageDecodeController::CreateTaskForImage( 127 scoped_refptr<ImageDecodeTask> ImageDecodeController::CreateTaskForImage(
74 const SkImage* image, 128 const ImageKey& key,
75 int layer_id, 129 const PositionImage& image,
76 uint64_t prepare_tiles_id) { 130 uint64_t prepare_tiles_id) {
77 return make_scoped_refptr( 131 return make_scoped_refptr(
78 new ImageDecodeTaskImpl(this, image, layer_id, prepare_tiles_id)); 132 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id));
79 } 133 }
80 134
81 void ImageDecodeController::DecodeImage(const SkImage* image) { 135 void ImageDecodeController::DecodeImage(const ImageKey& key,
82 image->preroll(); 136 const PositionImage& image) {
137 // For low quality, just decode the original image.
138 if (image.filter_quality == kLow_SkFilterQuality) {
139 image.image->preroll();
140 return;
141 }
142
143 // TODO(vmpstr): We need to start generating/caching mipmaps here (if needed)
144 // and interpolating the image between the nearest mipmaps.
145 if (image.filter_quality == kMedium_SkFilterQuality) {
146 image.image->preroll();
147 return;
148 }
149
150 // TODO(vmpstr, reed): Scale the image here without caching it in skia.
151 SkImageInfo info = SkImageInfo::MakeN32Premul(key.target_size().width(),
152 key.target_size().height());
153 scoped_ptr<base::DiscardableMemory> locked_memory =
154 base::DiscardableMemoryAllocator::GetInstance()
155 ->AllocateLockedDiscardableMemory(info.minRowBytes() * info.height());
156
157 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRasterDirect(
158 info, locked_memory->data(), info.minRowBytes()));
159 canvas->setMatrix(SkMatrix::MakeRectToRect(
160 SkRect::MakeWH(image.image->width(), image.image->height()),
161 SkRect::MakeWH(key.target_size().width(), key.target_size().height()),
162 SkMatrix::kFill_ScaleToFit));
163 canvas->clear(SK_ColorTRANSPARENT);
164 SkPaint paint;
165 paint.setFilterQuality(kHigh_SkFilterQuality);
166 canvas->drawImage(image.image, 0, 0, &paint);
167 canvas->flush();
168
169 // Add the image to the cache.
170 base::AutoLock lock(lock_);
171 decoded_images_.push_back(AnnotatedDecodedImage(
172 key, make_scoped_refptr(new DecodedImage(info, locked_memory.Pass()))));
83 } 173 }
84 174
85 void ImageDecodeController::AddLayerUsedCount(int layer_id) { 175 void ImageDecodeController::OnImageDecodeTaskCompleted(const ImageKey& key,
86 ++used_layer_counts_[layer_id]; 176 bool was_canceled) {
177 pending_image_tasks_.erase(
178 std::remove_if(
179 pending_image_tasks_.begin(), pending_image_tasks_.end(),
180 [key](const AnnotatedDecodeTask& task) { return key == task.first; }),
181 pending_image_tasks_.end());
87 } 182 }
88 183
89 void ImageDecodeController::SubtractLayerUsedCount(int layer_id) { 184 DecodedPositionImage ImageDecodeController::GetDecodedImage(
90 if (--used_layer_counts_[layer_id]) 185 const PositionImage& image) {
91 return; 186 // We don't cache low filter quality images.
187 if (image.filter_quality == kLow_SkFilterQuality) {
188 return DecodedPositionImage(image.image, SkSize::Make(1.f, 1.f),
189 image.filter_quality);
190 }
92 191
93 // Clean up decode tasks once a layer is no longer used. 192 // TODO(vmpstr): We need to start caching mipmaps for medium quality and
94 used_layer_counts_.erase(layer_id); 193 // caching the interpolated values from those. For now, pass these through
95 image_decode_tasks_.erase(layer_id); 194 // unchanged.
195 if (image.filter_quality == kMedium_SkFilterQuality) {
196 return DecodedPositionImage(image.image, SkSize::Make(1.f, 1.f),
197 image.filter_quality);
198 }
199
200 // XXX look up or decode. XXX XXX XXX XXX XXX XXX XXX XXX
201 // Also need to figure when to free the memory? When to unlock.
202 ImageKey key =
203 ImageKey::FromImageData(image.image, image.matrix, image.filter_quality);
204
205 base::AutoLock lock(lock_);
206 auto decoded_images_iterator =
207 std::find_if(decoded_images_.begin(), decoded_images_.end(),
208 [key](const AnnotatedDecodedImage& annotated_image) {
209 return key == annotated_image.first;
210 });
211 if (decoded_images_iterator != decoded_images_.end()) {
212 float x_scale =
213 key.target_size().width() / static_cast<float>(image.image->width());
214 float y_scale =
215 key.target_size().height() / static_cast<float>(image.image->height());
216
217 const scoped_refptr<DecodedImage>& decoded_image =
218 decoded_images_iterator->second;
219 return DecodedPositionImage(decoded_image->image(),
220 SkSize::Make(x_scale, y_scale),
221 kLow_SkFilterQuality);
222 }
223 CHECK(false);
224 return DecodedPositionImage(image.image, SkSize::Make(1.f, 1.f),
225 image.filter_quality);
96 } 226 }
97 227
98 void ImageDecodeController::OnImageDecodeTaskCompleted(int layer_id, 228 ImageDecodeController::ImageKey ImageDecodeController::ImageKey::FromImageData(
99 const SkImage* image, 229 const SkImage* image,
100 bool was_canceled) { 230 const SkMatrix& matrix,
101 // If the task has successfully finished, then keep the task until the layer 231 SkFilterQuality filter_quality) {
102 // is no longer in use. This ensures that we only decode a image once. 232 return ImageKey(image->uniqueID(), ExtractSizeFromImage(image, matrix),
103 // TODO(vmpstr): Remove this when decode lifetime is controlled by cc. 233 filter_quality);
104 if (!was_canceled) 234 }
105 return;
106 235
107 // Otherwise, we have to clean up the task so that a new one can be created if 236 ImageDecodeController::ImageKey::ImageKey(uint32_t image_id,
108 // we need to decode the image again. 237 const gfx::Size& size,
109 LayerImageTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id); 238 SkFilterQuality filter_quality)
110 if (layer_it == image_decode_tasks_.end()) 239 : image_id_(image_id), size_(size), filter_quality_(filter_quality) {}
111 return;
112 240
113 ImageTaskMap& image_tasks = layer_it->second; 241 // TODO(vmpstr): Not sure if this needs to do something. It could have some
114 ImageTaskMap::iterator task_it = image_tasks.find(image->uniqueID()); 242 // extra state to DCHECK if we pass it DecodedImage object as the context.
115 if (task_it == image_tasks.end()) 243 static void noop(const void* pixels, void* context) {}
116 return; 244
117 image_tasks.erase(task_it); 245 ImageDecodeController::DecodedImage::DecodedImage(
246 const SkImageInfo& info,
247 scoped_ptr<base::DiscardableMemory> memory)
248 : locked_(true), image_info_(info), memory_(memory.Pass()) {
249 CreateImageFromLockedMemory();
250 }
251
252 ImageDecodeController::DecodedImage::~DecodedImage() {}
253
254 bool ImageDecodeController::DecodedImage::Lock() {
255 DCHECK(!locked_);
256 bool success = memory_->Lock();
257 if (!success)
258 return false;
259 CreateImageFromLockedMemory();
260 return true;
261 }
262
263 void ImageDecodeController::DecodedImage::Unlock() {
264 DCHECK(locked_);
265 image_.clear();
266 memory_->Unlock();
267 locked_ = false;
268 }
269
270 void ImageDecodeController::DecodedImage::CreateImageFromLockedMemory() {
271 image_ = skia::AdoptRef(SkImage::NewFromRaster(
272 image_info_, memory_->data(), image_info_.minRowBytes(), &noop, nullptr));
118 } 273 }
119 274
120 } // namespace cc 275 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/image_decode_controller.h ('k') | cc/tiles/tile_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698