Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Unified Diff: content/browser/gpu/shader_disk_cache.cc

Issue 2565243002: Revert of gpu: Move ShaderDiskCache into //gpu/ipc/host component. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/gpu/shader_disk_cache.h ('k') | content/browser/gpu/shader_disk_cache_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/gpu/shader_disk_cache.cc
diff --git a/content/browser/gpu/shader_disk_cache.cc b/content/browser/gpu/shader_disk_cache.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a609b85a2376980dd82f9bbcc62db663bd0ee4ec
--- /dev/null
+++ b/content/browser/gpu/shader_disk_cache.cc
@@ -0,0 +1,607 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/gpu/shader_disk_cache.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "net/base/cache_type.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace content {
+
+namespace {
+
+static const base::FilePath::CharType kGpuCachePath[] =
+ FILE_PATH_LITERAL("GPUCache");
+
+static ShaderCacheFactory* factory_instance = nullptr;
+
+} // namespace
+
+// ShaderDiskCacheEntry handles the work of caching/updating the cached
+// shaders.
+class ShaderDiskCacheEntry : public base::ThreadChecker {
+ public:
+ ShaderDiskCacheEntry(ShaderDiskCache* cache,
+ const std::string& key,
+ const std::string& shader);
+ ~ShaderDiskCacheEntry();
+
+ void Cache();
+
+ private:
+ enum OpType {
+ OPEN_ENTRY,
+ WRITE_DATA,
+ CREATE_ENTRY,
+ };
+
+ void OnOpComplete(int rv);
+
+ int OpenCallback(int rv);
+ int WriteCallback(int rv);
+ int IOComplete(int rv);
+
+ ShaderDiskCache* cache_;
+ OpType op_type_;
+ std::string key_;
+ std::string shader_;
+ disk_cache::Entry* entry_;
+ base::WeakPtr<ShaderDiskCacheEntry> weak_ptr_;
+ base::WeakPtrFactory<ShaderDiskCacheEntry> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderDiskCacheEntry);
+};
+
+// ShaderDiskReadHelper is used to load all of the cached shaders from the
+// disk cache and send to the memory cache.
+class ShaderDiskReadHelper : public base::ThreadChecker {
+ public:
+ using ShaderLoadedCallback = ShaderDiskCache::ShaderLoadedCallback;
+ ShaderDiskReadHelper(ShaderDiskCache* cache,
+ const ShaderLoadedCallback& callback);
+ ~ShaderDiskReadHelper();
+
+ void LoadCache();
+
+ private:
+ enum OpType {
+ TERMINATE,
+ OPEN_NEXT,
+ OPEN_NEXT_COMPLETE,
+ READ_COMPLETE,
+ ITERATION_FINISHED
+ };
+
+
+ void OnOpComplete(int rv);
+
+ int OpenNextEntry();
+ int OpenNextEntryComplete(int rv);
+ int ReadComplete(int rv);
+ int IterationComplete(int rv);
+
+ ShaderDiskCache* cache_;
+ ShaderLoadedCallback shader_loaded_callback_;
+ OpType op_type_;
+ std::unique_ptr<disk_cache::Backend::Iterator> iter_;
+ scoped_refptr<net::IOBufferWithSize> buf_;
+ disk_cache::Entry* entry_;
+ base::WeakPtrFactory<ShaderDiskReadHelper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper);
+};
+
+class ShaderClearHelper : public base::ThreadChecker {
+ public:
+ ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache,
+ const base::FilePath& path,
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const base::Closure& callback);
+ ~ShaderClearHelper();
+
+ void Clear();
+
+ private:
+ enum OpType {
+ TERMINATE,
+ VERIFY_CACHE_SETUP,
+ DELETE_CACHE
+ };
+
+ void DoClearShaderCache(int rv);
+
+ scoped_refptr<ShaderDiskCache> cache_;
+ OpType op_type_;
+ base::FilePath path_;
+ base::Time delete_begin_;
+ base::Time delete_end_;
+ base::Closure callback_;
+ base::WeakPtrFactory<ShaderClearHelper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderClearHelper);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ShaderDiskCacheEntry
+
+ShaderDiskCacheEntry::ShaderDiskCacheEntry(ShaderDiskCache* cache,
+ const std::string& key,
+ const std::string& shader)
+ : cache_(cache),
+ op_type_(OPEN_ENTRY),
+ key_(key),
+ shader_(shader),
+ entry_(nullptr),
+ weak_ptr_factory_(this) {
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+}
+
+ShaderDiskCacheEntry::~ShaderDiskCacheEntry() {
+ DCHECK(CalledOnValidThread());
+ if (entry_)
+ entry_->Close();
+}
+
+void ShaderDiskCacheEntry::Cache() {
+ DCHECK(CalledOnValidThread());
+ int rv = cache_->backend()->OpenEntry(
+ key_, &entry_, base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (rv != net::ERR_IO_PENDING)
+ OnOpComplete(rv);
+}
+
+void ShaderDiskCacheEntry::OnOpComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ // The function calls inside the switch block below can end up destroying
+ // |this|. So hold on to a WeakPtr<>, and terminate the while loop if |this|
+ // has been destroyed.
+ auto weak_ptr = std::move(weak_ptr_);
+ do {
+ switch (op_type_) {
+ case OPEN_ENTRY:
+ rv = OpenCallback(rv);
+ break;
+ case CREATE_ENTRY:
+ rv = WriteCallback(rv);
+ break;
+ case WRITE_DATA:
+ rv = IOComplete(rv);
+ break;
+ }
+ } while (rv != net::ERR_IO_PENDING && weak_ptr);
+ if (weak_ptr)
+ weak_ptr_ = std::move(weak_ptr);
+}
+
+int ShaderDiskCacheEntry::OpenCallback(int rv) {
+ DCHECK(CalledOnValidThread());
+ if (rv == net::OK) {
+ cache_->backend()->OnExternalCacheHit(key_);
+ cache_->EntryComplete(this);
+ return rv;
+ }
+
+ op_type_ = CREATE_ENTRY;
+ return cache_->backend()->CreateEntry(
+ key_, &entry_, base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+int ShaderDiskCacheEntry::WriteCallback(int rv) {
+ DCHECK(CalledOnValidThread());
+ if (rv != net::OK) {
+ LOG(ERROR) << "Failed to create shader cache entry: " << rv;
+ cache_->EntryComplete(this);
+ return rv;
+ }
+
+ op_type_ = WRITE_DATA;
+ scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(shader_);
+ return entry_->WriteData(1, 0, io_buf.get(), shader_.length(),
+ base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
+ weak_ptr_factory_.GetWeakPtr()),
+ false);
+}
+
+int ShaderDiskCacheEntry::IOComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ cache_->EntryComplete(this);
+ return rv;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShaderDiskReadHelper
+
+ShaderDiskReadHelper::ShaderDiskReadHelper(ShaderDiskCache* cache,
+ const ShaderLoadedCallback& callback)
+ : cache_(cache),
+ shader_loaded_callback_(callback),
+ op_type_(OPEN_NEXT),
+ buf_(NULL),
+ entry_(NULL),
+ weak_ptr_factory_(this) {}
+
+ShaderDiskReadHelper::~ShaderDiskReadHelper() {
+ DCHECK(CalledOnValidThread());
+ if (entry_)
+ entry_->Close();
+ iter_ = nullptr;
+}
+
+void ShaderDiskReadHelper::LoadCache() {
+ DCHECK(CalledOnValidThread());
+ OnOpComplete(net::OK);
+}
+
+void ShaderDiskReadHelper::OnOpComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ do {
+ switch (op_type_) {
+ case OPEN_NEXT:
+ rv = OpenNextEntry();
+ break;
+ case OPEN_NEXT_COMPLETE:
+ rv = OpenNextEntryComplete(rv);
+ break;
+ case READ_COMPLETE:
+ rv = ReadComplete(rv);
+ break;
+ case ITERATION_FINISHED:
+ rv = IterationComplete(rv);
+ break;
+ case TERMINATE:
+ cache_->ReadComplete();
+ rv = net::ERR_IO_PENDING; // break the loop
+ break;
+ }
+ } while (rv != net::ERR_IO_PENDING);
+}
+
+int ShaderDiskReadHelper::OpenNextEntry() {
+ DCHECK(CalledOnValidThread());
+ op_type_ = OPEN_NEXT_COMPLETE;
+ if (!iter_)
+ iter_ = cache_->backend()->CreateIterator();
+ return iter_->OpenNextEntry(&entry_,
+ base::Bind(&ShaderDiskReadHelper::OnOpComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ if (rv == net::ERR_FAILED) {
+ iter_.reset();
+ op_type_ = ITERATION_FINISHED;
+ return net::OK;
+ }
+
+ if (rv < 0)
+ return rv;
+
+ op_type_ = READ_COMPLETE;
+ buf_ = new net::IOBufferWithSize(entry_->GetDataSize(1));
+ return entry_->ReadData(1, 0, buf_.get(), buf_->size(),
+ base::Bind(&ShaderDiskReadHelper::OnOpComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+int ShaderDiskReadHelper::ReadComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ if (rv && rv == buf_->size() && !shader_loaded_callback_.is_null()) {
+ shader_loaded_callback_.Run(entry_->GetKey(),
+ std::string(buf_->data(), buf_->size()));
+ }
+
+ buf_ = NULL;
+ entry_->Close();
+ entry_ = NULL;
+
+ op_type_ = OPEN_NEXT;
+ return net::OK;
+}
+
+int ShaderDiskReadHelper::IterationComplete(int rv) {
+ DCHECK(CalledOnValidThread());
+ iter_.reset();
+ op_type_ = TERMINATE;
+ return net::OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShaderClearHelper
+
+ShaderClearHelper::ShaderClearHelper(scoped_refptr<ShaderDiskCache> cache,
+ const base::FilePath& path,
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const base::Closure& callback)
+ : cache_(std::move(cache)),
+ op_type_(VERIFY_CACHE_SETUP),
+ path_(path),
+ delete_begin_(delete_begin),
+ delete_end_(delete_end),
+ callback_(callback),
+ weak_ptr_factory_(this) {}
+
+ShaderClearHelper::~ShaderClearHelper() {
+ DCHECK(CalledOnValidThread());
+}
+
+void ShaderClearHelper::Clear() {
+ DCHECK(CalledOnValidThread());
+ DoClearShaderCache(net::OK);
+}
+
+void ShaderClearHelper::DoClearShaderCache(int rv) {
+ DCHECK(CalledOnValidThread());
+ while (rv != net::ERR_IO_PENDING) {
+ switch (op_type_) {
+ case VERIFY_CACHE_SETUP:
+ rv = cache_->SetAvailableCallback(
+ base::Bind(&ShaderClearHelper::DoClearShaderCache,
+ weak_ptr_factory_.GetWeakPtr()));
+ op_type_ = DELETE_CACHE;
+ break;
+ case DELETE_CACHE:
+ rv = cache_->Clear(delete_begin_, delete_end_,
+ base::Bind(&ShaderClearHelper::DoClearShaderCache,
+ weak_ptr_factory_.GetWeakPtr()));
+ op_type_ = TERMINATE;
+ break;
+ case TERMINATE:
+ callback_.Run();
+ // Calling CacheCleared() destroys |this|.
+ ShaderCacheFactory::GetInstance()->CacheCleared(path_);
+ rv = net::ERR_IO_PENDING; // Break the loop.
+ break;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShaderCacheFactory
+
+// static
+void ShaderCacheFactory::InitInstance(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner) {
+ if (task_runner->BelongsToCurrentThread()) {
+ CreateFactoryInstance(std::move(cache_task_runner));
+ } else {
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&ShaderCacheFactory::CreateFactoryInstance,
+ std::move(cache_task_runner)));
+ }
+}
+
+// static
+ShaderCacheFactory* ShaderCacheFactory::GetInstance() {
+ DCHECK(!factory_instance || factory_instance->CalledOnValidThread());
+ return factory_instance;
+}
+
+ShaderCacheFactory::ShaderCacheFactory(
+ scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner)
+ : cache_task_runner_(std::move(cache_task_runner)) {}
+
+ShaderCacheFactory::~ShaderCacheFactory() {
+}
+
+// static
+void ShaderCacheFactory::CreateFactoryInstance(
+ scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner) {
+ DCHECK(!factory_instance);
+ factory_instance = new ShaderCacheFactory(std::move(cache_task_runner));
+}
+
+void ShaderCacheFactory::SetCacheInfo(int32_t client_id,
+ const base::FilePath& path) {
+ DCHECK(CalledOnValidThread());
+ client_id_to_path_map_[client_id] = path;
+}
+
+void ShaderCacheFactory::RemoveCacheInfo(int32_t client_id) {
+ DCHECK(CalledOnValidThread());
+ client_id_to_path_map_.erase(client_id);
+}
+
+scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32_t client_id) {
+ DCHECK(CalledOnValidThread());
+ ClientIdToPathMap::iterator iter = client_id_to_path_map_.find(client_id);
+ if (iter == client_id_to_path_map_.end())
+ return NULL;
+ return ShaderCacheFactory::GetByPath(iter->second);
+}
+
+scoped_refptr<ShaderDiskCache> ShaderCacheFactory::GetByPath(
+ const base::FilePath& path) {
+ DCHECK(CalledOnValidThread());
+ ShaderCacheMap::iterator iter = shader_cache_map_.find(path);
+ if (iter != shader_cache_map_.end())
+ return iter->second;
+
+ ShaderDiskCache* cache = new ShaderDiskCache(path);
+ cache->Init(cache_task_runner_);
+ return cache;
+}
+
+void ShaderCacheFactory::AddToCache(const base::FilePath& key,
+ ShaderDiskCache* cache) {
+ DCHECK(CalledOnValidThread());
+ shader_cache_map_[key] = cache;
+}
+
+void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) {
+ DCHECK(CalledOnValidThread());
+ shader_cache_map_.erase(key);
+}
+
+void ShaderCacheFactory::ClearByPath(const base::FilePath& path,
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const base::Closure& callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!callback.is_null());
+
+ auto helper = base::MakeUnique<ShaderClearHelper>(
+ GetByPath(path), path, delete_begin, delete_end, callback);
+
+ // We could receive requests to clear the same path with different
+ // begin/end times. So, we keep a list of requests. If we haven't seen this
+ // path before we kick off the clear and add it to the list. If we have see it
+ // already, then we already have a clear running. We add this clear to the
+ // list and wait for any previous clears to finish.
+ ShaderClearMap::iterator iter = shader_clear_map_.find(path);
+ if (iter != shader_clear_map_.end()) {
+ iter->second.push(std::move(helper));
+ return;
+ }
+
+ // Insert the helper in the map before calling Clear(), since it can lead to a
+ // call back into CacheCleared().
+ ShaderClearHelper* helper_ptr = helper.get();
+ shader_clear_map_.insert(
+ std::pair<base::FilePath, ShaderClearQueue>(path, ShaderClearQueue()));
+ shader_clear_map_[path].push(std::move(helper));
+ helper_ptr->Clear();
+}
+
+void ShaderCacheFactory::CacheCleared(const base::FilePath& path) {
+ DCHECK(CalledOnValidThread());
+
+ ShaderClearMap::iterator iter = shader_clear_map_.find(path);
+ if (iter == shader_clear_map_.end()) {
+ LOG(ERROR) << "Completed clear but missing clear helper.";
+ return;
+ }
+
+ iter->second.pop();
+
+ // If there are remaining items in the list we trigger the Clear on the
+ // next one.
+ if (!iter->second.empty()) {
+ iter->second.front()->Clear();
+ return;
+ }
+
+ shader_clear_map_.erase(iter);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ShaderDiskCache
+
+ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path)
+ : cache_available_(false),
+ cache_path_(cache_path),
+ is_initialized_(false) {
+ ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this);
+}
+
+ShaderDiskCache::~ShaderDiskCache() {
+ ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_);
+}
+
+void ShaderDiskCache::Init(
+ scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner) {
+ if (is_initialized_) {
+ NOTREACHED(); // can't initialize disk cache twice.
+ return;
+ }
+ is_initialized_ = true;
+
+ int rv = disk_cache::CreateCacheBackend(
+ net::SHADER_CACHE, net::CACHE_BACKEND_DEFAULT,
+ cache_path_.Append(kGpuCachePath),
+ gpu::kDefaultMaxProgramCacheMemoryBytes, true, cache_task_runner, NULL,
+ &backend_, base::Bind(&ShaderDiskCache::CacheCreatedCallback, this));
+
+ if (rv == net::OK)
+ cache_available_ = true;
+}
+
+void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) {
+ if (!cache_available_)
+ return;
+
+ auto shim = base::MakeUnique<ShaderDiskCacheEntry>(this, key, shader);
+ shim->Cache();
+ auto* raw_ptr = shim.get();
+ entries_.insert(std::make_pair(raw_ptr, std::move(shim)));
+}
+
+int ShaderDiskCache::Clear(
+ const base::Time begin_time, const base::Time end_time,
+ const net::CompletionCallback& completion_callback) {
+ int rv;
+ if (begin_time.is_null()) {
+ rv = backend_->DoomAllEntries(completion_callback);
+ } else {
+ rv = backend_->DoomEntriesBetween(begin_time, end_time,
+ completion_callback);
+ }
+ return rv;
+}
+
+int32_t ShaderDiskCache::Size() {
+ if (!cache_available_)
+ return -1;
+ return backend_->GetEntryCount();
+}
+
+int ShaderDiskCache::SetAvailableCallback(
+ const net::CompletionCallback& callback) {
+ if (cache_available_)
+ return net::OK;
+ available_callback_ = callback;
+ return net::ERR_IO_PENDING;
+}
+
+void ShaderDiskCache::CacheCreatedCallback(int rv) {
+ if (rv != net::OK) {
+ LOG(ERROR) << "Shader Cache Creation failed: " << rv;
+ return;
+ }
+ helper_ =
+ base::MakeUnique<ShaderDiskReadHelper>(this, shader_loaded_callback_);
+ helper_->LoadCache();
+}
+
+void ShaderDiskCache::EntryComplete(ShaderDiskCacheEntry* entry) {
+ entries_.erase(entry);
+ if (entries_.empty() && !cache_complete_callback_.is_null())
+ cache_complete_callback_.Run(net::OK);
+}
+
+void ShaderDiskCache::ReadComplete() {
+ helper_ = nullptr;
+
+ // The cache is considered available after we have finished reading any
+ // of the old cache values off disk. This prevents a potential race where we
+ // are reading from disk and execute a cache clear at the same time.
+ cache_available_ = true;
+ if (!available_callback_.is_null()) {
+ available_callback_.Run(net::OK);
+ available_callback_.Reset();
+ }
+}
+
+int ShaderDiskCache::SetCacheCompleteCallback(
+ const net::CompletionCallback& callback) {
+ if (entries_.empty()) {
+ return net::OK;
+ }
+ cache_complete_callback_ = callback;
+ return net::ERR_IO_PENDING;
+}
+
+} // namespace content
+
« no previous file with comments | « content/browser/gpu/shader_disk_cache.h ('k') | content/browser/gpu/shader_disk_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698