OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/browser/gpu/shader_disk_cache.h" | 5 #include "content/browser/gpu/shader_disk_cache.h" |
6 | 6 |
7 #include "base/threading/thread_checker.h" | 7 #include "base/threading/thread_checker.h" |
8 #include "content/browser/gpu/gpu_process_host.h" | 8 #include "content/browser/gpu/gpu_process_host.h" |
9 #include "content/public/browser/browser_thread.h" | 9 #include "content/public/browser/browser_thread.h" |
10 #include "net/base/io_buffer.h" | 10 #include "net/base/io_buffer.h" |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 base::WeakPtr<ShaderDiskCache> cache_; | 94 base::WeakPtr<ShaderDiskCache> cache_; |
95 OpType op_type_; | 95 OpType op_type_; |
96 void* iter_; | 96 void* iter_; |
97 scoped_refptr<net::IOBufferWithSize> buf_; | 97 scoped_refptr<net::IOBufferWithSize> buf_; |
98 int host_id_; | 98 int host_id_; |
99 disk_cache::Entry* entry_; | 99 disk_cache::Entry* entry_; |
100 | 100 |
101 DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper); | 101 DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper); |
102 }; | 102 }; |
103 | 103 |
| 104 class ShaderClearHelper : public base::RefCounted<ShaderClearHelper> { |
| 105 public: |
| 106 ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache, |
| 107 const base::FilePath& path, |
| 108 const base::Time& delete_begin, |
| 109 const base::Time& delete_end, |
| 110 const base::Closure& callback); |
| 111 void Clear(); |
| 112 |
| 113 private: |
| 114 friend class base::RefCounted<ShaderClearHelper>; |
| 115 |
| 116 enum OpType { |
| 117 TERMINATE, |
| 118 VERIFY_CACHE_SETUP, |
| 119 DELETE_CACHE |
| 120 }; |
| 121 |
| 122 ~ShaderClearHelper(); |
| 123 |
| 124 void DoClearShaderCache(int rv); |
| 125 |
| 126 scoped_refptr<ShaderDiskCache> cache_; |
| 127 OpType op_type_; |
| 128 base::FilePath path_; |
| 129 base::Time delete_begin_; |
| 130 base::Time delete_end_; |
| 131 base::Closure callback_; |
| 132 |
| 133 DISALLOW_COPY_AND_ASSIGN(ShaderClearHelper); |
| 134 }; |
| 135 |
104 ShaderDiskCacheEntry::ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, | 136 ShaderDiskCacheEntry::ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, |
105 const std::string& key, | 137 const std::string& key, |
106 const std::string& shader) | 138 const std::string& shader) |
107 : cache_(cache), | 139 : cache_(cache), |
108 op_type_(OPEN_ENTRY), | 140 op_type_(OPEN_ENTRY), |
109 key_(key), | 141 key_(key), |
110 shader_(shader), | 142 shader_(shader), |
111 entry_(NULL) { | 143 entry_(NULL) { |
112 } | 144 } |
113 | 145 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 op_type_ = TERMINATE; | 334 op_type_ = TERMINATE; |
303 return net::OK; | 335 return net::OK; |
304 } | 336 } |
305 | 337 |
306 ShaderDiskReadHelper::~ShaderDiskReadHelper() { | 338 ShaderDiskReadHelper::~ShaderDiskReadHelper() { |
307 if (entry_) | 339 if (entry_) |
308 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 340 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
309 base::Bind(&EntryCloser, entry_)); | 341 base::Bind(&EntryCloser, entry_)); |
310 } | 342 } |
311 | 343 |
| 344 ShaderClearHelper::ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache, |
| 345 const base::FilePath& path, |
| 346 const base::Time& delete_begin, |
| 347 const base::Time& delete_end, |
| 348 const base::Closure& callback) |
| 349 : cache_(cache), |
| 350 op_type_(VERIFY_CACHE_SETUP), |
| 351 path_(path), |
| 352 delete_begin_(delete_begin), |
| 353 delete_end_(delete_end), |
| 354 callback_(callback) { |
| 355 } |
| 356 |
| 357 ShaderClearHelper::~ShaderClearHelper() { |
| 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 359 } |
| 360 |
| 361 void ShaderClearHelper::Clear() { |
| 362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 363 DoClearShaderCache(net::OK); |
| 364 } |
| 365 |
| 366 void ShaderClearHelper::DoClearShaderCache(int rv) { |
| 367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 368 |
| 369 // Hold a ref to ourselves so when we do the CacheCleared call we don't get |
| 370 // auto-deleted when our ref count drops to zero. |
| 371 scoped_refptr<ShaderClearHelper> helper = this; |
| 372 |
| 373 while (rv != net::ERR_IO_PENDING) { |
| 374 switch (op_type_) { |
| 375 case VERIFY_CACHE_SETUP: |
| 376 rv = cache_->SetAvailableCallback( |
| 377 base::Bind(&ShaderClearHelper::DoClearShaderCache, this)); |
| 378 op_type_ = DELETE_CACHE; |
| 379 break; |
| 380 case DELETE_CACHE: |
| 381 rv = cache_->Clear( |
| 382 delete_begin_, delete_end_, |
| 383 base::Bind(&ShaderClearHelper::DoClearShaderCache, this)); |
| 384 op_type_ = TERMINATE; |
| 385 break; |
| 386 case TERMINATE: |
| 387 ShaderCacheFactory::GetInstance()->CacheCleared(path_); |
| 388 callback_.Run(); |
| 389 rv = net::ERR_IO_PENDING; // Break the loop. |
| 390 break; |
| 391 default: |
| 392 NOTREACHED(); // Invalid state provided. |
| 393 op_type_ = TERMINATE; |
| 394 break; |
| 395 } |
| 396 } |
| 397 } |
| 398 |
| 399 // static |
312 ShaderCacheFactory* ShaderCacheFactory::GetInstance() { | 400 ShaderCacheFactory* ShaderCacheFactory::GetInstance() { |
313 return Singleton<ShaderCacheFactory, | 401 return Singleton<ShaderCacheFactory, |
314 LeakySingletonTraits<ShaderCacheFactory> >::get(); | 402 LeakySingletonTraits<ShaderCacheFactory> >::get(); |
315 } | 403 } |
316 | 404 |
317 ShaderCacheFactory::ShaderCacheFactory() { | 405 ShaderCacheFactory::ShaderCacheFactory() { |
318 } | 406 } |
319 | 407 |
320 ShaderCacheFactory::~ShaderCacheFactory() { | 408 ShaderCacheFactory::~ShaderCacheFactory() { |
321 } | 409 } |
322 | 410 |
323 void ShaderCacheFactory::SetCacheInfo(int32 client_id, | 411 void ShaderCacheFactory::SetCacheInfo(int32 client_id, |
324 const base::FilePath& path) { | 412 const base::FilePath& path) { |
325 client_id_to_path_map_[client_id] = path.Append(kGpuCachePath); | 413 client_id_to_path_map_[client_id] = path; |
326 } | 414 } |
327 | 415 |
328 void ShaderCacheFactory::RemoveCacheInfo(int32 client_id) { | 416 void ShaderCacheFactory::RemoveCacheInfo(int32 client_id) { |
329 client_id_to_path_map_.erase(client_id); | 417 client_id_to_path_map_.erase(client_id); |
330 } | 418 } |
331 | 419 |
332 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32 client_id) { | 420 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32 client_id) { |
333 ClientIdToPathMap::iterator client_iter = | 421 ClientIdToPathMap::iterator iter = |
334 client_id_to_path_map_.find(client_id); | 422 client_id_to_path_map_.find(client_id); |
335 if (client_iter == client_id_to_path_map_.end()) | 423 if (iter == client_id_to_path_map_.end()) |
336 return NULL; | 424 return NULL; |
| 425 return ShaderCacheFactory::GetByPath(iter->second); |
| 426 } |
337 | 427 |
338 ShaderCacheMap::iterator iter = shader_cache_map_.find(client_iter->second); | 428 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::GetByPath( |
| 429 const base::FilePath& path) { |
| 430 ShaderCacheMap::iterator iter = shader_cache_map_.find(path); |
339 if (iter != shader_cache_map_.end()) | 431 if (iter != shader_cache_map_.end()) |
340 return iter->second; | 432 return iter->second; |
341 | 433 |
342 ShaderDiskCache* cache = new ShaderDiskCache(client_iter->second); | 434 ShaderDiskCache* cache = new ShaderDiskCache(path); |
343 cache->Init(); | 435 cache->Init(); |
344 | |
345 return cache; | 436 return cache; |
346 } | 437 } |
347 | 438 |
348 void ShaderCacheFactory::AddToCache(const base::FilePath& key, | 439 void ShaderCacheFactory::AddToCache(const base::FilePath& key, |
349 ShaderDiskCache* cache) { | 440 ShaderDiskCache* cache) { |
350 shader_cache_map_[key] = cache; | 441 shader_cache_map_[key] = cache; |
351 } | 442 } |
352 | 443 |
353 void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) { | 444 void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) { |
354 shader_cache_map_.erase(key); | 445 shader_cache_map_.erase(key); |
355 } | 446 } |
356 | 447 |
| 448 void ShaderCacheFactory::ClearByPath(const base::FilePath& path, |
| 449 const base::Time& delete_begin, |
| 450 const base::Time& delete_end, |
| 451 const base::Closure& callback) { |
| 452 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 453 DCHECK(!callback.is_null()); |
| 454 |
| 455 scoped_refptr<ShaderClearHelper> helper = new ShaderClearHelper( |
| 456 GetByPath(path), path, delete_begin, delete_end, callback); |
| 457 |
| 458 // We could receive requests to clear the same path with different |
| 459 // begin/end times. So, we keep a list of requests. If we haven't seen this |
| 460 // path before we kick off the clear and add it to the list. If we have see it |
| 461 // already, then we already have a clear running. We add this clear to the |
| 462 // list and wait for any previous clears to finish. |
| 463 ShaderClearMap::iterator iter = shader_clear_map_.find(path); |
| 464 if (iter != shader_clear_map_.end()) { |
| 465 iter->second.push(helper); |
| 466 return; |
| 467 } |
| 468 |
| 469 shader_clear_map_.insert( |
| 470 std::pair<base::FilePath, ShaderClearQueue>(path, ShaderClearQueue())); |
| 471 shader_clear_map_[path].push(helper); |
| 472 helper->Clear(); |
| 473 } |
| 474 |
| 475 void ShaderCacheFactory::CacheCleared(const base::FilePath& path) { |
| 476 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 477 |
| 478 ShaderClearMap::iterator iter = shader_clear_map_.find(path); |
| 479 if (iter == shader_clear_map_.end()) { |
| 480 LOG(ERROR) << "Completed clear but missing clear helper."; |
| 481 return; |
| 482 } |
| 483 |
| 484 iter->second.pop(); |
| 485 |
| 486 // If there are remaining items in the list we trigger the Clear on the |
| 487 // next one. |
| 488 if (!iter->second.empty()) { |
| 489 iter->second.front()->Clear(); |
| 490 return; |
| 491 } |
| 492 |
| 493 shader_clear_map_.erase(path); |
| 494 } |
| 495 |
357 ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path) | 496 ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path) |
358 : cache_available_(false), | 497 : cache_available_(false), |
359 max_cache_size_(0), | 498 max_cache_size_(0), |
360 host_id_(0), | 499 host_id_(0), |
361 cache_path_(cache_path), | 500 cache_path_(cache_path), |
362 is_initialized_(false), | 501 is_initialized_(false), |
363 backend_(NULL) { | 502 backend_(NULL) { |
364 ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this); | 503 ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this); |
365 } | 504 } |
366 | 505 |
367 ShaderDiskCache::~ShaderDiskCache() { | 506 ShaderDiskCache::~ShaderDiskCache() { |
368 ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_); | 507 ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_); |
| 508 if (backend_) |
| 509 delete backend_; |
369 } | 510 } |
370 | 511 |
371 void ShaderDiskCache::Init() { | 512 void ShaderDiskCache::Init() { |
372 if (is_initialized_) { | 513 if (is_initialized_) { |
373 NOTREACHED(); // can't initialize disk cache twice. | 514 NOTREACHED(); // can't initialize disk cache twice. |
374 return; | 515 return; |
375 } | 516 } |
376 is_initialized_ = true; | 517 is_initialized_ = true; |
377 | 518 |
378 int rv = disk_cache::CreateCacheBackend( | 519 int rv = disk_cache::CreateCacheBackend( |
379 net::SHADER_CACHE, | 520 net::SHADER_CACHE, |
380 cache_path_, | 521 cache_path_.Append(kGpuCachePath), |
381 max_cache_size_, | 522 max_cache_size_, |
382 true, | 523 true, |
383 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), | 524 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), |
384 NULL, | 525 NULL, |
385 &backend_, | 526 &backend_, |
386 base::Bind(&ShaderDiskCache::CacheCreatedCallback, this)); | 527 base::Bind(&ShaderDiskCache::CacheCreatedCallback, this)); |
387 | 528 |
388 if (rv == net::OK) | 529 if (rv == net::OK) |
389 cache_available_ = true; | 530 cache_available_ = true; |
390 } | 531 } |
391 | 532 |
392 void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) { | 533 void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) { |
393 if (!cache_available_) | 534 if (!cache_available_) |
394 return; | 535 return; |
395 | 536 |
396 ShaderDiskCacheEntry* shim = | 537 ShaderDiskCacheEntry* shim = |
397 new ShaderDiskCacheEntry(AsWeakPtr(), key, shader); | 538 new ShaderDiskCacheEntry(AsWeakPtr(), key, shader); |
398 shim->Cache(); | 539 shim->Cache(); |
399 | 540 |
400 entry_map_[shim] = shim; | 541 entry_map_[shim] = shim; |
401 } | 542 } |
402 | 543 |
| 544 int ShaderDiskCache::Clear( |
| 545 const base::Time begin_time, const base::Time end_time, |
| 546 const net::CompletionCallback& completion_callback) { |
| 547 int rv; |
| 548 if (begin_time.is_null()) { |
| 549 rv = backend_->DoomAllEntries(completion_callback); |
| 550 } else { |
| 551 rv = backend_->DoomEntriesBetween(begin_time, end_time, |
| 552 completion_callback); |
| 553 } |
| 554 return rv; |
| 555 } |
| 556 |
| 557 int32 ShaderDiskCache::Size() { |
| 558 if (!cache_available_) |
| 559 return -1; |
| 560 return backend_->GetEntryCount(); |
| 561 } |
| 562 |
| 563 int ShaderDiskCache::SetAvailableCallback( |
| 564 const net::CompletionCallback& callback) { |
| 565 if (cache_available_) |
| 566 return net::OK; |
| 567 available_callback_ = callback; |
| 568 return net::ERR_IO_PENDING; |
| 569 } |
| 570 |
403 void ShaderDiskCache::CacheCreatedCallback(int rv) { | 571 void ShaderDiskCache::CacheCreatedCallback(int rv) { |
404 if (rv != net::OK) { | 572 if (rv != net::OK) { |
405 LOG(ERROR) << "Shader Cache Creation failed: " << rv; | 573 LOG(ERROR) << "Shader Cache Creation failed: " << rv; |
406 return; | 574 return; |
407 } | 575 } |
408 | |
409 cache_available_ = true; | 576 cache_available_ = true; |
410 | 577 |
411 helper_ = new ShaderDiskReadHelper(AsWeakPtr(), host_id_); | 578 helper_ = new ShaderDiskReadHelper(AsWeakPtr(), host_id_); |
412 helper_->LoadCache(); | 579 helper_->LoadCache(); |
| 580 |
| 581 if (!available_callback_.is_null()) { |
| 582 available_callback_.Run(net::OK); |
| 583 available_callback_.Reset(); |
| 584 } |
413 } | 585 } |
414 | 586 |
415 void ShaderDiskCache::EntryComplete(void* entry) { | 587 void ShaderDiskCache::EntryComplete(void* entry) { |
416 entry_map_.erase(entry); | 588 entry_map_.erase(entry); |
| 589 |
| 590 if (entry_map_.empty() && !cache_complete_callback_.is_null()) |
| 591 cache_complete_callback_.Run(net::OK); |
417 } | 592 } |
418 | 593 |
419 void ShaderDiskCache::ReadComplete() { | 594 void ShaderDiskCache::ReadComplete() { |
420 helper_ = NULL; | 595 helper_ = NULL; |
421 } | 596 } |
422 | 597 |
| 598 int ShaderDiskCache::SetCacheCompleteCallback( |
| 599 const net::CompletionCallback& callback) { |
| 600 if (entry_map_.empty()) { |
| 601 return net::OK; |
| 602 } |
| 603 cache_complete_callback_ = callback; |
| 604 return net::ERR_IO_PENDING; |
| 605 } |
| 606 |
423 } // namespace content | 607 } // namespace content |
424 | 608 |
OLD | NEW |