| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ppapi/proxy/ppb_image_data_proxy.h" | 5 #include "ppapi/proxy/ppb_image_data_proxy.h" |
| 6 | 6 |
| 7 #include <string.h> // For memcpy | 7 #include <string.h> // For memcpy |
| 8 | 8 |
| 9 #include <map> | 9 #include <map> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 scoped_refptr<ImageData> Get(int width, int height, | 123 scoped_refptr<ImageData> Get(int width, int height, |
| 124 PP_ImageDataFormat format); | 124 PP_ImageDataFormat format); |
| 125 void Add(ImageData* image_data); | 125 void Add(ImageData* image_data); |
| 126 void ImageDataUsable(ImageData* image_data); | 126 void ImageDataUsable(ImageData* image_data); |
| 127 | 127 |
| 128 // Expires old entries. Returns true if there are still entries in the list, | 128 // Expires old entries. Returns true if there are still entries in the list, |
| 129 // false if this instance cache is now empty. | 129 // false if this instance cache is now empty. |
| 130 bool ExpireEntries(); | 130 bool ExpireEntries(); |
| 131 | 131 |
| 132 private: | 132 private: |
| 133 void IncrementInsertionPoint(); |
| 134 |
| 133 // We'll store this many ImageDatas per instance. | 135 // We'll store this many ImageDatas per instance. |
| 134 const static int kCacheSize = 2; | 136 const static int kCacheSize = 2; |
| 135 | 137 |
| 136 ImageDataCacheEntry images_[kCacheSize]; | 138 ImageDataCacheEntry images_[kCacheSize]; |
| 137 | 139 |
| 138 // Index into cache where the next item will go. | 140 // Index into cache where the next item will go. |
| 139 int next_insertion_point_; | 141 int next_insertion_point_; |
| 140 }; | 142 }; |
| 141 | 143 |
| 142 scoped_refptr<ImageData> ImageDataInstanceCache::Get( | 144 scoped_refptr<ImageData> ImageDataInstanceCache::Get( |
| 143 int width, int height, | 145 int width, int height, |
| 144 PP_ImageDataFormat format) { | 146 PP_ImageDataFormat format) { |
| 145 // Just do a brute-force search since the cache is so small. | 147 // Just do a brute-force search since the cache is so small. |
| 146 for (int i = 0; i < kCacheSize; i++) { | 148 for (int i = 0; i < kCacheSize; i++) { |
| 147 if (!images_[i].usable) | 149 if (!images_[i].usable) |
| 148 continue; | 150 continue; |
| 149 const PP_ImageDataDesc& desc = images_[i].image->desc(); | 151 const PP_ImageDataDesc& desc = images_[i].image->desc(); |
| 150 if (desc.format == format && | 152 if (desc.format == format && |
| 151 desc.size.width == width && desc.size.height == height) { | 153 desc.size.width == width && desc.size.height == height) { |
| 152 scoped_refptr<ImageData> ret(images_[i].image); | 154 scoped_refptr<ImageData> ret(images_[i].image); |
| 153 images_[i] = ImageDataCacheEntry(); | 155 images_[i] = ImageDataCacheEntry(); |
| 156 |
| 157 // Since we just removed an item, this entry is the best place to insert |
| 158 // a subsequent one. |
| 159 next_insertion_point_ = i; |
| 154 return ret; | 160 return ret; |
| 155 } | 161 } |
| 156 } | 162 } |
| 157 return scoped_refptr<ImageData>(); | 163 return scoped_refptr<ImageData>(); |
| 158 } | 164 } |
| 159 | 165 |
| 160 void ImageDataInstanceCache::Add(ImageData* image_data) { | 166 void ImageDataInstanceCache::Add(ImageData* image_data) { |
| 161 images_[next_insertion_point_] = ImageDataCacheEntry(image_data); | 167 images_[next_insertion_point_] = ImageDataCacheEntry(image_data); |
| 162 | 168 IncrementInsertionPoint(); |
| 163 // Go to the next location, wrapping around to get LRU. | |
| 164 next_insertion_point_++; | |
| 165 if (next_insertion_point_ >= kCacheSize) | |
| 166 next_insertion_point_ = 0; | |
| 167 } | 169 } |
| 168 | 170 |
| 169 void ImageDataInstanceCache::ImageDataUsable(ImageData* image_data) { | 171 void ImageDataInstanceCache::ImageDataUsable(ImageData* image_data) { |
| 170 for (int i = 0; i < kCacheSize; i++) { | 172 for (int i = 0; i < kCacheSize; i++) { |
| 171 if (images_[i].image.get() == image_data) { | 173 if (images_[i].image.get() == image_data) { |
| 172 images_[i].usable = true; | 174 images_[i].usable = true; |
| 175 |
| 176 // This test is important. The renderer doesn't guarantee how many image |
| 177 // datas it has or when it notifies us when one is usable. Its possible |
| 178 // to get into situations where it's always telling us the old one is |
| 179 // usable, and then the older one immediately gets expired. Therefore, |
| 180 // if the next insertion would overwrite this now-usable entry, make the |
| 181 // next insertion overwrite some other entry to avoid the replacement. |
| 182 if (next_insertion_point_ == i) |
| 183 IncrementInsertionPoint(); |
| 173 return; | 184 return; |
| 174 } | 185 } |
| 175 } | 186 } |
| 176 } | 187 } |
| 177 | 188 |
| 178 bool ImageDataInstanceCache::ExpireEntries() { | 189 bool ImageDataInstanceCache::ExpireEntries() { |
| 179 base::TimeTicks threshold_time = | 190 base::TimeTicks threshold_time = |
| 180 base::TimeTicks::Now() - base::TimeDelta::FromSeconds(kMaxAgeSeconds); | 191 base::TimeTicks::Now() - base::TimeDelta::FromSeconds(kMaxAgeSeconds); |
| 181 | 192 |
| 182 bool has_entry = false; | 193 bool has_entry = false; |
| 183 for (int i = 0; i < kCacheSize; i++) { | 194 for (int i = 0; i < kCacheSize; i++) { |
| 184 if (images_[i].image.get()) { | 195 if (images_[i].image.get()) { |
| 185 // Entry present. | 196 // Entry present. |
| 186 if (images_[i].added_time <= threshold_time) { | 197 if (images_[i].added_time <= threshold_time) { |
| 187 // Found an entry to expire. | 198 // Found an entry to expire. |
| 188 images_[i] = ImageDataCacheEntry(); | 199 images_[i] = ImageDataCacheEntry(); |
| 189 next_insertion_point_ = i; | 200 next_insertion_point_ = i; |
| 190 } else { | 201 } else { |
| 191 // Found an entry that we're keeping. | 202 // Found an entry that we're keeping. |
| 192 has_entry = true; | 203 has_entry = true; |
| 193 } | 204 } |
| 194 } | 205 } |
| 195 } | 206 } |
| 196 return has_entry; | 207 return has_entry; |
| 197 } | 208 } |
| 198 | 209 |
| 210 void ImageDataInstanceCache::IncrementInsertionPoint() { |
| 211 // Go to the next location, wrapping around to get LRU. |
| 212 next_insertion_point_++; |
| 213 if (next_insertion_point_ >= kCacheSize) |
| 214 next_insertion_point_ = 0; |
| 215 } |
| 216 |
| 199 // ImageDataCache -------------------------------------------------------------- | 217 // ImageDataCache -------------------------------------------------------------- |
| 200 | 218 |
| 201 class ImageDataCache { | 219 class ImageDataCache { |
| 202 public: | 220 public: |
| 203 ImageDataCache() : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} | 221 ImageDataCache() : weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} |
| 204 ~ImageDataCache() {} | 222 ~ImageDataCache() {} |
| 205 | 223 |
| 206 static ImageDataCache* GetInstance(); | 224 static ImageDataCache* GetInstance(); |
| 207 | 225 |
| 208 // Retrieves an image data from the cache of the specified size and format if | 226 // Retrieves an image data from the cache of the specified size and format if |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 | 299 |
| 282 } // namespace | 300 } // namespace |
| 283 | 301 |
| 284 // ImageData ------------------------------------------------------------------- | 302 // ImageData ------------------------------------------------------------------- |
| 285 | 303 |
| 286 #if !defined(OS_NACL) | 304 #if !defined(OS_NACL) |
| 287 ImageData::ImageData(const HostResource& resource, | 305 ImageData::ImageData(const HostResource& resource, |
| 288 const PP_ImageDataDesc& desc, | 306 const PP_ImageDataDesc& desc, |
| 289 ImageHandle handle) | 307 ImageHandle handle) |
| 290 : Resource(OBJECT_IS_PROXY, resource), | 308 : Resource(OBJECT_IS_PROXY, resource), |
| 291 desc_(desc) { | 309 desc_(desc), |
| 310 used_in_replace_contents_(false) { |
| 292 #if defined(OS_WIN) | 311 #if defined(OS_WIN) |
| 293 transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); | 312 transport_dib_.reset(TransportDIB::CreateWithHandle(handle)); |
| 294 #else | 313 #else |
| 295 transport_dib_.reset(TransportDIB::Map(handle)); | 314 transport_dib_.reset(TransportDIB::Map(handle)); |
| 296 #endif // defined(OS_WIN) | 315 #endif // defined(OS_WIN) |
| 297 } | 316 } |
| 298 #else // !defined(OS_NACL) | 317 #else // !defined(OS_NACL) |
| 299 | 318 |
| 300 ImageData::ImageData(const HostResource& resource, | 319 ImageData::ImageData(const HostResource& resource, |
| 301 const PP_ImageDataDesc& desc, | 320 const PP_ImageDataDesc& desc, |
| 302 const base::SharedMemoryHandle& handle) | 321 const base::SharedMemoryHandle& handle) |
| 303 : Resource(OBJECT_IS_PROXY, resource), | 322 : Resource(OBJECT_IS_PROXY, resource), |
| 304 desc_(desc), | 323 desc_(desc), |
| 305 shm_(handle, false /* read_only */), | 324 shm_(handle, false /* read_only */), |
| 306 size_(desc.size.width * desc.size.height * 4), | 325 size_(desc.size.width * desc.size.height * 4), |
| 307 map_count_(0) { | 326 map_count_(0), |
| 327 used_in_replace_contents_(false) { |
| 308 } | 328 } |
| 309 #endif // !defined(OS_NACL) | 329 #endif // !defined(OS_NACL) |
| 310 | 330 |
| 311 ImageData::~ImageData() { | 331 ImageData::~ImageData() { |
| 312 } | 332 } |
| 313 | 333 |
| 314 PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { | 334 PPB_ImageData_API* ImageData::AsPPB_ImageData_API() { |
| 315 return this; | 335 return this; |
| 316 } | 336 } |
| 317 | 337 |
| 318 void ImageData::LastPluginRefWasDeleted() { | 338 void ImageData::LastPluginRefWasDeleted() { |
| 319 // The plugin no longer needs this ImageData, add it to our cache. | 339 // The plugin no longer needs this ImageData, add it to our cache if it's |
| 320 ImageDataCache::GetInstance()->Add(this); | 340 // been used in a ReplaceContents. These are the ImageDatas that the renderer |
| 341 // will send back ImageDataUsable messages for. |
| 342 if (used_in_replace_contents_) |
| 343 ImageDataCache::GetInstance()->Add(this); |
| 321 } | 344 } |
| 322 | 345 |
| 323 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { | 346 PP_Bool ImageData::Describe(PP_ImageDataDesc* desc) { |
| 324 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); | 347 memcpy(desc, &desc_, sizeof(PP_ImageDataDesc)); |
| 325 return PP_TRUE; | 348 return PP_TRUE; |
| 326 } | 349 } |
| 327 | 350 |
| 328 void* ImageData::Map() { | 351 void* ImageData::Map() { |
| 329 #if defined(OS_NACL) | 352 #if defined(OS_NACL) |
| 330 if (map_count_++ == 0) | 353 if (map_count_++ == 0) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 } | 395 } |
| 373 | 396 |
| 374 SkCanvas* ImageData::GetCanvas() { | 397 SkCanvas* ImageData::GetCanvas() { |
| 375 #if defined(OS_NACL) | 398 #if defined(OS_NACL) |
| 376 return NULL; // No canvas in NaCl. | 399 return NULL; // No canvas in NaCl. |
| 377 #else | 400 #else |
| 378 return mapped_canvas_.get(); | 401 return mapped_canvas_.get(); |
| 379 #endif | 402 #endif |
| 380 } | 403 } |
| 381 | 404 |
| 382 void ImageData::ZeroContents() { | 405 void ImageData::RecycleToPlugin(bool zero_contents) { |
| 383 void* data = Map(); | 406 used_in_replace_contents_ = false; |
| 384 memset(data, 0, desc_.stride * desc_.size.height); | 407 if (zero_contents) { |
| 385 Unmap(); | 408 void* data = Map(); |
| 409 memset(data, 0, desc_.stride * desc_.size.height); |
| 410 Unmap(); |
| 411 } |
| 386 } | 412 } |
| 387 | 413 |
| 388 #if !defined(OS_NACL) | 414 #if !defined(OS_NACL) |
| 389 // static | 415 // static |
| 390 ImageHandle ImageData::NullHandle() { | 416 ImageHandle ImageData::NullHandle() { |
| 391 #if defined(OS_WIN) | 417 #if defined(OS_WIN) |
| 392 return NULL; | 418 return NULL; |
| 393 #elif defined(OS_MACOSX) || defined(OS_ANDROID) | 419 #elif defined(OS_MACOSX) || defined(OS_ANDROID) |
| 394 return ImageHandle(); | 420 return ImageHandle(); |
| 395 #else | 421 #else |
| (...skipping 28 matching lines...) Expand all Loading... |
| 424 PP_Bool init_to_zero) { | 450 PP_Bool init_to_zero) { |
| 425 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); | 451 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 426 if (!dispatcher) | 452 if (!dispatcher) |
| 427 return 0; | 453 return 0; |
| 428 | 454 |
| 429 // Check the cache. | 455 // Check the cache. |
| 430 scoped_refptr<ImageData> cached_image_data = | 456 scoped_refptr<ImageData> cached_image_data = |
| 431 ImageDataCache::GetInstance()->Get(instance, size.width, size.height, | 457 ImageDataCache::GetInstance()->Get(instance, size.width, size.height, |
| 432 format); | 458 format); |
| 433 if (cached_image_data.get()) { | 459 if (cached_image_data.get()) { |
| 434 // We have one we can re-use rather than allocating a new one. Only zero | 460 // We have one we can re-use rather than allocating a new one. |
| 435 // out if requested. | 461 cached_image_data->RecycleToPlugin(PP_ToBool(init_to_zero)); |
| 436 if (PP_ToBool(init_to_zero)) | |
| 437 cached_image_data->ZeroContents(); | |
| 438 return cached_image_data->GetReference(); | 462 return cached_image_data->GetReference(); |
| 439 } | 463 } |
| 440 | 464 |
| 441 HostResource result; | 465 HostResource result; |
| 442 std::string image_data_desc; | 466 std::string image_data_desc; |
| 443 #if defined(OS_NACL) | 467 #if defined(OS_NACL) |
| 444 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); | 468 base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle(); |
| 445 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl( | 469 dispatcher->Send(new PpapiHostMsg_PPBImageData_CreateNaCl( |
| 446 kApiID, instance, format, size, init_to_zero, | 470 kApiID, instance, format, size, init_to_zero, |
| 447 &result, &image_data_desc, &image_handle)); | 471 &result, &image_data_desc, &image_handle)); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 // still cached in our process, the proxy still holds a reference so we can | 621 // still cached in our process, the proxy still holds a reference so we can |
| 598 // remove the one the renderer just sent is. If the proxy no longer holds a | 622 // remove the one the renderer just sent is. If the proxy no longer holds a |
| 599 // reference, we released everything and we should also release the one the | 623 // reference, we released everything and we should also release the one the |
| 600 // renderer just sent us. | 624 // renderer just sent us. |
| 601 dispatcher()->Send(new PpapiHostMsg_PPBCore_ReleaseResource( | 625 dispatcher()->Send(new PpapiHostMsg_PPBCore_ReleaseResource( |
| 602 API_ID_PPB_CORE, old_image_data)); | 626 API_ID_PPB_CORE, old_image_data)); |
| 603 } | 627 } |
| 604 | 628 |
| 605 } // namespace proxy | 629 } // namespace proxy |
| 606 } // namespace ppapi | 630 } // namespace ppapi |
| OLD | NEW |