// 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: ProgramLoadResult LoadLinkedProgram( GLuint /* program */, Shader* /* shader_a */, Shader* /* shader_b */, const LocationMap* /* bind_attrib_location_map */, const std::vector& /* transform_feedback_varyings */, GLenum /* transform_feedback_buffer_mode */, const ShaderCacheCallback& /* callback */) override { return PROGRAM_LOAD_SUCCESS; } void SaveLinkedProgram( GLuint /* program */, const Shader* /* shader_a */, const Shader* /* shader_b */, const LocationMap* /* bind_attrib_location_map */, const std::vector& /* transform_feedback_varyings */, GLenum /* transform_feedback_buffer_mode */, const ShaderCacheCallback& /* callback */) override {} void LoadProgram(const std::string& /* program */) override {} void ClearBackend() override {} void SaySuccessfullyCached(const std::string& shader1, const std::string& shader2, std::map* attrib_map, const std::vector& varyings, GLenum buffer_mode) { char a_sha[kHashLength]; char b_sha[kHashLength]; ComputeShaderHash(shader1, a_sha); ComputeShaderHash(shader2, b_sha); char sha[kHashLength]; ComputeProgramHash(a_sha, b_sha, attrib_map, varyings, buffer_mode, sha); const std::string shaString(sha, kHashLength); LinkedProgramCacheSuccess(shaString); } void ComputeShaderHash(const std::string& shader, char* result) const { ProgramCache::ComputeShaderHash(shader, result); } void ComputeProgramHash( const char* hashed_shader_0, const char* hashed_shader_1, const LocationMap* bind_attrib_location_map, const std::vector& transform_feedback_varyings, GLenum transform_feedback_buffer_mode, char* result) const { ProgramCache::ComputeProgramHash(hashed_shader_0, hashed_shader_1, bind_attrib_location_map, transform_feedback_varyings, transform_feedback_buffer_mode, result); } void Evict(const std::string& program_hash) { ProgramCache::Evict(program_hash); } }; class ProgramCacheTest : public testing::Test { public: ProgramCacheTest() : cache_(new NoBackendProgramCache()) { } protected: scoped_ptr cache_; std::vector varyings_; }; 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, shader_b, NULL, varyings_, GL_NONE)); cache_->SaySuccessfullyCached(shader_a, shader_b, NULL, varyings_, GL_NONE); shader_a.clear(); shader_b.clear(); } // make sure it was copied EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( shader1, shader2, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, LinkUnknownOnFragmentSourceChange) { const std::string shader1 = "abcd1234"; std::string shader2 = "abcda sda b1~#4 bbbbb1234"; cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_NONE); shader2 = "different!"; EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, LinkUnknownOnVertexSourceChange) { std::string shader1 = "abcd1234"; const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_NONE); shader1 = "different!"; EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, StatusEviction) { const std::string shader1 = "abcd1234"; const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_NONE); char a_sha[ProgramCache::kHashLength]; char b_sha[ProgramCache::kHashLength]; cache_->ComputeShaderHash(shader1, a_sha); cache_->ComputeShaderHash(shader2, b_sha); char sha[ProgramCache::kHashLength]; cache_->ComputeProgramHash(a_sha, b_sha, NULL, varyings_, GL_NONE, sha); cache_->Evict(std::string(sha, ProgramCache::kHashLength)); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, EvictionWithReusedShader) { const std::string shader1 = "abcd1234"; const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; const std::string shader3 = "asbjbbjj239a"; cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_NONE); cache_->SaySuccessfullyCached(shader1, shader3, NULL, varyings_, GL_NONE); char a_sha[ProgramCache::kHashLength]; char b_sha[ProgramCache::kHashLength]; char c_sha[ProgramCache::kHashLength]; cache_->ComputeShaderHash(shader1, a_sha); cache_->ComputeShaderHash(shader2, b_sha); cache_->ComputeShaderHash(shader3, c_sha); char sha[ProgramCache::kHashLength]; cache_->ComputeProgramHash(a_sha, b_sha, NULL, varyings_, GL_NONE, sha); cache_->Evict(std::string(sha, ProgramCache::kHashLength)); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(shader1, shader3, NULL, varyings_, GL_NONE)); cache_->ComputeProgramHash(a_sha, c_sha, NULL, varyings_, GL_NONE, sha); cache_->Evict(std::string(sha, ProgramCache::kHashLength)); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader3, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, StatusClear) { const std::string shader1 = "abcd1234"; const std::string shader2 = "abcda sda b1~#4 bbbbb1234"; const std::string shader3 = "asbjbbjj239a"; cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_NONE); cache_->SaySuccessfullyCached(shader1, shader3, NULL, varyings_, GL_NONE); cache_->Clear(); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_NONE)); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader3, NULL, varyings_, GL_NONE)); } TEST_F(ProgramCacheTest, LinkUnknownOnTransformFeedbackChange) { const std::string shader1 = "abcd1234"; std::string shader2 = "abcda sda b1~#4 bbbbb1234"; varyings_.push_back("a"); cache_->SaySuccessfullyCached(shader1, shader2, NULL, varyings_, GL_INTERLEAVED_ATTRIBS); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_SEPARATE_ATTRIBS)); varyings_.push_back("b"); EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(shader1, shader2, NULL, varyings_, GL_INTERLEAVED_ATTRIBS)); } } // namespace gles2 } // namespace gpu