| // Copyright (c) 2011 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 <algorithm> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "gpu/command_buffer/common/gl_mock.h" |
| #include "gpu/command_buffer/service/mocks.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::gfx::MockGLInterface; |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::InSequence; |
| using ::testing::MatcherCast; |
| using ::testing::Pointee; |
| using ::testing::Return; |
| using ::testing::ReturnRef; |
| using ::testing::SetArrayArgument; |
| using ::testing::SetArgumentPointee; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class ProgramManagerTest : public testing::Test { |
| public: |
| ProgramManagerTest() { } |
| ~ProgramManagerTest() { |
| manager_.Destroy(false); |
| } |
| |
| protected: |
| virtual void SetUp() { |
| gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); |
| ::gfx::GLInterface::SetGLInterface(gl_.get()); |
| } |
| |
| virtual void TearDown() { |
| ::gfx::GLInterface::SetGLInterface(NULL); |
| gl_.reset(); |
| } |
| |
| // Use StrictMock to make 100% sure we know how GL will be called. |
| scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; |
| ProgramManager manager_; |
| }; |
| |
| TEST_F(ProgramManagerTest, Basic) { |
| const GLuint kClient1Id = 1; |
| const GLuint kService1Id = 11; |
| const GLuint kClient2Id = 2; |
| // Check we can create program. |
| manager_.CreateProgramInfo(kClient1Id, kService1Id); |
| // Check program got created. |
| ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kClient1Id); |
| ASSERT_TRUE(info1 != NULL); |
| GLuint client_id = 0; |
| EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id)); |
| EXPECT_EQ(kClient1Id, client_id); |
| // Check we get nothing for a non-existent program. |
| EXPECT_TRUE(manager_.GetProgramInfo(kClient2Id) == NULL); |
| } |
| |
| TEST_F(ProgramManagerTest, Destroy) { |
| const GLuint kClient1Id = 1; |
| const GLuint kService1Id = 11; |
| // Check we can create program. |
| manager_.CreateProgramInfo(kClient1Id, kService1Id); |
| // Check program got created. |
| ProgramManager::ProgramInfo* info1 = |
| manager_.GetProgramInfo(kClient1Id); |
| ASSERT_TRUE(info1 != NULL); |
| EXPECT_CALL(*gl_, DeleteProgram(kService1Id)) |
| .Times(1) |
| .RetiresOnSaturation(); |
| manager_.Destroy(true); |
| // Check the resources were released. |
| info1 = manager_.GetProgramInfo(kClient1Id); |
| ASSERT_TRUE(info1 == NULL); |
| } |
| |
| TEST_F(ProgramManagerTest, DeleteBug) { |
| ShaderManager shader_manager; |
| const GLuint kClient1Id = 1; |
| const GLuint kClient2Id = 2; |
| const GLuint kService1Id = 11; |
| const GLuint kService2Id = 12; |
| // Check we can create program. |
| manager_.CreateProgramInfo(kClient1Id, kService1Id); |
| manager_.CreateProgramInfo(kClient2Id, kService2Id); |
| // Check program got created. |
| ProgramManager::ProgramInfo::Ref info1(manager_.GetProgramInfo(kClient1Id)); |
| ProgramManager::ProgramInfo::Ref info2(manager_.GetProgramInfo(kClient2Id)); |
| ASSERT_TRUE(info1.get() != NULL); |
| ASSERT_TRUE(info2.get() != NULL); |
| manager_.UseProgram(info1); |
| manager_.MarkAsDeleted(&shader_manager, info1); |
| manager_.MarkAsDeleted(&shader_manager, info2); |
| EXPECT_TRUE(manager_.IsOwned(info1)); |
| EXPECT_FALSE(manager_.IsOwned(info2)); |
| } |
| |
| TEST_F(ProgramManagerTest, ProgramInfo) { |
| const GLuint kClient1Id = 1; |
| const GLuint kService1Id = 11; |
| // Check we can create program. |
| manager_.CreateProgramInfo(kClient1Id, kService1Id); |
| // Check program got created. |
| ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kClient1Id); |
| ASSERT_TRUE(info1 != NULL); |
| EXPECT_EQ(kService1Id, info1->service_id()); |
| EXPECT_FALSE(info1->InUse()); |
| EXPECT_FALSE(info1->IsValid()); |
| EXPECT_FALSE(info1->IsDeleted()); |
| EXPECT_FALSE(info1->CanLink()); |
| EXPECT_TRUE(info1->log_info() == NULL); |
| } |
| |
| class ProgramManagerWithShaderTest : public testing::Test { |
| public: |
| ProgramManagerWithShaderTest() |
| : program_info_(NULL) { |
| } |
| |
| ~ProgramManagerWithShaderTest() { |
| manager_.Destroy(false); |
| } |
| |
| static const GLint kNumVertexAttribs = 16; |
| |
| static const GLuint kClientProgramId = 123; |
| static const GLuint kServiceProgramId = 456; |
| |
| 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 char* kUniform1Name; |
| static const char* kUniform2Name; |
| static const char* kUniform3BadName; |
| static const char* kUniform3GoodName; |
| 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 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<gfx::MockGLInterface>()); |
| ::gfx::GLInterface::SetGLInterface(gl_.get()); |
| |
| SetupDefaultShaderExpectations(); |
| |
| manager_.CreateProgramInfo(kClientProgramId, kServiceProgramId); |
| program_info_ = manager_.GetProgramInfo(kClientProgramId); |
| 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_INFO_LOG_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(0)) |
| .RetiresOnSaturation(); |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _)) |
| .WillOnce(SetArgumentPointee<2>(num_attribs)) |
| .RetiresOnSaturation(); |
| size_t max_attrib_len = 0; |
| for (size_t ii = 0; ii < num_attribs; ++ii) { |
| size_t len = strlen(attribs[ii].name) + 1; |
| max_attrib_len = std::max(max_attrib_len, len); |
| } |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(max_attrib_len)) |
| .RetiresOnSaturation(); |
| for (size_t ii = 0; ii < num_attribs; ++ii) { |
| const AttribInfo& info = attribs[ii]; |
| EXPECT_CALL(*gl_, |
| GetActiveAttrib(service_id, ii, |
| max_attrib_len, _, _, _, _)) |
| .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(); |
| size_t max_uniform_len = 0; |
| for (size_t ii = 0; ii < num_uniforms; ++ii) { |
| size_t len = strlen(uniforms[ii].name) + 1; |
| max_uniform_len = std::max(max_uniform_len, len); |
| } |
| EXPECT_CALL(*gl_, |
| GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _)) |
| .WillOnce(SetArgumentPointee<2>(max_uniform_len)) |
| .RetiresOnSaturation(); |
| for (size_t ii = 0; ii < num_uniforms; ++ii) { |
| const UniformInfo& info = uniforms[ii]; |
| EXPECT_CALL(*gl_, |
| GetActiveUniform(service_id, ii, |
| max_uniform_len, _, _, _, _)) |
| .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) { |
| std::string base_name = info.name; |
| size_t array_pos = base_name.rfind("[0]"); |
| if (base_name.size() > 3 && array_pos == base_name.size() - 3) { |
| base_name = base_name.substr(0, base_name.size() - 3); |
| } |
| for (GLsizei jj = 1; jj < info.size; ++jj) { |
| std::string element_name( |
| std::string(base_name) + "[" + base::IntToString(jj) + "]"); |
| EXPECT_CALL(*gl_, GetUniformLocation(service_id, |
| StrEq(element_name))) |
| .WillOnce(Return(info.location + jj * 2)) |
| .RetiresOnSaturation(); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| void SetupDefaultShaderExpectations() { |
| SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, |
| kServiceProgramId); |
| } |
| |
| virtual void TearDown() { |
| ::gfx::GLInterface::SetGLInterface(NULL); |
| } |
| |
| static AttribInfo kAttribs[]; |
| static UniformInfo kUniforms[]; |
| |
| scoped_ptr<StrictMock<gfx::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::kClientProgramId; |
| const GLuint ProgramManagerWithShaderTest::kServiceProgramId; |
| 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::kUniform1Size; |
| const GLint ProgramManagerWithShaderTest::kUniform2Size; |
| const GLint ProgramManagerWithShaderTest::kUniform3Size; |
| const GLint ProgramManagerWithShaderTest::kUniform1Location; |
| const GLint ProgramManagerWithShaderTest::kUniform2Location; |
| 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, }, |
| { kUniform3BadName, 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"; |
| // Correctly has array spec. |
| const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2[0]"; |
| // Incorrectly missing array spec. |
| const char* ProgramManagerWithShaderTest::kUniform3BadName = "uniform3"; |
| const char* ProgramManagerWithShaderTest::kUniform3GoodName = "uniform3[0]"; |
| |
| TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) { |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| 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(kClientProgramId); |
| 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(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_EQ(kAttrib2Location, program_info->GetAttribLocation(kAttrib2Name)); |
| EXPECT_EQ(-1, program_info->GetAttribLocation(kInvalidName)); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetUniformInfo) { |
| const GLint kInvalidIndex = 1000; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| const ProgramManager::ProgramInfo::UniformInfo* info = |
| program_info->GetUniformInfo(0); |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(kUniform1Size, info->size); |
| EXPECT_EQ(kUniform1Type, info->type); |
| EXPECT_EQ(kUniform1Location, info->element_locations[0]); |
| EXPECT_STREQ(kUniform1Name, info->name.c_str()); |
| info = program_info->GetUniformInfo(1); |
| 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()); |
| info = program_info->GetUniformInfo(2); |
| // We emulate certain OpenGL drivers by supplying the name without |
| // the array spec. Our implementation should correctly add the required spec. |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(kUniform3Size, info->size); |
| EXPECT_EQ(kUniform3Type, info->type); |
| EXPECT_EQ(kUniform3Location, info->element_locations[0]); |
| EXPECT_STREQ(kUniform3GoodName, info->name.c_str()); |
| EXPECT_TRUE(program_info->GetUniformInfo(kInvalidIndex) == NULL); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) { |
| ShaderManager shader_manager; |
| ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_FALSE(program_info->CanLink()); |
| const GLuint kVShaderClientId = 2001; |
| const GLuint kFShaderClientId = 2002; |
| const GLuint kVShaderServiceId = 3001; |
| const GLuint kFShaderServiceId = 3002; |
| shader_manager.CreateShaderInfo( |
| kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER); |
| ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo( |
| kVShaderClientId); |
| vshader->SetStatus(true, "", NULL); |
| shader_manager.CreateShaderInfo( |
| kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); |
| ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo( |
| kFShaderClientId); |
| fshader->SetStatus(true, "", NULL); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader)); |
| EXPECT_FALSE(program_info->CanLink()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader)); |
| EXPECT_TRUE(program_info->CanLink()); |
| program_info->DetachShader(&shader_manager, vshader); |
| EXPECT_FALSE(program_info->CanLink()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader)); |
| EXPECT_TRUE(program_info->CanLink()); |
| program_info->DetachShader(&shader_manager, fshader); |
| EXPECT_FALSE(program_info->CanLink()); |
| EXPECT_FALSE(program_info->AttachShader(&shader_manager, vshader)); |
| EXPECT_FALSE(program_info->CanLink()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader)); |
| EXPECT_TRUE(program_info->CanLink()); |
| vshader->SetStatus(false, "", NULL); |
| EXPECT_FALSE(program_info->CanLink()); |
| vshader->SetStatus(true, "", NULL); |
| EXPECT_TRUE(program_info->CanLink()); |
| fshader->SetStatus(false, "", NULL); |
| EXPECT_FALSE(program_info->CanLink()); |
| fshader->SetStatus(true, "", NULL); |
| EXPECT_TRUE(program_info->CanLink()); |
| EXPECT_TRUE(program_info->DetachShader(&shader_manager, fshader)); |
| EXPECT_FALSE(program_info->DetachShader(&shader_manager, fshader)); |
| shader_manager.Destroy(false); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetUniformLocation) { |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_EQ(kUniform1Location, program_info->GetUniformLocation(kUniform1Name)); |
| EXPECT_EQ(kUniform2Location, program_info->GetUniformLocation(kUniform2Name)); |
| EXPECT_EQ(kUniform3Location, program_info->GetUniformLocation( |
| kUniform3BadName)); |
| // Check we can get uniform2 as "uniform2" even though the name is |
| // "uniform2[0]" |
| EXPECT_EQ(kUniform2Location, program_info->GetUniformLocation("uniform2")); |
| // Check we can get uniform3 as "uniform3[0]" even though we simulated GL |
| // returning "uniform3" |
| EXPECT_EQ(kUniform3Location, program_info->GetUniformLocation( |
| kUniform3GoodName)); |
| // Check that we can get the locations of the array elements > 1 |
| EXPECT_EQ(kUniform2Location + 2, |
| program_info->GetUniformLocation("uniform2[1]")); |
| EXPECT_EQ(kUniform2Location + 4, |
| program_info->GetUniformLocation("uniform2[2]")); |
| EXPECT_EQ(-1, |
| program_info->GetUniformLocation("uniform2[3]")); |
| EXPECT_EQ(kUniform3Location + 2, |
| program_info->GetUniformLocation("uniform3[1]")); |
| EXPECT_EQ(-1, |
| program_info->GetUniformLocation("uniform3[2]")); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, GetUniformInfoByLocation) { |
| const GLint kInvalidLocation = 1234; |
| const ProgramManager::ProgramInfo::UniformInfo* info; |
| const ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| GLint array_index = -1; |
| ASSERT_TRUE(program_info != NULL); |
| info = program_info->GetUniformInfoByLocation( |
| kUniform2Location, &array_index); |
| EXPECT_EQ(0, array_index); |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(kUniform2Type, info->type); |
| array_index = -1; |
| info = program_info->GetUniformInfoByLocation( |
| kInvalidLocation, &array_index); |
| EXPECT_TRUE(info == NULL); |
| EXPECT_EQ(-1, array_index); |
| GLint loc = program_info->GetUniformLocation("uniform2[2]"); |
| info = program_info->GetUniformInfoByLocation(loc, &array_index); |
| ASSERT_TRUE(info != NULL); |
| EXPECT_EQ(2, array_index); |
| } |
| |
| // Some GL drivers incorrectly return gl_DepthRange and possibly other uniforms |
| // that start with "gl_". Our implementation catches these and does not allow |
| // them back to client. |
| TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) { |
| static const char* kUniform2Name = "gl_longNameWeCanCheckFor"; |
| static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = { |
| { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, }, |
| { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, }, |
| { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, }, |
| }; |
| const size_t kNumUniforms = arraysize(kUniforms); |
| static const GLuint kClientProgramId = 1234; |
| static const GLuint kServiceProgramId = 5679; |
| SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, |
| kServiceProgramId); |
| manager_.CreateProgramInfo(kClientProgramId, kServiceProgramId); |
| ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| program_info->Update(); |
| GLint value = 0; |
| program_info->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &value); |
| EXPECT_EQ(3, value); |
| // Check that we skipped the "gl_" uniform. |
| program_info->GetProgramiv(GL_ACTIVE_UNIFORMS, &value); |
| EXPECT_EQ(2, value); |
| // Check that our max length adds room for the array spec and is not as long |
| // as the "gl_" uniform we skipped. |
| // +4u is to account for "gl_" and NULL terminator. |
| program_info->GetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH, &value); |
| EXPECT_EQ(strlen(kUniform3BadName) + 4u, static_cast<size_t>(value)); |
| } |
| |
| // Some GL drivers incorrectly return the wrong type. For example they return |
| // GL_FLOAT_VEC2 when they should return GL_FLOAT_MAT2. Check we handle this. |
| TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) { |
| const GLuint kShaderClientId = 999; |
| const GLuint kShaderServiceId = 998; |
| static GLenum kAttrib2BadType = GL_FLOAT_VEC2; |
| static GLenum kAttrib2GoodType = GL_FLOAT_MAT2; |
| static GLenum kUniform2BadType = GL_FLOAT_VEC3; |
| static GLenum kUniform2GoodType = GL_FLOAT_MAT3; |
| MockShaderTranslator shader_translator; |
| ShaderTranslator::VariableMap attrib_map; |
| ShaderTranslator::VariableMap uniform_map; |
| attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo( |
| kAttrib1Type, kAttrib1Size); |
| attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo( |
| kAttrib2GoodType, kAttrib2Size); |
| attrib_map[kAttrib3Name] = ShaderTranslatorInterface::VariableInfo( |
| kAttrib3Type, kAttrib3Size); |
| uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo( |
| kUniform1Type, kUniform1Size); |
| uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo( |
| kUniform2GoodType, kUniform2Size); |
| uniform_map[kUniform3GoodName] = ShaderTranslatorInterface::VariableInfo( |
| kUniform3Type, kUniform3Size); |
| EXPECT_CALL(shader_translator, attrib_map()) |
| .WillRepeatedly(ReturnRef(attrib_map)); |
| EXPECT_CALL(shader_translator, uniform_map()) |
| .WillRepeatedly(ReturnRef(uniform_map)); |
| ShaderManager shader_manager; |
| shader_manager.CreateShaderInfo( |
| kShaderClientId, kShaderServiceId, GL_FRAGMENT_SHADER); |
| ShaderManager::ShaderInfo* shader_info = |
| shader_manager.GetShaderInfo(kShaderClientId); |
| shader_info->SetStatus(true, "", &shader_translator); |
| static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = { |
| { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, |
| { kAttrib2Name, kAttrib2Size, kAttrib2BadType, kAttrib2Location, }, |
| { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, }, |
| }; |
| static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = { |
| { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, }, |
| { kUniform2Name, kUniform2Size, kUniform2BadType, kUniform2Location, }, |
| { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, }, |
| }; |
| const size_t kNumAttribs= arraysize(kAttribs); |
| const size_t kNumUniforms = arraysize(kUniforms); |
| static const GLuint kClientProgramId = 1234; |
| static const GLuint kServiceProgramId = 5679; |
| SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, |
| kServiceProgramId); |
| manager_.CreateProgramInfo(kClientProgramId, kServiceProgramId); |
| ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, shader_info)); |
| program_info->Update(); |
| // Check that we got the good type, not the bad. |
| // Check Attribs |
| for (unsigned index = 0; index < kNumAttribs; ++index) { |
| const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info = |
| program_info->GetAttribInfo(index); |
| ASSERT_TRUE(attrib_info != NULL); |
| ShaderTranslator::VariableMap::const_iterator it = attrib_map.find( |
| attrib_info->name); |
| ASSERT_TRUE(it != attrib_map.end()); |
| EXPECT_EQ(it->first, attrib_info->name); |
| EXPECT_EQ(static_cast<GLenum>(it->second.type), attrib_info->type); |
| EXPECT_EQ(it->second.size, attrib_info->size); |
| } |
| // Check Uniforms |
| for (unsigned index = 0; index < kNumUniforms; ++index) { |
| const ProgramManager::ProgramInfo::UniformInfo* uniform_info = |
| program_info->GetUniformInfo(index); |
| ASSERT_TRUE(uniform_info != NULL); |
| ShaderTranslator::VariableMap::const_iterator it = uniform_map.find( |
| uniform_info->name); |
| ASSERT_TRUE(it != uniform_map.end()); |
| EXPECT_EQ(it->first, uniform_info->name); |
| EXPECT_EQ(static_cast<GLenum>(it->second.type), uniform_info->type); |
| EXPECT_EQ(it->second.size, uniform_info->size); |
| } |
| shader_manager.Destroy(false); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount) { |
| ShaderManager shader_manager; |
| ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_FALSE(program_info->CanLink()); |
| const GLuint kVShaderClientId = 2001; |
| const GLuint kFShaderClientId = 2002; |
| const GLuint kVShaderServiceId = 3001; |
| const GLuint kFShaderServiceId = 3002; |
| shader_manager.CreateShaderInfo( |
| kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER); |
| ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo( |
| kVShaderClientId); |
| ASSERT_TRUE(vshader != NULL); |
| vshader->SetStatus(true, "", NULL); |
| shader_manager.CreateShaderInfo( |
| kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); |
| ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo( |
| kFShaderClientId); |
| ASSERT_TRUE(fshader != NULL); |
| fshader->SetStatus(true, "", NULL); |
| EXPECT_FALSE(vshader->InUse()); |
| EXPECT_FALSE(fshader->InUse()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader)); |
| EXPECT_TRUE(vshader->InUse()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader)); |
| EXPECT_TRUE(fshader->InUse()); |
| EXPECT_TRUE(program_info->CanLink()); |
| EXPECT_FALSE(program_info->InUse()); |
| EXPECT_FALSE(program_info->IsDeleted()); |
| manager_.UseProgram(program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| manager_.UseProgram(program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| manager_.MarkAsDeleted(&shader_manager, program_info); |
| EXPECT_TRUE(program_info->IsDeleted()); |
| ProgramManager::ProgramInfo* info2 = |
| manager_.GetProgramInfo(kClientProgramId); |
| EXPECT_EQ(program_info, info2); |
| manager_.UnuseProgram(&shader_manager, program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| // this should delete the info. |
| manager_.UnuseProgram(&shader_manager, program_info); |
| info2 = manager_.GetProgramInfo(kClientProgramId); |
| EXPECT_TRUE(info2 == NULL); |
| EXPECT_FALSE(vshader->InUse()); |
| EXPECT_FALSE(fshader->InUse()); |
| shader_manager.Destroy(false); |
| } |
| |
| TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount2) { |
| ShaderManager shader_manager; |
| ProgramManager::ProgramInfo* program_info = |
| manager_.GetProgramInfo(kClientProgramId); |
| ASSERT_TRUE(program_info != NULL); |
| EXPECT_FALSE(program_info->CanLink()); |
| const GLuint kVShaderClientId = 2001; |
| const GLuint kFShaderClientId = 2002; |
| const GLuint kVShaderServiceId = 3001; |
| const GLuint kFShaderServiceId = 3002; |
| shader_manager.CreateShaderInfo( |
| kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER); |
| ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo( |
| kVShaderClientId); |
| ASSERT_TRUE(vshader != NULL); |
| vshader->SetStatus(true, "", NULL); |
| shader_manager.CreateShaderInfo( |
| kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); |
| ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo( |
| kFShaderClientId); |
| ASSERT_TRUE(fshader != NULL); |
| fshader->SetStatus(true, "", NULL); |
| EXPECT_FALSE(vshader->InUse()); |
| EXPECT_FALSE(fshader->InUse()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, vshader)); |
| EXPECT_TRUE(vshader->InUse()); |
| EXPECT_TRUE(program_info->AttachShader(&shader_manager, fshader)); |
| EXPECT_TRUE(fshader->InUse()); |
| EXPECT_TRUE(program_info->CanLink()); |
| EXPECT_FALSE(program_info->InUse()); |
| EXPECT_FALSE(program_info->IsDeleted()); |
| manager_.UseProgram(program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| manager_.UseProgram(program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| manager_.UnuseProgram(&shader_manager, program_info); |
| EXPECT_TRUE(program_info->InUse()); |
| manager_.UnuseProgram(&shader_manager, program_info); |
| EXPECT_FALSE(program_info->InUse()); |
| ProgramManager::ProgramInfo* info2 = |
| manager_.GetProgramInfo(kClientProgramId); |
| EXPECT_EQ(program_info, info2); |
| // this should delete the program. |
| manager_.MarkAsDeleted(&shader_manager, program_info); |
| info2 = manager_.GetProgramInfo(kClientProgramId); |
| EXPECT_TRUE(info2 == NULL); |
| EXPECT_FALSE(vshader->InUse()); |
| EXPECT_FALSE(fshader->InUse()); |
| shader_manager.Destroy(false); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| |