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 |