1 //
2 // Copyright 2018 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 // CompilerPerfTest:
7 // Performance test for the shader translator. The test initializes the compiler once and then
8 // compiles the same shader repeatedly. There are different variations of the tests using
9 // different shaders.
10 //
11
12 #include "ANGLEPerfTest.h"
13
14 #include "GLSLANG/ShaderLang.h"
15 #include "compiler/translator/Compiler.h"
16 #include "compiler/translator/InitializeGlobals.h"
17 #include "compiler/translator/PoolAlloc.h"
18
19 namespace
20 {
21
22 const char *kSimpleESSL100FragSource = R"(
23 precision mediump float;
24 void main()
25 {
26 gl_FragColor = vec4(0, 1, 0, 1);
27 }
28 )";
29
30 const char *kSimpleESSL100Id = "SimpleESSL100";
31
32 const char *kSimpleESSL300FragSource = R"(#version 300 es
33 precision highp float;
34 out vec4 outColor;
35 void main()
36 {
37 outColor = vec4(0, 1, 0, 1);
38 }
39 )";
40
41 const char *kSimpleESSL300Id = "SimpleESSL300";
42
43 const char *kRealWorldESSL100FragSource = R"(precision highp float;
44 precision highp sampler2D;
45 precision highp int;
46 varying vec2 vPixelCoords; // in pixels
47 uniform int uCircleCount;
48 uniform sampler2D uCircleParameters;
49 uniform sampler2D uBrushTex;
50 void main(void)
51 {
52 float destAlpha = 0.0;
53 for (int i = 0; i < 32; ++i)
54 {
55 vec4 parameterColor = texture2D(uCircleParameters,vec2(0.25, (float(i) + 0.5) / 32.0));
56 vec2 center = parameterColor.xy;
57 float circleRadius = parameterColor.z;
58 float circleFlowAlpha = parameterColor.w;
59 vec4 parameterColor2 = texture2D(uCircleParameters,vec2(0.75, (float(i) + 0.5) / 32.0));
60 float circleRotation = parameterColor2.x;
61 vec2 centerDiff = vPixelCoords - center;
62 float radius = max(circleRadius, 0.5);
63 float flowAlpha = (circleRadius < 0.5) ? circleFlowAlpha * circleRadius * circleRadius * 4.0: circleFlowAlpha;
64 float antialiasMult = clamp((radius + 1.0 - length(centerDiff)) * 0.5, 0.0, 1.0);
65 mat2 texRotation = mat2(cos(circleRotation), -sin(circleRotation), sin(circleRotation), cos(circleRotation));
66 vec2 texCoords = texRotation * centerDiff / radius * 0.5 + 0.5;
67 float texValue = texture2D(uBrushTex, texCoords).r;
68 float circleAlpha = flowAlpha * antialiasMult * texValue;
69 if (i < uCircleCount)
70 {
71 destAlpha = clamp(circleAlpha + (1.0 - circleAlpha) * destAlpha, 0.0, 1.0);
72 }
73 }
74 gl_FragColor = vec4(0.0, 0.0, 0.0, destAlpha);
75 })";
76
77 const char *kRealWorldESSL100Id = "RealWorldESSL100";
78
79 // This shader is intended to trigger many AST transformations, particularly on the HLSL backend.
80 const char *kTrickyESSL300FragSource = R"(#version 300 es
81 precision highp float;
82 precision highp sampler2D;
83 precision highp isampler2D;
84 precision highp int;
85
86 float globalF;
87
88 uniform ivec4 uivec;
89 uniform int ui;
90
91 struct SS
92 {
93 int iField;
94 float fField;
95 vec2 f2Field;
96 sampler2D sField;
97 isampler2D isField;
98 };
99 uniform SS us;
100
101 out vec4 my_FragColor;
102
103 float[3] sideEffectArray()
104 {
105 globalF += 1.0;
106 return float[3](globalF, globalF * 2.0, globalF * 3.0);
107 }
108
109 // This struct is unused and can be pruned.
110 struct SUnused
111 {
112 vec2 fField;
113 };
114
115 void main()
116 {
117 struct S2
118 {
119 float fField;
120 } s2;
121 vec4 foo = vec4(ui);
122 mat4 fooM = mat4(foo.x);
123
124 // Some unused variables that can be pruned.
125 float fUnused, fUnused2;
126 ivec4 iUnused, iUnused2;
127
128 globalF = us.fField;
129 s2.fField = us.fField;
130
131 float[3] fa = sideEffectArray();
132
133 globalF -= us.fField;
134 if (fa == sideEffectArray())
135 {
136 globalF += us.fField * sin(2.0);
137 }
138
139 // Switch with fall-through.
140 switch (ui)
141 {
142 case 0:
143 // Sequence operator and matrix and vector dynamic indexing.
144 (globalF += 1.0, fooM[ui][ui] += fooM[ui - 1][uivec[ui] + 1]);
145 case 1:
146 // Built-in emulation.
147 foo[3] = tanh(foo[1]);
148 default:
149 // Sequence operator and length of an array expression with side effects.
150 foo[2] += (globalF -= 1.0, float((sideEffectArray()).length() * 2));
151 }
152 int i = 0;
153 do
154 {
155 s2.fField = us.fField * us.f2Field.x;
156 // Sequence operator and short-circuiting operator with side effects on the right hand side.
157 } while ((++i, i < int(us.fField) && ++i <= ui || ++i < ui * 2 - 3));
158 // Samplers in structures and integer texture sampling.
159 foo += texture(us.sField, us.f2Field) + intBitsToFloat(texture(us.isField, us.f2Field + 4.0));
160 my_FragColor = foo * s2.fField * globalF + fooM[ui];
161 })";
162
163 const char *kTrickyESSL300Id = "TrickyESSL300";
164
165 constexpr int kNumIterationsPerStep = 4;
166
167 struct CompilerParameters
168 {
CompilerParameters__anone5dac2730111::CompilerParameters169 CompilerParameters() { output = SH_HLSL_4_1_OUTPUT; }
170
CompilerParameters__anone5dac2730111::CompilerParameters171 CompilerParameters(ShShaderOutput output) : output(output) {}
172
str__anone5dac2730111::CompilerParameters173 const char *str() const
174 {
175 switch (output)
176 {
177 case SH_HLSL_4_1_OUTPUT:
178 return "HLSL_4_1";
179 case SH_GLSL_450_CORE_OUTPUT:
180 return "GLSL_4_50";
181 case SH_ESSL_OUTPUT:
182 return "ESSL";
183 default:
184 UNREACHABLE();
185 return "unk";
186 }
187 }
188
189 ShShaderOutput output;
190 };
191
IsPlatformAvailable(const CompilerParameters & param)192 bool IsPlatformAvailable(const CompilerParameters ¶m)
193 {
194 switch (param.output)
195 {
196 case SH_HLSL_4_1_OUTPUT:
197 case SH_HLSL_3_0_OUTPUT:
198 {
199 angle::PoolAllocator allocator;
200 InitializePoolIndex();
201 allocator.push();
202 SetGlobalPoolAllocator(&allocator);
203 ShHandle translator =
204 sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL2_SPEC, param.output);
205 bool success = translator != nullptr;
206 SetGlobalPoolAllocator(nullptr);
207 allocator.pop();
208 FreePoolIndex();
209 if (!success)
210 {
211 return false;
212 }
213 break;
214 }
215 case SH_HLSL_4_0_FL9_3_OUTPUT:
216 return false;
217 default:
218 break;
219 }
220 return true;
221 }
222
223 struct CompilerPerfParameters final : public CompilerParameters
224 {
CompilerPerfParameters__anone5dac2730111::CompilerPerfParameters225 CompilerPerfParameters(ShShaderOutput output,
226 const char *shaderSource,
227 const char *shaderSourceId)
228 : CompilerParameters(output), shaderSource(shaderSource)
229 {
230 testId = shaderSourceId;
231 testId += "_";
232 testId += CompilerParameters::str();
233 }
234
235 const char *shaderSource;
236 std::string testId;
237 };
238
operator <<(std::ostream & stream,const CompilerPerfParameters & p)239 std::ostream &operator<<(std::ostream &stream, const CompilerPerfParameters &p)
240 {
241 stream << p.testId;
242 return stream;
243 }
244
245 class CompilerPerfTest : public ANGLEPerfTest,
246 public ::testing::WithParamInterface<CompilerPerfParameters>
247 {
248 public:
249 CompilerPerfTest();
250
251 void step() override;
252
253 void SetUp() override;
254 void TearDown() override;
255
256 protected:
setTestShader(const char * str)257 void setTestShader(const char *str) { mTestShader = str; }
258
259 private:
260 const char *mTestShader;
261
262 ShBuiltInResources mResources;
263 angle::PoolAllocator mAllocator;
264 sh::TCompiler *mTranslator;
265 };
266
CompilerPerfTest()267 CompilerPerfTest::CompilerPerfTest()
268 : ANGLEPerfTest("CompilerPerf", "", GetParam().testId, kNumIterationsPerStep)
269 {}
270
SetUp()271 void CompilerPerfTest::SetUp()
272 {
273 ANGLEPerfTest::SetUp();
274
275 InitializePoolIndex();
276 mAllocator.push();
277 SetGlobalPoolAllocator(&mAllocator);
278
279 const auto ¶ms = GetParam();
280
281 mTranslator = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL2_SPEC, params.output);
282 sh::InitBuiltInResources(&mResources);
283 mResources.FragmentPrecisionHigh = true;
284 if (!mTranslator->Init(mResources))
285 {
286 SafeDelete(mTranslator);
287 }
288
289 setTestShader(params.shaderSource);
290 }
291
TearDown()292 void CompilerPerfTest::TearDown()
293 {
294 SafeDelete(mTranslator);
295
296 SetGlobalPoolAllocator(nullptr);
297 mAllocator.pop();
298
299 FreePoolIndex();
300
301 ANGLEPerfTest::TearDown();
302 }
303
step()304 void CompilerPerfTest::step()
305 {
306 const char *shaderStrings[] = {mTestShader};
307
308 ShCompileOptions compileOptions = SH_OBJECT_CODE | SH_VARIABLES |
309 SH_INITIALIZE_UNINITIALIZED_LOCALS | SH_INIT_OUTPUT_VARIABLES;
310
311 #if !defined(NDEBUG)
312 // Make sure that compilation succeeds and print the info log if it doesn't in debug mode.
313 if (!mTranslator->compile(shaderStrings, 1, compileOptions))
314 {
315 std::cout << "Compiling perf test shader failed with log:\n"
316 << mTranslator->getInfoSink().info.c_str();
317 }
318 #endif
319
320 for (unsigned int iteration = 0; iteration < kNumIterationsPerStep; ++iteration)
321 {
322 mTranslator->compile(shaderStrings, 1, compileOptions);
323 }
324 }
325
TEST_P(CompilerPerfTest,Run)326 TEST_P(CompilerPerfTest, Run)
327 {
328 run();
329 }
330
331 ANGLE_INSTANTIATE_TEST(
332 CompilerPerfTest,
333 CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
334 CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
335 CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kRealWorldESSL100FragSource, kRealWorldESSL100Id),
336 CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id),
337 CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
338 CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
339 CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT,
340 kRealWorldESSL100FragSource,
341 kRealWorldESSL100Id),
342 CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id),
343 CompilerPerfParameters(SH_ESSL_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
344 CompilerPerfParameters(SH_ESSL_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
345 CompilerPerfParameters(SH_ESSL_OUTPUT, kRealWorldESSL100FragSource, kRealWorldESSL100Id),
346 CompilerPerfParameters(SH_ESSL_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id));
347
348 } // anonymous namespace
349