Index: gpu/command_buffer/service/memory_program_cache_unittest.cc |
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bea98d76bdb6d81f6122fd9e45d0205d0eb7cc76 |
--- /dev/null |
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc |
@@ -0,0 +1,417 @@ |
+// 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/memory_program_cache.h" |
+ |
+#include "gpu/command_buffer/common/gl_mock.h" |
+#include "gpu/command_buffer/common/gles2_cmd_format.h" |
+#include "gpu/command_buffer/service/gl_utils.h" |
+#include "gpu/command_buffer/service/shader_translator.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "ui/gl/gl_bindings.h" |
+ |
+using ::testing::_; |
+using ::testing::ElementsAreArray; |
+using ::testing::Invoke; |
+using ::testing::SetArgPointee; |
+using ::testing::SetArrayArgument; |
+ |
+namespace { |
+typedef gpu::gles2::ShaderTranslator::VariableMap VariableMap; |
+} // anonymous namespace |
+ |
+namespace gpu { |
+namespace gles2 { |
+ |
+class ProgramBinaryEmulator { |
+ public: |
+ ProgramBinaryEmulator(GLsizei length, |
+ GLenum format, |
+ const char* binary) |
+ : length_(length), |
+ format_(format), |
+ binary_(binary) { } |
+ |
+ void GetProgramBinary(GLuint program, |
+ GLsizei buffer_size, |
+ GLsizei* length, |
+ GLenum* format, |
+ GLvoid* binary) { |
+ *length = length_; |
+ *format = format_; |
+ memcpy(binary, binary_, length_); |
+ } |
+ |
+ void ProgramBinary(GLuint program, |
+ GLenum format, |
+ const GLvoid* binary, |
+ GLsizei length) { |
+ // format and length are verified by matcher |
+ EXPECT_EQ(0, memcmp(binary_, binary, length)); |
+ } |
+ |
+ GLsizei length() const { return length_; } |
+ GLenum format() const { return format_; } |
+ const char* binary() const { return binary_; } |
+ |
+ private: |
+ GLsizei length_; |
+ GLenum format_; |
+ const char* binary_; |
+}; |
+ |
+class MemoryProgramCacheTest : public testing::Test { |
+ public: |
+ static const size_t kCacheSizeBytes = 1024; |
+ static const GLuint kVertexShaderClientId = 90; |
+ static const GLuint kVertexShaderServiceId = 100; |
+ static const GLuint kFragmentShaderClientId = 91; |
+ static const GLuint kFragmentShaderServiceId = 100; |
+ |
+ MemoryProgramCacheTest() |
+ : cache_(new MemoryProgramCache(kCacheSizeBytes)), |
+ vertex_shader_(NULL), |
+ fragment_shader_(NULL) { } |
+ ~MemoryProgramCacheTest() { |
+ shader_manager_.Destroy(false); |
+ } |
+ |
+ protected: |
+ virtual void SetUp() { |
+ gl_.reset(new ::testing::StrictMock<gfx::MockGLInterface>()); |
+ ::gfx::GLInterface::SetGLInterface(gl_.get()); |
+ |
+ vertex_shader_ = shader_manager_.CreateShaderInfo(kVertexShaderClientId, |
+ kVertexShaderServiceId, |
+ GL_VERTEX_SHADER); |
+ fragment_shader_ = shader_manager_.CreateShaderInfo( |
+ kFragmentShaderClientId, |
+ kFragmentShaderServiceId, |
+ GL_FRAGMENT_SHADER); |
+ ASSERT_TRUE(vertex_shader_ != NULL); |
+ ASSERT_TRUE(fragment_shader_ != NULL); |
+ typedef ShaderTranslatorInterface::VariableInfo VariableInfo; |
+ typedef ShaderTranslator::VariableMap VariableMap; |
+ VariableMap vertex_attrib_map; |
+ VariableMap vertex_uniform_map; |
+ VariableMap fragment_attrib_map; |
+ VariableMap fragment_uniform_map; |
+ |
+ vertex_attrib_map["a"] = VariableInfo(1, 34, "a"); |
+ vertex_uniform_map["a"] = VariableInfo(0, 10, "a"); |
+ vertex_uniform_map["b"] = VariableInfo(2, 3114, "b"); |
+ fragment_attrib_map["jjjbb"] = VariableInfo(463, 1114, "jjjbb"); |
+ fragment_uniform_map["k"] = VariableInfo(10, 34413, "k"); |
+ |
+ vertex_shader_->set_attrib_map(vertex_attrib_map); |
+ vertex_shader_->set_uniform_map(vertex_uniform_map); |
+ fragment_shader_->set_attrib_map(vertex_attrib_map); |
+ fragment_shader_->set_uniform_map(vertex_uniform_map); |
+ |
+ vertex_shader_->UpdateSource("bbbalsldkdkdkd"); |
+ fragment_shader_->UpdateSource("bbbal sldkdkdkas 134 ad"); |
+ vertex_shader_->FlagSourceAsCompiled(true); |
+ fragment_shader_->FlagSourceAsCompiled(true); |
+ |
+ vertex_shader_->SetStatus(true, NULL, NULL); |
+ fragment_shader_->SetStatus(true, NULL, NULL); |
+ } |
+ |
+ virtual void TearDown() { |
+ ::gfx::GLInterface::SetGLInterface(NULL); |
+ gl_.reset(); |
+ } |
+ |
+ void SetExpectationsForSaveLinkedProgram( |
+ const GLint program_id, |
+ ProgramBinaryEmulator* emulator) const { |
+ EXPECT_CALL(*gl_.get(), |
+ GetProgramiv(program_id, GL_PROGRAM_BINARY_LENGTH_OES, _)) |
+ .WillOnce(SetArgPointee<2>(emulator->length())); |
+ EXPECT_CALL(*gl_.get(), |
+ GetProgramBinary(program_id, emulator->length(), _, _, _)) |
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::GetProgramBinary)); |
+ } |
+ |
+ void SetExpectationsForLoadLinkedProgram( |
+ const GLint program_id, |
+ ProgramBinaryEmulator* emulator) const { |
+ EXPECT_CALL(*gl_.get(), |
+ ProgramBinary(program_id, |
+ emulator->format(), |
+ _, |
+ emulator->length())) |
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary)); |
+ EXPECT_CALL(*gl_.get(), |
+ GetProgramiv(program_id, GL_LINK_STATUS, _)) |
+ .WillOnce(SetArgPointee<2>(GL_TRUE)); |
+ } |
+ |
+ void SetExpectationsForLoadLinkedProgramFailure( |
+ const GLint program_id, |
+ ProgramBinaryEmulator* emulator) const { |
+ EXPECT_CALL(*gl_.get(), |
+ ProgramBinary(program_id, |
+ emulator->format(), |
+ _, |
+ emulator->length())) |
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary)); |
+ EXPECT_CALL(*gl_.get(), |
+ GetProgramiv(program_id, GL_LINK_STATUS, _)) |
+ .WillOnce(SetArgPointee<2>(GL_FALSE)); |
+ } |
+ |
+ // Use StrictMock to make 100% sure we know how GL will be called. |
+ scoped_ptr< ::testing::StrictMock<gfx::MockGLInterface> > gl_; |
+ scoped_ptr<MemoryProgramCache> cache_; |
+ ShaderManager shader_manager_; |
+ ShaderManager::ShaderInfo* vertex_shader_; |
+ ShaderManager::ShaderInfo* fragment_shader_; |
+}; |
+ |
+TEST_F(MemoryProgramCacheTest, CacheSave) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( |
+ *vertex_shader_->deferred_compilation_source(), |
+ *fragment_shader_->deferred_compilation_source(), |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ 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, LoadFailOnLinkFalse) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ SetExpectationsForLoadLinkedProgramFailure(kProgramId, &emulator); |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ const std::string vertex_orig_source = |
+ *vertex_shader_->deferred_compilation_source(); |
+ vertex_shader_->UpdateSource("different!"); |
+ vertex_shader_->FlagSourceAsCompiled(true); |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL)); |
+ |
+ vertex_shader_->UpdateSource(vertex_orig_source.c_str()); |
+ vertex_shader_->FlagSourceAsCompiled(true); |
+ fragment_shader_->UpdateSource("different!"); |
+ fragment_shader_->FlagSourceAsCompiled(true); |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ ProgramCache::LocationMap binding_map; |
+ binding_map["test"] = 512; |
+ cache_->SaveLinkedProgram(kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ &binding_map); |
+ |
+ binding_map["different!"] = 59; |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ &binding_map)); |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) { |
+ typedef ShaderTranslator::VariableMap VariableMap; |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, testBinary); |
+ |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ const int kEvictingProgramId = 11; |
+ const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1; |
+ |
+ // save old source and modify for new program |
+ const std::string old_source = |
+ *fragment_shader_->deferred_compilation_source(); |
+ fragment_shader_->UpdateSource("al sdfkjdk"); |
+ fragment_shader_->FlagSourceAsCompiled(true); |
+ |
+ scoped_array<char> bigTestBinary = |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ scoped_array<char>(new char[kEvictingBinaryLength]); |
+ for (size_t i = 0; i < kEvictingBinaryLength; ++i) { |
+ bigTestBinary[i] = i % 250; |
+ } |
+ ProgramBinaryEmulator emulator2(kEvictingBinaryLength, |
+ kFormat, |
+ bigTestBinary.get()); |
+ |
+ SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2); |
+ cache_->SaveLinkedProgram(kEvictingProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL); |
+ |
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( |
+ *vertex_shader_->deferred_compilation_source(), |
+ *fragment_shader_->deferred_compilation_source(), |
+ NULL)); |
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus( |
+ old_source, |
+ *fragment_shader_->deferred_compilation_source(), |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, SaveCorrectProgram) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, testBinary); |
+ |
+ vertex_shader_->UpdateSource("different!"); |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( |
+ *vertex_shader_->deferred_compilation_source(), |
+ *fragment_shader_->deferred_compilation_source(), |
+ NULL)); |
+} |
+ |
+TEST_F(MemoryProgramCacheTest, LoadCorrectProgram) { |
+ const GLenum kFormat = 1; |
+ const int kProgramId = 10; |
+ const int kBinaryLength = 20; |
+ char testBinary[kBinaryLength]; |
greggman
2012/07/21 00:49:32
style: variables are under_score
|
+ for (int i = 0; i < kBinaryLength; ++i) { |
+ testBinary[i] = i; |
+ } |
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, testBinary); |
+ |
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator); |
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL); |
+ |
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus( |
+ *vertex_shader_->deferred_compilation_source(), |
+ *fragment_shader_->deferred_compilation_source(), |
+ NULL)); |
+ |
+ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); |
+ |
+ fragment_shader_->UpdateSource("different!"); |
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram( |
+ kProgramId, |
+ vertex_shader_, |
+ fragment_shader_, |
+ NULL)); |
+} |
+ |
+} // namespace gles2 |
+} // namespace gpu |