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/memory_program_cache.h"
6
7#include "base/bind.h"
8#include "gpu/command_buffer/common/gles2_cmd_format.h"
9#include "gpu/command_buffer/service/gl_utils.h"
10#include "gpu/command_buffer/service/gpu_service_test.h"
11#include "gpu/command_buffer/service/shader_manager.h"
12#include "gpu/command_buffer/service/shader_translator.h"
13#include "gpu/command_buffer/service/test_helper.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "ui/gl/gl_bindings.h"
16#include "ui/gl/gl_mock.h"
17
18using ::testing::_;
19using ::testing::ElementsAreArray;
20using ::testing::Invoke;
21using ::testing::SetArgPointee;
22using ::testing::SetArrayArgument;
23
24namespace {
25typedef gpu::gles2::ShaderTranslator::VariableMap VariableMap;
26}  // anonymous namespace
27
28namespace gpu {
29namespace gles2 {
30
31class ProgramBinaryEmulator {
32 public:
33  ProgramBinaryEmulator(GLsizei length,
34                        GLenum format,
35                        const char* binary)
36      : length_(length),
37        format_(format),
38        binary_(binary) { }
39
40  void GetProgramBinary(GLuint program,
41                        GLsizei buffer_size,
42                        GLsizei* length,
43                        GLenum* format,
44                        GLvoid* binary) {
45    if (length) {
46      *length = length_;
47    }
48    *format = format_;
49    memcpy(binary, binary_, length_);
50  }
51
52  void ProgramBinary(GLuint program,
53                     GLenum format,
54                     const GLvoid* binary,
55                     GLsizei length) {
56    // format and length are verified by matcher
57    EXPECT_EQ(0, memcmp(binary_, binary, length));
58  }
59
60  GLsizei length() const { return length_; }
61  GLenum format() const { return format_; }
62  const char* binary() const { return binary_; }
63
64 private:
65  GLsizei length_;
66  GLenum format_;
67  const char* binary_;
68};
69
70class MemoryProgramCacheTest : public GpuServiceTest {
71 public:
72  static const size_t kCacheSizeBytes = 1024;
73  static const GLuint kVertexShaderClientId = 90;
74  static const GLuint kVertexShaderServiceId = 100;
75  static const GLuint kFragmentShaderClientId = 91;
76  static const GLuint kFragmentShaderServiceId = 100;
77
78  MemoryProgramCacheTest()
79      : cache_(new MemoryProgramCache(kCacheSizeBytes)),
80        vertex_shader_(NULL),
81        fragment_shader_(NULL),
82        shader_cache_count_(0) { }
83  virtual ~MemoryProgramCacheTest() {
84    shader_manager_.Destroy(false);
85  }
86
87  void ShaderCacheCb(const std::string& key, const std::string& shader) {
88    shader_cache_count_++;
89    shader_cache_shader_ = shader;
90  }
91
92  int32 shader_cache_count() { return shader_cache_count_; }
93  const std::string& shader_cache_shader() { return shader_cache_shader_; }
94
95 protected:
96  virtual void SetUp() {
97    GpuServiceTest::SetUp();
98
99    vertex_shader_ = shader_manager_.CreateShader(kVertexShaderClientId,
100                                                  kVertexShaderServiceId,
101                                                  GL_VERTEX_SHADER);
102    fragment_shader_ = shader_manager_.CreateShader(
103        kFragmentShaderClientId,
104        kFragmentShaderServiceId,
105        GL_FRAGMENT_SHADER);
106    ASSERT_TRUE(vertex_shader_ != NULL);
107    ASSERT_TRUE(fragment_shader_ != NULL);
108    typedef ShaderTranslatorInterface::VariableInfo VariableInfo;
109    typedef ShaderTranslator::VariableMap VariableMap;
110    VariableMap vertex_attrib_map;
111    VariableMap vertex_uniform_map;
112    VariableMap vertex_varying_map;
113    VariableMap fragment_attrib_map;
114    VariableMap fragment_uniform_map;
115    VariableMap fragment_varying_map;
116
117    vertex_attrib_map["a"] = VariableInfo(1, 34, SH_PRECISION_LOWP, 0, "a");
118    vertex_uniform_map["a"] = VariableInfo(0, 10, SH_PRECISION_MEDIUMP, 1, "a");
119    vertex_uniform_map["b"] = VariableInfo(2, 3114, SH_PRECISION_HIGHP, 1, "b");
120    vertex_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, 1, "c");
121    fragment_attrib_map["jjjbb"] =
122        VariableInfo(463, 1114, SH_PRECISION_MEDIUMP, 0, "jjjbb");
123    fragment_uniform_map["k"] =
124        VariableInfo(10, 34413, SH_PRECISION_MEDIUMP, 1, "k");
125    fragment_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, 1, "c");
126
127    vertex_shader_->set_source("bbbalsldkdkdkd");
128    fragment_shader_->set_source("bbbal   sldkdkdkas 134 ad");
129
130    TestHelper::SetShaderStates(
131        gl_.get(), vertex_shader_, true, NULL, NULL,
132        &vertex_attrib_map, &vertex_uniform_map, &vertex_varying_map,
133        NULL);
134    TestHelper::SetShaderStates(
135        gl_.get(), fragment_shader_, true, NULL, NULL,
136        &fragment_attrib_map, &fragment_uniform_map, &fragment_varying_map,
137        NULL);
138  }
139
140  void SetExpectationsForSaveLinkedProgram(
141      const GLint program_id,
142      ProgramBinaryEmulator* emulator) const {
143    EXPECT_CALL(*gl_.get(),
144                GetProgramiv(program_id, GL_PROGRAM_BINARY_LENGTH_OES, _))
145        .WillOnce(SetArgPointee<2>(emulator->length()));
146    EXPECT_CALL(*gl_.get(),
147                GetProgramBinary(program_id, emulator->length(), _, _, _))
148        .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::GetProgramBinary));
149  }
150
151  void SetExpectationsForLoadLinkedProgram(
152      const GLint program_id,
153      ProgramBinaryEmulator* emulator) const {
154    EXPECT_CALL(*gl_.get(),
155                ProgramBinary(program_id,
156                              emulator->format(),
157                              _,
158                              emulator->length()))
159        .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary));
160    EXPECT_CALL(*gl_.get(),
161                GetProgramiv(program_id, GL_LINK_STATUS, _))
162                .WillOnce(SetArgPointee<2>(GL_TRUE));
163  }
164
165  void SetExpectationsForLoadLinkedProgramFailure(
166      const GLint program_id,
167      ProgramBinaryEmulator* emulator) const {
168    EXPECT_CALL(*gl_.get(),
169                ProgramBinary(program_id,
170                              emulator->format(),
171                              _,
172                              emulator->length()))
173        .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary));
174    EXPECT_CALL(*gl_.get(),
175                GetProgramiv(program_id, GL_LINK_STATUS, _))
176                .WillOnce(SetArgPointee<2>(GL_FALSE));
177  }
178
179  scoped_ptr<MemoryProgramCache> cache_;
180  ShaderManager shader_manager_;
181  Shader* vertex_shader_;
182  Shader* fragment_shader_;
183  int32 shader_cache_count_;
184  std::string shader_cache_shader_;
185};
186
187TEST_F(MemoryProgramCacheTest, CacheSave) {
188  const GLenum kFormat = 1;
189  const int kProgramId = 10;
190  const int kBinaryLength = 20;
191  char test_binary[kBinaryLength];
192  for (int i = 0; i < kBinaryLength; ++i) {
193    test_binary[i] = i;
194  }
195  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
196
197  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
198  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
199                            fragment_shader_, NULL, NULL,
200                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
201                                       base::Unretained(this)));
202
203  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
204      vertex_shader_->signature_source(),
205      NULL,
206      fragment_shader_->signature_source(),
207      NULL,
208      NULL));
209  EXPECT_EQ(1, shader_cache_count());
210}
211
212TEST_F(MemoryProgramCacheTest, LoadProgram) {
213  const GLenum kFormat = 1;
214  const int kProgramId = 10;
215  const int kBinaryLength = 20;
216  char test_binary[kBinaryLength];
217  for (int i = 0; i < kBinaryLength; ++i) {
218    test_binary[i] = i;
219  }
220  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
221
222  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
223  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
224                            fragment_shader_, NULL, NULL,
225                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
226                                       base::Unretained(this)));
227
228  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
229      vertex_shader_->signature_source(),
230      NULL,
231      fragment_shader_->signature_source(),
232      NULL,
233      NULL));
234  EXPECT_EQ(1, shader_cache_count());
235
236  cache_->Clear();
237
238  cache_->LoadProgram(shader_cache_shader());
239  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
240      vertex_shader_->signature_source(),
241      NULL,
242      fragment_shader_->signature_source(),
243      NULL,
244      NULL));
245}
246
247TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) {
248  const GLenum kFormat = 1;
249  const int kProgramId = 10;
250  const int kBinaryLength = 20;
251  char test_binary[kBinaryLength];
252  for (int i = 0; i < kBinaryLength; ++i) {
253    test_binary[i] = i;
254  }
255  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
256
257  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
258  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
259                            fragment_shader_, NULL, NULL,
260                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
261                                       base::Unretained(this)));
262  EXPECT_EQ(1, shader_cache_count());
263
264  VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
265  VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
266  VariableMap vertex_varying_map = vertex_shader_->varying_map();
267  VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
268  VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
269  VariableMap fragment_varying_map = fragment_shader_->varying_map();
270
271  vertex_shader_->set_attrib_map(VariableMap());
272  vertex_shader_->set_uniform_map(VariableMap());
273  vertex_shader_->set_varying_map(VariableMap());
274  fragment_shader_->set_attrib_map(VariableMap());
275  fragment_shader_->set_uniform_map(VariableMap());
276  fragment_shader_->set_varying_map(VariableMap());
277
278  SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
279
280  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
281      kProgramId,
282      vertex_shader_,
283      NULL,
284      fragment_shader_,
285      NULL,
286      NULL,
287      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
288                 base::Unretained(this))));
289
290  // apparently the hash_map implementation on android doesn't have the
291  // equality operator
292#if !defined(OS_ANDROID)
293  EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
294  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
295  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
296  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
297  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
298  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
299#endif
300}
301
302TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) {
303  const GLenum kFormat = 1;
304  const int kProgramId = 10;
305  const int kBinaryLength = 20;
306  char test_binary[kBinaryLength];
307  for (int i = 0; i < kBinaryLength; ++i) {
308    test_binary[i] = i;
309  }
310  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
311
312  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
313  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
314                            fragment_shader_, NULL, NULL,
315                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
316                                       base::Unretained(this)));
317  EXPECT_EQ(1, shader_cache_count());
318
319  VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
320  VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
321  VariableMap vertex_varying_map = vertex_shader_->varying_map();
322  VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
323  VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
324  VariableMap fragment_varying_map = fragment_shader_->varying_map();
325
326  vertex_shader_->set_attrib_map(VariableMap());
327  vertex_shader_->set_uniform_map(VariableMap());
328  vertex_shader_->set_varying_map(VariableMap());
329  fragment_shader_->set_attrib_map(VariableMap());
330  fragment_shader_->set_uniform_map(VariableMap());
331  fragment_shader_->set_varying_map(VariableMap());
332
333  SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
334
335  cache_->Clear();
336  cache_->LoadProgram(shader_cache_shader());
337
338  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
339      kProgramId,
340      vertex_shader_,
341      NULL,
342      fragment_shader_,
343      NULL,
344      NULL,
345      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
346                 base::Unretained(this))));
347
348  // apparently the hash_map implementation on android doesn't have the
349  // equality operator
350#if !defined(OS_ANDROID)
351  EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
352  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
353  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
354  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
355  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
356  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
357#endif
358}
359
360TEST_F(MemoryProgramCacheTest, LoadFailOnLinkFalse) {
361  const GLenum kFormat = 1;
362  const int kProgramId = 10;
363  const int kBinaryLength = 20;
364  char test_binary[kBinaryLength];
365  for (int i = 0; i < kBinaryLength; ++i) {
366    test_binary[i] = i;
367  }
368  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
369
370  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
371  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
372                            fragment_shader_, NULL, NULL,
373                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
374                                       base::Unretained(this)));
375
376  SetExpectationsForLoadLinkedProgramFailure(kProgramId, &emulator);
377  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
378      kProgramId,
379      vertex_shader_,
380      NULL,
381      fragment_shader_,
382      NULL,
383      NULL,
384      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
385                 base::Unretained(this))));
386}
387
388TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) {
389  const GLenum kFormat = 1;
390  const int kProgramId = 10;
391  const int kBinaryLength = 20;
392  char test_binary[kBinaryLength];
393  for (int i = 0; i < kBinaryLength; ++i) {
394    test_binary[i] = i;
395  }
396  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
397
398  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
399  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
400                            fragment_shader_, NULL, NULL,
401                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
402                                       base::Unretained(this)));
403
404  const std::string vertex_orig_source = vertex_shader_->signature_source();
405  vertex_shader_->set_source("different!");
406  TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true);
407  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
408      kProgramId,
409      vertex_shader_,
410      NULL,
411      fragment_shader_,
412      NULL,
413      NULL,
414      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
415                 base::Unretained(this))));
416
417  vertex_shader_->set_source(vertex_orig_source);
418  TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true);
419  fragment_shader_->set_source("different!");
420  TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
421  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
422      kProgramId,
423      vertex_shader_,
424      NULL,
425      fragment_shader_,
426      NULL,
427      NULL,
428      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
429                 base::Unretained(this))));
430}
431
432TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) {
433  const GLenum kFormat = 1;
434  const int kProgramId = 10;
435  const int kBinaryLength = 20;
436  char test_binary[kBinaryLength];
437  for (int i = 0; i < kBinaryLength; ++i) {
438    test_binary[i] = i;
439  }
440  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
441
442  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
443  ProgramCache::LocationMap binding_map;
444  binding_map["test"] = 512;
445  cache_->SaveLinkedProgram(kProgramId,
446                            vertex_shader_,
447                            NULL,
448                            fragment_shader_,
449                            NULL,
450                            &binding_map,
451                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
452                                       base::Unretained(this)));
453
454  binding_map["different!"] = 59;
455  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
456      kProgramId,
457      vertex_shader_,
458      NULL,
459      fragment_shader_,
460      NULL,
461      &binding_map,
462      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
463                 base::Unretained(this))));
464  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
465      kProgramId,
466      vertex_shader_,
467      NULL,
468      fragment_shader_,
469      NULL,
470      NULL,
471      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
472                 base::Unretained(this))));
473}
474
475TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) {
476  const GLenum kFormat = 1;
477  const int kProgramId = 10;
478  const int kBinaryLength = 20;
479  char test_binary[kBinaryLength];
480  for (int i = 0; i < kBinaryLength; ++i) {
481    test_binary[i] = i;
482  }
483  ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
484
485
486  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
487  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
488                            fragment_shader_, NULL, NULL,
489                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
490                                       base::Unretained(this)));
491
492  const int kEvictingProgramId = 11;
493  const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1;
494
495  // save old source and modify for new program
496  const std::string& old_source = fragment_shader_->signature_source();
497  fragment_shader_->set_source("al sdfkjdk");
498  TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
499
500  scoped_ptr<char[]> bigTestBinary =
501      scoped_ptr<char[]>(new char[kEvictingBinaryLength]);
502  for (size_t i = 0; i < kEvictingBinaryLength; ++i) {
503    bigTestBinary[i] = i % 250;
504  }
505  ProgramBinaryEmulator emulator2(kEvictingBinaryLength,
506                                  kFormat,
507                                  bigTestBinary.get());
508
509  SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2);
510  cache_->SaveLinkedProgram(kEvictingProgramId,
511                            vertex_shader_,
512                            NULL,
513                            fragment_shader_,
514                            NULL,
515                            NULL,
516                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
517                                       base::Unretained(this)));
518
519  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
520      vertex_shader_->signature_source(),
521      NULL,
522      fragment_shader_->signature_source(),
523      NULL,
524      NULL));
525  EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(
526      old_source,
527      NULL,
528      fragment_shader_->signature_source(),
529      NULL,
530      NULL));
531}
532
533TEST_F(MemoryProgramCacheTest, SaveCorrectProgram) {
534  const GLenum kFormat = 1;
535  const int kProgramId = 10;
536  const int kBinaryLength = 20;
537  char test_binary[kBinaryLength];
538  for (int i = 0; i < kBinaryLength; ++i) {
539    test_binary[i] = i;
540  }
541  ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
542
543  vertex_shader_->set_source("different!");
544  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
545  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
546                            fragment_shader_, NULL, NULL,
547                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
548                                       base::Unretained(this)));
549
550  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
551      vertex_shader_->signature_source(),
552      NULL,
553      fragment_shader_->signature_source(),
554      NULL,
555      NULL));
556}
557
558TEST_F(MemoryProgramCacheTest, LoadCorrectProgram) {
559  const GLenum kFormat = 1;
560  const int kProgramId = 10;
561  const int kBinaryLength = 20;
562  char test_binary[kBinaryLength];
563  for (int i = 0; i < kBinaryLength; ++i) {
564    test_binary[i] = i;
565  }
566  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
567
568  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
569  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
570                            fragment_shader_, NULL, NULL,
571                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
572                                       base::Unretained(this)));
573
574  EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
575      vertex_shader_->signature_source(),
576      NULL,
577      fragment_shader_->signature_source(),
578      NULL,
579      NULL));
580
581  SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
582
583  fragment_shader_->set_source("different!");
584  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
585      kProgramId,
586      vertex_shader_,
587      NULL,
588      fragment_shader_,
589      NULL,
590      NULL,
591      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
592                 base::Unretained(this))));
593}
594
595TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) {
596  const GLenum kFormat = 1;
597  const int kProgramId = 10;
598  const int kBinaryLength = 20;
599  char test_binary[kBinaryLength];
600  for (int i = 0; i < kBinaryLength; ++i) {
601    test_binary[i] = i;
602  }
603  ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
604
605  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
606  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
607                            fragment_shader_, NULL, NULL,
608                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
609                                       base::Unretained(this)));
610
611
612  char test_binary2[kBinaryLength];
613  for (int i = 0; i < kBinaryLength; ++i) {
614    test_binary2[i] = (i*2) % 250;
615  }
616  ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2);
617  SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2);
618  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
619                            fragment_shader_, NULL, NULL,
620                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
621                                       base::Unretained(this)));
622
623  SetExpectationsForLoadLinkedProgram(kProgramId, &emulator2);
624  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
625      kProgramId,
626      vertex_shader_,
627      NULL,
628      fragment_shader_,
629      NULL,
630      NULL,
631      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
632                 base::Unretained(this))));
633}
634
635}  // namespace gles2
636}  // namespace gpu
637