• 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 // UnrollFlatten_test.cpp:
7 //   Test for the outputting of [[unroll]] and [[flatten]] for the D3D compiler.
8 //   This test can only be enabled when HLSL support is enabled.
9 //
10 
11 #include "GLSLANG/ShaderLang.h"
12 #include "angle_gl.h"
13 #include "common/angleutils.h"
14 #include "gtest/gtest.h"
15 #include "tests/test_utils/compiler_test.h"
16 
17 using namespace sh;
18 
19 namespace
20 {
21 
22 class UnrollFlattenTest : public testing::Test
23 {
24   public:
UnrollFlattenTest()25     UnrollFlattenTest() : mInputSpec(SH_GLES2_SPEC) {}
UnrollFlattenTest(ShShaderSpec inputSpec)26     UnrollFlattenTest(ShShaderSpec inputSpec) : mInputSpec(inputSpec) {}
27 
28   protected:
compile(const std::string & shaderString)29     void compile(const std::string &shaderString)
30     {
31         std::string infoLog;
32         bool compilationSuccess =
33             compileTestShader(GL_FRAGMENT_SHADER, mInputSpec, SH_HLSL_4_1_OUTPUT, shaderString,
34                               SH_VARIABLES, &mTranslatedSource, &infoLog);
35         if (!compilationSuccess)
36         {
37             FAIL() << "Shader compilation failed " << infoLog;
38         }
39         // Ignore the beginning of the shader to avoid the definitions of LOOP and FLATTEN
40         mCurrentPosition = static_cast<int>(mTranslatedSource.find("cbuffer DriverConstants"));
41     }
42 
expect(const char * patterns[],size_t count)43     void expect(const char *patterns[], size_t count)
44     {
45         const char *badPatterns[] = {UNROLL, FLATTEN};
46         for (size_t i = 0; i < count; i++)
47         {
48             const char *pattern = patterns[i];
49             auto position       = mTranslatedSource.find(pattern, mCurrentPosition);
50             if (position == std::string::npos)
51             {
52                 FAIL() << "Couldn't find '" << pattern << "' after expectations '"
53                        << mExpectationList << "' in translated source:\n"
54                        << mTranslatedSource;
55             }
56 
57             for (size_t j = 0; j < ArraySize(badPatterns); j++)
58             {
59                 const char *badPattern = badPatterns[j];
60                 if (pattern != badPattern &&
61                     mTranslatedSource.find(badPattern, mCurrentPosition) < position)
62                 {
63                     FAIL() << "Found '" << badPattern << "' before '" << pattern
64                            << "' after expectations '" << mExpectationList
65                            << "' in translated source:\n"
66                            << mTranslatedSource;
67                 }
68             }
69             mExpectationList += " - " + std::string(pattern);
70             mCurrentPosition = static_cast<int>(position) + 1;
71         }
72     }
73 
74     static const char *UNROLL;
75     static const char *FLATTEN;
76 
77   private:
78     ShShaderSpec mInputSpec;
79     std::string mTranslatedSource;
80 
81     int mCurrentPosition;
82     std::string mExpectationList;
83 };
84 
85 const char *UnrollFlattenTest::UNROLL  = "LOOP";
86 const char *UnrollFlattenTest::FLATTEN = "FLATTEN";
87 
88 // Check that the nothing is added if there is no gradient operation
89 // even when there is ifs and discontinuous loops
TEST_F(UnrollFlattenTest,NoGradient)90 TEST_F(UnrollFlattenTest, NoGradient)
91 {
92     const std::string &shaderString =
93         "precision mediump float;\n"
94         "uniform float f;\n"
95         "float fun(float a){\n"           // 1
96         "    if (a > 1.0) {return f;}\n"  // 2
97         "    else {return a + 1.0;}\n"
98         "}\n"
99         "float fun2(float a){\n"                // 3
100         "    for (int i = 0; i < 10; i++) {\n"  // 4
101         "        if (a > 1.0) {break;}\n"       // 5
102         "        a = fun(a);\n"                 // 6
103         "    }\n"
104         "    return a;\n"
105         "}\n"
106         "void main() {\n"
107         "    float accum = 0.0;\n"
108         "    if (f < 5.0) {accum = fun2(accum);}\n"  // 7
109         "    gl_FragColor = vec4(accum);\n"
110         "}\n";
111     compile(shaderString);
112     // 1 - shouldn't get a Lod0 version generated
113     // 2 - no FLATTEN because does not contain discont loop
114     // 3 - shouldn't get a Lod0 version generated
115     // 4 - no LOOP because discont, and also no gradient
116     // 5 - no FLATTEN because does not contain loop with a gradient
117     // 6 - call non-Lod0 version
118     // 7 - no FLATTEN
119     const char *expectations[] = {"fun(",  "if",   "fun2(", "for", "if",
120                                   "break", "fun(", "main(", "if",  "fun2("};
121     expect(expectations, ArraySize(expectations));
122 }
123 
124 // Check that when we have a gradient in a non-discontinuous loop
125 // we use the regular version of the functions. Also checks that
126 // LOOP is generated for the loop containing the gradient.
TEST_F(UnrollFlattenTest,GradientNotInDiscont)127 TEST_F(UnrollFlattenTest, GradientNotInDiscont)
128 {
129     const std::string &shaderString =
130         "precision mediump float;\n"
131         "uniform float f;\n"
132         "uniform sampler2D tex;"
133         "float fun(float a){\n"                         // 1
134         "    return texture2D(tex, vec2(0.5, f)).x;\n"  // 2
135         "}\n"
136         "float fun2(float a){\n"                        // 3
137         "    for (int i = 0; i < 10; i++) {\n"          // 4
138         "        if (a > 1.0) {}\n"                     // 5
139         "        a = fun(a);\n"                         // 6
140         "        a += texture2D(tex, vec2(a, 0.0)).x;"  // 7
141         "    }\n"
142         "    return a;\n"
143         "}\n"
144         "void main() {\n"
145         "    float accum = 0.0;\n"
146         "    if (f < 5.0) {accum = fun2(accum);}\n"  // 8
147         "    gl_FragColor = vec4(accum);\n"
148         "}\n";
149     // 1 - shouldn't get a Lod0 version generated
150     // 2 - no Lod0 version generated
151     // 3 - shouldn't get a Lod0 version generated (not in discont loop)
152     // 4 - should have LOOP because it contains a gradient operation (even if Lod0)
153     // 5 - no FLATTEN because doesn't contain loop with a gradient
154     // 6 - call non-Lod0 version
155     // 7 - call non-Lod0 version
156     // 8 - FLATTEN because it contains a loop with a gradient
157     compile(shaderString);
158     const char *expectations[] = {"fun(", "texture2D(", "fun2(", "LOOP",    "for", "if",
159                                   "fun(", "texture2D(", "main(", "FLATTEN", "if",  "fun2("};
160     expect(expectations, ArraySize(expectations));
161 }
162 
163 // Check that when we have a gradient in a discontinuous loop
164 // we use the Lod0 version of the functions.
TEST_F(UnrollFlattenTest,GradientInDiscont)165 TEST_F(UnrollFlattenTest, GradientInDiscont)
166 {
167     const std::string &shaderString =
168         "precision mediump float;\n"
169         "uniform float f;\n"
170         "uniform sampler2D tex;"
171         "float fun(float a){\n"                         // 1
172         "    return texture2D(tex, vec2(0.5, f)).x;\n"  // 2
173         "}\n"
174         "float fun2(float a){\n"                        // 3
175         "    for (int i = 0; i < 10; i++) {\n"          // 4
176         "        if (a > 1.0) {break;}\n"               // 5
177         "        a = fun(a);\n"                         // 6
178         "        a += texture2D(tex, vec2(a, 0.0)).x;"  // 7
179         "    }\n"
180         "    return a;\n"
181         "}\n"
182         "void main() {\n"
183         "    float accum = 0.0;\n"
184         "    if (f < 5.0) {accum = fun2(accum);}\n"  // 8
185         "    gl_FragColor = vec4(accum);\n"
186         "}\n";
187     // 1 - should get a Lod0 version generated (gradient + discont loop)
188     // 2 - will get the Lod0 if in funLod0
189     // 3 - shouldn't get a Lod0 version generated (not in discont loop)
190     // 4 - should have LOOP because it contains a gradient operation (even if Lod0)
191     // 5 - no FLATTEN because doesn't contain a loop with a gradient
192     // 6 - call Lod0 version
193     // 7 - call Lod0 version
194     // 8 - FLATTEN because it contains a loop with a gradient
195     compile(shaderString);
196     const char *expectations[] = {
197         "fun(",  "texture2D(", "funLod0(",      "texture2DLod0(", "fun2(",   "LOOP", "for",  "if",
198         "break", "funLod0(",   "texture2DLod0", "main(",          "FLATTEN", "if",   "fun2("};
199     expect(expectations, ArraySize(expectations));
200 }
201 
202 class UnrollFlattenTest_ES3 : public UnrollFlattenTest
203 {
204   public:
UnrollFlattenTest_ES3()205     UnrollFlattenTest_ES3() : UnrollFlattenTest(SH_GLES3_SPEC) {}
206 };
207 
208 // Check that we correctly detect the ES3 builtin "texture" function as a gradient operation.
TEST_F(UnrollFlattenTest_ES3,TextureBuiltin)209 TEST_F(UnrollFlattenTest_ES3, TextureBuiltin)
210 {
211     const std::string &shaderString =
212         "#version 300 es\n"
213         "precision mediump float;\n"
214         "uniform sampler2D tex;"
215         "out float fragColor;\n"
216         "void main() {\n"
217         "    float a = 0.0;"
218         "    for (int i = 0; i < 10; i++) {\n"
219         "        if (a > 1.0) {break;}\n"
220         "        a += texture(tex, vec2(a, 0.0)).x;"
221         "    }\n"
222         "    fragColor = a;\n"
223         "}\n";
224 
225     compile(shaderString);
226     const char *expectations[] = {"main(", "LOOP", "Lod0("};
227     expect(expectations, ArraySize(expectations));
228 }
229 }  // namespace
230