Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/tests/compiler_tests/ExpressionLimit_test.cpp
1693 views
1
//
2
// Copyright 2002 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 "GLSLANG/ShaderLang.h"
10
#include "angle_gl.h"
11
#include "gtest/gtest.h"
12
13
class ExpressionLimitTest : public testing::Test
14
{
15
protected:
16
static const int kMaxExpressionComplexity = 16;
17
static const int kMaxCallStackDepth = 16;
18
static const int kMaxFunctionParameters = 16;
19
static const char *kExpressionTooComplex;
20
static const char *kCallStackTooDeep;
21
static const char *kHasRecursion;
22
static const char *kTooManyParameters;
23
static const char *kTooComplexSwitch;
24
static const char *kGlobalVariableInit;
25
26
virtual void SetUp()
27
{
28
memset(&resources, 0, sizeof(resources));
29
30
GenerateResources(&resources);
31
}
32
33
// Set up the per compile resources
34
static void GenerateResources(ShBuiltInResources *res)
35
{
36
sh::InitBuiltInResources(res);
37
38
res->MaxVertexAttribs = 8;
39
res->MaxVertexUniformVectors = 128;
40
res->MaxVaryingVectors = 8;
41
res->MaxVertexTextureImageUnits = 0;
42
res->MaxCombinedTextureImageUnits = 8;
43
res->MaxTextureImageUnits = 8;
44
res->MaxFragmentUniformVectors = 16;
45
res->MaxDrawBuffers = 1;
46
47
res->OES_standard_derivatives = 0;
48
res->OES_EGL_image_external = 0;
49
50
res->MaxExpressionComplexity = kMaxExpressionComplexity;
51
res->MaxCallStackDepth = kMaxCallStackDepth;
52
res->MaxFunctionParameters = kMaxFunctionParameters;
53
}
54
55
static void GenerateLongExpression(int length, std::stringstream *ss)
56
{
57
for (int ii = 0; ii < length; ++ii)
58
{
59
*ss << "+ vec4(" << ii << ")";
60
}
61
}
62
63
static std::string GenerateShaderWithLongExpression(int length)
64
{
65
static const char *shaderStart =
66
R"(precision mediump float;
67
uniform vec4 u_color;
68
void main()
69
{
70
gl_FragColor = u_color
71
)";
72
73
std::stringstream ss;
74
ss << shaderStart;
75
GenerateLongExpression(length, &ss);
76
ss << "; }";
77
78
return ss.str();
79
}
80
81
static std::string GenerateShaderWithUnusedLongExpression(int length)
82
{
83
static const char *shaderStart =
84
R"(precision mediump float;
85
uniform vec4 u_color;
86
void main()
87
{
88
gl_FragColor = u_color;
89
}
90
vec4 someFunction() {
91
return u_color
92
)";
93
94
std::stringstream ss;
95
96
ss << shaderStart;
97
GenerateLongExpression(length, &ss);
98
ss << "; }";
99
100
return ss.str();
101
}
102
103
static void GenerateDeepFunctionStack(int length, std::stringstream *ss)
104
{
105
static const char *shaderStart =
106
R"(precision mediump float;
107
uniform vec4 u_color;
108
vec4 function0() {
109
return u_color;
110
}
111
)";
112
113
*ss << shaderStart;
114
for (int ii = 0; ii < length; ++ii)
115
{
116
*ss << "vec4 function" << (ii + 1) << "() {\n"
117
<< " return function" << ii << "();\n"
118
<< "}\n";
119
}
120
}
121
122
static std::string GenerateShaderWithDeepFunctionStack(int length)
123
{
124
std::stringstream ss;
125
126
GenerateDeepFunctionStack(length, &ss);
127
128
ss << "void main() {\n"
129
<< " gl_FragColor = function" << length << "();\n"
130
<< "}";
131
132
return ss.str();
133
}
134
135
static std::string GenerateShaderWithUnusedDeepFunctionStack(int length)
136
{
137
std::stringstream ss;
138
139
GenerateDeepFunctionStack(length, &ss);
140
141
ss << "void main() {\n"
142
<< " gl_FragColor = vec4(0,0,0,0);\n"
143
<< "}";
144
145
return ss.str();
146
}
147
148
static std::string GenerateShaderWithFunctionParameters(int parameters)
149
{
150
std::stringstream ss;
151
152
ss << "precision mediump float;\n"
153
<< "\n"
154
<< "float foo(";
155
for (int i = 0; i < parameters; ++i)
156
{
157
ss << "float f" << i;
158
if (i + 1 < parameters)
159
{
160
ss << ", ";
161
}
162
}
163
ss << ")\n"
164
<< "{\n"
165
<< " return f0;\n"
166
<< "}\n"
167
<< "\n"
168
<< "void main()\n"
169
<< "{\n"
170
<< " gl_FragColor = vec4(0,0,0,0);\n"
171
<< "}";
172
173
return ss.str();
174
}
175
176
static std::string GenerateShaderWithNestingInsideSwitch(int nesting)
177
{
178
std::stringstream shaderString;
179
shaderString <<
180
R"(#version 300 es
181
uniform int u;
182
183
void main()
184
{
185
int x;
186
switch (u)
187
{
188
case 0:
189
x = x)";
190
for (int i = 0; i < nesting; ++i)
191
{
192
shaderString << " + x";
193
}
194
shaderString <<
195
R"(;
196
} // switch (u)
197
})";
198
return shaderString.str();
199
}
200
201
static std::string GenerateShaderWithNestingInsideGlobalInitializer(int nesting)
202
{
203
std::stringstream shaderString;
204
shaderString <<
205
R"(uniform int u;
206
int x = u)";
207
208
for (int i = 0; i < nesting; ++i)
209
{
210
shaderString << " + u";
211
}
212
shaderString << R"(;
213
void main()
214
{
215
gl_FragColor = vec4(0.0);
216
})";
217
return shaderString.str();
218
}
219
220
// Compiles a shader and if there's an error checks for a specific
221
// substring in the error log. This way we know the error is specific
222
// to the issue we are testing.
223
bool CheckShaderCompilation(ShHandle compiler,
224
const char *source,
225
ShCompileOptions compileOptions,
226
const char *expected_error)
227
{
228
bool success = sh::Compile(compiler, &source, 1, compileOptions) != 0;
229
if (success)
230
{
231
success = !expected_error;
232
}
233
else
234
{
235
std::string log = sh::GetInfoLog(compiler);
236
if (expected_error)
237
success = log.find(expected_error) != std::string::npos;
238
239
EXPECT_TRUE(success) << log << "\n----shader----\n" << source;
240
}
241
return success;
242
}
243
244
ShBuiltInResources resources;
245
};
246
247
const char *ExpressionLimitTest::kExpressionTooComplex = "Expression too complex";
248
const char *ExpressionLimitTest::kCallStackTooDeep = "Call stack too deep";
249
const char *ExpressionLimitTest::kHasRecursion =
250
"Recursive function call in the following call chain";
251
const char *ExpressionLimitTest::kTooManyParameters = "Function has too many parameters";
252
const char *ExpressionLimitTest::kTooComplexSwitch =
253
"too complex expressions inside a switch statement";
254
const char *ExpressionLimitTest::kGlobalVariableInit =
255
"global variable initializers must be constant expressions";
256
257
TEST_F(ExpressionLimitTest, ExpressionComplexity)
258
{
259
ShShaderSpec spec = SH_WEBGL_SPEC;
260
ShShaderOutput output = SH_ESSL_OUTPUT;
261
ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
262
ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
263
264
// Test expression under the limit passes.
265
EXPECT_TRUE(CheckShaderCompilation(
266
vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity - 10).c_str(),
267
compileOptions, nullptr));
268
// Test expression over the limit fails.
269
EXPECT_TRUE(CheckShaderCompilation(
270
vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity + 10).c_str(),
271
compileOptions, kExpressionTooComplex));
272
// Test expression over the limit without a limit does not fail.
273
EXPECT_TRUE(CheckShaderCompilation(
274
vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity + 10).c_str(),
275
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
276
sh::Destruct(vertexCompiler);
277
}
278
279
TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)
280
{
281
ShShaderSpec spec = SH_WEBGL_SPEC;
282
ShShaderOutput output = SH_ESSL_OUTPUT;
283
ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
284
ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
285
286
// Test expression under the limit passes.
287
EXPECT_TRUE(CheckShaderCompilation(
288
vertexCompiler,
289
GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity - 10).c_str(),
290
compileOptions, nullptr));
291
// Test expression over the limit fails.
292
EXPECT_TRUE(CheckShaderCompilation(
293
vertexCompiler,
294
GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity + 10).c_str(),
295
compileOptions, kExpressionTooComplex));
296
// Test expression over the limit without a limit does not fail.
297
EXPECT_TRUE(CheckShaderCompilation(
298
vertexCompiler,
299
GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity + 10).c_str(),
300
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
301
sh::Destruct(vertexCompiler);
302
}
303
304
TEST_F(ExpressionLimitTest, CallStackDepth)
305
{
306
ShShaderSpec spec = SH_WEBGL_SPEC;
307
ShShaderOutput output = SH_ESSL_OUTPUT;
308
ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
309
ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
310
311
// Test call stack under the limit passes.
312
EXPECT_TRUE(CheckShaderCompilation(
313
vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth - 10).c_str(),
314
compileOptions, nullptr));
315
// Test call stack over the limit fails.
316
EXPECT_TRUE(CheckShaderCompilation(
317
vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),
318
compileOptions, kCallStackTooDeep));
319
// Test call stack over the limit without limit does not fail.
320
EXPECT_TRUE(CheckShaderCompilation(
321
vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),
322
compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, nullptr));
323
sh::Destruct(vertexCompiler);
324
}
325
326
TEST_F(ExpressionLimitTest, UnusedCallStackDepth)
327
{
328
ShShaderSpec spec = SH_WEBGL_SPEC;
329
ShShaderOutput output = SH_ESSL_OUTPUT;
330
ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
331
ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
332
333
// Test call stack under the limit passes.
334
EXPECT_TRUE(CheckShaderCompilation(
335
vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth - 10).c_str(),
336
compileOptions, nullptr));
337
// Test call stack over the limit fails.
338
EXPECT_TRUE(CheckShaderCompilation(
339
vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),
340
compileOptions, kCallStackTooDeep));
341
// Test call stack over the limit without limit does not fail.
342
EXPECT_TRUE(CheckShaderCompilation(
343
vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),
344
compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, nullptr));
345
sh::Destruct(vertexCompiler);
346
}
347
348
TEST_F(ExpressionLimitTest, Recursion)
349
{
350
ShShaderSpec spec = SH_WEBGL_SPEC;
351
ShShaderOutput output = SH_ESSL_OUTPUT;
352
ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
353
ShCompileOptions compileOptions = 0;
354
355
static const char *shaderWithRecursion0 =
356
R"(precision mediump float;
357
uniform vec4 u_color;
358
vec4 someFunc() {
359
return someFunc();
360
}
361
362
void main() {
363
gl_FragColor = u_color * someFunc();
364
}
365
)";
366
367
static const char *shaderWithRecursion1 =
368
R"(precision mediump float;
369
uniform vec4 u_color;
370
371
vec4 someFunc();
372
373
vec4 someFunc1() {
374
return someFunc();
375
}
376
377
vec4 someFunc() {
378
return someFunc1();
379
}
380
381
void main() {
382
gl_FragColor = u_color * someFunc();
383
}
384
)";
385
386
static const char *shaderWithRecursion2 =
387
R"(precision mediump float;
388
uniform vec4 u_color;
389
vec4 someFunc() {
390
if (u_color.x > 0.5) {
391
return someFunc();
392
} else {
393
return vec4(1);
394
}
395
}
396
397
void main() {
398
gl_FragColor = someFunc();
399
}
400
)";
401
402
static const char *shaderWithRecursion3 =
403
R"(precision mediump float;
404
uniform vec4 u_color;
405
vec4 someFunc() {
406
if (u_color.x > 0.5) {
407
return vec4(1);
408
} else {
409
return someFunc();
410
}
411
}
412
413
void main() {
414
gl_FragColor = someFunc();
415
}
416
)";
417
418
static const char *shaderWithRecursion4 =
419
R"(precision mediump float;
420
uniform vec4 u_color;
421
vec4 someFunc() {
422
return (u_color.x > 0.5) ? vec4(1) : someFunc();
423
}
424
425
void main() {
426
gl_FragColor = someFunc();
427
}
428
)";
429
430
static const char *shaderWithRecursion5 =
431
R"(precision mediump float;
432
uniform vec4 u_color;
433
vec4 someFunc() {
434
return (u_color.x > 0.5) ? someFunc() : vec4(1);
435
}
436
437
void main() {
438
gl_FragColor = someFunc();
439
}
440
)";
441
442
static const char *shaderWithRecursion6 =
443
R"(precision mediump float;
444
uniform vec4 u_color;
445
vec4 someFunc() {
446
return someFunc();
447
}
448
449
void main() {
450
gl_FragColor = u_color;
451
}
452
)";
453
454
static const char *shaderWithNoRecursion =
455
R"(precision mediump float;
456
uniform vec4 u_color;
457
458
vec3 rgb(int r, int g, int b) {
459
return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
460
}
461
462
void main() {
463
vec3 hairColor0 = rgb(151, 200, 234);
464
vec3 faceColor2 = rgb(183, 148, 133);
465
gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);
466
}
467
)";
468
469
static const char *shaderWithRecursion7 =
470
R"(precision mediump float;
471
uniform vec4 u_color;
472
473
vec4 function2() {
474
return u_color;
475
}
476
477
vec4 function1() {
478
vec4 a = function2();
479
vec4 b = function1();
480
return a + b;
481
}
482
483
void main() {
484
gl_FragColor = function1();
485
}
486
)";
487
488
static const char *shaderWithRecursion8 =
489
R"(precision mediump float;
490
uniform vec4 u_color;
491
492
vec4 function1();
493
494
vec4 function3() {
495
return function1();
496
}
497
498
vec4 function2() {
499
return function3();
500
}
501
502
vec4 function1() {
503
return function2();
504
}
505
506
void main() {
507
gl_FragColor = function1();
508
}
509
)";
510
511
// Check simple recursions fails.
512
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion0, compileOptions,
513
kHasRecursion));
514
// Check simple recursions fails.
515
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion1, compileOptions,
516
kHasRecursion));
517
// Check if recursions fails.
518
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion2, compileOptions,
519
kHasRecursion));
520
// Check if recursions fails.
521
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion3, compileOptions,
522
kHasRecursion));
523
// Check ternary recursions fails.
524
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion4, compileOptions,
525
kHasRecursion));
526
// Check ternary recursions fails.
527
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion5, compileOptions,
528
kHasRecursion));
529
530
// Check some more forms of recursion
531
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion6, compileOptions,
532
kHasRecursion));
533
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion7, compileOptions,
534
kHasRecursion));
535
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion8, compileOptions,
536
kHasRecursion));
537
// Check unused recursions fails if limiting call stack
538
// since we check all paths.
539
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion6,
540
compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));
541
542
// Check unused recursions passes.
543
EXPECT_TRUE(
544
CheckShaderCompilation(vertexCompiler, shaderWithNoRecursion, compileOptions, nullptr));
545
// Check unused recursions passes if limiting call stack.
546
EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithNoRecursion,
547
compileOptions | SH_LIMIT_CALL_STACK_DEPTH, nullptr));
548
sh::Destruct(vertexCompiler);
549
}
550
551
TEST_F(ExpressionLimitTest, FunctionParameterCount)
552
{
553
ShShaderSpec spec = SH_WEBGL_SPEC;
554
ShShaderOutput output = SH_ESSL_OUTPUT;
555
ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
556
ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
557
558
// Test parameters under the limit succeeds.
559
EXPECT_TRUE(CheckShaderCompilation(
560
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters).c_str(),
561
compileOptions, nullptr));
562
// Test parameters over the limit fails.
563
EXPECT_TRUE(CheckShaderCompilation(
564
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),
565
compileOptions, kTooManyParameters));
566
// Test parameters over the limit without limit does not fail.
567
EXPECT_TRUE(CheckShaderCompilation(
568
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),
569
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
570
sh::Destruct(compiler);
571
}
572
573
TEST_F(ExpressionLimitTest, NestingInsideSwitch)
574
{
575
ShShaderSpec spec = SH_WEBGL2_SPEC;
576
ShShaderOutput output = SH_ESSL_OUTPUT;
577
ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
578
ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
579
580
// Test nesting over the limit fails.
581
EXPECT_TRUE(CheckShaderCompilation(
582
compiler, GenerateShaderWithNestingInsideSwitch(kMaxExpressionComplexity + 1).c_str(),
583
compileOptions, kExpressionTooComplex));
584
// Test nesting over the limit without limit does not fail.
585
EXPECT_TRUE(CheckShaderCompilation(
586
compiler, GenerateShaderWithNestingInsideSwitch(kMaxExpressionComplexity + 1).c_str(),
587
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
588
// Test that nesting way over the limit doesn't cause stack overflow but is handled
589
// gracefully.
590
EXPECT_TRUE(CheckShaderCompilation(compiler,
591
GenerateShaderWithNestingInsideSwitch(5000).c_str(),
592
compileOptions, kTooComplexSwitch));
593
sh::Destruct(compiler);
594
}
595
596
TEST_F(ExpressionLimitTest, NestingInsideGlobalInitializer)
597
{
598
ShShaderSpec spec = SH_WEBGL_SPEC;
599
ShShaderOutput output = SH_ESSL_OUTPUT;
600
ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
601
ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
602
603
// Test nesting over the limit fails.
604
EXPECT_TRUE(CheckShaderCompilation(
605
compiler,
606
GenerateShaderWithNestingInsideGlobalInitializer(kMaxExpressionComplexity + 1).c_str(),
607
compileOptions, kExpressionTooComplex));
608
// Test nesting over the limit without limit does not fail.
609
EXPECT_TRUE(CheckShaderCompilation(
610
compiler,
611
GenerateShaderWithNestingInsideGlobalInitializer(kMaxExpressionComplexity + 1).c_str(),
612
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
613
// Test that nesting way over the limit doesn't cause stack overflow but is handled
614
// gracefully.
615
EXPECT_TRUE(CheckShaderCompilation(
616
compiler, GenerateShaderWithNestingInsideGlobalInitializer(5000).c_str(), compileOptions,
617
kGlobalVariableInit));
618
sh::Destruct(compiler);
619
}
620
621