1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gpu/command_buffer/service/program_cache.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "gpu/command_buffer/service/mocks.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using ::testing::Return;
12
13namespace gpu {
14namespace gles2 {
15
16class NoBackendProgramCache : public ProgramCache {
17 public:
18  virtual ProgramLoadResult LoadLinkedProgram(
19      GLuint /* program */,
20      Shader* /* shader_a */,
21      const ShaderTranslatorInterface* /* translator_a */,
22      Shader* /* shader_b */,
23      const ShaderTranslatorInterface* /* translator_b */,
24      const LocationMap* /* bind_attrib_location_map */,
25      const ShaderCacheCallback& /* callback */) OVERRIDE {
26    return PROGRAM_LOAD_SUCCESS;
27  }
28  virtual void SaveLinkedProgram(
29      GLuint /* program */,
30      const Shader* /* shader_a */,
31      const ShaderTranslatorInterface* /* translator_b */,
32      const Shader* /* shader_b */,
33      const ShaderTranslatorInterface* /* translator_b */,
34      const LocationMap* /* bind_attrib_location_map */,
35      const ShaderCacheCallback& /* callback */) OVERRIDE { }
36
37  virtual void LoadProgram(const std::string& /* program */) OVERRIDE {}
38
39  virtual void ClearBackend() OVERRIDE {}
40
41  void SaySuccessfullyCached(const std::string& shader1,
42                             const ShaderTranslatorInterface* translator_1,
43                             const std::string& shader2,
44                             const ShaderTranslatorInterface* translator_2,
45                             std::map<std::string, GLint>* attrib_map) {
46    char a_sha[kHashLength];
47    char b_sha[kHashLength];
48    ComputeShaderHash(shader1, translator_1, a_sha);
49    ComputeShaderHash(shader2, translator_2, b_sha);
50
51    char sha[kHashLength];
52    ComputeProgramHash(a_sha,
53                       b_sha,
54                       attrib_map,
55                       sha);
56    const std::string shaString(sha, kHashLength);
57
58    LinkedProgramCacheSuccess(shaString);
59  }
60
61  void ComputeShaderHash(const std::string& shader,
62                         const ShaderTranslatorInterface* translator,
63                         char* result) const {
64    ProgramCache::ComputeShaderHash(shader, translator, result);
65  }
66
67  void ComputeProgramHash(const char* hashed_shader_0,
68                          const char* hashed_shader_1,
69                          const LocationMap* bind_attrib_location_map,
70                          char* result) const {
71    ProgramCache::ComputeProgramHash(hashed_shader_0,
72                                     hashed_shader_1,
73                                     bind_attrib_location_map,
74                                     result);
75  }
76
77  void Evict(const std::string& program_hash) {
78    ProgramCache::Evict(program_hash);
79  }
80};
81
82class ProgramCacheTest : public testing::Test {
83 public:
84  ProgramCacheTest() :
85    cache_(new NoBackendProgramCache()) { }
86
87 protected:
88  scoped_ptr<NoBackendProgramCache> cache_;
89};
90
91TEST_F(ProgramCacheTest, LinkStatusSave) {
92  const std::string shader1 = "abcd1234";
93  const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
94  {
95    std::string shader_a = shader1;
96    std::string shader_b = shader2;
97    EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
98              cache_->GetLinkedProgramStatus(
99                  shader_a, NULL, shader_b, NULL, NULL));
100    cache_->SaySuccessfullyCached(shader_a, NULL, shader_b, NULL, NULL);
101
102    shader_a.clear();
103    shader_b.clear();
104  }
105  // make sure it was copied
106  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
107            cache_->GetLinkedProgramStatus(
108                shader1, NULL, shader2, NULL, NULL));
109}
110
111TEST_F(ProgramCacheTest, LinkUnknownOnFragmentSourceChange) {
112  const std::string shader1 = "abcd1234";
113  std::string shader2 = "abcda sda b1~#4 bbbbb1234";
114  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
115
116  shader2 = "different!";
117  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
118            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
119}
120
121TEST_F(ProgramCacheTest, LinkUnknownOnVertexSourceChange) {
122  std::string shader1 = "abcd1234";
123  const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
124  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
125
126  shader1 = "different!";
127  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
128            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
129}
130
131TEST_F(ProgramCacheTest, StatusEviction) {
132  const std::string shader1 = "abcd1234";
133  const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
134  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
135  char a_sha[ProgramCache::kHashLength];
136  char b_sha[ProgramCache::kHashLength];
137  cache_->ComputeShaderHash(shader1, NULL, a_sha);
138  cache_->ComputeShaderHash(shader2, NULL, b_sha);
139
140  char sha[ProgramCache::kHashLength];
141  cache_->ComputeProgramHash(a_sha,
142                             b_sha,
143                             NULL,
144                             sha);
145  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
146  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
147            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
148}
149
150TEST_F(ProgramCacheTest, EvictionWithReusedShader) {
151  const std::string shader1 = "abcd1234";
152  const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
153  const std::string shader3 = "asbjbbjj239a";
154  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
155  cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
156
157  char a_sha[ProgramCache::kHashLength];
158  char b_sha[ProgramCache::kHashLength];
159  char c_sha[ProgramCache::kHashLength];
160  cache_->ComputeShaderHash(shader1, NULL, a_sha);
161  cache_->ComputeShaderHash(shader2, NULL, b_sha);
162  cache_->ComputeShaderHash(shader3, NULL, c_sha);
163
164  char sha[ProgramCache::kHashLength];
165  cache_->ComputeProgramHash(a_sha,
166                             b_sha,
167                             NULL,
168                             sha);
169  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
170  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
171            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
172  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
173            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
174
175
176  cache_->ComputeProgramHash(a_sha,
177                             c_sha,
178                             NULL,
179                             sha);
180  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
181  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
182            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
183  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
184            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
185}
186
187TEST_F(ProgramCacheTest, StatusClear) {
188  const std::string shader1 = "abcd1234";
189  const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
190  const std::string shader3 = "asbjbbjj239a";
191  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
192  cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
193  cache_->Clear();
194  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
195            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
196  EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
197            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
198}
199
200}  // namespace gles2
201}  // namespace gpu
202