• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      = SH_OBJECT_CODE | SH_VARIABLES | SH_INIT_OUTPUT_VARIABLES;
43         bool success                  = sh::Compile(mCompiler, shaderStrings, stringCount, options);
44         const std::string &compileLog = sh::GetInfoLog(mCompiler);
45         EXPECT_EQ(expectation, success) << compileLog;
46     }
47 
48     ShBuiltInResources mResources;
49 
50     class ANGLE_NO_DISCARD ScopedRestoreDefaultLocale : angle::NonCopyable
51     {
52       public:
53         ScopedRestoreDefaultLocale();
54         ~ScopedRestoreDefaultLocale();
55 
56       private:
57         std::locale defaultLocale;
58     };
59 
60   public:
61     ShHandle mCompiler;
62 };
63 
ScopedRestoreDefaultLocale()64 ShCompileTest::ScopedRestoreDefaultLocale::ScopedRestoreDefaultLocale()
65 {
66     defaultLocale = std::locale();
67 }
68 
~ScopedRestoreDefaultLocale()69 ShCompileTest::ScopedRestoreDefaultLocale::~ScopedRestoreDefaultLocale()
70 {
71     std::locale::global(defaultLocale);
72 }
73 
74 class ShCompileComputeTest : public ShCompileTest
75 {
76   public:
ShCompileComputeTest()77     ShCompileComputeTest() {}
78 
79   protected:
SetUp()80     void SetUp() override
81     {
82         sh::InitBuiltInResources(&mResources);
83         mCompiler = sh::ConstructCompiler(GL_COMPUTE_SHADER, SH_WEBGL3_SPEC,
84                                           SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
85         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
86     }
87 };
88 
89 // Test calling sh::Compile with compute shader source string.
TEST_F(ShCompileComputeTest,ComputeShaderString)90 TEST_F(ShCompileComputeTest, ComputeShaderString)
91 {
92     constexpr char kComputeShaderString[] =
93         R"(#version 310 es
94         layout(local_size_x=1) in;
95         void main()
96         {
97         })";
98 
99     const char *shaderStrings[] = {kComputeShaderString};
100 
101     testCompile(shaderStrings, 1, true);
102 }
103 
104 // Test calling sh::Compile with more than one shader source string.
TEST_F(ShCompileTest,MultipleShaderStrings)105 TEST_F(ShCompileTest, MultipleShaderStrings)
106 {
107     const std::string &shaderString1 =
108         "precision mediump float;\n"
109         "void main() {\n";
110     const std::string &shaderString2 =
111         "    gl_FragColor = vec4(0.0);\n"
112         "}";
113 
114     const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str()};
115 
116     testCompile(shaderStrings, 2, true);
117 }
118 
119 // Test calling sh::Compile with a tokens split into different shader source strings.
TEST_F(ShCompileTest,TokensSplitInShaderStrings)120 TEST_F(ShCompileTest, TokensSplitInShaderStrings)
121 {
122     const std::string &shaderString1 =
123         "precision mediump float;\n"
124         "void ma";
125     const std::string &shaderString2 =
126         "in() {\n"
127         "#i";
128     const std::string &shaderString3 =
129         "f 1\n"
130         "    gl_FragColor = vec4(0.0);\n"
131         "#endif\n"
132         "}";
133 
134     const char *shaderStrings[] = {shaderString1.c_str(), shaderString2.c_str(),
135                                    shaderString3.c_str()};
136 
137     testCompile(shaderStrings, 3, true);
138 }
139 
140 // Parsing floats in shaders can run afoul of locale settings.
141 // Eg. in de_DE, `strtof("1.9")` will yield `1.0f`. (It's expecting "1,9")
TEST_F(ShCompileTest,DecimalSepLocale)142 TEST_F(ShCompileTest, DecimalSepLocale)
143 {
144     // Locale names are platform dependent, add platform-specific names of locales to be tested here
145     const std::string availableLocales[] = {
146         "de_DE",
147         "de-DE",
148         "de_DE.UTF-8",
149         "de_DE.ISO8859-1",
150         "de_DE.ISO8859-15",
151         "de_DE@euro",
152         "de_DE.88591",
153         "de_DE.88591.en",
154         "de_DE.iso88591",
155         "de_DE.ISO-8859-1",
156         "de_DE.ISO_8859-1",
157         "de_DE.iso885915",
158         "de_DE.ISO-8859-15",
159         "de_DE.ISO_8859-15",
160         "de_DE.8859-15",
161         "de_DE.8859-15@euro",
162 #if !defined(_WIN32)
163         // TODO(https://crbug.com/972372): Add this test back on Windows once the
164         // CRT no longer throws on code page sections ('ISO-8859-15@euro') that
165         // are >= 16 characters long.
166         "de_DE.ISO-8859-15@euro",
167 #endif
168         "de_DE.UTF-8@euro",
169         "de_DE.utf8",
170         "German_germany",
171         "German_Germany",
172         "German_Germany.1252",
173         "German_Germany.UTF-8",
174         "German",
175         // One ubuntu tester doesn't have a german locale, but da_DK.utf8 has similar float
176         // representation
177         "da_DK.utf8"
178     };
179 
180     const auto localeExists = [](const std::string name) {
181         return bool(setlocale(LC_ALL, name.c_str()));
182     };
183 
184     const char kSource[] = R"(
185     void main()
186     {
187         gl_FragColor = vec4(1.9);
188     })";
189     const char *parts[]  = {kSource};
190 
191     // Ensure the locale is reset after the test runs.
192     ScopedRestoreDefaultLocale restoreLocale;
193 
194     for (const std::string &locale : availableLocales)
195     {
196         // If the locale doesn't exist on the testing platform, the locale constructor will fail,
197         // throwing an exception
198         // We use setlocale() (through localeExists) to test whether a locale
199         // exists before calling the locale constructor
200         if (localeExists(locale))
201         {
202             std::locale localizedLoc(locale);
203 
204             // std::locale::global() must be used instead of setlocale() to affect new streams'
205             // default locale
206             std::locale::global(std::locale::classic());
207             sh::Compile(mCompiler, parts, 1, SH_OBJECT_CODE);
208             std::string referenceOut = sh::GetObjectCode(mCompiler);
209             EXPECT_NE(referenceOut.find("1.9"), std::string::npos)
210                 << "float formatted incorrectly with classic locale";
211 
212             sh::ClearResults(mCompiler);
213 
214             std::locale::global(localizedLoc);
215             sh::Compile(mCompiler, parts, 1, SH_OBJECT_CODE);
216             std::string localizedOut = sh::GetObjectCode(mCompiler);
217             EXPECT_NE(localizedOut.find("1.9"), std::string::npos)
218                 << "float formatted incorrectly with locale (" << localizedLoc.name() << ") set";
219 
220             ASSERT_EQ(referenceOut, localizedOut)
221                 << "different output with locale (" << localizedLoc.name() << ") set";
222         }
223     }
224 }
225 
226 // Desktop GLSL support is not enabled on Android
227 #if !defined(ANGLE_PLATFORM_ANDROID)
228 
229 // For testing Desktop GL Shaders
230 class ShCompileDesktopGLTest : public ShCompileTest
231 {
232   public:
ShCompileDesktopGLTest()233     ShCompileDesktopGLTest() {}
234 
235   protected:
SetUp()236     void SetUp() override
237     {
238         sh::InitBuiltInResources(&mResources);
239         mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_GL_COMPATIBILITY_SPEC,
240                                           SH_GLSL_330_CORE_OUTPUT, &mResources);
241         ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
242     }
243 };
244 
245 // Test calling sh::Compile with fragment shader source string
TEST_F(ShCompileDesktopGLTest,DesktopGLString)246 TEST_F(ShCompileDesktopGLTest, DesktopGLString)
247 {
248     constexpr char kFragmentShaderString[] =
249         R"(#version 330
250         void main()
251         {
252         })";
253 
254     const char *shaderStrings[] = {kFragmentShaderString};
255 
256     testCompile(shaderStrings, 1, true);
257 }
258 
259 // Test calling sh::Compile with core version
TEST_F(ShCompileDesktopGLTest,FragmentShaderCoreVersion)260 TEST_F(ShCompileDesktopGLTest, FragmentShaderCoreVersion)
261 {
262     constexpr char kFragmentShaderString[] =
263         R"(#version 330 core
264         void main()
265         {
266         })";
267 
268     const char *shaderStrings[] = {kFragmentShaderString};
269 
270     testCompile(shaderStrings, 1, true);
271 }
272 
273 // Implicit conversions in basic operations
TEST_F(ShCompileDesktopGLTest,ImplicitConversionBasicOperation)274 TEST_F(ShCompileDesktopGLTest, ImplicitConversionBasicOperation)
275 {
276     constexpr char kFragmentShaderString[] =
277         R"(#version 330 core
278         void main()
279         {
280             //float a = 1 + 1.5;
281             //float b = 1 - 1.5;
282             //float c = 1 * 1.5;
283             //float d = 1 / 1.5;
284             //float e = 1.5 + 1;
285             //float f = 1.5 - 1;
286             float g = 1.5 * 1;
287             //float h = 1.5 / 1;
288         })";
289 
290     const char *shaderStrings[] = {kFragmentShaderString};
291 
292     testCompile(shaderStrings, 1, true);
293 }
294 
295 // Implicit conversions when assigning
TEST_F(ShCompileDesktopGLTest,ImplicitConversionAssign)296 TEST_F(ShCompileDesktopGLTest, ImplicitConversionAssign)
297 {
298     constexpr char kFragmentShaderString[] =
299         R"(#version 330 core
300         void main()
301         {
302             float a = 1;
303             uint b = 2u;
304             a = b;
305             a += b;
306             a -= b;
307             a *= b;
308             a /= b;
309         })";
310 
311     const char *shaderStrings[] = {kFragmentShaderString};
312 
313     testCompile(shaderStrings, 1, true);
314 }
315 
316 // Implicit conversions for vectors
TEST_F(ShCompileDesktopGLTest,ImplicitConversionVector)317 TEST_F(ShCompileDesktopGLTest, ImplicitConversionVector)
318 {
319     constexpr char kFragmentShaderString[] =
320         R"(#version 330 core
321         void main()
322         {
323             vec3 a;
324             ivec3 b = ivec3(1, 1, 1);
325             a = b;
326         })";
327 
328     const char *shaderStrings[] = {kFragmentShaderString};
329 
330     testCompile(shaderStrings, 1, true);
331 }
332 
333 // Implicit conversions should not convert between ints and uints
TEST_F(ShCompileDesktopGLTest,ImplicitConversionAssignFailed)334 TEST_F(ShCompileDesktopGLTest, ImplicitConversionAssignFailed)
335 {
336     constexpr char kFragmentShaderString[] =
337         R"(#version 330 core
338         void main()
339         {
340             int a = 1;
341             uint b = 2;
342             a = b;
343         })";
344 
345     const char *shaderStrings[] = {kFragmentShaderString};
346 
347     testCompile(shaderStrings, 1, false);
348 }
349 
350 // GL shaders use implicit conversions between types
351 // Testing internal implicit conversions
TEST_F(ShCompileDesktopGLTest,ImplicitConversionFunction)352 TEST_F(ShCompileDesktopGLTest, ImplicitConversionFunction)
353 {
354     constexpr char kFragmentShaderString[] =
355         R"(#version 330 core
356         void main()
357         {
358             float cosTheta = clamp(0.5,0,1);
359             float exp = pow(0.5,2);
360         })";
361 
362     const char *shaderStrings[] = {kFragmentShaderString};
363 
364     testCompile(shaderStrings, 1, true);
365 }
366 
367 #endif  // !defined(ANGLE_PLATFORM_ANDROID)
368