| // Copyright (c) 2012 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 "gpu/command_buffer/service/program_cache.h" |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "gpu/command_buffer/service/mocks.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::Return; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class NoBackendProgramCache : public ProgramCache { |
| public: |
| virtual ProgramLoadResult LoadLinkedProgram( |
| GLuint /* program */, |
| Shader* /* shader_a */, |
| const ShaderTranslatorInterface* /* translator_a */, |
| Shader* /* shader_b */, |
| const ShaderTranslatorInterface* /* translator_b */, |
| const LocationMap* /* bind_attrib_location_map */, |
| const ShaderCacheCallback& /* callback */) OVERRIDE { |
| return PROGRAM_LOAD_SUCCESS; |
| } |
| virtual void SaveLinkedProgram( |
| GLuint /* program */, |
| const Shader* /* shader_a */, |
| const ShaderTranslatorInterface* /* translator_b */, |
| const Shader* /* shader_b */, |
| const ShaderTranslatorInterface* /* translator_b */, |
| const LocationMap* /* bind_attrib_location_map */, |
| const ShaderCacheCallback& /* callback */) OVERRIDE { } |
| |
| virtual void LoadProgram(const std::string& /* program */) OVERRIDE {} |
| |
| virtual void ClearBackend() OVERRIDE {} |
| |
| void SaySuccessfullyCached(const std::string& shader1, |
| const ShaderTranslatorInterface* translator_1, |
| const std::string& shader2, |
| const ShaderTranslatorInterface* translator_2, |
| std::map<std::string, GLint>* attrib_map) { |
| char a_sha[kHashLength]; |
| char b_sha[kHashLength]; |
| ComputeShaderHash(shader1, translator_1, a_sha); |
| ComputeShaderHash(shader2, translator_2, b_sha); |
| |
| char sha[kHashLength]; |
| ComputeProgramHash(a_sha, |
| b_sha, |
| attrib_map, |
| sha); |
| const std::string shaString(sha, kHashLength); |
| |
| LinkedProgramCacheSuccess(shaString, |
| std::string(a_sha, kHashLength), |
| std::string(b_sha, kHashLength)); |
| } |
| |
| void ComputeShaderHash(const std::string& shader, |
| const ShaderTranslatorInterface* translator, |
| char* result) const { |
| ProgramCache::ComputeShaderHash(shader, translator, result); |
| } |
| |
| void ComputeProgramHash(const char* hashed_shader_0, |
| const char* hashed_shader_1, |
| const LocationMap* bind_attrib_location_map, |
| char* result) const { |
| ProgramCache::ComputeProgramHash(hashed_shader_0, |
| hashed_shader_1, |
| bind_attrib_location_map, |
| result); |
| } |
| |
| void Evict(const std::string& program_hash, |
| const std::string& shader_0_hash, |
| const std::string& shader_1_hash) { |
| ProgramCache::Evict(program_hash, shader_0_hash, shader_1_hash); |
| } |
| }; |
| |
| class ProgramCacheTest : public testing::Test { |
| public: |
| ProgramCacheTest() : |
| cache_(new NoBackendProgramCache()) { } |
| |
| protected: |
| scoped_ptr<NoBackendProgramCache> cache_; |
| }; |
| |
| TEST_F(ProgramCacheTest, CompilationStatusSave) { |
| const std::string shader1 = "abcd1234"; |
| { |
| std::string shader = shader1; |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader, NULL)); |
| cache_->ShaderCompilationSucceeded(shader, NULL); |
| shader.clear(); |
| } |
| // make sure it was copied |
| EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, CompilationStatusTranslatorOptionDependent) { |
| MockShaderTranslator translator; |
| |
| EXPECT_CALL(translator, GetStringForOptionsThatWouldEffectCompilation()) |
| .WillOnce(Return("foo")) // GetShaderCompilationStatus |
| .WillOnce(Return("foo")) // ShaderCompilationSucceeded |
| .WillOnce(Return("foo")) // GetShaderCompilationStatus |
| .WillOnce(Return("bar")); // GetShaderCompilationStatus |
| |
| const std::string shader1 = "abcd1234"; |
| { |
| std::string shader = shader1; |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader, &translator)); |
| cache_->ShaderCompilationSucceeded(shader, &translator); |
| shader.clear(); |
| } |
| // make sure it was copied |
| EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED, |
| cache_->GetShaderCompilationStatus(shader1, &translator)); |
| // make sure if the options change it's not copied. |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader1, &translator)); |
| } |
| |
| TEST_F(ProgramCacheTest, CompilationUnknownOnSourceChange) { |
| std::string shader1 = "abcd1234"; |
| cache_->ShaderCompilationSucceeded(shader1, NULL); |
| |
| shader1 = "different!"; |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, LinkStatusSave) { |
| const std::string shader1 = "abcd1234"; |
| const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| { |
| std::string shader_a = shader1; |
| std::string shader_b = shader2; |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus( |
| shader_a, NULL, shader_b, NULL, NULL)); |
| cache_->SaySuccessfullyCached(shader_a, NULL, shader_b, NULL, NULL); |
| |
| shader_a.clear(); |
| shader_b.clear(); |
| } |
| // make sure it was copied |
| EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, |
| cache_->GetLinkedProgramStatus( |
| shader1, NULL, shader2, NULL, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, LinkUnknownOnFragmentSourceChange) { |
| const std::string shader1 = "abcd1234"; |
| std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL); |
| |
| shader2 = "different!"; |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, LinkUnknownOnVertexSourceChange) { |
| std::string shader1 = "abcd1234"; |
| const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL); |
| |
| shader1 = "different!"; |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, StatusEviction) { |
| const std::string shader1 = "abcd1234"; |
| const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| cache_->ShaderCompilationSucceeded(shader1, NULL); |
| cache_->ShaderCompilationSucceeded(shader2, NULL); |
| cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL); |
| char a_sha[ProgramCache::kHashLength]; |
| char b_sha[ProgramCache::kHashLength]; |
| cache_->ComputeShaderHash(shader1, NULL, a_sha); |
| cache_->ComputeShaderHash(shader2, NULL, b_sha); |
| |
| char sha[ProgramCache::kHashLength]; |
| cache_->ComputeProgramHash(a_sha, |
| b_sha, |
| NULL, |
| sha); |
| cache_->Evict(std::string(sha, ProgramCache::kHashLength), |
| std::string(a_sha, ProgramCache::kHashLength), |
| std::string(b_sha, ProgramCache::kHashLength)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader2, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, EvictionWithReusedShader) { |
| const std::string shader1 = "abcd1234"; |
| const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| const std::string shader3 = "asbjbbjj239a"; |
| cache_->ShaderCompilationSucceeded(shader1, NULL); |
| cache_->ShaderCompilationSucceeded(shader2, NULL); |
| cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL); |
| cache_->ShaderCompilationSucceeded(shader1, NULL); |
| cache_->ShaderCompilationSucceeded(shader3, NULL); |
| cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL); |
| |
| char a_sha[ProgramCache::kHashLength]; |
| char b_sha[ProgramCache::kHashLength]; |
| char c_sha[ProgramCache::kHashLength]; |
| cache_->ComputeShaderHash(shader1, NULL, a_sha); |
| cache_->ComputeShaderHash(shader2, NULL, b_sha); |
| cache_->ComputeShaderHash(shader3, NULL, c_sha); |
| |
| char sha[ProgramCache::kHashLength]; |
| cache_->ComputeProgramHash(a_sha, |
| b_sha, |
| NULL, |
| sha); |
| cache_->Evict(std::string(sha, ProgramCache::kHashLength), |
| std::string(a_sha, ProgramCache::kHashLength), |
| std::string(b_sha, ProgramCache::kHashLength)); |
| EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader2, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED, |
| cache_->GetShaderCompilationStatus(shader3, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL)); |
| |
| |
| cache_->ComputeProgramHash(a_sha, |
| c_sha, |
| NULL, |
| sha); |
| cache_->Evict(std::string(sha, ProgramCache::kHashLength), |
| std::string(a_sha, ProgramCache::kHashLength), |
| std::string(c_sha, ProgramCache::kHashLength)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader2, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader3, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL)); |
| } |
| |
| TEST_F(ProgramCacheTest, StatusClear) { |
| const std::string shader1 = "abcd1234"; |
| const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; |
| const std::string shader3 = "asbjbbjj239a"; |
| cache_->ShaderCompilationSucceeded(shader1, NULL); |
| cache_->ShaderCompilationSucceeded(shader2, NULL); |
| cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL); |
| cache_->ShaderCompilationSucceeded(shader3, NULL); |
| cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL); |
| cache_->Clear(); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader1, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader2, NULL)); |
| EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN, |
| cache_->GetShaderCompilationStatus(shader3, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL)); |
| EXPECT_EQ(ProgramCache::LINK_UNKNOWN, |
| cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL)); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |