diff options
author | zmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-02 19:23:24 +0000 |
---|---|---|
committer | zmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-02 19:23:24 +0000 |
commit | c3e4c4eedddbbbe09dbbbe4b8c12539f0dccd0f7 (patch) | |
tree | 75361dad9b2efec4f0b1772c61c1f027f8c011d0 /gpu | |
parent | 5deede1bc2116cd637ff825b6c688b15e04af392 (diff) | |
download | chromium_src-c3e4c4eedddbbbe09dbbbe4b8c12539f0dccd0f7.zip chromium_src-c3e4c4eedddbbbe09dbbbe4b8c12539f0dccd0f7.tar.gz chromium_src-c3e4c4eedddbbbe09dbbbe4b8c12539f0dccd0f7.tar.bz2 |
Fails glLinkProgram if two glBindAttribLocation conflicts.
i.e., two declared attributes are bound to the same location, then we fail the link.
Many drivers already do this, but not all of them. For example, mesa does not, and it caused memory corruption actually. So we do this in chrome command buffer.
BUG=112569
TEST=test case in 112569
R=gman
Review URL: https://chromiumcodereview.appspot.com/9570023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@124707 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 1 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager.cc | 30 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager.h | 14 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager_unittest.cc | 82 |
4 files changed, 126 insertions, 1 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 8539dcd..0ecc3d8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -3802,6 +3802,7 @@ void GLES2DecoderImpl::DoBindAttribLocation( if (!info) { return; } + info->SetAttribLocationBinding(name, static_cast<GLint>(index)); glBindAttribLocation(info->service_id(), index, name); } diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index e601aed..18593356 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -5,6 +5,7 @@ #include "gpu/command_buffer/service/program_manager.h" #include <algorithm> +#include <set> #include "base/basictypes.h" #include "base/logging.h" @@ -168,6 +169,10 @@ void ProgramManager::ProgramInfo::Link() { set_log_info("missing shaders"); return; } + if (DetectAttribLocationBindingConflicts()) { + set_log_info("glBindAttribLocation() conflicts"); + return; + } glLinkProgram(service_id()); GLint success = 0; @@ -442,6 +447,31 @@ bool ProgramManager::ProgramInfo::CanLink() const { return true; } +bool ProgramManager::ProgramInfo::DetectAttribLocationBindingConflicts() const { + std::set<GLint> location_binding_used; + for (std::map<std::string, GLint>::const_iterator it = + bind_attrib_location_map_.begin(); + it != bind_attrib_location_map_.end(); ++it) { + // Find out if an attribute is declared in this program's shaders. + bool active = false; + for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { + if (!attached_shaders_[ii] || !attached_shaders_[ii]->IsValid()) + continue; + if (attached_shaders_[ii]->GetAttribInfo(it->first)) { + active = true; + break; + } + } + if (active) { + std::pair<std::set<GLint>::iterator, bool> result = + location_binding_used.insert(it->second); + if (!result.second) + return true; + } + } + return false; +} + static uint32 ComputeOffset(const void* start, const void* position) { return static_cast<const uint8*>(position) - static_cast<const uint8*>(start); diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 330ef53..c627957 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -154,6 +154,17 @@ class GPU_EXPORT ProgramManager { return use_count_ != 0; } + // Sets attribute-location binding from a glBindAttribLocation() call. + void SetAttribLocationBinding(const std::string& attrib, + GLint location) { + bind_attrib_location_map_[attrib] = location; + } + + // Detects if there are attribute location conflicts from + // glBindAttribLocation() calls. + // We only consider the declared attributes in the program. + bool DetectAttribLocationBindingConflicts() const; + static inline GLint GetFakeLocation( GLint fake_base_location, GLint element_index) { return fake_base_location | element_index << 16; @@ -248,6 +259,9 @@ class GPU_EXPORT ProgramManager { // Log info scoped_ptr<std::string> log_info_; + + // attribute-location binding map from glBindAttribLocation() calls. + std::map<std::string, GLint> bind_attrib_location_map_; }; ProgramManager(); diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 9ac98fd..ba7288ae 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -334,7 +334,6 @@ class ProgramManagerWithShaderTest : public testing::Test { } } - void SetupDefaultShaderExpectations() { SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, kServiceProgramId); @@ -344,6 +343,20 @@ class ProgramManagerWithShaderTest : public testing::Test { ::gfx::GLInterface::SetGLInterface(NULL); } + // Return true if link status matches expected_link_status + bool LinkAsExpected(ProgramManager::ProgramInfo* program_info, + bool expected_link_status) { + GLuint service_id = program_info->service_id(); + if (expected_link_status) { + SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms, + service_id); + } + program_info->Link(); + GLint link_status; + program_info->GetProgramiv(GL_LINK_STATUS, &link_status); + return (static_cast<bool>(link_status) == expected_link_status); + } + static AttribInfo kAttribs[]; static UniformInfo kUniforms[]; @@ -938,6 +951,73 @@ TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetProgramInfo) { static_cast<uint32>(input - inputs)); } +TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) { + // Set up shader + const GLuint kVShaderClientId = 1; + const GLuint kVShaderServiceId = 11; + const GLuint kFShaderClientId = 2; + const GLuint kFShaderServiceId = 12; + MockShaderTranslator shader_translator; + ShaderTranslator::VariableMap attrib_map; + for (uint32 ii = 0; ii < kNumAttribs; ++ii) { + attrib_map[kAttribs[ii].name] = ShaderTranslatorInterface::VariableInfo( + kAttribs[ii].type, kAttribs[ii].size, kAttribs[ii].name); + } + ShaderTranslator::VariableMap uniform_map; + EXPECT_CALL(shader_translator, attrib_map()) + .WillRepeatedly(ReturnRef(attrib_map)); + EXPECT_CALL(shader_translator, uniform_map()) + .WillRepeatedly(ReturnRef(uniform_map)); + // Check we can create shader. + ShaderManager::ShaderInfo* vshader = shader_manager_.CreateShaderInfo( + kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER); + ShaderManager::ShaderInfo* fshader = shader_manager_.CreateShaderInfo( + kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); + // Check shader got created. + ASSERT_TRUE(vshader != NULL && fshader != NULL); + // Set Status + vshader->SetStatus(true, "", &shader_translator); + // Check attrib infos got copied. + for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin(); + it != attrib_map.end(); ++it) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + vshader->GetAttribInfo(it->first); + ASSERT_TRUE(variable_info != NULL); + EXPECT_EQ(it->second.type, variable_info->type); + EXPECT_EQ(it->second.size, variable_info->size); + EXPECT_EQ(it->second.name, variable_info->name); + } + fshader->SetStatus(true, "", NULL); + + // Set up program + const GLuint kClientProgramId = 6666; + const GLuint kServiceProgramId = 8888; + ProgramManager::ProgramInfo* program_info = + manager_.CreateProgramInfo(kClientProgramId, kServiceProgramId); + ASSERT_TRUE(program_info != NULL); + EXPECT_TRUE(program_info->AttachShader(&shader_manager_, vshader)); + EXPECT_TRUE(program_info->AttachShader(&shader_manager_, fshader)); + + EXPECT_FALSE(program_info->DetectAttribLocationBindingConflicts()); + EXPECT_TRUE(LinkAsExpected(program_info, true)); + + program_info->SetAttribLocationBinding(kAttrib1Name, 0); + EXPECT_FALSE(program_info->DetectAttribLocationBindingConflicts()); + EXPECT_TRUE(LinkAsExpected(program_info, true)); + + program_info->SetAttribLocationBinding("xxx", 0); + EXPECT_FALSE(program_info->DetectAttribLocationBindingConflicts()); + EXPECT_TRUE(LinkAsExpected(program_info, true)); + + program_info->SetAttribLocationBinding(kAttrib2Name, 1); + EXPECT_FALSE(program_info->DetectAttribLocationBindingConflicts()); + EXPECT_TRUE(LinkAsExpected(program_info, true)); + + program_info->SetAttribLocationBinding(kAttrib2Name, 0); + EXPECT_TRUE(program_info->DetectAttribLocationBindingConflicts()); + EXPECT_TRUE(LinkAsExpected(program_info, false)); +} + } // namespace gles2 } // namespace gpu |