xref: /aosp_15_r20/external/angle/src/tests/compiler_tests/ShCompile_test.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ShCompile_test.cpp
7 //   Test the sh::Compile interface with different parameters.
8 //
9 
10 #include <clocale>
11 #include "GLSLANG/ShaderLang.h"
12 #include "angle_gl.h"
13 #include "common/angleutils.h"
14 #include "common/platform.h"
15 #include "gtest/gtest.h"
16 
17 class ShCompileTest : public testing::Test
18 {
19   public:
ShCompileTest()20     ShCompileTest() {}
21 
22   protected:
SetUp()23     void SetUp() override
24     {
25         sh::InitBuiltInResources(&mResources);
26         mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
27                                           SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
28         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
29     }
30 
TearDown()31     void TearDown() override
32     {
33         if (mCompiler)
34         {
35             sh::Destruct(mCompiler);
36             mCompiler = nullptr;
37         }
38     }
39 
testCompile(const char ** shaderStrings,int stringCount,bool expectation)40     void testCompile(const char **shaderStrings, int stringCount, bool expectation)
41     {
42         ShCompileOptions options    = {};
43         options.objectCode          = true;
44         options.initOutputVariables = true;
45 
46         bool success                  = sh::Compile(mCompiler, shaderStrings, stringCount, options);
47         const std::string &compileLog = sh::GetInfoLog(mCompiler);
48         EXPECT_EQ(expectation, success) << compileLog;
49     }
50 
51     ShBuiltInResources mResources;
52 
53     class [[nodiscard]] ScopedRestoreDefaultLocale : angle::NonCopyable
54     {
55       public:
56         ScopedRestoreDefaultLocale();
57         ~ScopedRestoreDefaultLocale();
58 
59       private:
60         std::locale defaultLocale;
61     };
62 
63   public:
64     ShHandle mCompiler;
65 };
66 
ScopedRestoreDefaultLocale()67 ShCompileTest::ScopedRestoreDefaultLocale::ScopedRestoreDefaultLocale()
68 {
69     defaultLocale = std::locale();
70 }
71 
~ScopedRestoreDefaultLocale()72 ShCompileTest::ScopedRestoreDefaultLocale::~ScopedRestoreDefaultLocale()
73 {
74     std::locale::global(defaultLocale);
75 }
76 
77 class ShCompileComputeTest : public ShCompileTest
78 {
79   public:
ShCompileComputeTest()80     ShCompileComputeTest() {}
81 
82   protected:
SetUp()83     void SetUp() override
84     {
85         sh::InitBuiltInResources(&mResources);
86         mCompiler = sh::ConstructCompiler(GL_COMPUTE_SHADER, SH_WEBGL3_SPEC,
87                                           SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
88         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
89     }
90 };
91 
92 // Test calling sh::Compile with compute shader source string.
TEST_F(ShCompileComputeTest,ComputeShaderString)93 TEST_F(ShCompileComputeTest, ComputeShaderString)
94 {
95     constexpr char kComputeShaderString[] =
96         R"(#version 310 es
97         layout(local_size_x=1) in;
98         void main()
99         {
100         })";
101 
102     const char *shaderStrings[] = {kComputeShaderString};
103 
104     testCompile(shaderStrings, 1, true);
105 }
106 
107 // Test calling sh::Compile with more than one shader source string.
TEST_F(ShCompileTest,MultipleShaderStrings)108 TEST_F(ShCompileTest, MultipleShaderStrings)
109 {
110     const std::string &shaderString1 =
111         "precision mediump float;\n"
112         "void main() {\n";
113     const std::string &shaderString2 =
114         "    gl_FragColor = vec4(0.0);\n"
115         "}";
116 
117     const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str()};
118 
119     testCompile(shaderStrings, 2, true);
120 }
121 
122 // Test calling sh::Compile with a tokens split into different shader source strings.
TEST_F(ShCompileTest,TokensSplitInShaderStrings)123 TEST_F(ShCompileTest, TokensSplitInShaderStrings)
124 {
125     const std::string &shaderString1 =
126         "precision mediump float;\n"
127         "void ma";
128     const std::string &shaderString2 =
129         "in() {\n"
130         "#i";
131     const std::string &shaderString3 =
132         "f 1\n"
133         "    gl_FragColor = vec4(0.0);\n"
134         "#endif\n"
135         "}";
136 
137     const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str(),
138                                    shaderString3.c_str()};
139 
140     testCompile(shaderStrings, 3, true);
141 }
142 
143 // Parsing floats in shaders can run afoul of locale settings.
144 // Eg. in de_DE, `strtof("1.5")` will yield `1.0f`. (It's expecting "1.5")
TEST_F(ShCompileTest,DecimalSepLocale)145 TEST_F(ShCompileTest, DecimalSepLocale)
146 {
147     // Locale names are platform dependent, add platform-specific names of locales to be tested here
148     const std::string availableLocales[] = {
149         "de_DE",
150         "de-DE",
151         "de_DE.UTF-8",
152         "de_DE.ISO8859-1",
153         "de_DE.ISO8859-15",
154         "de_DE@euro",
155         "de_DE.88591",
156         "de_DE.88591.en",
157         "de_DE.iso88591",
158         "de_DE.ISO-8859-1",
159         "de_DE.ISO_8859-1",
160         "de_DE.iso885915",
161         "de_DE.ISO-8859-15",
162         "de_DE.ISO_8859-15",
163         "de_DE.8859-15",
164         "de_DE.8859-15@euro",
165 #if !defined(_WIN32)
166         // TODO(https://crbug.com/972372): Add this test back on Windows once the
167         // CRT no longer throws on code page sections ('ISO-8859-15@euro') that
168         // are >= 16 characters long.
169         "de_DE.ISO-8859-15@euro",
170 #endif
171         "de_DE.UTF-8@euro",
172         "de_DE.utf8",
173         "German_germany",
174         "German_Germany",
175         "German_Germany.1252",
176         "German_Germany.UTF-8",
177         "German",
178         // One ubuntu tester doesn't have a german locale, but da_DK.utf8 has similar float
179         // representation
180         "da_DK.utf8"
181     };
182 
183     const auto localeExists = [](const std::string name) {
184         return bool(setlocale(LC_ALL, name.c_str()));
185     };
186 
187     const char kSource[] = R"(
188     void main()
189     {
190         gl_FragColor = vec4(1.5);
191     })";
192     const char *parts[]  = {kSource};
193 
194     // Ensure the locale is reset after the test runs.
195     ScopedRestoreDefaultLocale restoreLocale;
196 
197     for (const std::string &locale : availableLocales)
198     {
199         // If the locale doesn't exist on the testing platform, the locale constructor will fail,
200         // throwing an exception
201         // We use setlocale() (through localeExists) to test whether a locale
202         // exists before calling the locale constructor
203         if (localeExists(locale))
204         {
205             std::locale localizedLoc(locale);
206 
207             ShCompileOptions compileOptions = {};
208             compileOptions.objectCode       = true;
209 
210             // std::locale::global() must be used instead of setlocale() to affect new streams'
211             // default locale
212             std::locale::global(std::locale::classic());
213             sh::Compile(mCompiler, parts, 1, compileOptions);
214             std::string referenceOut = sh::GetObjectCode(mCompiler);
215             EXPECT_NE(referenceOut.find("1.5"), std::string::npos)
216                 << "float formatted incorrectly with classic locale";
217 
218             sh::ClearResults(mCompiler);
219 
220             std::locale::global(localizedLoc);
221             sh::Compile(mCompiler, parts, 1, compileOptions);
222             std::string localizedOut = sh::GetObjectCode(mCompiler);
223             EXPECT_NE(localizedOut.find("1.5"), std::string::npos)
224                 << "float formatted incorrectly with locale (" << localizedLoc.name() << ") set";
225 
226             ASSERT_EQ(referenceOut, localizedOut)
227                 << "different output with locale (" << localizedLoc.name() << ") set";
228         }
229     }
230 }
231