Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/gpu_image_decode_controller.h" | 5 #include "cc/tiles/gpu_image_decode_controller.h" |
| 6 | 6 |
| 7 #include "base/memory/discardable_memory_allocator.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "base/strings/stringprintf.h" | |
| 10 #include "base/thread_task_runner_handle.h" | |
| 7 #include "cc/debug/devtools_instrumentation.h" | 11 #include "cc/debug/devtools_instrumentation.h" |
| 12 #include "cc/output/context_provider.h" | |
| 8 #include "cc/raster/tile_task_runner.h" | 13 #include "cc/raster/tile_task_runner.h" |
| 14 #include "gpu/command_buffer/client/context_support.h" | |
| 15 #include "gpu/command_buffer/client/gles2_interface.h" | |
| 16 #include "gpu_image_decode_controller.h" | |
| 9 #include "skia/ext/refptr.h" | 17 #include "skia/ext/refptr.h" |
| 18 #include "skia/ext/texture_handle.h" | |
| 19 #include "third_party/skia/include/core/SkCanvas.h" | |
| 20 #include "third_party/skia/include/core/SkSurface.h" | |
| 21 #include "third_party/skia/include/gpu/GrContext.h" | |
| 22 #include "third_party/skia/include/gpu/GrTexture.h" | |
| 23 #include "ui/gfx/skia_util.h" | |
| 24 #include "ui/gl/trace_util.h" | |
| 10 | 25 |
| 11 namespace cc { | 26 namespace cc { |
| 27 namespace { | |
| 12 | 28 |
| 29 static const int kMaxGpuImageBytes = 1024 * 1024 * 96; | |
| 30 static const int kMaxDiscardableItems = 1000; | |
| 31 | |
| 32 // Returns true if an image would not be drawn and should therefore be | |
| 33 // skipped rather than decoded. | |
| 34 bool SkipImage(const DrawImage& draw_image) { | |
| 35 if (!SkIRect::Intersects(draw_image.src_rect(), draw_image.image()->bounds())) | |
| 36 return true; | |
| 37 if (draw_image.matrix_is_decomposable() && | |
| 38 (draw_image.scale().width() == 0 || draw_image.scale().height() == 0)) | |
|
vmpstr
2016/03/25 22:37:30
width() and height() are floats, so maybe check if
ericrk
2016/03/28 22:10:52
Done.
| |
| 39 return true; | |
| 40 return false; | |
| 41 } | |
| 42 | |
| 43 SkImage::DeferredTextureImageUsageParams ParamsFromDrawImage( | |
| 44 const DrawImage& draw_image) { | |
| 45 SkImage::DeferredTextureImageUsageParams params; | |
| 46 params.fMatrix = draw_image.matrix(); | |
| 47 params.fQuality = draw_image.filter_quality(); | |
| 48 | |
| 49 return params; | |
| 50 } | |
| 51 | |
| 52 SkImageInfo ImageInfoFromDrawImage(const DrawImage& draw_image) { | |
| 53 return SkImageInfo::MakeN32Premul(draw_image.image()->width(), | |
|
vmpstr
2016/03/25 22:37:29
The software idc changed to use different info dep
ericrk
2016/03/28 22:10:52
refactored both to use a new function in resource_
| |
| 54 draw_image.image()->height()); | |
| 55 } | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 // Task which decodes an image and stores the result in discardable memory. | |
| 60 // This task does not use GPU resources and can be run on any thread. | |
| 13 class ImageDecodeTaskImpl : public ImageDecodeTask { | 61 class ImageDecodeTaskImpl : public ImageDecodeTask { |
| 14 public: | 62 public: |
| 15 ImageDecodeTaskImpl(GpuImageDecodeController* controller, | 63 ImageDecodeTaskImpl(GpuImageDecodeController* controller, |
| 16 const DrawImage& image, | 64 const DrawImage& draw_image, |
| 17 uint64_t source_prepare_tiles_id) | 65 uint64_t source_prepare_tiles_id) |
| 18 : controller_(controller), | 66 : controller_(controller), |
| 19 image_(image), | 67 image_(draw_image), |
| 20 image_ref_(skia::SharePtr(image.image())), | 68 image_ref_(skia::SharePtr(draw_image.image())), |
| 21 source_prepare_tiles_id_(source_prepare_tiles_id) {} | 69 source_prepare_tiles_id_(source_prepare_tiles_id) {} |
| 22 | 70 |
| 23 // Overridden from Task: | 71 // Overridden from Task: |
| 24 void RunOnWorkerThread() override { | 72 void RunOnWorkerThread() override { |
| 25 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", "gpu", | 73 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", "gpu", |
| 26 "source_prepare_tiles_id", source_prepare_tiles_id_); | 74 "source_prepare_tiles_id", source_prepare_tiles_id_); |
| 27 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( | |
| 28 image_ref_.get()); | |
| 29 controller_->DecodeImage(image_); | 75 controller_->DecodeImage(image_); |
| 30 } | 76 } |
| 31 | 77 |
| 32 // Overridden from TileTask: | 78 // Overridden from TileTask: |
| 33 void ScheduleOnOriginThread(TileTaskClient* client) override {} | 79 void ScheduleOnOriginThread(TileTaskClient* client) override {} |
| 34 void CompleteOnOriginThread(TileTaskClient* client) override { | 80 void CompleteOnOriginThread(TileTaskClient* client) override { |
| 35 controller_->RemovePendingTaskForImage(image_); | 81 controller_->RemovePendingDecodeTaskForImage(image_); |
| 36 } | 82 } |
| 37 | 83 |
| 38 protected: | 84 protected: |
| 39 ~ImageDecodeTaskImpl() override {} | 85 ~ImageDecodeTaskImpl() override {} |
| 40 | 86 |
| 41 private: | 87 private: |
| 42 GpuImageDecodeController* controller_; | 88 GpuImageDecodeController* controller_; |
| 43 DrawImage image_; | 89 DrawImage image_; |
| 44 skia::RefPtr<const SkImage> image_ref_; | 90 skia::RefPtr<const SkImage> image_ref_; |
| 91 const uint64_t source_prepare_tiles_id_; | |
| 92 | |
| 93 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); | |
| 94 }; | |
| 95 | |
| 96 // Task which creates an image from decoded data. Typically this involves | |
| 97 // uploading data to the GPU, which requires this task be run on the non- | |
| 98 // concurrent thread. | |
| 99 class ImageUploadTaskImpl : public ImageDecodeTask { | |
| 100 public: | |
| 101 ImageUploadTaskImpl(GpuImageDecodeController* controller, | |
| 102 const DrawImage& draw_image, | |
| 103 uint64_t source_prepare_tiles_id) | |
| 104 : ImageDecodeTask(controller->GetImageDecodeTaskAndRefLocked( | |
| 105 draw_image, | |
| 106 source_prepare_tiles_id)), | |
| 107 controller_(controller), | |
| 108 image_(draw_image), | |
| 109 image_ref_(skia::SharePtr(draw_image.image())), | |
| 110 source_prepare_tiles_id_(source_prepare_tiles_id) {} | |
| 111 | |
| 112 // Override from Task: | |
| 113 void RunOnWorkerThread() override { | |
| 114 TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu", | |
| 115 "source_prepare_tiles_id", source_prepare_tiles_id_); | |
| 116 controller_->UploadImage(image_); | |
| 117 } | |
| 118 | |
| 119 void ScheduleOnOriginThread(TileTaskClient* client) override {} | |
| 120 void CompleteOnOriginThread(TileTaskClient* client) override { | |
| 121 // We're done with the image decode, so un-ref it. | |
| 122 controller_->UnrefImageDecode(image_); | |
| 123 controller_->RemovePendingUploadTaskForImage(image_); | |
| 124 } | |
| 125 | |
| 126 // Override from ImageDecodeTask: | |
| 127 bool SupportsConcurrentExecution() const override { return false; } | |
| 128 | |
| 129 protected: | |
| 130 ~ImageUploadTaskImpl() override {} | |
| 131 | |
| 132 private: | |
| 133 GpuImageDecodeController* controller_; | |
| 134 DrawImage image_; | |
| 135 skia::RefPtr<const SkImage> image_ref_; | |
| 45 uint64_t source_prepare_tiles_id_; | 136 uint64_t source_prepare_tiles_id_; |
| 46 | 137 |
| 47 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); | 138 DISALLOW_COPY_AND_ASSIGN(ImageUploadTaskImpl); |
| 48 }; | 139 }; |
| 49 | 140 |
| 50 GpuImageDecodeController::GpuImageDecodeController() {} | 141 GpuImageDecodeController::ImageData::ImageData(DecodedDataMode mode, |
| 142 size_t size) | |
| 143 : mode(mode), | |
| 144 size(size), | |
| 145 decoded_data_ref_count(0), | |
| 146 decoded_data_is_locked(false), | |
| 147 image_pending(false), | |
| 148 image_ref_count(0), | |
| 149 is_at_raster(false) {} | |
| 150 | |
| 151 GpuImageDecodeController::ImageData::~ImageData() = default; | |
| 152 | |
| 153 GpuImageDecodeController::GpuImageDecodeController(ContextProvider* context) | |
| 154 : image_data_(decltype(image_data_)::NO_AUTO_EVICT), | |
|
vmpstr
2016/03/25 22:37:29
Can you typedef the map in the header instead :)
ericrk
2016/03/28 22:10:52
haha, forgot I had this :P - sure.
| |
| 155 cached_items_limit_(kMaxDiscardableItems), | |
| 156 cached_bytes_limit_(kMaxGpuImageBytes), | |
| 157 bytes_used_(0), | |
| 158 context_(context), | |
| 159 context_threadsafe_proxy_(context->GrContext()->threadSafeProxy()) {} | |
| 51 | 160 |
| 52 GpuImageDecodeController::~GpuImageDecodeController() {} | 161 GpuImageDecodeController::~GpuImageDecodeController() {} |
| 53 | 162 |
| 54 bool GpuImageDecodeController::GetTaskForImageAndRef( | 163 bool GpuImageDecodeController::GetTaskForImageAndRef( |
| 55 const DrawImage& image, | 164 const DrawImage& draw_image, |
| 56 uint64_t prepare_tiles_id, | 165 uint64_t prepare_tiles_id, |
| 57 scoped_refptr<ImageDecodeTask>* task) { | 166 scoped_refptr<ImageDecodeTask>* task) { |
| 58 auto image_id = image.image()->uniqueID(); | 167 if (SkipImage(draw_image)) { |
| 59 base::AutoLock lock(lock_); | |
| 60 if (prerolled_images_.count(image_id) != 0) { | |
| 61 *task = nullptr; | 168 *task = nullptr; |
| 62 return false; | 169 return false; |
| 63 } | 170 } |
| 64 | 171 |
| 172 base::AutoLock lock(lock_); | |
| 173 | |
| 174 const auto image_id = draw_image.image()->uniqueID(); | |
| 175 | |
| 176 auto found = image_data_.Get(image_id); | |
| 177 if (found != image_data_.end() && found->second->uploaded_image) { | |
| 178 // The image is already uploaded. If the image is not at raster, all we have | |
| 179 // to do is ref and return it. If the image is at raster, we should | |
| 180 // convert it to a non-at-raster image if possible. Otherwise we will | |
| 181 // continue using it in at-raster mode. | |
| 182 if (found->second->is_at_raster) { | |
| 183 if (EnsureCapacityLocked(found->second->size)) { | |
| 184 // Convert to non-at-raster, we have room now. | |
| 185 found->second->is_at_raster = false; | |
| 186 } else { | |
| 187 // Image won't fit in memory, Do at-raster decode. | |
| 188 *task = nullptr; | |
| 189 return false; | |
| 190 } | |
| 191 } | |
| 192 RefImageLocked(draw_image); | |
| 193 *task = nullptr; | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 // We didn't have a pre-uploaded image. Create or find the upload task. | |
| 65 scoped_refptr<ImageDecodeTask>& existing_task = | 198 scoped_refptr<ImageDecodeTask>& existing_task = |
| 66 pending_image_tasks_[image_id]; | 199 pending_image_upload_tasks_[image_id]; |
| 200 if (!existing_task) { | |
|
vmpstr
2016/03/25 22:37:29
It might be less indentation to do
if (existing_t
ericrk
2016/03/28 22:10:52
sure... less indentation is good.
| |
| 201 // We will be decoding and uploading image data. Create a placeholder | |
| 202 // ImageData to hold the result. | |
| 203 scoped_ptr<ImageData> new_data; | |
| 204 ImageData* data; | |
| 205 if (found == image_data_.end()) { | |
| 206 new_data = NewImageData(draw_image); | |
| 207 data = new_data.get(); | |
| 208 } else { | |
| 209 data = found->second.get(); | |
| 210 } | |
| 211 | |
| 212 if (!EnsureCapacityLocked(data->size)) { | |
| 213 // Image won't fit in memory. Do at-raster decode. | |
| 214 *task = nullptr; | |
| 215 return false; | |
| 216 } | |
| 217 | |
| 218 if (new_data) | |
| 219 image_data_.Put(image_id, std::move(new_data)); | |
| 220 | |
| 221 bytes_used_ += data->size; | |
| 222 data->image_pending = true; | |
| 223 existing_task = make_scoped_refptr( | |
| 224 new ImageUploadTaskImpl(this, draw_image, prepare_tiles_id)); | |
| 225 } | |
| 226 | |
| 227 RefImageLocked(draw_image); | |
| 228 *task = existing_task; | |
| 229 return true; | |
| 230 } | |
| 231 | |
| 232 void GpuImageDecodeController::UnrefImage(const DrawImage& draw_image) { | |
| 233 base::AutoLock lock(lock_); | |
| 234 UnrefImageLocked(draw_image); | |
|
vmpstr
2016/03/25 22:37:30
There's two different uses of Locked it seems. One
ericrk
2016/03/28 22:10:52
Ok... let me know how the new names are.
| |
| 235 } | |
| 236 | |
| 237 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( | |
| 238 const DrawImage& draw_image) { | |
| 239 TRACE_EVENT0("cc", "GpuImageDecodeController::GetDecodedImageForDraw"); | |
| 240 if (SkipImage(draw_image)) | |
| 241 return DecodedDrawImage(nullptr, draw_image.filter_quality()); | |
| 242 | |
| 243 const uint32_t unique_id = draw_image.image()->uniqueID(); | |
| 244 | |
| 245 context_->GetLock()->AssertAcquired(); | |
| 246 base::AutoLock lock(lock_); | |
| 247 auto found = image_data_.Peek(unique_id); | |
| 248 if (found == image_data_.end()) { | |
| 249 auto data = NewImageData(draw_image); | |
| 250 if (!EnsureCapacityLocked(data->size)) { | |
|
vmpstr
2016/03/25 22:37:30
When would it be the case that we get to GetDecode
ericrk
2016/03/28 22:10:52
Likely not possible. Converting to a DCHECK, will
| |
| 251 // Image won't fit in memory. Mark it as at-raster so it will not be | |
| 252 // retained longer than necessary. | |
| 253 data->is_at_raster = true; | |
| 254 } | |
| 255 bytes_used_ += data->size; | |
| 256 data->image_pending = true; | |
| 257 found = image_data_.Put(unique_id, std::move(data)); | |
| 258 } | |
| 259 RefImageLocked(draw_image); | |
| 260 | |
| 261 // We may or may not need to decode and upload the image we've found, the | |
| 262 // following functions early-out to if we already decoded. | |
| 263 DecodeImageIfNecessaryLocked(draw_image, found->second.get()); | |
| 264 UploadImageIfNecessaryLocked(draw_image, found->second.get()); | |
| 265 SkImage* image = found->second->uploaded_image.get(); | |
|
vmpstr
2016/03/25 22:37:29
DCHECK(image)? or can it be null here?
ericrk
2016/03/28 22:10:52
Done.
| |
| 266 | |
| 267 DecodedDrawImage decoded_draw_image(image, draw_image.filter_quality()); | |
| 268 decoded_draw_image.set_at_raster_decode(found->second->is_at_raster); | |
| 269 return decoded_draw_image; | |
| 270 } | |
| 271 | |
| 272 void GpuImageDecodeController::DrawWithImageFinished( | |
| 273 const DrawImage& draw_image, | |
| 274 const DecodedDrawImage& decoded_draw_image) { | |
| 275 if (SkipImage(draw_image)) | |
| 276 return; | |
| 277 | |
| 278 UnrefImage(draw_image); | |
| 279 | |
| 280 // We are mid-draw and holding the context lock, ensure we clean up any | |
| 281 // textures (especially at-raster), which may have just been marked for | |
| 282 // deletion by UnrefImage. | |
| 283 DeletePendingImagesLocked(); | |
| 284 } | |
| 285 | |
| 286 void GpuImageDecodeController::ReduceCacheUsage() { | |
| 287 base::AutoLock lock(lock_); | |
| 288 EnsureCapacityLocked(0); | |
| 289 } | |
| 290 | |
| 291 void GpuImageDecodeController::DecodeImage(const DrawImage& draw_image) { | |
| 292 base::AutoLock lock(lock_); | |
| 293 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | |
| 294 if (found == image_data_.end() || | |
| 295 found->second->decoded_data_ref_count == 0) { | |
| 296 // All references to this image decode were released before the task had a | |
| 297 // chance | |
| 298 // to run. Early out. | |
| 299 return; | |
| 300 } | |
| 301 | |
| 302 // Take a ref on the image to ensure it stays alive while decode is in | |
| 303 // progress. | |
| 304 RefImageDecodeLocked(draw_image); | |
| 305 DecodeImageIfNecessaryLocked(draw_image, found->second.get()); | |
| 306 | |
| 307 // Remove the pending task before unreffing the image to ensure that | |
| 308 // the image is still alive while any caller might try to re-use this | |
| 309 // task. | |
| 310 RemovePendingDecodeTaskForImageLocked(draw_image); | |
| 311 UnrefImageDecodeLocked(draw_image); | |
| 312 } | |
| 313 | |
| 314 void GpuImageDecodeController::UploadImage(const DrawImage& draw_image) { | |
| 315 ContextProvider::ScopedContextLock context_lock(context_); | |
| 316 base::AutoLock lock(lock_); | |
| 317 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | |
| 318 if (found == image_data_.end() || found->second->image_ref_count == 0) { | |
| 319 // All references to this image were released before the task had a chance | |
| 320 // to run. Early out. | |
| 321 return; | |
| 322 } | |
| 323 DCHECK(found != image_data_.end()); | |
| 324 | |
| 325 // We are about to upload a new image and are holding the context lock. | |
| 326 // Ensure that any images which have been marked for deletion are actually | |
| 327 // cleaned up so we don't exceed our memory limit during this upload. | |
| 328 DeletePendingImagesLocked(); | |
| 329 | |
| 330 // Take a ref on the image to ensure it stays alive while upload is in | |
| 331 // progress. | |
| 332 RefImageLocked(draw_image); | |
| 333 UploadImageIfNecessaryLocked(draw_image, found->second.get()); | |
| 334 | |
| 335 // Remove the pending task before unreffing the image to ensure that | |
| 336 // the image is still alive while any caller might try to re-use this | |
| 337 // task. | |
| 338 RemovePendingUploadTaskForImageLocked(draw_image); | |
| 339 UnrefImageLocked(draw_image); | |
| 340 } | |
| 341 | |
| 342 void GpuImageDecodeController::RemovePendingDecodeTaskForImage( | |
| 343 const DrawImage& draw_image) { | |
| 344 base::AutoLock lock(lock_); | |
| 345 RemovePendingDecodeTaskForImageLocked(draw_image); | |
| 346 } | |
| 347 | |
| 348 void GpuImageDecodeController::RemovePendingUploadTaskForImage( | |
| 349 const DrawImage& draw_image) { | |
| 350 base::AutoLock lock(lock_); | |
| 351 RemovePendingUploadTaskForImageLocked(draw_image); | |
| 352 } | |
| 353 | |
| 354 scoped_refptr<ImageDecodeTask> | |
| 355 GpuImageDecodeController::GetImageDecodeTaskAndRefLocked( | |
| 356 const DrawImage& draw_image, | |
| 357 uint64_t prepare_tiles_id) { | |
| 358 lock_.AssertAcquired(); | |
| 359 uint32_t image_id = draw_image.image()->uniqueID(); | |
| 360 RefImageDecodeLocked(draw_image); | |
| 361 | |
| 362 auto found = image_data_.Peek(image_id); | |
| 363 if (found != image_data_.end() && found->second->decoded_data_is_locked) { | |
| 364 // We should never be creating a decode task for an at raster image. | |
| 365 DCHECK(!found->second->is_at_raster); | |
| 366 return nullptr; | |
| 367 } | |
| 368 | |
| 369 scoped_refptr<ImageDecodeTask>& existing_task = | |
| 370 pending_image_decode_tasks_[image_id]; | |
| 67 if (!existing_task) { | 371 if (!existing_task) { |
| 68 existing_task = make_scoped_refptr( | 372 existing_task = make_scoped_refptr( |
| 69 new ImageDecodeTaskImpl(this, image, prepare_tiles_id)); | 373 new ImageDecodeTaskImpl(this, draw_image, prepare_tiles_id)); |
| 70 } | 374 } |
| 71 *task = existing_task; | 375 return existing_task; |
| 376 } | |
| 377 | |
| 378 void GpuImageDecodeController::UnrefImageDecode(const DrawImage& draw_image) { | |
| 379 base::AutoLock lock(lock_); | |
| 380 UnrefImageDecodeLocked(draw_image); | |
| 381 } | |
| 382 | |
| 383 void GpuImageDecodeController::RefImageDecodeLocked( | |
| 384 const DrawImage& draw_image) { | |
| 385 lock_.AssertAcquired(); | |
| 386 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | |
| 387 DCHECK(found != image_data_.end()); | |
| 388 // At raster never uses Image Decode refs. | |
| 389 DCHECK(!found->second->is_at_raster); | |
| 390 ++found->second->decoded_data_ref_count; | |
|
vmpstr
2016/03/25 22:37:30
DCHECK that the memory is locked maybe?
ericrk
2016/03/28 22:10:52
We ref the image when we create a decode task - if
| |
| 391 } | |
| 392 | |
| 393 void GpuImageDecodeController::UnrefImageDecodeLocked( | |
| 394 const DrawImage& draw_image) { | |
| 395 lock_.AssertAcquired(); | |
| 396 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | |
| 397 DCHECK(found != image_data_.end()); | |
| 398 DCHECK_GT(found->second->decoded_data_ref_count, 0u); | |
| 399 // At raster never uses Image Decode refs. | |
| 400 DCHECK(!found->second->is_at_raster); | |
| 401 --found->second->decoded_data_ref_count; | |
| 402 if (found->second->decoded_data_ref_count == 0) { | |
| 403 if (found->second->decoded_data_is_locked) { | |
| 404 found->second->decoded_data_is_locked = false; | |
| 405 found->second->decoded_data->Unlock(); | |
| 406 } | |
| 407 EnsureCapacityLocked(0); | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 void GpuImageDecodeController::RefImageLocked(const DrawImage& draw_image) { | |
| 412 lock_.AssertAcquired(); | |
| 413 auto image_id = draw_image.image()->uniqueID(); | |
| 414 auto found = image_data_.Peek(image_id); | |
| 415 DCHECK(found != image_data_.end()); | |
| 416 ++found->second->image_ref_count; | |
| 417 if (found->second->image_ref_count == 1) { | |
|
vmpstr
2016/03/25 22:37:29
Dead code?
ericrk
2016/03/28 22:10:52
Done.
| |
| 418 } | |
| 419 } | |
| 420 | |
| 421 void GpuImageDecodeController::UnrefImageLocked(const DrawImage& draw_image) { | |
| 422 lock_.AssertAcquired(); | |
| 423 auto image_id = draw_image.image()->uniqueID(); | |
| 424 auto found = image_data_.Peek(image_id); | |
| 425 DCHECK(found != image_data_.end()); | |
| 426 DCHECK_GT(found->second->image_ref_count, 0u); | |
| 427 uint32_t count = --found->second->image_ref_count; | |
| 428 if (count == 0) { | |
| 429 // Covert this image to not-at-raster. Its ref count is 0, so it will be | |
|
vmpstr
2016/03/25 22:37:30
Why are we converting this to not-at-raster?
ericrk
2016/03/28 22:10:52
Updated the comment.
| |
| 430 // cleaned up in the next step if it doesn't fit anyway. | |
| 431 found->second->is_at_raster = false; | |
| 432 if (found->second->image_pending) { | |
| 433 found->second->image_pending = false; | |
|
vmpstr
2016/03/25 22:37:29
This is kind of weird for me. If the task is pendi
ericrk
2016/03/28 22:10:52
This was meant to mean that the image was budgeted
| |
| 434 bytes_used_ -= found->second->size; | |
| 435 } | |
| 436 EnsureCapacityLocked(0); | |
| 437 } | |
| 438 } | |
| 439 | |
| 440 bool GpuImageDecodeController::EnsureCapacityLocked(size_t new_size) { | |
| 441 lock_.AssertAcquired(); | |
| 442 const size_t new_elements = new_size ? 1 : 0; | |
| 443 if (CanFitSize(new_size) && CanFitCount(new_elements)) | |
| 444 return true; | |
| 445 | |
| 446 // While we are over memory or item capacity, we iterate through our set of | |
| 447 // cached image data in LRU order. For each image, we can do two things: | |
| 448 // 1) We can free the uploaded image, reducing the memory usage of the cache | |
| 449 // and 2) we can remove the entry entirely, reducing the count of elements in | |
| 450 // the cache. | |
| 451 for (auto it = image_data_.rbegin(); it != image_data_.rend();) { | |
| 452 if (it->second->decoded_data_ref_count == 0 && | |
|
vmpstr
2016/03/25 22:37:29
nit: Can you structure this as
if (... != 0 || ..
ericrk
2016/03/28 22:10:52
Done.
ericrk
2016/03/28 22:10:52
Done.
| |
| 453 it->second->image_ref_count == 0) { | |
| 454 if (it->second->uploaded_image) { | |
|
vmpstr
2016/03/25 22:37:30
uploaded_image implies that upload_pending is fals
ericrk
2016/03/28 22:10:52
Done.
ericrk
2016/03/28 22:10:52
Done.
| |
| 455 DCHECK_GE(bytes_used_, it->second->size); | |
| 456 bytes_used_ -= it->second->size; | |
| 457 images_pending_deletion_.push_back( | |
| 458 std::move(it->second->uploaded_image)); | |
| 459 it->second->uploaded_image = nullptr; | |
| 460 } | |
| 461 if (!CanFitCount(new_elements)) { | |
| 462 it = image_data_.Erase(it); | |
| 463 } else { | |
| 464 ++it; | |
| 465 } | |
| 466 | |
| 467 if (CanFitSize(new_size) && CanFitCount(new_elements)) | |
| 468 return true; | |
| 469 } else { | |
| 470 ++it; | |
| 471 } | |
| 472 } | |
| 473 | |
| 474 // We couldn't reach a state where we are under our memory / count limites. | |
| 72 return false; | 475 return false; |
| 73 } | 476 } |
| 74 | 477 |
| 75 void GpuImageDecodeController::UnrefImage(const DrawImage& image) { | 478 bool GpuImageDecodeController::CanFitSize(size_t size) const { |
| 76 NOTREACHED(); | 479 return bytes_used_ + size <= cached_bytes_limit_; |
| 77 } | 480 } |
| 78 | 481 |
| 79 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( | 482 bool GpuImageDecodeController::CanFitCount(size_t num_elements) const { |
| 80 const DrawImage& draw_image) { | 483 return image_data_.size() + num_elements <= cached_items_limit_; |
| 81 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); | 484 } |
| 82 } | 485 |
| 83 | 486 void GpuImageDecodeController::DecodeImageIfNecessaryLocked( |
| 84 void GpuImageDecodeController::DrawWithImageFinished( | 487 const DrawImage& draw_image, |
| 85 const DrawImage& image, | 488 ImageData* image_data) { |
| 86 const DecodedDrawImage& decoded_image) {} | 489 lock_.AssertAcquired(); |
| 87 | 490 if (image_data->uploaded_image) { |
| 88 void GpuImageDecodeController::ReduceCacheUsage() {} | 491 // We already have an uploaded image, no reason to decode. |
| 89 | 492 return; |
| 90 void GpuImageDecodeController::DecodeImage(const DrawImage& image) { | 493 } |
| 91 image.image()->preroll(); | 494 if (image_data->decoded_data && (image_data->decoded_data_is_locked || |
| 92 base::AutoLock lock(lock_); | 495 image_data->decoded_data->Lock())) { |
| 93 prerolled_images_.insert(image.image()->uniqueID()); | 496 // We already decoded this, or we just needed to lock, early out. |
| 94 } | 497 image_data->decoded_data_is_locked = true; |
| 95 | 498 return; |
| 96 void GpuImageDecodeController::RemovePendingTaskForImage( | 499 } |
| 97 const DrawImage& image) { | 500 |
| 98 base::AutoLock lock(lock_); | 501 TRACE_EVENT0("cc", "GpuImageDecodeController::DecodeImage"); |
| 99 pending_image_tasks_.erase(image.image()->uniqueID()); | 502 scoped_ptr<base::DiscardableMemory> backing_memory; |
| 503 { | |
| 504 base::AutoUnlock unlock(lock_); | |
| 505 if (image_data->mode == DECODED_DATA_MODE_CPU) { | |
|
vmpstr
2016/03/25 22:37:29
Can you make this a switch, so the "else" case is
ericrk
2016/03/28 22:10:52
Done.
| |
| 506 backing_memory = base::DiscardableMemoryAllocator::GetInstance() | |
| 507 ->AllocateLockedDiscardableMemory(image_data->size); | |
| 508 memset(backing_memory->data(), 0, image_data->size); | |
|
vmpstr
2016/03/25 22:37:30
Why the clear?
ericrk
2016/03/28 22:10:52
This shouldn't be here.
| |
| 509 SkImageInfo image_info = ImageInfoFromDrawImage(draw_image); | |
| 510 bool result = draw_image.image()->readPixels( | |
| 511 image_info, backing_memory->data(), image_info.minRowBytes(), 0, 0, | |
| 512 SkImage::kDisallow_CachingHint); | |
| 513 if (!result) { | |
| 514 backing_memory->Unlock(); | |
| 515 return; | |
| 516 } | |
| 517 } else { | |
| 518 backing_memory = base::DiscardableMemoryAllocator::GetInstance() | |
| 519 ->AllocateLockedDiscardableMemory(image_data->size); | |
| 520 memset(backing_memory->data(), 0, image_data->size); | |
| 521 auto params = ParamsFromDrawImage(draw_image); | |
| 522 size_t data_size = draw_image.image()->getDeferredTextureImageData( | |
| 523 *context_threadsafe_proxy_, ¶ms, 1, backing_memory->data()); | |
| 524 | |
| 525 if (!data_size) { | |
| 526 backing_memory->Unlock(); | |
| 527 return; | |
| 528 } | |
| 529 } | |
| 530 } | |
| 531 image_data->decoded_data = std::move(backing_memory); | |
| 532 image_data->decoded_data_is_locked = true; | |
| 533 } | |
| 534 | |
| 535 void GpuImageDecodeController::UploadImageIfNecessaryLocked( | |
| 536 const DrawImage& draw_image, | |
| 537 ImageData* image_data) { | |
| 538 lock_.AssertAcquired(); | |
| 539 if (image_data->uploaded_image) { | |
| 540 // Someone has uploaded this image before us (at raster). | |
| 541 return; | |
| 542 } | |
| 543 TRACE_EVENT0("cc", "GpuImageDecodeController::UploadImage"); | |
| 544 DCHECK(image_data->decoded_data_is_locked); | |
| 545 | |
| 546 skia::RefPtr<SkImage> uploaded_image; | |
| 547 { | |
| 548 base::AutoUnlock unlock(lock_); | |
| 549 if (image_data->mode == DECODED_DATA_MODE_CPU) { | |
|
vmpstr
2016/03/25 22:37:29
switch here too please
ericrk
2016/03/28 22:10:52
Done.
| |
| 550 SkImageInfo image_info = ImageInfoFromDrawImage(draw_image); | |
| 551 uploaded_image = skia::AdoptRef(SkImage::NewFromRaster( | |
| 552 image_info, image_data->decoded_data->data(), | |
| 553 image_info.minRowBytes(), [](const void*, void*) {}, nullptr)); | |
| 554 } else { | |
| 555 uploaded_image = skia::AdoptRef(SkImage::NewFromDeferredTextureImageData( | |
| 556 context_->GrContext(), image_data->decoded_data->data(), | |
| 557 SkBudgeted::kNo)); | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 image_data->uploaded_image = uploaded_image; | |
| 562 image_data->image_pending = false; | |
| 563 } | |
| 564 | |
| 565 scoped_ptr<GpuImageDecodeController::ImageData> | |
| 566 GpuImageDecodeController::NewImageData(const DrawImage& draw_image) { | |
|
vmpstr
2016/03/25 22:37:30
maybe CreateImageData?
ericrk
2016/03/28 22:10:52
sure
| |
| 567 DecodedDataMode mode; | |
| 568 SkImageInfo info = ImageInfoFromDrawImage(draw_image); | |
| 569 auto params = ParamsFromDrawImage(draw_image); | |
|
vmpstr
2016/03/25 22:37:30
SkImageInfo info ...
auto params ...
why auto? Is
ericrk
2016/03/28 22:10:52
I guess not :P
| |
| 570 size_t data_size = draw_image.image()->getDeferredTextureImageData( | |
| 571 *context_threadsafe_proxy_, ¶ms, 1, nullptr); | |
| 572 | |
| 573 if (data_size == 0) { | |
|
vmpstr
2016/03/25 22:37:30
0 is returned in case of general failure, not just
ericrk
2016/03/28 22:10:52
Done.
| |
| 574 // Can't upload image, too large. Use SW fallback. | |
| 575 data_size = info.getSafeSize(info.minRowBytes()); | |
| 576 mode = GpuImageDecodeController::DECODED_DATA_MODE_CPU; | |
| 577 } else { | |
| 578 mode = GpuImageDecodeController::DECODED_DATA_MODE_GPU; | |
|
vmpstr
2016/03/25 22:37:29
s/GpuImageDecodeController:://
ericrk
2016/03/28 22:10:52
Done.
| |
| 579 } | |
| 580 | |
| 581 return make_scoped_ptr(new ImageData(mode, data_size)); | |
| 582 } | |
| 583 | |
| 584 void GpuImageDecodeController::RemovePendingDecodeTaskForImageLocked( | |
| 585 const DrawImage& draw_image) { | |
| 586 lock_.AssertAcquired(); | |
| 587 pending_image_decode_tasks_.erase(draw_image.image()->uniqueID()); | |
| 588 } | |
| 589 | |
| 590 void GpuImageDecodeController::RemovePendingUploadTaskForImageLocked( | |
| 591 const DrawImage& draw_image) { | |
| 592 lock_.AssertAcquired(); | |
| 593 pending_image_upload_tasks_.erase(draw_image.image()->uniqueID()); | |
| 594 } | |
| 595 | |
| 596 void GpuImageDecodeController::DeletePendingImagesLocked() { | |
| 597 context_->GetLock()->AssertAcquired(); | |
| 598 lock_.AssertAcquired(); | |
| 599 images_pending_deletion_.clear(); | |
| 100 } | 600 } |
| 101 | 601 |
| 102 } // namespace cc | 602 } // namespace cc |
| OLD | NEW |