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