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 /gpu | |
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
Diffstat (limited to 'gpu')
21 files changed, 390 insertions, 42 deletions
@@ -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, ], |