diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 17:58:32 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 17:58:32 +0000 |
commit | d81e8c5fd686ff034a6e904b3f575675c2a05a1e (patch) | |
tree | e211aa0e8a7713cd379db67fd12fbcc026a6706e /gpu | |
parent | 1a5520603bc006aa0f73ef6762d2886b6719ee10 (diff) | |
download | chromium_src-d81e8c5fd686ff034a6e904b3f575675c2a05a1e.zip chromium_src-d81e8c5fd686ff034a6e904b3f575675c2a05a1e.tar.gz chromium_src-d81e8c5fd686ff034a6e904b3f575675c2a05a1e.tar.bz2 |
Makes LinkProgram fail if both a vertex and fragment shader
are not present. Desktop GL doesn't fail this case because
the fixed function pipeline can be a substitute for either
TEST=unit tests
BUG=none
Review URL: http://codereview.chromium.org/2582002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49073 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
7 files changed, 197 insertions, 31 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 588be6e..dd0c665 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -2584,6 +2584,12 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIds( void GLES2DecoderImpl::DoDrawArrays( GLenum mode, GLint first, GLsizei count) { + // We have to check this here because the prototype for glDrawArrays + // is GLint not GLsizei. + if (first < 0) { + SetGLError(GL_INVALID_ENUM, "glDrawArrays: first < 0"); + return; + } if (IsDrawValid(first + count - 1)) { bool simulated_attrib_0 = SimulateAttrib0(first + count - 1); bool textures_set = SetBlackTextureForNonRenderableTextures(); @@ -2684,6 +2690,11 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program) { if (!info) { return; } + if (!info->CanLink()) { + SetGLError(GL_INVALID_OPERATION, + "glLinkProgram: must have both vertex and fragment shader"); + return; + } glLinkProgram(info->service_id()); GLint success = 0; glGetProgramiv(info->service_id(), GL_LINK_STATUS, &success); @@ -3387,6 +3398,7 @@ void GLES2DecoderImpl::DoAttachShader( if (!shader_info) { return; } + program_info->AttachShader(shader_info); glAttachShader(program_info->service_id(), shader_info->service_id()); } @@ -3402,6 +3414,7 @@ void GLES2DecoderImpl::DoDetachShader( if (!shader_info) { return; } + program_info->DetachShader(shader_info); glDetachShader(program_info->service_id(), shader_info->service_id()); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc index bf89ac7..54964d8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc @@ -34,7 +34,24 @@ class GLES2DecoderTest2 : public GLES2DecoderTestBase { template <> void GLES2DecoderTestBase::SpecializedSetup<LinkProgram, 0>(bool /* valid */) { + const GLuint kClientVertexShaderId = 5001; + const GLuint kServiceVertexShaderId = 6001; + const GLuint kClientFragmentShaderId = 5002; + const GLuint kServiceFragmentShaderId = 6002; + DoCreateShader( + GL_VERTEX_SHADER, kClientVertexShaderId, kServiceVertexShaderId); + DoCreateShader( + GL_FRAGMENT_SHADER, kClientFragmentShaderId, kServiceFragmentShaderId); + InSequence dummy; + EXPECT_CALL(*gl_, + AttachShader(kServiceProgramId, kServiceVertexShaderId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, + AttachShader(kServiceProgramId, kServiceFragmentShaderId)) + .Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _)) .WillOnce(SetArgumentPointee<2>(1)); EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTES, _)) @@ -49,6 +66,14 @@ void GLES2DecoderTestBase::SpecializedSetup<LinkProgram, 0>(bool /* valid */) { *gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, _)) .WillOnce(SetArgumentPointee<2>(0)); + + AttachShader attach_cmd; + attach_cmd.Init(client_program_id_, kClientVertexShaderId); + EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); + + attach_cmd.Init(client_program_id_, kClientFragmentShaderId); + EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); + }; template <> diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index a9cc632..bda68e8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -185,15 +185,7 @@ void GLES2DecoderTestBase::SetUp() { EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } - { - EXPECT_CALL(*gl_, CreateShader(_)) - .Times(1) - .WillOnce(Return(kServiceShaderId)) - .RetiresOnSaturation(); - CreateShader cmd; - cmd.Init(GL_VERTEX_SHADER, client_shader_id_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - } + DoCreateShader(GL_VERTEX_SHADER, client_shader_id_, kServiceShaderId); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } @@ -224,6 +216,17 @@ GLint GLES2DecoderTestBase::GetGLError() { return static_cast<GLint>(*GetSharedMemoryAs<GLenum*>()); } +void GLES2DecoderTestBase::DoCreateShader( + GLenum shader_type, GLuint client_id, GLuint service_id) { + EXPECT_CALL(*gl_, CreateShader(shader_type)) + .Times(1) + .WillOnce(Return(service_id)) + .RetiresOnSaturation(); + CreateShader cmd; + cmd.Init(shader_type, client_id); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + void GLES2DecoderTestBase::SetBucketAsCString( uint32 bucket_id, const char* str) { uint32 size = str ? (strlen(str) + 1) : 0; @@ -246,8 +249,14 @@ void GLES2DecoderTestBase::SetupShaderForUniform() { static UniformInfo uniforms[] = { { "bar", 1, GL_INT, 1, }, }; + const GLuint kClientVertexShaderId = 5001; + const GLuint kServiceVertexShaderId = 6001; + const GLuint kClientFragmentShaderId = 5002; + const GLuint kServiceFragmentShaderId = 6002; SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), - client_program_id_, kServiceProgramId); + client_program_id_, kServiceProgramId, + kClientVertexShaderId, kServiceVertexShaderId, + kClientFragmentShaderId, kServiceFragmentShaderId); EXPECT_CALL(*gl_, UseProgram(kServiceProgramId)) .Times(1) @@ -388,7 +397,9 @@ void GLES2DecoderWithShaderTestBase::SetUp() { { kUniform3Name, kUniform3Size, kUniform3Type, kUniform3Location, }, }; SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms), - client_program_id_, kServiceProgramId); + client_program_id_, kServiceProgramId, + client_vertex_shader_id_, kServiceVertexShaderId, + client_fragment_shader_id_, kServiceFragmentShaderId); } { @@ -408,20 +419,28 @@ void GLES2DecoderWithShaderTestBase::TearDown() { void GLES2DecoderTestBase::SetupShader( GLES2DecoderTestBase::AttribInfo* attribs, size_t num_attribs, GLES2DecoderTestBase::UniformInfo* uniforms, size_t num_uniforms, - GLuint client_id, GLuint service_id) { - LinkProgram cmd; - cmd.Init(client_id); - + GLuint program_client_id, GLuint program_service_id, + GLuint vertex_shader_client_id, GLuint vertex_shader_service_id, + GLuint fragment_shader_client_id, GLuint fragment_shader_service_id) { { InSequence s; - EXPECT_CALL(*gl_, LinkProgram(service_id)) + + EXPECT_CALL(*gl_, + AttachShader(program_service_id, vertex_shader_service_id)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, + AttachShader(program_service_id, fragment_shader_service_id)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, LinkProgram(program_service_id)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, GetProgramiv(service_id, GL_LINK_STATUS, _)) + EXPECT_CALL(*gl_, GetProgramiv(program_service_id, GL_LINK_STATUS, _)) .WillOnce(SetArgumentPointee<2>(1)) .RetiresOnSaturation(); EXPECT_CALL(*gl_, - GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _)) + GetProgramiv(program_service_id, GL_ACTIVE_ATTRIBUTES, _)) .WillOnce(SetArgumentPointee<2>(num_attribs)) .RetiresOnSaturation(); size_t max_attrib_len = 0; @@ -430,13 +449,13 @@ void GLES2DecoderTestBase::SetupShader( max_attrib_len = std::max(max_attrib_len, len); } EXPECT_CALL(*gl_, - GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _)) + GetProgramiv(program_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, _, _, _, _)) + GetActiveAttrib(program_service_id, ii, max_attrib_len, _, _, _, _)) .WillOnce(DoAll( SetArgumentPointee<3>(strlen(info.name)), SetArgumentPointee<4>(info.size), @@ -445,14 +464,14 @@ void GLES2DecoderTestBase::SetupShader( info.name + strlen(info.name) + 1))) .RetiresOnSaturation(); if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { - EXPECT_CALL(*gl_, GetAttribLocation(service_id, + EXPECT_CALL(*gl_, GetAttribLocation(program_service_id, StrEq(info.name))) .WillOnce(Return(info.location)) .RetiresOnSaturation(); } } EXPECT_CALL(*gl_, - GetProgramiv(service_id, GL_ACTIVE_UNIFORMS, _)) + GetProgramiv(program_service_id, GL_ACTIVE_UNIFORMS, _)) .WillOnce(SetArgumentPointee<2>(num_uniforms)) .RetiresOnSaturation(); size_t max_uniform_len = 0; @@ -461,13 +480,13 @@ void GLES2DecoderTestBase::SetupShader( max_uniform_len = std::max(max_uniform_len, len); } EXPECT_CALL(*gl_, - GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _)) + GetProgramiv(program_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, _, _, _, _)) + GetActiveUniform(program_service_id, ii, max_uniform_len, _, _, _, _)) .WillOnce(DoAll( SetArgumentPointee<3>(strlen(info.name)), SetArgumentPointee<4>(info.size), @@ -476,7 +495,7 @@ void GLES2DecoderTestBase::SetupShader( info.name + strlen(info.name) + 1))) .RetiresOnSaturation(); if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { - EXPECT_CALL(*gl_, GetUniformLocation(service_id, + EXPECT_CALL(*gl_, GetUniformLocation(program_service_id, StrEq(info.name))) .WillOnce(Return(info.location)) .RetiresOnSaturation(); @@ -484,7 +503,7 @@ void GLES2DecoderTestBase::SetupShader( for (GLsizei jj = 1; jj < info.size; ++jj) { std::string element_name( std::string(info.name) + "[" + IntToString(jj) + "]"); - EXPECT_CALL(*gl_, GetUniformLocation(service_id, + EXPECT_CALL(*gl_, GetUniformLocation(program_service_id, StrEq(element_name))) .WillOnce(Return(info.location + jj)) .RetiresOnSaturation(); @@ -494,7 +513,23 @@ void GLES2DecoderTestBase::SetupShader( } } - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + DoCreateShader( + GL_VERTEX_SHADER, vertex_shader_client_id, vertex_shader_service_id); + DoCreateShader( + GL_FRAGMENT_SHADER, fragment_shader_client_id, + fragment_shader_service_id); + + AttachShader attach_cmd; + attach_cmd.Init(program_client_id, vertex_shader_client_id); + EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); + + attach_cmd.Init(program_client_id, fragment_shader_client_id); + EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd)); + + LinkProgram link_cmd; + link_cmd.Init(program_client_id); + + EXPECT_EQ(error::kNoError, ExecuteCmd(link_cmd)); } void GLES2DecoderWithShaderTestBase::DoEnableVertexAttribArray(GLint index) { @@ -576,6 +611,9 @@ void GLES2DecoderWithShaderTestBase::DeleteIndexBuffer() { // GCC requires these declarations, but MSVC requires they not be present #ifndef COMPILER_MSVC +const GLuint GLES2DecoderWithShaderTestBase::kServiceVertexShaderId; +const GLuint GLES2DecoderWithShaderTestBase::kServiceFragmentShaderId; + const GLsizei GLES2DecoderWithShaderTestBase::kNumVertices; const GLsizei GLES2DecoderWithShaderTestBase::kNumIndices; const int GLES2DecoderWithShaderTestBase::kValidIndexRangeStart; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index e4e7be2..d96ef99 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -162,6 +162,8 @@ class GLES2DecoderTestBase : public testing::Test { return group_.program_manager()->GetProgramInfo(service_id); } + void DoCreateShader(GLenum shader_type, GLuint client_id, GLuint service_id); + void SetBucketAsCString(uint32 bucket_id, const char* str); struct AttribInfo { @@ -178,9 +180,12 @@ class GLES2DecoderTestBase : public testing::Test { GLint location; }; - void SetupShader(AttribInfo* attribs, size_t num_attribs, - UniformInfo* uniforms, size_t num_uniforms, - GLuint client_id, GLuint service_id); + void SetupShader( + AttribInfo* attribs, size_t num_attribs, + UniformInfo* uniforms, size_t num_uniforms, + GLuint client_id, GLuint service_id, + GLuint vertex_shader_client_id, GLuint vertex_shader_service_id, + GLuint fragment_shader_client_id, GLuint fragment_shader_service_id); // Setups up a shader for testing glUniform. void SetupShaderForUniform(); @@ -278,9 +283,14 @@ class GLES2DecoderTestBase : public testing::Test { class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase { public: GLES2DecoderWithShaderTestBase() - : GLES2DecoderTestBase() { + : GLES2DecoderTestBase(), + client_vertex_shader_id_(121), + client_fragment_shader_id_(122) { } + static const GLuint kServiceVertexShaderId = 321; + static const GLuint kServiceFragmentShaderId = 322; + static const GLsizei kNumVertices = 100; static const GLsizei kNumIndices = 10; static const int kValidIndexRangeStart = 1; @@ -345,6 +355,9 @@ class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase { void DeleteVertexBuffer(); void DeleteIndexBuffer(); + + GLuint client_vertex_shader_id_; + GLuint client_fragment_shader_id_; }; } // namespace gles2 diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index 77b0c96..2dcb368 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -12,6 +12,18 @@ namespace gpu { namespace gles2 { +static int ShaderTypeToIndex(GLenum shader_type) { + switch (shader_type) { + case GL_VERTEX_SHADER: + return 0; + case GL_FRAGMENT_SHADER: + return 1; + default: + NOTREACHED(); + return 0; + } +} + bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) { static const char kInvalidPrefix[] = { 'g', 'l', '_' }; return (length >= sizeof(kInvalidPrefix) && @@ -246,12 +258,35 @@ void ProgramManager::ProgramInfo::GetProgramiv(GLenum pname, GLint* params) { // Notice +1 to accomodate NULL terminator. *params = max_uniform_name_length_ + 1; break; + case GL_LINK_STATUS: + *params = valid_; + break; default: glGetProgramiv(service_id_, pname, params); break; } } +void ProgramManager::ProgramInfo::AttachShader( + ShaderManager::ShaderInfo* info) { + attached_shaders_[ShaderTypeToIndex(info->shader_type())] = + ShaderManager::ShaderInfo::Ref(info); +} + +void ProgramManager::ProgramInfo::DetachShader( + ShaderManager::ShaderInfo* info) { + attached_shaders_[ShaderTypeToIndex(info->shader_type())] = NULL; +} + +bool ProgramManager::ProgramInfo::CanLink() const { + for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { + if (!attached_shaders_[ii]) { + return false; + } + } + return true; +} + void ProgramManager::CreateProgramInfo(GLuint client_id, GLuint service_id) { std::pair<ProgramInfoMap::iterator, bool> result = program_infos_.insert( diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 7104242..77cb39d 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/ref_counted.h" #include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/shader_manager.h" namespace gpu { namespace gles2 { @@ -29,6 +30,8 @@ class ProgramManager { public: typedef scoped_refptr<ProgramInfo> Ref; + static const int kMaxAttachedShaders = 2; + struct UniformInfo { UniformInfo(GLsizei _size, GLenum _type, const std::string& _name) : size(_size), @@ -132,6 +135,11 @@ class ProgramManager { return valid_; } + void AttachShader(ShaderManager::ShaderInfo* info); + void DetachShader(ShaderManager::ShaderInfo* info); + + bool CanLink() const; + private: friend class base::RefCounted<ProgramInfo>; friend class ProgramManager; @@ -167,6 +175,9 @@ class ProgramManager { // The program this ProgramInfo is tracking. GLuint service_id_; + // Shaders by type of shader. + ShaderManager::ShaderInfo::Ref attached_shaders_[kMaxAttachedShaders]; + // This is true if glLinkProgram was successful. bool valid_; }; diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 6767646..b683927 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -47,6 +47,7 @@ TEST_F(ProgramManagerTest, Basic) { ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kClient1Id); ASSERT_TRUE(info1 != NULL); EXPECT_EQ(kService1Id, info1->service_id()); + EXPECT_FALSE(info1->CanLink()); GLuint client_id = 0; EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id)); EXPECT_EQ(kClient1Id, client_id); @@ -357,6 +358,36 @@ TEST_F(ProgramManagerWithShaderTest, GetUniformInfo) { 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); + shader_manager.CreateShaderInfo( + kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); + ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo( + kFShaderClientId); + program_info->AttachShader(vshader); + EXPECT_FALSE(program_info->CanLink()); + program_info->AttachShader(fshader); + EXPECT_TRUE(program_info->CanLink()); + program_info->DetachShader(vshader); + EXPECT_FALSE(program_info->CanLink()); + program_info->AttachShader(vshader); + EXPECT_TRUE(program_info->CanLink()); + program_info->DetachShader(fshader); + EXPECT_FALSE(program_info->CanLink()); +} + TEST_F(ProgramManagerWithShaderTest, GetUniformLocation) { const ProgramManager::ProgramInfo* program_info = manager_.GetProgramInfo(kClientProgramId); |