Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / tests / compiler_tests / ExpressionLimit_test.cpp
1 //
2 // Copyright (c) 2002-2013 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 #include <sstream>
7 #include <string>
8 #include <vector>
9 #include "angle_gl.h"
10 #include "gtest/gtest.h"
11 #include "GLSLANG/ShaderLang.h"
12
13 #define SHADER(Src) #Src
14
15 class ExpressionLimitTest : public testing::Test {
16 protected:
17     static const int kMaxExpressionComplexity = 16;
18     static const int kMaxCallStackDepth = 16;
19     static const char* kExpressionTooComplex;
20     static const char* kCallStackTooDeep;
21     static const char* kHasRecursion;
22
23     virtual void SetUp()
24     {
25         memset(&resources, 0, sizeof(resources));
26
27         GenerateResources(&resources);
28     }
29
30     // Set up the per compile resources
31     void GenerateResources(ShBuiltInResources* resources)
32     {
33         ShInitBuiltInResources(resources);
34
35         resources->MaxVertexAttribs = 8;
36         resources->MaxVertexUniformVectors = 128;
37         resources->MaxVaryingVectors = 8;
38         resources->MaxVertexTextureImageUnits = 0;
39         resources->MaxCombinedTextureImageUnits = 8;
40         resources->MaxTextureImageUnits = 8;
41         resources->MaxFragmentUniformVectors = 16;
42         resources->MaxDrawBuffers = 1;
43
44         resources->OES_standard_derivatives = 0;
45         resources->OES_EGL_image_external = 0;
46
47         resources->MaxExpressionComplexity = kMaxExpressionComplexity;
48         resources->MaxCallStackDepth = kMaxCallStackDepth;
49     }
50
51     void GenerateLongExpression(int length, std::stringstream* ss)
52     {
53         for (int ii = 0; ii < length; ++ii) {
54           *ss << "+ vec4(" << ii << ")";
55         }
56     }
57
58     std::string GenerateShaderWithLongExpression(int length)
59     {
60         static const char* shaderStart = SHADER(
61             precision mediump float;
62             uniform vec4 u_color;
63             void main()
64             {
65                gl_FragColor = u_color
66         );
67
68         std::stringstream ss;
69         ss << shaderStart;
70         GenerateLongExpression(length, &ss);
71         ss << "; }";
72
73         return ss.str();
74     }
75
76     std::string GenerateShaderWithUnusedLongExpression(int length)
77     {
78         static const char* shaderStart = SHADER(
79             precision mediump float;
80             uniform vec4 u_color;
81             void main()
82             {
83                gl_FragColor = u_color;
84             }
85             vec4 someFunction() {
86               return u_color
87         );
88
89         std::stringstream ss;
90
91         ss << shaderStart;
92         GenerateLongExpression(length, &ss);
93         ss << "; }";
94
95         return ss.str();
96     }
97
98     void GenerateDeepFunctionStack(int length, std::stringstream* ss)
99     {
100         static const char* shaderStart = SHADER(
101             precision mediump float;
102             uniform vec4 u_color;
103             vec4 function0()  {
104               return u_color;
105             }
106         );
107
108         *ss << shaderStart;
109         for (int ii = 0; ii < length; ++ii) {
110           *ss << "vec4 function" << (ii + 1) << "() {\n"
111               << "  return function" << ii << "();\n"
112               << "}\n";
113         }
114     }
115
116     std::string GenerateShaderWithDeepFunctionStack(int length)
117     {
118         std::stringstream ss;
119
120         GenerateDeepFunctionStack(length, &ss);
121
122         ss << "void main() {\n"
123            << "  gl_FragColor = function" << length << "();\n"
124            << "}";
125
126         return ss.str();
127     }
128
129     std::string GenerateShaderWithUnusedDeepFunctionStack(int length)
130     {
131         std::stringstream ss;
132
133         GenerateDeepFunctionStack(length, &ss);
134
135         ss << "void main() {\n"
136            << "  gl_FragColor = vec4(0,0,0,0);\n"
137            << "}";
138
139
140         return ss.str();
141     }
142
143     // Compiles a shader and if there's an error checks for a specific
144     // substring in the error log. This way we know the error is specific
145     // to the issue we are testing.
146     bool CheckShaderCompilation(ShHandle compiler,
147                                 const char* source,
148                                 int compileOptions,
149                                 const char* expected_error) {
150         bool success = ShCompile(compiler, &source, 1, compileOptions) != 0;
151         if (success) {
152             success = !expected_error;
153         } else {
154             size_t bufferLen = 0;
155             ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen);
156             char* buffer(new char [bufferLen]);
157             ShGetInfoLog(compiler, buffer);
158             std::string log(buffer, buffer + bufferLen);
159             delete [] buffer;
160             if (expected_error)
161                 success = log.find(expected_error) != std::string::npos;
162
163             EXPECT_TRUE(success) << log << "\n----shader----\n" << source;
164         }
165         return success;
166     }
167
168     ShBuiltInResources resources;
169 };
170
171 const char* ExpressionLimitTest::kExpressionTooComplex =
172     "Expression too complex";
173 const char* ExpressionLimitTest::kCallStackTooDeep =
174     "call stack too deep";
175 const char* ExpressionLimitTest::kHasRecursion =
176     "Function recursion detected";
177
178 TEST_F(ExpressionLimitTest, ExpressionComplexity)
179 {
180     ShShaderSpec spec = SH_WEBGL_SPEC;
181     ShShaderOutput output = SH_ESSL_OUTPUT;
182     ShHandle vertexCompiler = ShConstructCompiler(
183         GL_FRAGMENT_SHADER, spec, output, &resources);
184     int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
185
186     // Test expression under the limit passes.
187     EXPECT_TRUE(CheckShaderCompilation(
188         vertexCompiler,
189         GenerateShaderWithLongExpression(
190             kMaxExpressionComplexity - 10).c_str(),
191         compileOptions, NULL));
192     // Test expression over the limit fails.
193     EXPECT_TRUE(CheckShaderCompilation(
194         vertexCompiler,
195         GenerateShaderWithLongExpression(
196             kMaxExpressionComplexity + 10).c_str(),
197         compileOptions, kExpressionTooComplex));
198     // Test expression over the limit without a limit does not fail.
199     EXPECT_TRUE(CheckShaderCompilation(
200         vertexCompiler,
201         GenerateShaderWithLongExpression(
202             kMaxExpressionComplexity + 10).c_str(),
203         compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
204     ShDestruct(vertexCompiler);
205 }
206
207 TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)
208 {
209     ShShaderSpec spec = SH_WEBGL_SPEC;
210     ShShaderOutput output = SH_ESSL_OUTPUT;
211     ShHandle vertexCompiler = ShConstructCompiler(
212         GL_FRAGMENT_SHADER, spec, output, &resources);
213     int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
214
215     // Test expression under the limit passes.
216     EXPECT_TRUE(CheckShaderCompilation(
217         vertexCompiler,
218         GenerateShaderWithUnusedLongExpression(
219             kMaxExpressionComplexity - 10).c_str(),
220         compileOptions, NULL));
221     // Test expression over the limit fails.
222     EXPECT_TRUE(CheckShaderCompilation(
223         vertexCompiler,
224         GenerateShaderWithUnusedLongExpression(
225             kMaxExpressionComplexity + 10).c_str(),
226         compileOptions, kExpressionTooComplex));
227     // Test expression over the limit without a limit does not fail.
228     EXPECT_TRUE(CheckShaderCompilation(
229         vertexCompiler,
230         GenerateShaderWithUnusedLongExpression(
231             kMaxExpressionComplexity + 10).c_str(),
232         compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
233     ShDestruct(vertexCompiler);
234 }
235
236 TEST_F(ExpressionLimitTest, CallStackDepth)
237 {
238     ShShaderSpec spec = SH_WEBGL_SPEC;
239     ShShaderOutput output = SH_ESSL_OUTPUT;
240     ShHandle vertexCompiler = ShConstructCompiler(
241         GL_FRAGMENT_SHADER, spec, output, &resources);
242     int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
243
244     // Test call stack under the limit passes.
245     EXPECT_TRUE(CheckShaderCompilation(
246         vertexCompiler,
247         GenerateShaderWithDeepFunctionStack(
248             kMaxCallStackDepth - 10).c_str(),
249         compileOptions, NULL));
250     // Test call stack over the limit fails.
251     EXPECT_TRUE(CheckShaderCompilation(
252         vertexCompiler,
253         GenerateShaderWithDeepFunctionStack(
254             kMaxCallStackDepth + 10).c_str(),
255         compileOptions, kCallStackTooDeep));
256     // Test call stack over the limit without limit does not fail.
257     EXPECT_TRUE(CheckShaderCompilation(
258         vertexCompiler,
259         GenerateShaderWithDeepFunctionStack(
260             kMaxCallStackDepth + 10).c_str(),
261         compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
262     ShDestruct(vertexCompiler);
263 }
264
265 TEST_F(ExpressionLimitTest, UnusedCallStackDepth)
266 {
267     ShShaderSpec spec = SH_WEBGL_SPEC;
268     ShShaderOutput output = SH_ESSL_OUTPUT;
269     ShHandle vertexCompiler = ShConstructCompiler(
270         GL_FRAGMENT_SHADER, spec, output, &resources);
271     int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
272
273     // Test call stack under the limit passes.
274     EXPECT_TRUE(CheckShaderCompilation(
275         vertexCompiler,
276         GenerateShaderWithUnusedDeepFunctionStack(
277             kMaxCallStackDepth - 10).c_str(),
278         compileOptions, NULL));
279     // Test call stack over the limit fails.
280     EXPECT_TRUE(CheckShaderCompilation(
281         vertexCompiler,
282         GenerateShaderWithUnusedDeepFunctionStack(
283             kMaxCallStackDepth + 10).c_str(),
284         compileOptions, kCallStackTooDeep));
285     // Test call stack over the limit without limit does not fail.
286     EXPECT_TRUE(CheckShaderCompilation(
287         vertexCompiler,
288         GenerateShaderWithUnusedDeepFunctionStack(
289             kMaxCallStackDepth + 10).c_str(),
290         compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
291     ShDestruct(vertexCompiler);
292 }
293
294 TEST_F(ExpressionLimitTest, Recursion)
295 {
296     ShShaderSpec spec = SH_WEBGL_SPEC;
297     ShShaderOutput output = SH_ESSL_OUTPUT;
298     ShHandle vertexCompiler = ShConstructCompiler(
299         GL_FRAGMENT_SHADER, spec, output, &resources);
300     int compileOptions = 0;
301
302     static const char* shaderWithRecursion0 = SHADER(
303         precision mediump float;
304         uniform vec4 u_color;
305         vec4 someFunc()  {
306             return someFunc();
307         }
308
309         void main() {
310             gl_FragColor = u_color * someFunc();
311         }
312     );
313
314     static const char* shaderWithRecursion1 = SHADER(
315         precision mediump float;
316         uniform vec4 u_color;
317
318         vec4 someFunc();
319
320         vec4 someFunc1()  {
321             return someFunc();
322         }
323
324         vec4 someFunc()  {
325             return someFunc1();
326         }
327
328         void main() {
329             gl_FragColor = u_color * someFunc();
330         }
331     );
332
333     static const char* shaderWithRecursion2 = SHADER(
334         precision mediump float;
335         uniform vec4 u_color;
336         vec4 someFunc()  {
337             if (u_color.x > 0.5) {
338                 return someFunc();
339             } else {
340                 return vec4(1);
341             }
342         }
343
344         void main() {
345             gl_FragColor = someFunc();
346         }
347     );
348
349     static const char* shaderWithRecursion3 = SHADER(
350         precision mediump float;
351         uniform vec4 u_color;
352         vec4 someFunc()  {
353             if (u_color.x > 0.5) {
354                 return vec4(1);
355             } else {
356                 return someFunc();
357             }
358         }
359
360         void main() {
361             gl_FragColor = someFunc();
362         }
363     );
364
365     static const char* shaderWithRecursion4 = SHADER(
366         precision mediump float;
367         uniform vec4 u_color;
368         vec4 someFunc()  {
369             return (u_color.x > 0.5) ? vec4(1) : someFunc();
370         }
371
372         void main() {
373             gl_FragColor = someFunc();
374         }
375     );
376
377     static const char* shaderWithRecursion5 = SHADER(
378         precision mediump float;
379         uniform vec4 u_color;
380         vec4 someFunc()  {
381             return (u_color.x > 0.5) ? someFunc() : vec4(1);
382         }
383
384         void main() {
385             gl_FragColor = someFunc();
386         }
387     );
388
389     static const char* shaderWithRecursion6 = SHADER(
390         precision mediump float;
391         uniform vec4 u_color;
392         vec4 someFunc()  {
393             return someFunc();
394         }
395
396         void main() {
397             gl_FragColor = u_color;
398         }
399     );
400
401     static const char* shaderWithNoRecursion = SHADER(
402         precision mediump float;
403         uniform vec4 u_color;
404
405         vec3 rgb(int r, int g, int b) {
406             return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
407         }
408
409         // these external calls used to incorrectly trigger
410         // recursion detection.
411         vec3 hairColor0 = rgb(151, 200, 234);
412         vec3 faceColor2 = rgb(183, 148, 133);
413
414         void main() {
415             gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);
416         }
417     );
418
419     static const char* shaderWithRecursion7 = SHADER(
420         precision mediump float;
421         uniform vec4 u_color;
422
423         vec4 function2() {
424             return u_color;
425         }
426
427         vec4 function1() {
428             vec4 a = function2();
429             vec4 b = function1();
430             return a + b;
431         }
432
433         void main() {
434             gl_FragColor = function1();
435         }
436     );
437
438     static const char* shaderWithRecursion8 = SHADER(
439         precision mediump float;
440         uniform vec4 u_color;
441
442         vec4 function1();
443
444         vec4 function3() {
445             return function1();
446         }
447
448         vec4 function2() {
449             return function3();
450         }
451
452         vec4 function1() {
453             return function2();
454         }
455
456         void main() {
457             gl_FragColor = function1();
458         }
459     );
460
461     // Check simple recursions fails.
462     EXPECT_TRUE(CheckShaderCompilation(
463         vertexCompiler, shaderWithRecursion0,
464         compileOptions, kHasRecursion));
465     // Check simple recursions fails.
466     EXPECT_TRUE(CheckShaderCompilation(
467         vertexCompiler, shaderWithRecursion1,
468         compileOptions, kHasRecursion));
469     // Check if recursions fails.
470     EXPECT_TRUE(CheckShaderCompilation(
471         vertexCompiler, shaderWithRecursion2,
472         compileOptions, kHasRecursion));
473     // Check if recursions fails.
474     EXPECT_TRUE(CheckShaderCompilation(
475         vertexCompiler, shaderWithRecursion3,
476         compileOptions, kHasRecursion));
477     // Check ternary recursions fails.
478     EXPECT_TRUE(CheckShaderCompilation(
479         vertexCompiler, shaderWithRecursion4,
480         compileOptions, kHasRecursion));
481     // Check ternary recursions fails.
482     EXPECT_TRUE(CheckShaderCompilation(
483         vertexCompiler, shaderWithRecursion5,
484         compileOptions, kHasRecursion));
485     // Check unused recursions passes.
486     EXPECT_TRUE(CheckShaderCompilation(
487         vertexCompiler, shaderWithRecursion6,
488         compileOptions, NULL));
489     EXPECT_TRUE(CheckShaderCompilation(
490         vertexCompiler, shaderWithRecursion7,
491         compileOptions, kHasRecursion));
492     EXPECT_TRUE(CheckShaderCompilation(
493         vertexCompiler, shaderWithRecursion8,
494         compileOptions, kHasRecursion));
495     // Check unused recursions fails if limiting call stack
496     // since we check all paths.
497     EXPECT_TRUE(CheckShaderCompilation(
498         vertexCompiler, shaderWithRecursion6,
499         compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));
500
501     // Check unused recursions passes.
502     EXPECT_TRUE(CheckShaderCompilation(
503         vertexCompiler, shaderWithNoRecursion,
504         compileOptions, NULL));
505     // Check unused recursions passes if limiting call stack.
506     EXPECT_TRUE(CheckShaderCompilation(
507         vertexCompiler, shaderWithNoRecursion,
508         compileOptions | SH_LIMIT_CALL_STACK_DEPTH, NULL));
509     ShDestruct(vertexCompiler);
510 }
511