| // Copyright (c) 2010 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_manager.h" |
| #include "base/scoped_ptr.h" |
| #include "base/string_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "gpu/command_buffer/service/gl_mock.h" |
| |
| using ::gles2::MockGLInterface; |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::InSequence; |
| using ::testing::MatcherCast; |
| using ::testing::Pointee; |
| using ::testing::Return; |
| using ::testing::SetArrayArgument; |
| using ::testing::SetArgumentPointee; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class ProgramManagerTest : public testing::Test { |
| public: |
| ProgramManagerTest() { } |
| |
| protected: |
| virtual void SetUp() { |
| } |
| |
| virtual void TearDown() { |
| } |
| |
| ProgramManager manager_; |
| }; |
| |
| TEST_F(ProgramManagerTest, Basic) { |
| const GLuint kProgram1Id = 1; |
| const GLuint kProgram2Id = 2; |
| // Check we can create program. |
| manager_.CreateProgramInfo(kProgram1Id); |
| // Check program got created. |
| ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kProgram1Id); |
| ASSERT_TRUE(info1 != NULL); |
| // Check we get nothing for a non-existent program. |
| EXPECT_TRUE(manager_.GetProgramInfo(kProgram2Id) == NULL); |
| // Check trying to a remove non-existent programs does not crash. |
| manager_.RemoveProgramInfo(kProgram2Id); |
| // Check we can't get the program after we remove it. |
| manager_.RemoveProgramInfo(kProgram1Id); |
| EXPECT_TRUE(manager_.GetProgramInfo(kProgram1Id) == NULL); |
| } |
| |
| class ProgramManagerWithShaderTest : public testing::Test { |
| public: |
| ProgramManagerWithShaderTest() |
| : program_info_(NULL) { |
| } |
| |
| static const GLint kNumVertexAttribs = 16; |
| |
| static const GLuint kProgramId = 123; |
| |
| static const GLint kMaxAttribLength = 10; |
| static const char* kAttrib1Name; |
| static const char* kAttrib2Name; |
| static const char* kAttrib3Name; |
| static const GLint kAttrib1Size = 1; |
| static const GLint kAttrib2Size = 1; |
| static const GLint kAttrib3Size = 1; |
| static const GLint kAttrib1Location = 0; |
| static const GLint kAttrib2Location = 1; |
| static const GLint kAttrib3Location = 2; |
| static const GLenum kAttrib1Type = GL_FLOAT_VEC4; |
| static const GLenum kAttrib2Type = GL_FLOAT_VEC2; |
| static const GLenum kAttrib3Type = GL_FLOAT_VEC3; |
| static const GLint kInvalidAttribLocation = 30; |
| static const GLint kBadAttribIndex = kNumVertexAttribs; |
| |
| static const GLint kMaxUniformLength = 10; |
| static const char* kUniform1Name; |
| static const char* kUniform2Name; |
| static const char* kUniform3Name; |
| static const GLint kUniform1Size = 1; |
| static const GLint kUniform2Size = 3; |
| static const GLint kUniform3Size = 2; |
| static const GLint kUniform1Location = 3; |
| static const GLint kUniform2Location = 10; |
| static const GLint kUniform2ElementLocation = 12; |
| static const GLint kUniform3Location = 20; |
| static const GLenum kUniform1Type = GL_FLOAT_VEC4; |
| static const GLenum kUniform2Type = GL_INT_VEC2; |
| static const GLenum kUniform3Type = GL_FLOAT_VEC3; |
| static const GLint kInvalidUniformLocation = 30; |
| static const GLint kBadUniformIndex = 1000; |
| |
| static const size_t kNumAttribs; |
| static const size_t kNumUniforms; |
| |
| protected: |
| struct AttribInfo { |
| const char* name; |
| GLint size; |
| GLenum type; |
| GLint location; |
| }; |
| |
| struct UniformInfo { |
| const char* name; |
| GLint size; |
| GLenum type; |
| GLint location; |
| }; |
| |
| virtual void SetUp() { |
| gl_.reset(new StrictMock<MockGLInterface>()); |
| ::gles2::GLInterface::SetGLInterface(gl_.get()); |
| |
| SetupDefaultShaderExpectations(); |
| |
| manager_.CreateProgramInfo(kProgramId); |
| program_info_ = manager_.GetProgramInfo(kProgramId); |
| program_info_->Update(); |
| } |
| |
| void SetupShader(AttribInfo* attribs, size_t num_attribs, |
| UniformInfo* uniforms, size_t num_uniforms, |
| GLuint service_id) { |
| InSequence s; |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _)) |
| .WillOnce(SetArgumentPointee<2>(num_attribs)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(kMaxAttribLength)) |
| .RetiresOnSaturation(); |
| for (size_t ii = 0; ii < num_attribs; ++ii) { |
| const AttribInfo& info = attribs[ii]; |
| EXPECT_CALL(*gl_, |
| GetActiveAttrib(service_id, ii, |
| kMaxAttribLength, _, _, _, _)) |
| .WillOnce(DoAll( |
| SetArgumentPointee<3>(strlen(info.name)), |
| SetArgumentPointee<4>(info.size), |
| SetArgumentPointee<5>(info.type), |
| SetArrayArgument<6>(info.name, |
| info.name + strlen(info.name) + 1))) |
| .RetiresOnSaturation(); |
| if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { |
| EXPECT_CALL(*gl_, GetAttribLocation(service_id, |
| StrEq(info.name))) |
| .WillOnce(Return(info.location)) |
| .RetiresOnSaturation(); |
| } |
| } |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_UNIFORMS, _)) |
| .WillOnce(SetArgumentPointee<2>(num_uniforms)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(kMaxUniformLength)) |
| .RetiresOnSaturation(); |
| for (size_t ii = 0; ii < num_uniforms; ++ii) { |
| const UniformInfo& info = uniforms[ii]; |
| EXPECT_CALL(*gl_, |
| GetActiveUniform(service_id, ii, |
| kMaxUniformLength, _, _, _, _)) |
| .WillOnce(DoAll( |
| SetArgumentPointee<3>(strlen(info.name)), |
| SetArgumentPointee<4>(info.size), |
| SetArgumentPointee<5>(info.type), |
| SetArrayArgument<6>(info.name, |
| info.name + strlen(info.name) + 1))) |
| .RetiresOnSaturation(); |
| if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { |
| EXPECT_CALL(*gl_, GetUniformLocation(service_id, |
| StrEq(info.name))) |
| .WillOnce(Return(info.location)) |
| .RetiresOnSaturation(); |
| if (info.size > 1) { |
| for (GLsizei jj = 1; jj < info.size; ++jj) { |
| std::string element_name( |
| std::string(info.name) + "[" + IntToString(jj) + "]"); |
| EXPECT_CALL(*gl_, GetUniformLocation(service_id, |
| StrEq(element_name))) |
| .WillOnce(Return(info.location + jj)) |
| .RetiresOnSaturation(); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| void SetupDefaultShaderExpectations() { |
| SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, |
| kProgramId); |
| } |
| |
| virtual void TearDown() { |
| } |
| |
| static AttribInfo kAttribs[]; |
| static UniformInfo kUniforms[]; |
| |
| scoped_ptr<StrictMock<MockGLInterface> > gl_; |
| |
| ProgramManager manager_; |
| |
| ProgramManager::ProgramInfo* program_info_; |
| }; |
| |
| ProgramManagerWithShaderTest::AttribInfo |
| ProgramManagerWithShaderTest::kAttribs[] = { |
| { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, |
| { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, }, |
| { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, |
| }; |
| |
| // GCC requires these declarations, but MSVC requires they not be present |
| #ifndef COMPILER_MSVC |
| const GLint ProgramManagerWithShaderTest::kNumVertexAttribs; |
| const GLuint ProgramManagerWithShaderTest::kProgramId; |
| const GLint ProgramManagerWithShaderTest::kMaxAttribLength; |
| const GLint ProgramManagerWithShaderTest::kAttrib1Size; |
| const GLint ProgramManagerWithShaderTest::kAttrib2Size; |
| const GLint ProgramManagerWithShaderTest::kAttrib3Size; |
| const GLint ProgramManagerWithShaderTest::kAttrib1Location; |
| const GLint ProgramManagerWithShaderTest::kAttrib2Location; |
| const GLint ProgramManagerWithShaderTest::kAttrib3Location; |
| const GLenum ProgramManagerWithShaderTest::kAttrib1Type; |
| const GLenum ProgramManagerWithShaderTest::kAttrib2Type; |
| const GLenum ProgramManagerWithShaderTest::kAttrib3Type; |
| const GLint ProgramManagerWithShaderTest::kInvalidAttribLocation; |
| const GLint ProgramManagerWithShaderTest::kBadAttribIndex; |
| const GLint ProgramManagerWithShaderTest::kMaxUniformLength; |
| const GLint ProgramManagerWithShaderTest::kUniform1Size; |
| const GLint ProgramManagerWithShaderTest::kUniform2Size; |
| const GLint ProgramManagerWithShaderTest::kUniform3Size; |
| const GLint ProgramManagerWithShaderTest::kUniform1Location; |
| const GLint ProgramManagerWithShaderTest::kUniform2Location; |
| const GLint ProgramManagerWithShaderTest::kUniform2ElementLocation; |
| const GLint ProgramManagerWithShaderTest::kUniform3Location; |
| const GLenum ProgramManagerWithShaderTest::kUniform1Type; |
| const GLenum ProgramManagerWithShaderTest::kUniform2Type; |
| const GLenum ProgramManagerWithShaderTest::kUniform3Type; |
| const GLint ProgramManagerWithShaderTest::kInvalidUniformLocation; |
| const GLint ProgramManagerWithShaderTest::kBadUniformIndex; |
| #endif |
| |
| const size_t ProgramManagerWithShaderTest::kNumAttribs = |
| arraysize(ProgramManagerWithShaderTest::kAttribs); |
| |
| ProgramManagerWithShaderTest::UniformInfo |
| ProgramManagerWithShaderTest::kUniforms[] = { |
| { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, }, |
| { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, }, |
| { kUniform3Name, kUniform3Size, kUniform3Type, kUniform3Location, }, |
| }; |
| |
| const size_t ProgramManagerWithShaderTest::kNumUniforms = |
| arraysize(ProgramManagerWithShaderTest::kUniforms); |
| |
| const char* ProgramManagerWithShaderTest::kAttrib1Name = "attrib1"; |
| const char* ProgramManagerWithShaderTest::kAttrib2Name = "attrib2"; |
| const char* ProgramManagerWithShaderTest::kAttrib3Name = "attrib3"; |
| const char* ProgramManagerWithShaderTest::kUniform1Name = "uniform1"; |
| const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2"; |
| const char* ProgramManagerWithShaderTest::kUniform3Name = "uniform3"; |
| |
| TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) { |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| const ProgramManager::ProgramInfo::AttribInfoVector& infos = |
| program_info->GetAttribInfos(); |
| for (size_t ii = 0; ii < kNumAttribs; ++ii) { |
| const ProgramManager::ProgramInfo::VertexAttribInfo& info = infos[ii]; |
| const AttribInfo& expected = kAttribs[ii]; |
| EXPECT_EQ(expected.size, info.size); |
| EXPECT_EQ(expected.type, info.type); |
| EXPECT_EQ(expected.location, info.location); |
| EXPECT_STREQ(expected.name, info.name.c_str()); |
| } |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetAttribInfo) { |
| const GLint kValidIndex = 1; |
| const GLint kInvalidIndex = 1000; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| const ProgramManager::ProgramInfo::VertexAttribInfo* info = |
| program_info->GetAttribInfo(kValidIndex); |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(kAttrib2Size, info->size); |
| EXPECT_EQ(kAttrib2Type, info->type); |
| EXPECT_EQ(kAttrib2Location, info->location); |
| EXPECT_STREQ(kAttrib2Name, info->name.c_str()); |
| EXPECT_TRUE(program_info->GetAttribInfo(kInvalidIndex) == NULL); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetAttribLocation) { |
| const char* kInvalidName = "foo"; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_EQ(kAttrib2Location, program_info->GetAttribLocation(kAttrib2Name)); |
| EXPECT_EQ(-1, program_info->GetAttribLocation(kInvalidName)); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetUniformLocation) { |
| const GLint kValidIndex = 1; |
| const GLint kInvalidIndex = 1000; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| const ProgramManager::ProgramInfo::UniformInfo* info = |
| program_info->GetUniformInfo(kValidIndex); |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(kUniform2Size, info->size); |
| EXPECT_EQ(kUniform2Type, info->type); |
| EXPECT_EQ(kUniform2Location, info->element_locations[0]); |
| EXPECT_STREQ(kUniform2Name, info->name.c_str()); |
| EXPECT_TRUE(program_info->GetUniformInfo(kInvalidIndex) == NULL); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetUniformTypeByLocation) { |
| const GLint kInvalidLocation = 1234; |
| GLenum type = 0u; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_TRUE(program_info->GetUniformTypeByLocation(kUniform2Location, &type)); |
| EXPECT_EQ(kUniform2Type, type); |
| type = 0u; |
| EXPECT_FALSE(program_info->GetUniformTypeByLocation( |
| kInvalidLocation, &type)); |
| EXPECT_EQ(0u, type); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| |