diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-12 00:51:34 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-12 00:51:34 +0000 |
commit | f57bb2865fa146140d27e64c68148b79724f2f35 (patch) | |
tree | 03becedc67abf8a12fb1970ccaa7b3bbca06b6b7 /gpu/command_buffer/service | |
parent | 339d6dd4d356d062365a9a1a1aaf17f42d5349d3 (diff) | |
download | chromium_src-f57bb2865fa146140d27e64c68148b79724f2f35.zip chromium_src-f57bb2865fa146140d27e64c68148b79724f2f35.tar.gz chromium_src-f57bb2865fa146140d27e64c68148b79724f2f35.tar.bz2 |
Use the shader translator to correct bad type information
returned by OpenGL drivers.
TEST=unit tests, ran OpenGL ES 2.0 conformance tests and ran WebGL conformance test. Things that used to fail now pass.
BUG=none
Review URL: http://codereview.chromium.org/4829001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65882 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/service')
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 9 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/mocks.h | 24 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager.cc | 44 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager.h | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/program_manager_unittest.cc | 119 | ||||
-rw-r--r-- | gpu/command_buffer/service/shader_manager.cc | 27 | ||||
-rw-r--r-- | gpu/command_buffer/service/shader_manager.h | 18 | ||||
-rw-r--r-- | gpu/command_buffer/service/shader_manager_unittest.cc | 76 | ||||
-rw-r--r-- | gpu/command_buffer/service/shader_translator.cc | 4 | ||||
-rw-r--r-- | gpu/command_buffer/service/shader_translator.h | 56 |
12 files changed, 339 insertions, 50 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 110ea12..4b76497 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -4084,12 +4084,13 @@ void GLES2DecoderImpl::DoCompileShader(GLuint client_id) { // Translate GL ES 2.0 shader to Desktop GL shader and pass that to // glShaderSource and then glCompileShader. const char* shader_src = info->source().c_str(); + ShaderTranslator* translator = NULL; if (use_shader_translator_) { - ShaderTranslator* translator = info->shader_type() == GL_VERTEX_SHADER ? + translator = info->shader_type() == GL_VERTEX_SHADER ? vertex_translator_.get() : fragment_translator_.get(); if (!translator->Translate(shader_src)) { - info->SetStatus(false, translator->info_log()); + info->SetStatus(false, translator->info_log(), NULL); return; } shader_src = translator->translated_shader(); @@ -4100,7 +4101,7 @@ void GLES2DecoderImpl::DoCompileShader(GLuint client_id) { GLint status = GL_FALSE; glGetShaderiv(info->service_id(), GL_COMPILE_STATUS, &status); if (status) { - info->SetStatus(true, ""); + info->SetStatus(true, "", translator); } else { // We cannot reach here if we are using the shader translator. // All invalid shaders must be rejected by the translator. @@ -4114,7 +4115,7 @@ void GLES2DecoderImpl::DoCompileShader(GLuint client_id) { glGetShaderInfoLog(info->service_id(), max_len, &len, temp.get()); DCHECK(max_len == 0 || len < max_len); DCHECK(len ==0 || temp[len] == '\0'); - info->SetStatus(false, std::string(temp.get(), len)); + info->SetStatus(false, std::string(temp.get(), len), NULL); } }; 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 8ea4d27..925e28f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc @@ -43,8 +43,8 @@ void GLES2DecoderTestBase::SpecializedSetup<LinkProgram, 0>(bool /* valid */) { DoCreateShader( GL_FRAGMENT_SHADER, kClientFragmentShaderId, kServiceFragmentShaderId); - GetShaderInfo(kClientVertexShaderId)->SetStatus(true, ""); - GetShaderInfo(kClientFragmentShaderId)->SetStatus(true, ""); + GetShaderInfo(kClientVertexShaderId)->SetStatus(true, "", NULL); + GetShaderInfo(kClientFragmentShaderId)->SetStatus(true, "", NULL); InSequence dummy; EXPECT_CALL(*gl_, 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 de3a528..e253a73 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -566,8 +566,8 @@ void GLES2DecoderTestBase::SetupShader( GL_FRAGMENT_SHADER, fragment_shader_client_id, fragment_shader_service_id); - GetShaderInfo(vertex_shader_client_id)->SetStatus(true, ""); - GetShaderInfo(fragment_shader_client_id)->SetStatus(true, ""); + GetShaderInfo(vertex_shader_client_id)->SetStatus(true, "", NULL); + GetShaderInfo(fragment_shader_client_id)->SetStatus(true, "", NULL); AttachShader attach_cmd; attach_cmd.Init(program_client_id, vertex_shader_client_id); diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h index 647fead..8c84547 100644 --- a/gpu/command_buffer/service/mocks.h +++ b/gpu/command_buffer/service/mocks.h @@ -4,9 +4,8 @@ // This file contains definitions for mock objects, used for testing. -// TODO: This file "manually" defines some mock objects. Using gMock -// would be definitely preferable, unfortunately it doesn't work on Windows -// yet. +// TODO(apatrick): This file "manually" defines some mock objects. Using gMock +// would be definitely preferable, unfortunately it doesn't work on Windows yet. #ifndef GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_ #define GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_ @@ -16,6 +15,7 @@ #include "base/logging.h" #include "gpu/command_buffer/service/cmd_parser.h" #include "gpu/command_buffer/service/cmd_buffer_engine.h" +#include "gpu/command_buffer/service/shader_translator.h" #include "testing/gmock/include/gmock/gmock.h" namespace gpu { @@ -77,6 +77,24 @@ class AsyncAPIMock : public AsyncAPIInterface { CommandBufferEngine *engine_; }; +namespace gles2 { + +class MockShaderTranslator : public ShaderTranslatorInterface { + public: + virtual ~MockShaderTranslator() { } + + MOCK_METHOD3(Init, bool( + ShShaderType shader_type, + ShShaderSpec shader_spec, + const ShBuiltInResources* resources)); + MOCK_METHOD1(Translate, bool(const char* shader)); + MOCK_CONST_METHOD0(translated_shader, const char*()); + MOCK_CONST_METHOD0(info_log, const char*()); + MOCK_CONST_METHOD0(attrib_map, const VariableMap&()); + MOCK_CONST_METHOD0(uniform_map, const VariableMap&()); +}; + +} // namespace gles2 } // namespace gpu #endif // GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_ diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index c94bd9b..596c8c9 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -27,7 +27,6 @@ static int ShaderTypeToIndex(GLenum shader_type) { } } - ProgramManager::ProgramInfo::UniformInfo::UniformInfo(GLsizei _size, GLenum _type, const std::string& _name) @@ -92,13 +91,14 @@ void ProgramManager::ProgramInfo::Update() { DCHECK(max_len == 0 || length < max_len); DCHECK(length == 0 || name_buffer[length] == '\0'); if (!IsInvalidPrefix(name_buffer.get(), length)) { + std::string name; + GetCorrectedVariableInfo(false, name_buffer.get(), &name, &size, &type); // TODO(gman): Should we check for error? GLint location = glGetAttribLocation(service_id_, name_buffer.get()); if (location > max_location) { max_location = location; } - attrib_infos_.push_back( - VertexAttribInfo(size, type, name_buffer.get(), location)); + attrib_infos_.push_back(VertexAttribInfo(size, type, name, location)); max_attrib_name_length_ = std::max(max_attrib_name_length_, length); } } @@ -131,8 +131,9 @@ void ProgramManager::ProgramInfo::Update() { // TODO(gman): Should we check for error? if (!IsInvalidPrefix(name_buffer.get(), length)) { GLint location = glGetUniformLocation(service_id_, name_buffer.get()); - const UniformInfo* info = - AddUniformInfo(size, type, location, name_buffer.get()); + std::string name; + GetCorrectedVariableInfo(true, name_buffer.get(), &name, &size, &type); + const UniformInfo* info = AddUniformInfo(size, type, location, name); for (size_t jj = 0; jj < info->element_locations.size(); ++jj) { if (info->element_locations[jj] > max_location) { max_location = info->element_locations[jj]; @@ -221,6 +222,39 @@ bool ProgramManager::ProgramInfo::GetUniformTypeByLocation( return false; } +// Note: This is only valid to call right after a program has been linked +// successfully. +void ProgramManager::ProgramInfo::GetCorrectedVariableInfo( + bool use_uniforms, + const std::string& name, std::string* corrected_name, + GLsizei* size, GLenum* type) const { + DCHECK(corrected_name); + DCHECK(size); + DCHECK(type); + const char* kArraySpec = "[0]"; + for (int jj = 0; jj < 2; ++jj) { + std::string test_name(name + ((jj == 1) ? kArraySpec : "")); + for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { + ShaderManager::ShaderInfo* shader_info = attached_shaders_[ii].get(); + if (shader_info) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + use_uniforms ? shader_info->GetUniformInfo(test_name) : + shader_info->GetAttribInfo(test_name); + // Note: There is an assuption here that if an attrib is defined in more + // than 1 attached shader their types and sizes match. Should we check + // for that case? + if (variable_info) { + *corrected_name = test_name; + *type = variable_info->type; + *size = variable_info->size; + return; + } + } + } + } + *corrected_name = name; +} + const ProgramManager::ProgramInfo::UniformInfo* ProgramManager::ProgramInfo::AddUniformInfo( GLsizei size, GLenum type, GLint location, const std::string& name) { diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 7fb6fa4..53893b3 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -156,6 +156,10 @@ class ProgramManager { const UniformInfo* AddUniformInfo( GLsizei size, GLenum type, GLint location, const std::string& name); + void GetCorrectedVariableInfo( + bool use_uniforms, const std::string& name, std::string* corrected_name, + GLsizei* size, GLenum* type) const; + GLsizei max_attrib_name_length_; // Attrib by index. diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 1f66fd6..7f4fa21 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -10,6 +10,7 @@ #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; @@ -19,6 +20,7 @@ using ::testing::InSequence; using ::testing::MatcherCast; using ::testing::Pointee; using ::testing::Return; +using ::testing::ReturnRef; using ::testing::SetArrayArgument; using ::testing::SetArgumentPointee; using ::testing::StrEq; @@ -124,7 +126,8 @@ class ProgramManagerWithShaderTest : public testing::Test { static const char* kUniform1Name; static const char* kUniform2Name; - static const char* kUniform3Name; + static const char* kUniform3BadName; + static const char* kUniform3GoodName; static const GLint kUniform1Size = 1; static const GLint kUniform2Size = 3; static const GLint kUniform3Size = 2; @@ -322,7 +325,7 @@ ProgramManagerWithShaderTest::UniformInfo ProgramManagerWithShaderTest::kUniforms[] = { { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, }, { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, }, - { kUniform3Name, kUniform3Size, kUniform3Type, kUniform3Location, }, + { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, }, }; const size_t ProgramManagerWithShaderTest::kNumUniforms = @@ -335,7 +338,8 @@ const char* ProgramManagerWithShaderTest::kUniform1Name = "uniform1"; // Correctly has array spec. const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2[0]"; // Incorrectly missing array spec. -const char* ProgramManagerWithShaderTest::kUniform3Name = "uniform3"; +const char* ProgramManagerWithShaderTest::kUniform3BadName = "uniform3"; +const char* ProgramManagerWithShaderTest::kUniform3GoodName = "uniform3[0]"; TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) { const ProgramManager::ProgramInfo* program_info = @@ -399,12 +403,11 @@ TEST_F(ProgramManagerWithShaderTest, GetUniformInfo) { 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. - const std::string expected_name(std::string(kUniform3Name) + "[0]"); ASSERT_TRUE(info != NULL); EXPECT_EQ(kUniform3Size, info->size); EXPECT_EQ(kUniform3Type, info->type); EXPECT_EQ(kUniform3Location, info->element_locations[0]); - EXPECT_STREQ(expected_name.c_str(), info->name.c_str()); + EXPECT_STREQ(kUniform3GoodName, info->name.c_str()); EXPECT_TRUE(program_info->GetUniformInfo(kInvalidIndex) == NULL); } @@ -422,12 +425,12 @@ TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) { kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER); ShaderManager::ShaderInfo* vshader = shader_manager.GetShaderInfo( kVShaderClientId); - vshader->SetStatus(true, ""); + vshader->SetStatus(true, "", NULL); shader_manager.CreateShaderInfo( kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER); ShaderManager::ShaderInfo* fshader = shader_manager.GetShaderInfo( kFShaderClientId); - fshader->SetStatus(true, ""); + fshader->SetStatus(true, "", NULL); EXPECT_TRUE(program_info->AttachShader(vshader)); EXPECT_FALSE(program_info->CanLink()); EXPECT_TRUE(program_info->AttachShader(fshader)); @@ -442,13 +445,13 @@ TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) { EXPECT_FALSE(program_info->CanLink()); EXPECT_TRUE(program_info->AttachShader(fshader)); EXPECT_TRUE(program_info->CanLink()); - vshader->SetStatus(false, ""); + vshader->SetStatus(false, "", NULL); EXPECT_FALSE(program_info->CanLink()); - vshader->SetStatus(true, ""); + vshader->SetStatus(true, "", NULL); EXPECT_TRUE(program_info->CanLink()); - fshader->SetStatus(false, ""); + fshader->SetStatus(false, "", NULL); EXPECT_FALSE(program_info->CanLink()); - fshader->SetStatus(true, ""); + fshader->SetStatus(true, "", NULL); EXPECT_TRUE(program_info->CanLink()); shader_manager.Destroy(false); } @@ -459,13 +462,15 @@ TEST_F(ProgramManagerWithShaderTest, GetUniformLocation) { 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(kUniform3Name)); + 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("uniform3[0]")); + 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]")); @@ -501,7 +506,7 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) { static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = { { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, }, { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, }, - { kUniform3Name, kUniform3Size, kUniform3Type, kUniform3Location, }, + { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, }, }; const size_t kNumUniforms = arraysize(kUniforms); static const GLuint kClientProgramId = 1234; @@ -523,7 +528,91 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) { // 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(kUniform3Name) + 4u, static_cast<size_t>(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_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); } } // namespace gles2 diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc index 2f82ea4..794c75e 100644 --- a/gpu/command_buffer/service/shader_manager.cc +++ b/gpu/command_buffer/service/shader_manager.cc @@ -8,6 +8,33 @@ namespace gpu { namespace gles2 { +void ShaderManager::ShaderInfo::SetStatus( + bool valid, const std::string& log, ShaderTranslatorInterface* translator) { + valid_ = valid; + log_info_ = log; + if (translator && valid) { + attrib_map_ = translator->attrib_map(); + uniform_map_ = translator->uniform_map(); + } else { + attrib_map_.clear(); + uniform_map_.clear(); + } +} + +const ShaderManager::ShaderInfo::VariableInfo* + ShaderManager::ShaderInfo::GetAttribInfo( + const std::string& name) const { + VariableMap::const_iterator it = attrib_map_.find(name); + return it != attrib_map_.end() ? &it->second : NULL; +} + +const ShaderManager::ShaderInfo::VariableInfo* + ShaderManager::ShaderInfo::GetUniformInfo( + const std::string& name) const { + VariableMap::const_iterator it = uniform_map_.find(name); + return it != uniform_map_.end() ? &it->second : NULL; +} + ShaderManager::ShaderManager() {} ShaderManager::~ShaderManager() { diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h index e056a3e..0b173c3 100644 --- a/gpu/command_buffer/service/shader_manager.h +++ b/gpu/command_buffer/service/shader_manager.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/ref_counted.h" #include "gpu/command_buffer/service/gl_utils.h" +#include "gpu/command_buffer/service/shader_translator.h" namespace gpu { namespace gles2 { @@ -27,6 +28,7 @@ class ShaderManager { class ShaderInfo : public base::RefCounted<ShaderInfo> { public: typedef scoped_refptr<ShaderInfo> Ref; + typedef ShaderTranslator::VariableInfo VariableInfo; explicit ShaderInfo(GLuint service_id, GLenum shader_type) : service_id_(service_id), @@ -50,10 +52,12 @@ class ShaderManager { return source_; } - void SetStatus(bool valid, const std::string& log) { - valid_ = valid; - log_info_ = log; - } + void SetStatus( + bool valid, const std::string& log, + ShaderTranslatorInterface* translator); + + const VariableInfo* GetAttribInfo(const std::string& name) const; + const VariableInfo* GetUniformInfo(const std::string& name) const; const std::string& log_info() const { return log_info_; @@ -68,6 +72,8 @@ class ShaderManager { } private: + typedef ShaderTranslator::VariableMap VariableMap; + friend class base::RefCounted<ShaderInfo>; friend class ShaderManager; ~ShaderInfo() { } @@ -89,6 +95,10 @@ class ShaderManager { // The shader translation log. std::string log_info_; + + // The type info when the shader was last compiled. + VariableMap attrib_map_; + VariableMap uniform_map_; }; ShaderManager(); diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc index 8deace2..c069257 100644 --- a/gpu/command_buffer/service/shader_manager_unittest.cc +++ b/gpu/command_buffer/service/shader_manager_unittest.cc @@ -6,8 +6,12 @@ #include "base/scoped_ptr.h" #include "gpu/command_buffer/common/gl_mock.h" +#include "gpu/command_buffer/service/mocks.h" #include "testing/gtest/include/gtest/gtest.h" +using ::testing::Return; +using ::testing::ReturnRef; + namespace gpu { namespace gles2 { @@ -53,7 +57,7 @@ TEST_F(ShaderManagerTest, Basic) { EXPECT_FALSE(info1->IsValid()); EXPECT_STREQ("", info1->log_info().c_str()); const char* kLog = "foo"; - info1->SetStatus(true, kLog); + info1->SetStatus(true, kLog, NULL); EXPECT_TRUE(info1->IsValid()); EXPECT_STREQ(kLog, info1->log_info().c_str()); // Check we can set its source. @@ -86,6 +90,76 @@ TEST_F(ShaderManagerTest, Destroy) { ASSERT_TRUE(info1 == NULL); } +TEST_F(ShaderManagerTest, GetInfo) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + const GLenum kShader1Type = GL_VERTEX_SHADER; + const GLenum kAttrib1Type = GL_FLOAT_VEC2; + const GLsizei kAttrib1Size = 2; + const char* kAttrib1Name = "attr1"; + const GLenum kAttrib2Type = GL_FLOAT_VEC3; + const GLsizei kAttrib2Size = 4; + const char* kAttrib2Name = "attr2"; + const GLenum kUniform1Type = GL_FLOAT_MAT2; + const GLsizei kUniform1Size = 3; + const char* kUniform1Name = "uni1"; + const GLenum kUniform2Type = GL_FLOAT_MAT3; + const GLsizei kUniform2Size = 5; + const char* kUniform2Name = "uni2"; + MockShaderTranslator shader_translator; + ShaderTranslator::VariableMap attrib_map; + attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo( + kAttrib1Type, kAttrib1Size); + attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo( + kAttrib2Type, kAttrib2Size); + ShaderTranslator::VariableMap uniform_map; + uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo( + kUniform1Type, kUniform1Size); + uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo( + kUniform2Type, kUniform2Size); + 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. + manager_.CreateShaderInfo(kClient1Id, kService1Id, kShader1Type); + // Check shader got created. + ShaderManager::ShaderInfo* info1 = manager_.GetShaderInfo(kClient1Id); + // Set Status + info1->SetStatus(true, "", &shader_translator); + // Check attrib and uniform infos got copied. + for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin(); + it != attrib_map.end(); ++it) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + info1->GetAttribInfo(it->first); + ASSERT_TRUE(variable_info != NULL); + EXPECT_EQ(it->second.type, variable_info->type); + EXPECT_EQ(it->second.size, variable_info->size); + } + for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin(); + it != uniform_map.end(); ++it) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + info1->GetUniformInfo(it->first); + ASSERT_TRUE(variable_info != NULL); + EXPECT_EQ(it->second.type, variable_info->type); + EXPECT_EQ(it->second.size, variable_info->size); + } + // Check attrib and uniform get cleared. + info1->SetStatus(true, "", NULL); + for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin(); + it != attrib_map.end(); ++it) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + info1->GetAttribInfo(it->first); + EXPECT_TRUE(variable_info == NULL); + } + for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin(); + it != uniform_map.end(); ++it) { + const ShaderManager::ShaderInfo::VariableInfo* variable_info = + info1->GetUniformInfo(it->first); + ASSERT_TRUE(variable_info == NULL); + } +} + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc index 1b5ab6d..551ae14 100644 --- a/gpu/command_buffer/service/shader_translator.cc +++ b/gpu/command_buffer/service/shader_translator.cc @@ -53,9 +53,7 @@ void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type, default: NOTREACHED(); } - ShaderTranslator::VariableInfo info = {0}; - info.type = type; - info.size = size; + ShaderTranslator::VariableInfo info(type, size); (*var_map)[name.get()] = info; } } diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h index 5054972..852ee5f 100644 --- a/gpu/command_buffer/service/shader_translator.h +++ b/gpu/command_buffer/service/shader_translator.h @@ -16,35 +16,69 @@ namespace gpu { namespace gles2 { // Translates GLSL ES 2.0 shader to desktop GLSL shader. -class ShaderTranslator { +class ShaderTranslatorInterface { public: - ShaderTranslator(); - ~ShaderTranslator(); + virtual ~ShaderTranslatorInterface() { } // Initializes the translator. // Must be called once before using the translator object. - bool Init(ShShaderType shader_type, - ShShaderSpec shader_spec, - const ShBuiltInResources* resources); + virtual bool Init( + ShShaderType shader_type, + ShShaderSpec shader_spec, + const ShBuiltInResources* resources) = 0; + // Translates the given shader source. // Returns true if translation is successful, false otherwise. - bool Translate(const char* shader); + virtual bool Translate(const char* shader) = 0; // The following functions return results from the last translation. // The results are NULL/empty if the translation was unsuccessful. // A valid info-log is always returned irrespective of whether translation // was successful or not. - const char* translated_shader() { return translated_shader_.get(); } - const char* info_log() { return info_log_.get(); } + virtual const char* translated_shader() const = 0; + virtual const char* info_log() const = 0; struct VariableInfo { + VariableInfo() + : type(0), + size(0) { + } + VariableInfo(int _type, int _size) + : type(_type), + size(_size) { + } int type; int size; }; // Mapping between variable name and info. typedef std::map<std::string, VariableInfo> VariableMap; - const VariableMap& attrib_map() { return attrib_map_; } - const VariableMap& uniform_map() { return uniform_map_; } + virtual const VariableMap& attrib_map() const = 0; + virtual const VariableMap& uniform_map() const = 0; +}; + +// Implementation of ShaderTranslatorInterface +class ShaderTranslator : public ShaderTranslatorInterface { + public: + ShaderTranslator(); + ~ShaderTranslator(); + + // Overridden from ShaderTranslatorInterface. + virtual bool Init( + ShShaderType shader_type, + ShShaderSpec shader_spec, + const ShBuiltInResources* resources); + + // Overridden from ShaderTranslatorInterface. + virtual bool Translate(const char* shader); + + // Overridden from ShaderTranslatorInterface. + virtual const char* translated_shader() const { + return translated_shader_.get(); } + virtual const char* info_log() const { return info_log_.get(); } + + // Overridden from ShaderTranslatorInterface. + virtual const VariableMap& attrib_map() const { return attrib_map_; } + virtual const VariableMap& uniform_map() const { return uniform_map_; } private: void ClearResults(); |