| // Copyright (c) 2012 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 <GLES2/gl2.h> |
| |
| #include "gpu/command_buffer/service/shader_translator.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| class ShaderTranslatorTest : public testing::Test { |
| public: |
| ShaderTranslatorTest() { |
| } |
| |
| ~ShaderTranslatorTest() override {} |
| |
| protected: |
| void SetUp() override { |
| ShBuiltInResources resources; |
| ShInitBuiltInResources(&resources); |
| resources.MaxExpressionComplexity = 32; |
| resources.MaxCallStackDepth = 32; |
| |
| vertex_translator_ = new ShaderTranslator(); |
| fragment_translator_ = new ShaderTranslator(); |
| |
| ASSERT_TRUE(vertex_translator_->Init( |
| GL_VERTEX_SHADER, SH_GLES2_SPEC, &resources, |
| ShaderTranslatorInterface::kGlsl, |
| SH_EMULATE_BUILT_IN_FUNCTIONS)); |
| ASSERT_TRUE(fragment_translator_->Init( |
| GL_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources, |
| ShaderTranslatorInterface::kGlsl, |
| static_cast<ShCompileOptions>(0))); |
| } |
| void TearDown() override { |
| vertex_translator_ = NULL; |
| fragment_translator_ = NULL; |
| } |
| |
| scoped_refptr<ShaderTranslator> vertex_translator_; |
| scoped_refptr<ShaderTranslator> fragment_translator_; |
| }; |
| |
| TEST_F(ShaderTranslatorTest, ValidVertexShader) { |
| const char* shader = |
| "void main() {\n" |
| " gl_Position = vec4(1.0);\n" |
| "}"; |
| |
| // A valid shader should be successfully translated. |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_TRUE(vertex_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be NULL. |
| EXPECT_TRUE(info_log.empty()); |
| // Translated shader must be valid and non-empty. |
| ASSERT_FALSE(translated_source.empty()); |
| // There should be no attributes, uniforms, and only one built-in |
| // varying: gl_Position. |
| EXPECT_TRUE(attrib_map.empty()); |
| EXPECT_TRUE(uniform_map.empty()); |
| EXPECT_EQ(1u, varying_map.size()); |
| // There should be no name mapping. |
| EXPECT_TRUE(name_map.empty()); |
| } |
| |
| TEST_F(ShaderTranslatorTest, InvalidVertexShader) { |
| const char* bad_shader = "foo-bar"; |
| const char* good_shader = |
| "void main() {\n" |
| " gl_Position = vec4(1.0);\n" |
| "}"; |
| |
| // An invalid shader should fail. |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_FALSE(vertex_translator_->Translate(bad_shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be valid and non-empty. |
| ASSERT_FALSE(info_log.empty()); |
| // Translated shader must be NULL. |
| EXPECT_TRUE(translated_source.empty()); |
| // There should be no attributes, uniforms, varyings, or name mapping. |
| EXPECT_TRUE(attrib_map.empty()); |
| EXPECT_TRUE(uniform_map.empty()); |
| EXPECT_TRUE(varying_map.empty()); |
| EXPECT_TRUE(name_map.empty()); |
| |
| // Try a good shader after bad. |
| info_log.clear(); |
| EXPECT_TRUE(vertex_translator_->Translate(good_shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| EXPECT_TRUE(info_log.empty()); |
| EXPECT_FALSE(translated_source.empty()); |
| } |
| |
| TEST_F(ShaderTranslatorTest, ValidFragmentShader) { |
| const char* shader = |
| "void main() {\n" |
| " gl_FragColor = vec4(1.0);\n" |
| "}"; |
| |
| // A valid shader should be successfully translated. |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_TRUE(fragment_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be NULL. |
| EXPECT_TRUE(info_log.empty()); |
| // Translated shader must be valid and non-empty. |
| ASSERT_FALSE(translated_source.empty()); |
| // There should be no attributes, uniforms, varyings, or name mapping. |
| EXPECT_TRUE(attrib_map.empty()); |
| EXPECT_TRUE(uniform_map.empty()); |
| EXPECT_TRUE(varying_map.empty()); |
| EXPECT_TRUE(name_map.empty()); |
| } |
| |
| TEST_F(ShaderTranslatorTest, InvalidFragmentShader) { |
| const char* shader = "foo-bar"; |
| |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| // An invalid shader should fail. |
| EXPECT_FALSE(fragment_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be valid and non-empty. |
| EXPECT_FALSE(info_log.empty()); |
| // Translated shader must be NULL. |
| EXPECT_TRUE(translated_source.empty()); |
| // There should be no attributes or uniforms. |
| EXPECT_TRUE(attrib_map.empty()); |
| EXPECT_TRUE(uniform_map.empty()); |
| EXPECT_TRUE(varying_map.empty()); |
| EXPECT_TRUE(name_map.empty()); |
| } |
| |
| TEST_F(ShaderTranslatorTest, GetAttributes) { |
| const char* shader = |
| "attribute vec4 vPosition;\n" |
| "void main() {\n" |
| " gl_Position = vPosition;\n" |
| "}"; |
| |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_TRUE(vertex_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be NULL. |
| EXPECT_TRUE(info_log.empty()); |
| // Translated shader must be valid and non-empty. |
| EXPECT_FALSE(translated_source.empty()); |
| // There should be no uniforms. |
| EXPECT_TRUE(uniform_map.empty()); |
| // There should be one attribute with following characteristics: |
| // name:vPosition type:GL_FLOAT_VEC4 size:0. |
| EXPECT_EQ(1u, attrib_map.size()); |
| AttributeMap::const_iterator iter = attrib_map.find("vPosition"); |
| EXPECT_TRUE(iter != attrib_map.end()); |
| EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), iter->second.type); |
| EXPECT_EQ(0u, iter->second.arraySize); |
| EXPECT_EQ("vPosition", iter->second.name); |
| } |
| |
| TEST_F(ShaderTranslatorTest, GetUniforms) { |
| const char* shader = |
| "precision mediump float;\n" |
| "struct Foo {\n" |
| " vec4 color[1];\n" |
| "};\n" |
| "struct Bar {\n" |
| " Foo foo;\n" |
| "};\n" |
| "uniform Bar bar[2];\n" |
| "void main() {\n" |
| " gl_FragColor = bar[0].foo.color[0] + bar[1].foo.color[0];\n" |
| "}"; |
| |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_TRUE(fragment_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be NULL. |
| EXPECT_TRUE(info_log.empty()); |
| // Translated shader must be valid and non-empty. |
| EXPECT_FALSE(translated_source.empty()); |
| // There should be no attributes. |
| EXPECT_TRUE(attrib_map.empty()); |
| // There should be two uniforms with following characteristics: |
| // 1. name:bar[0].foo.color[0] type:GL_FLOAT_VEC4 size:1 |
| // 2. name:bar[1].foo.color[0] type:GL_FLOAT_VEC4 size:1 |
| // However, there will be only one entry "bar" in the map. |
| EXPECT_EQ(1u, uniform_map.size()); |
| UniformMap::const_iterator iter = uniform_map.find("bar"); |
| EXPECT_TRUE(iter != uniform_map.end()); |
| // First uniform. |
| const sh::ShaderVariable* info; |
| std::string original_name; |
| EXPECT_TRUE(iter->second.findInfoByMappedName( |
| "bar[0].foo.color[0]", &info, &original_name)); |
| EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), info->type); |
| EXPECT_EQ(1u, info->arraySize); |
| EXPECT_STREQ("color", info->name.c_str()); |
| EXPECT_STREQ("bar[0].foo.color[0]", original_name.c_str()); |
| // Second uniform. |
| EXPECT_TRUE(iter->second.findInfoByMappedName( |
| "bar[1].foo.color[0]", &info, &original_name)); |
| EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), info->type); |
| EXPECT_EQ(1u, info->arraySize); |
| EXPECT_STREQ("color", info->name.c_str()); |
| EXPECT_STREQ("bar[1].foo.color[0]", original_name.c_str()); |
| } |
| |
| #if defined(OS_MACOSX) |
| TEST_F(ShaderTranslatorTest, BuiltInFunctionEmulation) { |
| // This test might become invalid in the future when ANGLE Translator is no |
| // longer emulate dot(float, float) in Mac, or the emulated function name is |
| // no longer webgl_dot_emu. |
| const char* shader = |
| "void main() {\n" |
| " gl_Position = vec4(dot(1.0, 1.0), 1.0, 1.0, 1.0);\n" |
| "}"; |
| |
| std::string info_log, translated_source; |
| AttributeMap attrib_map; |
| UniformMap uniform_map; |
| VaryingMap varying_map; |
| NameMap name_map; |
| EXPECT_TRUE(vertex_translator_->Translate(shader, |
| &info_log, |
| &translated_source, |
| &attrib_map, |
| &uniform_map, |
| &varying_map, |
| &name_map)); |
| // Info log must be NULL. |
| EXPECT_TRUE(info_log.empty()); |
| // Translated shader must be valid and non-empty. |
| ASSERT_FALSE(translated_source.empty()); |
| EXPECT_TRUE(strstr(translated_source.c_str(), |
| "webgl_dot_emu") != NULL); |
| } |
| #endif |
| |
| TEST_F(ShaderTranslatorTest, OptionsString) { |
| scoped_refptr<ShaderTranslator> translator_1 = new ShaderTranslator(); |
| scoped_refptr<ShaderTranslator> translator_2 = new ShaderTranslator(); |
| scoped_refptr<ShaderTranslator> translator_3 = new ShaderTranslator(); |
| |
| ShBuiltInResources resources; |
| ShInitBuiltInResources(&resources); |
| |
| ASSERT_TRUE(translator_1->Init( |
| GL_VERTEX_SHADER, SH_GLES2_SPEC, &resources, |
| ShaderTranslatorInterface::kGlsl, |
| SH_EMULATE_BUILT_IN_FUNCTIONS)); |
| ASSERT_TRUE(translator_2->Init( |
| GL_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources, |
| ShaderTranslatorInterface::kGlsl, |
| static_cast<ShCompileOptions>(0))); |
| resources.EXT_draw_buffers = 1; |
| ASSERT_TRUE(translator_3->Init( |
| GL_VERTEX_SHADER, SH_GLES2_SPEC, &resources, |
| ShaderTranslatorInterface::kGlsl, |
| SH_EMULATE_BUILT_IN_FUNCTIONS)); |
| |
| std::string options_1( |
| translator_1->GetStringForOptionsThatWouldAffectCompilation()); |
| std::string options_2( |
| translator_1->GetStringForOptionsThatWouldAffectCompilation()); |
| std::string options_3( |
| translator_2->GetStringForOptionsThatWouldAffectCompilation()); |
| std::string options_4( |
| translator_3->GetStringForOptionsThatWouldAffectCompilation()); |
| |
| EXPECT_EQ(options_1, options_2); |
| EXPECT_NE(options_1, options_3); |
| EXPECT_NE(options_1, options_4); |
| EXPECT_NE(options_3, options_4); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |