diff options
author | dsinclair@chromium.org <dsinclair@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 00:01:37 +0000 |
---|---|---|
committer | dsinclair@chromium.org <dsinclair@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-13 00:01:37 +0000 |
commit | e3932abb978b39d8b28db6e9b7d15869d817dad2 (patch) | |
tree | e86df2495c23edf37fb72c2e6b306ef0f0458c70 | |
parent | a11b00cf82c61489fe42878204375524fa2f952a (diff) | |
download | chromium_src-e3932abb978b39d8b28db6e9b7d15869d817dad2.zip chromium_src-e3932abb978b39d8b28db6e9b7d15869d817dad2.tar.gz chromium_src-e3932abb978b39d8b28db6e9b7d15869d817dad2.tar.bz2 |
Add per-profile disk caching of complied GPU shaders.
This CL adds a per-profile disk cache for any shaders that are
complied while using the profile. When the profile is first opened
the shaders will be loaded from disk and used to pre-populate the
GPU memory shader cache.
The disk cache takes the load time for From Dust from ~30 seconds
to ~18 seconds on my Linux machine for any loads after the first.
BUG=166763
Review URL: https://chromiumcodereview.appspot.com/12036056
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187704 0039d316-1c4b-4281-b951-d872f2087c98
35 files changed, 1066 insertions, 43 deletions
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index 0ee45c7..cb79685 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc @@ -76,6 +76,7 @@ std::string DeriveCommandLine(const GURL& start_url, ::switches::kDisableBrowserPluginCompositing, ::switches::kDisableEncryptedMedia, ::switches::kDisableForceCompositingMode, + ::switches::kDisableGpuShaderDiskCache, ::switches::kDisableGpuWatchdog, ::switches::kDisableLoginAnimations, ::switches::kDisableOobeAnimation, diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index ea817c1..607ef84f 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -4,6 +4,7 @@ #include "content/browser/gpu/gpu_process_host.h" +#include "base/base64.h" #include "base/base_switches.h" #include "base/bind.h" #include "base/bind_helpers.h" @@ -12,11 +13,13 @@ #include "base/memory/ref_counted.h" #include "base/metrics/histogram.h" #include "base/process_util.h" +#include "base/sha1.h" #include "base/threading/thread.h" #include "content/browser/browser_child_process_host_impl.h" #include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/gpu/gpu_process_host_ui_shim.h" #include "content/browser/gpu/gpu_surface_tracker.h" +#include "content/browser/gpu/shader_disk_cache.h" #include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/common/child_process_host_impl.h" @@ -28,8 +31,10 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" +#include "gpu/command_buffer/common/constants.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_switches.h" @@ -586,6 +591,11 @@ bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceRelease, OnAcceleratedSurfaceRelease) #endif + IPC_MESSAGE_HANDLER(GpuHostMsg_DestroyChannel, + OnDestroyChannel) + IPC_MESSAGE_HANDLER(GpuHostMsg_CacheShader, + OnCacheShader) + IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message)) IPC_END_MESSAGE_MAP() @@ -619,6 +629,11 @@ void GpuProcessHost::EstablishGpuChannel( } else { callback.Run(IPC::ChannelHandle(), GPUInfo()); } + + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableGpuShaderDiskCache)) { + CreateChannelCache(client_id, gpu::kDefaultMaxProgramCacheMemoryBytes); + } } void GpuProcessHost::CreateViewCommandBuffer( @@ -1091,4 +1106,56 @@ void GpuProcessHost::BlockLiveOffscreenContexts() { } } +std::string GpuProcessHost::GetShaderPrefixKey() { + if (shader_prefix_key_.empty()) { + GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo(); + + std::string in_str = GetContentClient()->GetProduct() + "-" + + info.gl_vendor + "-" + info.gl_renderer + "-" + + info.driver_version + "-" + info.driver_vendor; + + base::Base64Encode(base::SHA1HashString(in_str), &shader_prefix_key_); + } + + return shader_prefix_key_; +} + +void GpuProcessHost::LoadedShader(const std::string& key, + const std::string& data) { + std::string prefix = GetShaderPrefixKey(); + if (!key.compare(0, prefix.length(), prefix)) + Send(new GpuMsg_LoadedShader(data)); +} + +void GpuProcessHost::CreateChannelCache(int32 client_id, size_t cache_size) { + TRACE_EVENT0("gpu", "GpuProcessHost::CreateChannelCache"); + + scoped_refptr<ShaderDiskCache> cache = + ShaderCacheFactory::GetInstance()->Get(client_id); + if (!cache) + return; + + cache->set_max_cache_size(cache_size); + cache->set_host_id(host_id_); + + client_id_to_shader_cache_[client_id] = cache; +} + +void GpuProcessHost::OnDestroyChannel(int32 client_id) { + TRACE_EVENT0("gpu", "GpuProcessHost::OnDestroyChannel"); + client_id_to_shader_cache_.erase(client_id); +} + +void GpuProcessHost::OnCacheShader(int32 client_id, + const std::string& key, + const std::string& shader) { + TRACE_EVENT0("gpu", "GpuProcessHost::OnCacheShader"); + ClientIdToShaderCacheMap::iterator iter = + client_id_to_shader_cache_.find(client_id); + // If the cache doesn't exist then this is an off the record profile. + if (iter == client_id_to_shader_cache_.end()) + return; + iter->second->Cache(GetShaderPrefixKey() + ":" + key, shader); +} + } // namespace content diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h index aaee4e60..2655b36 100644 --- a/content/browser/gpu/gpu_process_host.h +++ b/content/browser/gpu/gpu_process_host.h @@ -39,6 +39,7 @@ struct ChannelHandle; namespace content { class BrowserChildProcessHostImpl; class GpuMainThread; +class ShaderDiskCache; class GpuProcessHost : public BrowserChildProcessHostDelegate, public IPC::Sender, @@ -122,6 +123,8 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate, void ForceShutdown(); + void LoadedShader(const std::string& key, const std::string& data); + private: static bool ValidateHost(GpuProcessHost* host); @@ -166,12 +169,19 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate, const GpuHostMsg_AcceleratedSurfaceRelease_Params& params); #endif + void CreateChannelCache(int32 client_id, size_t cache_size); + void OnDestroyChannel(int32 client_id); + void OnCacheShader(int32 client_id, const std::string& key, + const std::string& shader); + bool LaunchGpuProcess(const std::string& channel_id); void SendOutstandingReplies(); void BlockLiveOffscreenContexts(); + std::string GetShaderPrefixKey(); + // The serial number of the GpuProcessHost / GpuProcessHostUIShim pair. int host_id_; @@ -239,6 +249,12 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate, bool uma_memory_stats_received_; GPUMemoryUmaStats uma_memory_stats_; + typedef std::map<int32, scoped_refptr<ShaderDiskCache> > + ClientIdToShaderCacheMap; + ClientIdToShaderCacheMap client_id_to_shader_cache_; + + std::string shader_prefix_key_; + DISALLOW_COPY_AND_ASSIGN(GpuProcessHost); }; diff --git a/content/browser/gpu/shader_disk_cache.cc b/content/browser/gpu/shader_disk_cache.cc new file mode 100644 index 0000000..ca30937 --- /dev/null +++ b/content/browser/gpu/shader_disk_cache.cc @@ -0,0 +1,424 @@ +// 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/threading/thread_checker.h" +#include "content/browser/gpu/gpu_process_host.h" +#include "content/public/browser/browser_thread.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"); + +void EntryCloser(disk_cache::Entry* entry) { + entry->Close(); +} + +} // namespace + +// ShaderDiskCacheEntry handles the work of caching/updating the cached +// shaders. +class ShaderDiskCacheEntry + : public base::ThreadChecker, + public base::RefCounted<ShaderDiskCacheEntry> { + public: + ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, + const std::string& key, + const std::string& shader); + void Cache(); + + private: + friend class base::RefCounted<ShaderDiskCacheEntry>; + + enum OpType { + TERMINATE, + OPEN_ENTRY, + WRITE_DATA, + CREATE_ENTRY, + }; + + ~ShaderDiskCacheEntry(); + + void OnOpComplete(int rv); + + int OpenCallback(int rv); + int WriteCallback(int rv); + int IOComplete(int rv); + + base::WeakPtr<ShaderDiskCache> cache_; + OpType op_type_; + std::string key_; + std::string shader_; + disk_cache::Entry* entry_; + + 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 base::RefCounted<ShaderDiskReadHelper> { + public: + ShaderDiskReadHelper(base::WeakPtr<ShaderDiskCache> cache, int host_id); + void LoadCache(); + + private: + friend class base::RefCounted<ShaderDiskReadHelper>; + + enum OpType { + TERMINATE, + OPEN_NEXT, + OPEN_NEXT_COMPLETE, + READ_COMPLETE, + ITERATION_FINISHED + }; + + + ~ShaderDiskReadHelper(); + + void OnOpComplete(int rv); + + int OpenNextEntry(); + int OpenNextEntryComplete(int rv); + int ReadComplete(int rv); + int IterationComplete(int rv); + + base::WeakPtr<ShaderDiskCache> cache_; + OpType op_type_; + void* iter_; + scoped_refptr<net::IOBufferWithSize> buf_; + int host_id_; + disk_cache::Entry* entry_; + + DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper); +}; + +ShaderDiskCacheEntry::ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, + const std::string& key, + const std::string& shader) + : cache_(cache), + op_type_(OPEN_ENTRY), + key_(key), + shader_(shader), + entry_(NULL) { +} + +ShaderDiskCacheEntry::~ShaderDiskCacheEntry() { + if (entry_) + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&EntryCloser, entry_)); +} + +void ShaderDiskCacheEntry::Cache() { + DCHECK(CalledOnValidThread()); + if (!cache_) + return; + + int rv = cache_->backend()->OpenEntry( + key_, + &entry_, + base::Bind(&ShaderDiskCacheEntry::OnOpComplete, this)); + if (rv != net::ERR_IO_PENDING) + OnOpComplete(rv); +} + +void ShaderDiskCacheEntry::OnOpComplete(int rv) { + DCHECK(CalledOnValidThread()); + if (!cache_) + return; + + 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; + case TERMINATE: + rv = net::ERR_IO_PENDING; // break the loop. + break; + default: + NOTREACHED(); // Invalid op_type_ provided. + break; + } + } while (rv != net::ERR_IO_PENDING); +} + +int ShaderDiskCacheEntry::OpenCallback(int rv) { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + if (rv == net::OK) { + cache_->backend()->OnExternalCacheHit(key_); + cache_->EntryComplete(this); + op_type_ = TERMINATE; + return rv; + } + + op_type_ = CREATE_ENTRY; + return cache_->backend()->CreateEntry( + key_, + &entry_, + base::Bind(&ShaderDiskCacheEntry::OnOpComplete, this)); +} + +int ShaderDiskCacheEntry::WriteCallback(int rv) { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + if (rv != net::OK) { + LOG(ERROR) << "Failed to create shader cache entry: " << rv; + cache_->EntryComplete(this); + op_type_ = TERMINATE; + return rv; + } + + op_type_ = WRITE_DATA; + scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(shader_); + return entry_->WriteData(1, 0, io_buf, shader_.length(), + base::Bind(&ShaderDiskCacheEntry::OnOpComplete, + this), + false); +} + +int ShaderDiskCacheEntry::IOComplete(int rv) { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + cache_->EntryComplete(this); + op_type_ = TERMINATE; + return rv; +} + +ShaderDiskReadHelper::ShaderDiskReadHelper( + base::WeakPtr<ShaderDiskCache> cache, + int host_id) + : cache_(cache), + op_type_(OPEN_NEXT), + iter_(NULL), + buf_(NULL), + host_id_(host_id), + entry_(NULL) { +} + +void ShaderDiskReadHelper::LoadCache() { + DCHECK(CalledOnValidThread()); + if (!cache_) + return; + OnOpComplete(net::OK); +} + +void ShaderDiskReadHelper::OnOpComplete(int rv) { + DCHECK(CalledOnValidThread()); + if (!cache_) + return; + + 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; + default: + NOTREACHED(); // Invalid state for read helper + rv = net::ERR_FAILED; + break; + } + } while (rv != net::ERR_IO_PENDING); +} + +int ShaderDiskReadHelper::OpenNextEntry() { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + op_type_ = OPEN_NEXT_COMPLETE; + return cache_->backend()->OpenNextEntry( + &iter_, + &entry_, + base::Bind(&ShaderDiskReadHelper::OnOpComplete, this)); +} + +int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + if (rv == net::ERR_FAILED) { + 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_, buf_->size(), + base::Bind(&ShaderDiskReadHelper::OnOpComplete, + this)); +} + +int ShaderDiskReadHelper::ReadComplete(int rv) { + DCHECK(CalledOnValidThread()); + // Called through OnOpComplete, so we know |cache_| is valid. + if (rv && rv == buf_->size()) { + GpuProcessHost* host = GpuProcessHost::FromID(host_id_); + if (host) + host->LoadedShader(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()); + // Called through OnOpComplete, so we know |cache_| is valid. + cache_->backend()->EndEnumeration(&iter_); + iter_ = NULL; + op_type_ = TERMINATE; + return net::OK; +} + +ShaderDiskReadHelper::~ShaderDiskReadHelper() { + if (entry_) + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&EntryCloser, entry_)); +} + +ShaderCacheFactory* ShaderCacheFactory::GetInstance() { + return Singleton<ShaderCacheFactory, + LeakySingletonTraits<ShaderCacheFactory> >::get(); +} + +ShaderCacheFactory::ShaderCacheFactory() { +} + +ShaderCacheFactory::~ShaderCacheFactory() { +} + +void ShaderCacheFactory::SetCacheInfo(int32 client_id, + const base::FilePath& path) { + client_id_to_path_map_[client_id] = path.Append(kGpuCachePath); +} + +void ShaderCacheFactory::RemoveCacheInfo(int32 client_id) { + client_id_to_path_map_.erase(client_id); +} + +scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32 client_id) { + ClientIdToPathMap::iterator client_iter = + client_id_to_path_map_.find(client_id); + if (client_iter == client_id_to_path_map_.end()) + return NULL; + + ShaderCacheMap::iterator iter = shader_cache_map_.find(client_iter->second); + if (iter != shader_cache_map_.end()) + return iter->second; + + ShaderDiskCache* cache = new ShaderDiskCache(client_iter->second); + cache->Init(); + + return cache; +} + +void ShaderCacheFactory::AddToCache(const base::FilePath& key, + ShaderDiskCache* cache) { + shader_cache_map_[key] = cache; +} + +void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) { + shader_cache_map_.erase(key); +} + +ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path) + : cache_available_(false), + max_cache_size_(0), + host_id_(0), + cache_path_(cache_path), + is_initialized_(false), + backend_(NULL) { + ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this); +} + +ShaderDiskCache::~ShaderDiskCache() { + ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_); +} + +void ShaderDiskCache::Init() { + if (is_initialized_) { + NOTREACHED(); // can't initialize disk cache twice. + return; + } + is_initialized_ = true; + + int rv = disk_cache::CreateCacheBackend( + net::SHADER_CACHE, + cache_path_, + max_cache_size_, + true, + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), + 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; + + ShaderDiskCacheEntry* shim = + new ShaderDiskCacheEntry(AsWeakPtr(), key, shader); + shim->Cache(); + + entry_map_[shim] = shim; +} + +void ShaderDiskCache::CacheCreatedCallback(int rv) { + if (rv != net::OK) { + LOG(ERROR) << "Shader Cache Creation failed: " << rv; + return; + } + + cache_available_ = true; + + helper_ = new ShaderDiskReadHelper(AsWeakPtr(), host_id_); + helper_->LoadCache(); +} + +void ShaderDiskCache::EntryComplete(void* entry) { + entry_map_.erase(entry); +} + +void ShaderDiskCache::ReadComplete() { + helper_ = NULL; +} + +} // namespace content + diff --git a/content/browser/gpu/shader_disk_cache.h b/content/browser/gpu/shader_disk_cache.h new file mode 100644 index 0000000..3ca5420 --- /dev/null +++ b/content/browser/gpu/shader_disk_cache.h @@ -0,0 +1,102 @@ +// 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. + +#ifndef CONTENT_BROWSER_GPU_SHADER_DISK_CACHE_H_ +#define CONTENT_BROWSER_GPU_SHADER_DISK_CACHE_H_ + +#include <map> +#include <string> + +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "net/disk_cache/disk_cache.h" + +namespace content { + +class ShaderDiskCacheEntry; +class ShaderDiskReadHelper; + +// ShaderDiskCache is the interface to the on disk cache for +// GL shaders. +// +// While this class is both RefCounted and SupportsWeakPtr +// when using this class you should work with the RefCounting. +// The WeakPtr is needed interally. +class ShaderDiskCache + : public base::RefCounted<ShaderDiskCache>, + public base::SupportsWeakPtr<ShaderDiskCache> { + public: + void Init(); + + void set_host_id(int host_id) { host_id_ = host_id; } + void set_max_cache_size(size_t max_cache_size) { + max_cache_size_ = max_cache_size; + } + + void Cache(const std::string& key, const std::string& shader); + + private: + friend class base::RefCounted<ShaderDiskCache>; + friend class ShaderDiskCacheEntry; + friend class ShaderDiskReadHelper; + friend class ShaderCacheFactory; + + explicit ShaderDiskCache(const base::FilePath& cache_path); + ~ShaderDiskCache(); + + void CacheCreatedCallback(int rv); + + disk_cache::Backend* backend() { return backend_; } + + void EntryComplete(void* entry); + void ReadComplete(); + + bool cache_available_; + size_t max_cache_size_; + int host_id_; + base::FilePath cache_path_; + bool is_initialized_; + + disk_cache::Backend* backend_; + + scoped_refptr<ShaderDiskReadHelper> helper_; + std::map<void*, scoped_refptr<ShaderDiskCacheEntry> > entry_map_; + + DISALLOW_COPY_AND_ASSIGN(ShaderDiskCache); +}; + +// ShaderCacheFactory maintains a cache of ShaderDiskCache objects +// so we only create one per profile directory. +class ShaderCacheFactory { + public: + static ShaderCacheFactory* GetInstance(); + + scoped_refptr<ShaderDiskCache> Get(int32 client_id); + + void SetCacheInfo(int32 client_id, const base::FilePath& path); + void RemoveCacheInfo(int32 client_id); + + void AddToCache(const base::FilePath& path, ShaderDiskCache* cache); + void RemoveFromCache(const base::FilePath& path); + + private: + friend struct DefaultSingletonTraits<ShaderCacheFactory>; + + ShaderCacheFactory(); + ~ShaderCacheFactory(); + + typedef std::map<base::FilePath, ShaderDiskCache*> ShaderCacheMap; + ShaderCacheMap shader_cache_map_; + + typedef std::map<int32, base::FilePath> ClientIdToPathMap; + ClientIdToPathMap client_id_to_path_map_; + + DISALLOW_COPY_AND_ASSIGN(ShaderCacheFactory); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_GPU_SHADER_DISK_CACHE_H_ + diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index fa7fb67..62f6687 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -53,6 +53,7 @@ #include "content/browser/geolocation/geolocation_dispatcher_host.h" #include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/gpu/gpu_process_host.h" +#include "content/browser/gpu/shader_disk_cache.h" #include "content/browser/histogram_message_filter.h" #include "content/browser/hyphenator/hyphenator_message_filter.h" #include "content/browser/in_process_webkit/indexed_db_context_impl.h" @@ -136,6 +137,17 @@ extern bool g_exited_main_message_loop; static const char* kSiteProcessMapKeyName = "content_site_process_map"; namespace content { +namespace { + +void CacheShaderInfo(int32 id, base::FilePath path) { + ShaderCacheFactory::GetInstance()->SetCacheInfo(id, path); +} + +void RemoveShaderInfo(int32 id) { + ShaderCacheFactory::GetInstance()->RemoveCacheInfo(id); +} + +} // namespace // This class creates the IO thread for the renderer when running in // single-process mode. It's not used in multi-process mode. @@ -355,6 +367,13 @@ RenderProcessHostImpl::RenderProcessHostImpl( g_all_hosts.Get().set_check_on_null_data(true); // Initialize |child_process_activity_time_| to a reasonable value. mark_child_process_activity_time(); + + if (!GetBrowserContext()->IsOffTheRecord()) { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&CacheShaderInfo, GetID(), + GetBrowserContext()->GetPath())); + } + // Note: When we create the RenderProcessHostImpl, it's technically // backgrounded, because it has no visible listeners. But the process // doesn't actually exist yet, so we'll Background it later, after @@ -374,6 +393,9 @@ RenderProcessHostImpl::~RenderProcessHostImpl() { ClearTransportDIBCache(); UnregisterHost(GetID()); + + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&RemoveShaderInfo, GetID())); } void RenderProcessHostImpl::EnableSendQueue() { diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index 52554284..d9b26d4 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc @@ -26,9 +26,9 @@ #include "content/public/common/content_switches.h" #include "crypto/hmac.h" #include "gpu/command_buffer/common/mailbox.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "gpu/command_buffer/service/image_manager.h" #include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/gpu_scheduler.h" #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_proxy.h" #include "ui/gl/gl_context.h" @@ -966,4 +966,10 @@ void GpuChannel::MessageProcessed() { } } +void GpuChannel::CacheShader(const std::string& key, + const std::string& shader) { + gpu_channel_manager_->Send( + new GpuHostMsg_CacheShader(client_id_, key, shader)); +} + } // namespace content diff --git a/content/common/gpu/gpu_channel.h b/content/common/gpu/gpu_channel.h index 8f21b35..44fd75d8 100644 --- a/content/common/gpu/gpu_channel.h +++ b/content/common/gpu/gpu_channel.h @@ -148,6 +148,8 @@ class GpuChannel : public IPC::Listener, } #endif + void CacheShader(const std::string& key, const std::string& shader); + protected: virtual ~GpuChannel(); diff --git a/content/common/gpu/gpu_channel_manager.cc b/content/common/gpu/gpu_channel_manager.cc index 7f775df..808c8d9 100644 --- a/content/common/gpu/gpu_channel_manager.cc +++ b/content/common/gpu/gpu_channel_manager.cc @@ -69,6 +69,7 @@ gpu::gles2::ProgramCache* GpuChannelManager::program_cache() { } void GpuChannelManager::RemoveChannel(int client_id) { + Send(new GpuHostMsg_DestroyChannel(client_id)); gpu_channels_.erase(client_id); } @@ -103,6 +104,7 @@ bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) { OnCreateViewCommandBuffer) IPC_MESSAGE_HANDLER(GpuMsg_CreateImage, OnCreateImage) IPC_MESSAGE_HANDLER(GpuMsg_DeleteImage, OnDeleteImage) + IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() return handled; @@ -252,6 +254,11 @@ void GpuChannelManager::OnDeleteImageSyncPointRetired( } } +void GpuChannelManager::OnLoadedShader(std::string program_proto) { + if (program_cache()) + program_cache()->LoadProgram(program_proto); +} + void GpuChannelManager::LoseAllContexts() { MessageLoop::current()->PostTask( FROM_HERE, diff --git a/content/common/gpu/gpu_channel_manager.h b/content/common/gpu/gpu_channel_manager.h index 0892cda..bc75f56 100644 --- a/content/common/gpu/gpu_channel_manager.h +++ b/content/common/gpu/gpu_channel_manager.h @@ -6,6 +6,7 @@ #define CONTENT_COMMON_GPU_GPU_CHANNEL_MANAGER_H_ #include <deque> +#include <string> #include <vector> #include "base/hash_tables.h" @@ -121,6 +122,7 @@ class GpuChannelManager : public IPC::Listener, void DeleteImage(int32 client_id, int32 image_id); void OnDeleteImage(int32 client_id, int32 image_id, int32 sync_point); void OnDeleteImageSyncPointRetired(ImageOperation*); + void OnLoadedShader(std::string shader); void OnLoseAllContexts(); diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index 7e53996..c74d437 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc @@ -467,6 +467,9 @@ void GpuCommandBufferStub::OnInitialize( decoder_->SetMsgCallback( base::Bind(&GpuCommandBufferStub::SendConsoleMessage, base::Unretained(this))); + decoder_->SetShaderCacheCallback( + base::Bind(&GpuCommandBufferStub::SendCachedShader, + base::Unretained(this))); decoder_->SetWaitSyncPointCallback( base::Bind(&GpuCommandBufferStub::OnWaitSyncPoint, base::Unretained(this))); @@ -824,6 +827,11 @@ void GpuCommandBufferStub::SendConsoleMessage( Send(msg); } +void GpuCommandBufferStub::SendCachedShader( + const std::string& key, const std::string& shader) { + channel_->CacheShader(key, shader); +} + void GpuCommandBufferStub::AddDestructionObserver( DestructionObserver* observer) { destruction_observers_.AddObserver(observer); diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index 400b125..03de927 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h @@ -119,6 +119,8 @@ class GpuCommandBufferStub // Sends a message to the console. void SendConsoleMessage(int32 id, const std::string& message); + void SendCachedShader(const std::string& key, const std::string& shader); + gfx::GLSurface* surface() const { return surface_; } void AddDestructionObserver(DestructionObserver* observer); diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 0c1ccdb..1cac2e7 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -319,6 +319,20 @@ IPC_MESSAGE_CONTROL1(GpuHostMsg_Initialized, IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished, IPC::ChannelHandle /* channel_handle */) +// Message from GPU to notify to destroy the channel. +IPC_MESSAGE_CONTROL1(GpuHostMsg_DestroyChannel, + int32 /* client_id */) + +// Message to cache the given shader information. +IPC_MESSAGE_CONTROL3(GpuHostMsg_CacheShader, + int32 /* client_id */, + std::string /* key */, + std::string /* shader */) + +// Message to the GPU that a shader was loaded from disk. +IPC_MESSAGE_CONTROL1(GpuMsg_LoadedShader, + std::string /* encoded shader */) + // Respond from GPU to a GpuMsg_CreateViewCommandBuffer message. IPC_MESSAGE_CONTROL1(GpuHostMsg_CommandBufferCreated, int32 /* route_id */) diff --git a/content/content_browser.gypi b/content/content_browser.gypi index e31f9b6..332e4f7 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -492,6 +492,8 @@ 'browser/gpu/gpu_surface_tracker.h', 'browser/gpu/gpu_util.cc', 'browser/gpu/gpu_util.h', + 'browser/gpu/shader_disk_cache.cc', + 'browser/gpu/shader_disk_cache.h', 'browser/histogram_controller.cc', 'browser/histogram_controller.h', 'browser/histogram_internals_request_job.cc', @@ -4,6 +4,7 @@ include_rules = [ "+third_party/amd", "+third_party/re2", "+third_party/smhasher", + "+third_party/protbuf", "+../../gpu_export.h", "+../command_buffer", "+../client", diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h index a2eeb74..491f443 100644 --- a/gpu/command_buffer/common/constants.h +++ b/gpu/command_buffer/common/constants.h @@ -50,6 +50,9 @@ const int32 kInvalidSharedMemoryId = -1; // Common Command Buffer shared memory transfer buffer ID. const int32 kCommandBufferSharedMemoryId = 4; +// The size to set for the program cache. +const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024; + } // namespace gpu #endif // GPU_COMMAND_BUFFER_COMMON_CONSTANTS_H_ diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto new file mode 100644 index 0000000..c165443 --- /dev/null +++ b/gpu/command_buffer/service/disk_cache_proto.proto @@ -0,0 +1,23 @@ +option optimize_for = LITE_RUNTIME; + +message ShaderInfoProto { + optional int32 type = 1; + optional int32 size = 2; + optional string name = 3; + optional string key = 4; +} + +message ShaderProto { + optional bytes sha = 1; + repeated ShaderInfoProto attribs = 2; + repeated ShaderInfoProto uniforms = 3; +} + +message GpuProgramProto { + optional bytes sha = 1; + optional int32 format = 2; + optional bytes program = 3; + + optional ShaderProto vertex_shader = 4; + optional ShaderProto fragment_shader = 5; +} diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 388525a..94de0f5 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -632,6 +632,8 @@ class GLES2DecoderImpl : public GLES2Decoder { const base::Callback<void(gfx::Size)>& callback) OVERRIDE; virtual void SetMsgCallback(const MsgCallback& callback) OVERRIDE; + virtual void SetShaderCacheCallback( + const ShaderCacheCallback& callback) OVERRIDE; virtual void SetWaitSyncPointCallback( const WaitSyncPointCallback& callback) OVERRIDE; @@ -1720,6 +1722,8 @@ class GLES2DecoderImpl : public GLES2Decoder { MsgCallback msg_callback_; WaitSyncPointCallback wait_sync_point_callback_; + ShaderCacheCallback shader_cache_callback_; + StreamTextureManager* stream_texture_manager_; scoped_ptr<gfx::AsyncPixelTransferDelegate> async_pixel_transfer_delegate_; @@ -3104,6 +3108,11 @@ void GLES2DecoderImpl::SetMsgCallback(const MsgCallback& callback) { msg_callback_ = callback; } +void GLES2DecoderImpl::SetShaderCacheCallback( + const ShaderCacheCallback& callback) { + shader_cache_callback_ = callback; +} + void GLES2DecoderImpl::SetWaitSyncPointCallback( const WaitSyncPointCallback& callback) { wait_sync_point_callback_ = callback; @@ -5149,7 +5158,8 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program_id) { if (program->Link(shader_manager(), vertex_translator, fragment_translator, - feature_info_)) { + feature_info_, + shader_cache_callback_)) { if (program == state_.current_program.get()) { if (workarounds().use_current_program_after_successful_link) { glUseProgram(program->service_id()); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index da25df6..27fe968 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -78,6 +78,9 @@ struct DisallowedFeatures { bool gpu_memory_manager; }; +typedef base::Callback<void(const std::string& key, + const std::string& shader)> ShaderCacheCallback; + // This class implements the AsyncAPIInterface interface, decoding GLES2 // commands and calling GL. class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>, @@ -271,6 +274,7 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>, // A callback for messages from the decoder. virtual void SetMsgCallback(const MsgCallback& callback) = 0; + virtual void SetShaderCacheCallback(const ShaderCacheCallback& callback) = 0; // Sets the callback for waiting on a sync point. The callback returns the // scheduling status (i.e. true if the channel is still scheduled). diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h index eb3487c..2dd0df8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h @@ -109,6 +109,8 @@ class MockGLES2Decoder : public GLES2Decoder { const char* file, int line, const char* filename)); MOCK_METHOD1(SetMsgCallback, void(const MsgCallback& callback)); + MOCK_METHOD1(SetShaderCacheCallback, + void(const ShaderCacheCallback& callback)); MOCK_METHOD1(SetWaitSyncPointCallback, void(const WaitSyncPointCallback& callback)); MOCK_METHOD0(GetTextureUploadCount, uint32()); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc index 70ce437..daa98ae 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc @@ -27,6 +27,11 @@ using ::testing::StrEq; namespace gpu { namespace gles2 { +namespace { +void ShaderCacheCb(const std::string& key, const std::string& shader) { +} +} // namespace + class GLES2DecoderTest1 : public GLES2DecoderTestBase { public: GLES2DecoderTest1() { } @@ -246,7 +251,7 @@ void GLES2DecoderTestBase::SpecializedSetup<cmds::GetProgramInfoLog, 0>( attach_cmd.Init(client_program_id_, kClientFragmentShaderId); EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); }; template <> diff --git a/gpu/command_buffer/service/gpu_switches.cc b/gpu/command_buffer/service/gpu_switches.cc index d029cfb..ce9e49b 100644 --- a/gpu/command_buffer/service/gpu_switches.cc +++ b/gpu/command_buffer/service/gpu_switches.cc @@ -53,6 +53,9 @@ const char kGpuProgramCacheSizeKb[] = "gpu-program-cache-size-kb"; const char kTraceGL[] = "trace-gl"; +// Disables the GPU shader on disk cache. +const char kDisableGpuShaderDiskCache[] = "disable-gpu-shader-disk-cache"; + const char* kGpuSwitches[] = { kCompileShaderAlwaysSucceeds, kDisableGLErrorLimit, @@ -68,6 +71,7 @@ const char* kGpuSwitches[] = { kForceGpuMemAvailableMb, kGpuProgramCacheSizeKb, kTraceGL, + kDisableGpuShaderDiskCache, }; const int kNumGpuSwitches = arraysize(kGpuSwitches); diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h index 0a51e70..72e5f92 100644 --- a/gpu/command_buffer/service/gpu_switches.h +++ b/gpu/command_buffer/service/gpu_switches.h @@ -25,6 +25,7 @@ GPU_EXPORT extern const char kForceGLFinishWorkaround[]; GPU_EXPORT extern const char kForceGpuMemAvailableMb[]; GPU_EXPORT extern const char kGpuProgramCacheSizeKb[]; GPU_EXPORT extern const char kTraceGL[]; +GPU_EXPORT extern const char kDisableGpuShaderDiskCache[]; GPU_EXPORT extern const char* kGpuSwitches[]; GPU_EXPORT extern const int kNumGpuSwitches; diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc index c153b75..32db0c7 100644 --- a/gpu/command_buffer/service/memory_program_cache.cc +++ b/gpu/command_buffer/service/memory_program_cache.cc @@ -4,16 +4,21 @@ #include "gpu/command_buffer/service/memory_program_cache.h" +#include "base/base64.h" #include "base/command_line.h" #include "base/metrics/histogram.h" #include "base/sha1.h" #include "base/string_number_conversions.h" +#include "gpu/command_buffer/common/constants.h" +#include "gpu/command_buffer/service/disk_cache_proto.pb.h" #include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/shader_manager.h" #include "ui/gl/gl_bindings.h" namespace { + size_t GetCacheSizeBytes() { size_t size; const CommandLine* command_line = CommandLine::ForCurrentProcess(); @@ -23,13 +28,48 @@ size_t GetCacheSizeBytes() { &size)) { return size * 1024; } - return gpu::gles2::MemoryProgramCache::kDefaultMaxProgramCacheMemoryBytes; + return gpu::kDefaultMaxProgramCacheMemoryBytes; } + } // anonymous namespace namespace gpu { namespace gles2 { +namespace { + +enum ShaderMapType { + ATTRIB_MAP = 0, + UNIFORM_MAP +}; + +void StoreShaderInfo(ShaderMapType type, ShaderProto *proto, + const ShaderTranslator::VariableMap& map) { + ShaderTranslator::VariableMap::const_iterator iter; + for (iter = map.begin(); iter != map.end(); iter++) { + ShaderInfoProto* info; + if (type == UNIFORM_MAP) { + info = proto->add_uniforms(); + } else { + info = proto->add_attribs(); + } + + info->set_key(iter->first); + info->set_type(iter->second.type); + info->set_size(iter->second.size); + info->set_name(iter->second.name); + } +} + +void RetrieveShaderInfo(const ShaderInfoProto& proto, + ShaderTranslator::VariableMap* map) { + ShaderTranslator::VariableInfo info(proto.type(), proto.size(), + proto.name()); + (*map)[proto.key()] = info; +} + +} // namespace + MemoryProgramCache::MemoryProgramCache() : max_size_bytes_(GetCacheSizeBytes()), curr_size_bytes_(0) { } @@ -88,7 +128,8 @@ void MemoryProgramCache::SaveLinkedProgram( GLuint program, const Shader* shader_a, const Shader* shader_b, - const LocationMap* bind_attrib_location_map) { + const LocationMap* bind_attrib_location_map, + const ShaderCacheCallback& shader_callback) { GLenum format; GLsizei length = 0; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length); @@ -136,6 +177,34 @@ void MemoryProgramCache::SaveLinkedProgram( store_.erase(found); eviction_helper_.PopKey(); } + + if (!shader_callback.is_null() && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableGpuShaderDiskCache)) { + std::string key; + base::Base64Encode(sha_string, &key); + + GpuProgramProto* proto = GpuProgramProto::default_instance().New(); + proto->set_sha(sha, kHashLength); + proto->set_format(format); + proto->set_program(binary.get(), length); + + ShaderProto* vertex_shader = proto->mutable_vertex_shader(); + vertex_shader->set_sha(a_sha, kHashLength); + StoreShaderInfo(ATTRIB_MAP, vertex_shader, shader_a->attrib_map()); + StoreShaderInfo(UNIFORM_MAP, vertex_shader, shader_a->uniform_map()); + + ShaderProto* fragment_shader = proto->mutable_fragment_shader(); + fragment_shader->set_sha(b_sha, kHashLength); + StoreShaderInfo(ATTRIB_MAP, fragment_shader, shader_b->attrib_map()); + StoreShaderInfo(UNIFORM_MAP, fragment_shader, shader_b->uniform_map()); + + std::string shader; + proto->SerializeToString(&shader); + + shader_callback.Run(key, shader); + } + store_[sha_string] = new ProgramCacheValue(length, format, binary.release(), @@ -156,6 +225,60 @@ void MemoryProgramCache::SaveLinkedProgram( std::string(b_sha, kHashLength)); } +void MemoryProgramCache::LoadProgram(const std::string& program) { + GpuProgramProto* proto = GpuProgramProto::default_instance().New(); + if (proto->ParseFromString(program)) { + ShaderTranslator::VariableMap vertex_attribs; + ShaderTranslator::VariableMap vertex_uniforms; + + for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) { + RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs); + } + + for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) { + RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms); + } + + ShaderTranslator::VariableMap fragment_attribs; + ShaderTranslator::VariableMap fragment_uniforms; + + for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) { + RetrieveShaderInfo(proto->fragment_shader().attribs(i), + &fragment_attribs); + } + + for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) { + RetrieveShaderInfo(proto->fragment_shader().uniforms(i), + &fragment_uniforms); + } + + scoped_array<char> binary(new char[proto->program().length()]); + memcpy(binary.get(), proto->program().c_str(), proto->program().length()); + + store_[proto->sha()] = new ProgramCacheValue(proto->program().length(), + proto->format(), binary.release(), + proto->vertex_shader().sha().c_str(), vertex_attribs, vertex_uniforms, + proto->fragment_shader().sha().c_str(), fragment_attribs, + fragment_uniforms); + + ShaderCompilationSucceededSha(proto->sha()); + ShaderCompilationSucceededSha(proto->vertex_shader().sha()); + ShaderCompilationSucceededSha(proto->fragment_shader().sha()); + + curr_size_bytes_ += proto->program().length(); + eviction_helper_.KeyUsed(proto->sha()); + + UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb", + curr_size_bytes_ / 1024); + + LinkedProgramCacheSuccess(proto->sha(), + proto->vertex_shader().sha(), + proto->fragment_shader().sha()); + } else { + LOG(ERROR) << "Failed to parse proto file."; + } +} + MemoryProgramCache::ProgramCacheValue::ProgramCacheValue( GLsizei _length, GLenum _format, diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h index de699dd..be487d9 100644 --- a/gpu/command_buffer/service/memory_program_cache.h +++ b/gpu/command_buffer/service/memory_program_cache.h @@ -11,6 +11,7 @@ #include "base/hash_tables.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/program_cache.h" #include "gpu/command_buffer/service/program_cache_lru_helper.h" #include "gpu/command_buffer/service/shader_translator.h" @@ -21,8 +22,6 @@ namespace gles2 { // Program cache that stores binaries completely in-memory class GPU_EXPORT MemoryProgramCache : public ProgramCache { public: - static const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024; - MemoryProgramCache(); explicit MemoryProgramCache(const size_t max_cache_size_bytes); virtual ~MemoryProgramCache(); @@ -36,7 +35,10 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache { GLuint program, const Shader* shader_a, const Shader* shader_b, - const LocationMap* bind_attrib_location_map) OVERRIDE; + const LocationMap* bind_attrib_location_map, + const ShaderCacheCallback& shader_callback) OVERRIDE; + + virtual void LoadProgram(const std::string& program) OVERRIDE; private: virtual void ClearBackend() OVERRIDE; diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc index 3c64d3f..f20caeb 100644 --- a/gpu/command_buffer/service/memory_program_cache_unittest.cc +++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc @@ -4,6 +4,7 @@ #include "gpu/command_buffer/service/memory_program_cache.h" +#include "base/bind.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/service/gl_utils.h" #include "gpu/command_buffer/service/shader_manager.h" @@ -75,11 +76,20 @@ class MemoryProgramCacheTest : public testing::Test { MemoryProgramCacheTest() : cache_(new MemoryProgramCache(kCacheSizeBytes)), vertex_shader_(NULL), - fragment_shader_(NULL) { } + fragment_shader_(NULL), + shader_cache_count_(0) { } virtual ~MemoryProgramCacheTest() { shader_manager_.Destroy(false); } + void ShaderCacheCb(const std::string& key, const std::string& shader) { + shader_cache_count_++; + shader_cache_shader_ = shader; + } + + int32 shader_cache_count() { return shader_cache_count_; } + const std::string& shader_cache_shader() { return shader_cache_shader_; } + protected: virtual void SetUp() { gl_.reset(new ::testing::StrictMock<gfx::MockGLInterface>()); @@ -171,6 +181,8 @@ class MemoryProgramCacheTest : public testing::Test { ShaderManager shader_manager_; Shader* vertex_shader_; Shader* fragment_shader_; + int32 shader_cache_count_; + std::string shader_cache_shader_; }; TEST_F(MemoryProgramCacheTest, CacheSave) { @@ -184,12 +196,45 @@ TEST_F(MemoryProgramCacheTest, CacheSave) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( *vertex_shader_->deferred_compilation_source(), *fragment_shader_->deferred_compilation_source(), NULL)); + EXPECT_EQ(1, shader_cache_count()); +} + +TEST_F(MemoryProgramCacheTest, LoadProgram) { + const GLenum kFormat = 1; + const int kProgramId = 10; + const int kBinaryLength = 20; + char test_binary[kBinaryLength]; + for (int i = 0; i < kBinaryLength; ++i) { + test_binary[i] = i; + } + ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); + + SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); + + EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( + *vertex_shader_->deferred_compilation_source(), + *fragment_shader_->deferred_compilation_source(), + NULL)); + EXPECT_EQ(1, shader_cache_count()); + + cache_->Clear(); + + cache_->LoadProgram(shader_cache_shader()); + EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( + *vertex_shader_->deferred_compilation_source(), + *fragment_shader_->deferred_compilation_source(), + NULL)); } TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { @@ -203,7 +248,54 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); + EXPECT_EQ(1, shader_cache_count()); + + VariableMap vertex_attrib_map = vertex_shader_->attrib_map(); + VariableMap vertex_uniform_map = vertex_shader_->uniform_map(); + VariableMap fragment_attrib_map = fragment_shader_->attrib_map(); + VariableMap fragment_uniform_map = fragment_shader_->uniform_map(); + + vertex_shader_->set_attrib_map(VariableMap()); + vertex_shader_->set_uniform_map(VariableMap()); + fragment_shader_->set_attrib_map(VariableMap()); + fragment_shader_->set_uniform_map(VariableMap()); + + SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); + + EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram( + kProgramId, + vertex_shader_, + fragment_shader_, + NULL)); + + // apparently the hash_map implementation on android doesn't have the + // equality operator +#if !defined(OS_ANDROID) + EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map()); + EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map()); + EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map()); + EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map()); +#endif +} + +TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) { + const GLenum kFormat = 1; + const int kProgramId = 10; + const int kBinaryLength = 20; + char test_binary[kBinaryLength]; + for (int i = 0; i < kBinaryLength; ++i) { + test_binary[i] = i; + } + ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); + + SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); + EXPECT_EQ(1, shader_cache_count()); VariableMap vertex_attrib_map = vertex_shader_->attrib_map(); VariableMap vertex_uniform_map = vertex_shader_->uniform_map(); @@ -217,6 +309,9 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); + cache_->Clear(); + cache_->LoadProgram(shader_cache_shader()); + EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram( kProgramId, vertex_shader_, @@ -244,7 +339,9 @@ TEST_F(MemoryProgramCacheTest, LoadFailOnLinkFalse) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); SetExpectationsForLoadLinkedProgramFailure(kProgramId, &emulator); EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( @@ -265,7 +362,9 @@ TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); const std::string vertex_orig_source = *vertex_shader_->deferred_compilation_source(); @@ -304,7 +403,9 @@ TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) { cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, - &binding_map); + &binding_map, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); binding_map["different!"] = 59; EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( @@ -332,7 +433,9 @@ TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) { SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); const int kEvictingProgramId = 11; const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1; @@ -356,7 +459,9 @@ TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) { cache_->SaveLinkedProgram(kEvictingProgramId, vertex_shader_, fragment_shader_, - NULL); + NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( *vertex_shader_->deferred_compilation_source(), @@ -380,7 +485,9 @@ TEST_F(MemoryProgramCacheTest, SaveCorrectProgram) { vertex_shader_->UpdateSource("different!"); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( *vertex_shader_->deferred_compilation_source(), @@ -399,7 +506,9 @@ TEST_F(MemoryProgramCacheTest, LoadCorrectProgram) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( *vertex_shader_->deferred_compilation_source(), @@ -427,7 +536,9 @@ TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) { ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); char test_binary2[kBinaryLength]; @@ -436,7 +547,9 @@ TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) { } ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2); SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2); - cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); + cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL, + base::Bind(&MemoryProgramCacheTest::ShaderCacheCb, + base::Unretained(this))); SetExpectationsForLoadLinkedProgram(kProgramId, &emulator2); EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram( diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h index 35fc9c1..949314d 100644 --- a/gpu/command_buffer/service/mocks.h +++ b/gpu/command_buffer/service/mocks.h @@ -10,6 +10,7 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_ #define GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_ +#include <string> #include <vector> #include "base/logging.h" @@ -103,11 +104,14 @@ class MockProgramCache : public ProgramCache { Shader* shader_b, const LocationMap* bind_attrib_location_map)); - MOCK_METHOD4(SaveLinkedProgram, void( + MOCK_METHOD5(SaveLinkedProgram, void( GLuint program, const Shader* shader_a, const Shader* shader_b, - const LocationMap* bind_attrib_location_map)); + const LocationMap* bind_attrib_location_map, + const ShaderCacheCallback& callback)); + MOCK_METHOD1(LoadProgram, void(const std::string&)); + private: MOCK_METHOD0(ClearBackend, void()); }; diff --git a/gpu/command_buffer/service/program_cache.cc b/gpu/command_buffer/service/program_cache.cc index 821b6e1..bc32dfc 100644 --- a/gpu/command_buffer/service/program_cache.cc +++ b/gpu/command_buffer/service/program_cache.cc @@ -39,7 +39,11 @@ void ProgramCache::ShaderCompilationSucceeded( char sha[kHashLength]; ComputeShaderHash(shader_src, sha); const std::string sha_string(sha, kHashLength); + ShaderCompilationSucceededSha(sha_string); +} +void ProgramCache::ShaderCompilationSucceededSha( + const std::string& sha_string) { CompileStatusMap::iterator it = shader_status_.find(sha_string); if (it == shader_status_.end()) { shader_status_[sha_string] = CompiledShaderInfo(COMPILATION_SUCCEEDED); diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h index c7917d9..e7057e5 100644 --- a/gpu/command_buffer/service/program_cache.h +++ b/gpu/command_buffer/service/program_cache.h @@ -11,6 +11,8 @@ #include "base/hash_tables.h" #include "base/sha1.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/command_buffer/service/shader_manager.h" namespace gpu { namespace gles2 { @@ -45,6 +47,7 @@ class GPU_EXPORT ProgramCache { CompiledShaderStatus GetShaderCompilationStatus( const std::string& shader_src) const; void ShaderCompilationSucceeded(const std::string& shader_src); + void ShaderCompilationSucceededSha(const std::string& sha_string); LinkedProgramStatus GetLinkedProgramStatus( const std::string& untranslated_a, @@ -65,7 +68,10 @@ class GPU_EXPORT ProgramCache { GLuint program, const Shader* shader_a, const Shader* shader_b, - const LocationMap* bind_attrib_location_map) = 0; + const LocationMap* bind_attrib_location_map, + const ShaderCacheCallback& shader_callback) = 0; + + virtual void LoadProgram(const std::string& program) = 0; // clears the cache void Clear(); diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc index d764df7..65f39be 100644 --- a/gpu/command_buffer/service/program_cache_unittest.cc +++ b/gpu/command_buffer/service/program_cache_unittest.cc @@ -23,7 +23,10 @@ class NoBackendProgramCache : public ProgramCache { GLuint /* program */, const Shader* /* shader_a */, const Shader* /* shader_b */, - const LocationMap* /* bind_attrib_location_map */) OVERRIDE { } + const LocationMap* /* bind_attrib_location_map */, + const ShaderCacheCallback& /* callback */) OVERRIDE { } + + virtual void LoadProgram(const std::string& /* program */) OVERRIDE {} virtual void ClearBackend() OVERRIDE {} diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index 2725476..db935b7c 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -534,7 +534,8 @@ void ProgramManager::ForceCompileShader(const std::string* source, bool Program::Link(ShaderManager* manager, ShaderTranslator* vertex_translator, ShaderTranslator* fragment_translator, - FeatureInfo* feature_info) { + FeatureInfo* feature_info, + const ShaderCacheCallback& shader_callback) { ClearLinkStatus(); if (!CanLink()) { set_log_info("missing shaders"); @@ -605,7 +606,8 @@ bool Program::Link(ShaderManager* manager, cache->SaveLinkedProgram(service_id(), attached_shaders_[0], attached_shaders_[1], - &bind_attrib_location_map_); + &bind_attrib_location_map_, + shader_callback); } UMA_HISTOGRAM_CUSTOM_COUNTS( "GPU.ProgramCache.BinaryCacheMissTime", diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 4513d45..16dd97d 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -13,6 +13,8 @@ #include "base/memory/ref_counted.h" #include "gpu/command_buffer/service/common_decoder.h" #include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/command_buffer/service/shader_manager.h" #include "gpu/gpu_export.h" namespace gpu { @@ -155,7 +157,8 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { bool Link(ShaderManager* manager, ShaderTranslator* vertex_translator, ShaderTranslator* fragment_shader, - FeatureInfo* feature_info); + FeatureInfo* feature_info, + const ShaderCacheCallback& shader_callback); // Performs glValidateProgram and related activities. void Validate(); diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 46ba708..94bce93 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -35,6 +35,10 @@ using ::testing::StrictMock; namespace gpu { namespace gles2 { +namespace { +void ShaderCacheCb(const std::string& key, const std::string& shader) {} +} // namespace + class ProgramManagerTest : public testing::Test { public: ProgramManagerTest() : manager_(NULL) { } @@ -219,7 +223,7 @@ class ProgramManagerWithShaderTest : public testing::Test { program_->AttachShader(&shader_manager_, vertex_shader); program_->AttachShader(&shader_manager_, fragment_shader); - program_->Link(NULL, NULL, NULL, NULL); + program_->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); } void SetupShader(AttribInfo* attribs, size_t num_attribs, @@ -252,7 +256,7 @@ class ProgramManagerWithShaderTest : public testing::Test { SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, service_id); } - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); GLint link_status; program->GetProgramiv(GL_LINK_STATUS, &link_status); return (static_cast<bool>(link_status) == expected_link_status); @@ -579,7 +583,7 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) { ASSERT_TRUE(program != NULL); EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader)); EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader)); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); GLint value = 0; program->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &value); EXPECT_EQ(3, value); @@ -647,7 +651,7 @@ TEST_F(ProgramManagerWithShaderTest, SimilarArrayNames) { ASSERT_TRUE(program != NULL); EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader)); EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader)); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); // Check that we get the correct locations. EXPECT_EQ(kUniform2FakeLocation, @@ -736,10 +740,10 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) { kServiceProgramId); Program* program = manager_.CreateProgram( kClientProgramId, kServiceProgramId); - ASSERT_TRUE(program != NULL); + ASSERT_TRUE(program!= NULL); EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader)); EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader)); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); // Check that we got the good type, not the bad. // Check Attribs for (unsigned index = 0; index < kNumAttribs; ++index) { @@ -1058,7 +1062,7 @@ TEST_F(ProgramManagerWithShaderTest, ClearWithSamplerTypes) { const size_t kNumUniforms = arraysize(kUniforms); SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, kServiceProgramId); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); SetupExpectationsForClearingUniforms(kUniforms, kNumUniforms); manager_.ClearUniforms(program); } @@ -1130,7 +1134,7 @@ TEST_F(ProgramManagerWithShaderTest, BindUniformLocation) { const size_t kNumUniforms = arraysize(kUniforms); SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, kServiceProgramId); - program->Link(NULL, NULL, NULL, NULL); + program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb)); EXPECT_EQ(kUniform1DesiredLocation, program->GetUniformFakeLocation(kUniform1Name)); @@ -1223,7 +1227,8 @@ class ProgramManagerWithCacheTest : public testing::Test { program->service_id(), vertex_shader, fragment_shader, - &program->bind_attrib_location_map())).Times(1); + &program->bind_attrib_location_map(), + _)).Times(1); } void SetExpectationsForNotCachingProgram() { @@ -1240,7 +1245,8 @@ class ProgramManagerWithCacheTest : public testing::Test { program->service_id(), vertex_shader, fragment_shader, - &program->bind_attrib_location_map())).Times(0); + &program->bind_attrib_location_map(), + _)).Times(0); } void SetExpectationsForProgramLoad(ProgramCache::ProgramLoadResult result) { @@ -1375,7 +1381,8 @@ TEST_F(ProgramManagerWithCacheTest, CacheProgramOnSuccessfulLink) { SetShadersCompiled(); SetExpectationsForProgramLink(); SetExpectationsForProgramCached(); - EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL)); + EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL, + base::Bind(&ShaderCacheCb))); } TEST_F(ProgramManagerWithCacheTest, CompileShaderOnLinkCacheMiss) { @@ -1387,7 +1394,8 @@ TEST_F(ProgramManagerWithCacheTest, CompileShaderOnLinkCacheMiss) { SetExpectationsForSuccessCompile(vertex_shader_); SetExpectationsForProgramLink(); SetExpectationsForProgramCached(); - EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL, info.get())); + EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL, + info.get(), base::Bind(&ShaderCacheCb))); } TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) { @@ -1400,7 +1408,8 @@ TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) { SetExpectationsForNotCachingProgram(); SetExpectationsForProgramLoadSuccess(); - EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL)); + EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL, + base::Bind(&ShaderCacheCb))); } TEST_F(ProgramManagerWithCacheTest, CompileAndLinkOnProgramCacheError) { @@ -1414,7 +1423,8 @@ TEST_F(ProgramManagerWithCacheTest, CompileAndLinkOnProgramCacheError) { SetExpectationsForProgramCached(); scoped_refptr<FeatureInfo> info(new FeatureInfo()); - EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL, info.get())); + EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL, info.get(), + base::Bind(&ShaderCacheCb))); } TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeNoCompile) { @@ -1467,7 +1477,8 @@ TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeNoCompile) { SetExpectationsForProgramLoadSuccess(kNewProgramServiceId); scoped_refptr<FeatureInfo> info(new FeatureInfo()); - EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL, info.get())); + EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL, info.get(), + base::Bind(&ShaderCacheCb))); } TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeWithCompile) { @@ -1518,7 +1529,8 @@ TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeWithCompile) { fragment_shader_); SetExpectationsForProgramLink(kNewProgramServiceId); - EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL, info.get())); + EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL, + info.get(), base::Bind(&ShaderCacheCb))); } } // namespace gles2 diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi index f42c527e..c3913b3 100644 --- a/gpu/command_buffer_service.gypi +++ b/gpu/command_buffer_service.gypi @@ -20,6 +20,7 @@ '../ui/ui.gyp:ui', '../third_party/angle/src/build_angle.gyp:translator_glsl', '../third_party/khronos/khronos.gyp:khronos_headers', + '../third_party/protobuf/protobuf.gyp:protobuf_lite', '../third_party/smhasher/smhasher.gyp:cityhash', '../third_party/re2/re2.gyp:re2', ], diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 005573d..8255fd88 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -288,6 +288,16 @@ 'conditions': [ ['component=="static_library"', { 'targets': [ + { + 'target_name': 'disk_cache_proto', + 'type': 'static_library', + 'sources': [ 'command_buffer/service/disk_cache_proto.proto' ], + 'variables': { + 'proto_in_dir': 'command_buffer/service', + 'proto_out_dir': 'gpu/command_buffer/service', + }, + 'includes': [ '../build/protoc.gypi' ], + }, { 'target_name': 'gpu', 'type': 'none', @@ -351,6 +361,7 @@ ], 'dependencies': [ 'command_buffer_common', + 'disk_cache_proto', ], # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [4267, ], @@ -369,6 +380,16 @@ }, { # component != static_library 'targets': [ + { + 'target_name': 'disk_cache_proto', + 'type': 'static_library', + 'sources': [ 'command_buffer/service/disk_cache_proto.proto' ], + 'variables': { + 'proto_in_dir': 'command_buffer/service', + 'proto_out_dir': 'gpu/command_buffer/service', + }, + 'includes': [ '../build/protoc.gypi' ], + }, { 'target_name': 'gpu', 'type': 'shared_library', @@ -388,6 +409,7 @@ 'dependencies': [ '../base/base.gyp:base', 'command_buffer/command_buffer.gyp:gles2_utils', + 'disk_cache_proto', ], # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [4267, ], |