xref: /aosp_15_r20/external/angle/src/tests/perf_tests/CompilerPerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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__anonc1b4337d0111::CompilerParameters169     CompilerParameters() { output = SH_HLSL_4_1_OUTPUT; }
170 
CompilerParameters__anonc1b4337d0111::CompilerParameters171     CompilerParameters(ShShaderOutput output) : output(output) {}
172 
str__anonc1b4337d0111::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 &param)
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         default:
216             break;
217     }
218     return true;
219 }
220 
221 struct CompilerPerfParameters final : public CompilerParameters
222 {
CompilerPerfParameters__anonc1b4337d0111::CompilerPerfParameters223     CompilerPerfParameters(ShShaderOutput output,
224                            const char *shaderSource,
225                            const char *shaderSourceId)
226         : CompilerParameters(output), shaderSource(shaderSource)
227     {
228         testId = shaderSourceId;
229         testId += "_";
230         testId += CompilerParameters::str();
231     }
232 
233     const char *shaderSource;
234     std::string testId;
235 };
236 
operator <<(std::ostream & stream,const CompilerPerfParameters & p)237 std::ostream &operator<<(std::ostream &stream, const CompilerPerfParameters &p)
238 {
239     stream << p.testId;
240     return stream;
241 }
242 
243 class CompilerPerfTest : public ANGLEPerfTest,
244                          public ::testing::WithParamInterface<CompilerPerfParameters>
245 {
246   public:
247     CompilerPerfTest();
248 
249     void step() override;
250 
251     void SetUp() override;
252     void TearDown() override;
253 
254   protected:
setTestShader(const char * str)255     void setTestShader(const char *str) { mTestShader = str; }
256 
257   private:
258     const char *mTestShader;
259 
260     ShBuiltInResources mResources;
261     angle::PoolAllocator mAllocator;
262     sh::TCompiler *mTranslator;
263 };
264 
CompilerPerfTest()265 CompilerPerfTest::CompilerPerfTest()
266     : ANGLEPerfTest("CompilerPerf", "", GetParam().testId, kNumIterationsPerStep)
267 {}
268 
SetUp()269 void CompilerPerfTest::SetUp()
270 {
271     ANGLEPerfTest::SetUp();
272 
273     InitializePoolIndex();
274     mAllocator.push();
275     SetGlobalPoolAllocator(&mAllocator);
276 
277     const auto &params = GetParam();
278 
279     mTranslator = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL2_SPEC, params.output);
280     sh::InitBuiltInResources(&mResources);
281     mResources.FragmentPrecisionHigh = true;
282     if (!mTranslator->Init(mResources))
283     {
284         SafeDelete(mTranslator);
285     }
286 
287     setTestShader(params.shaderSource);
288 }
289 
TearDown()290 void CompilerPerfTest::TearDown()
291 {
292     SafeDelete(mTranslator);
293 
294     SetGlobalPoolAllocator(nullptr);
295     mAllocator.pop();
296 
297     FreePoolIndex();
298 
299     ANGLEPerfTest::TearDown();
300 }
301 
step()302 void CompilerPerfTest::step()
303 {
304     const char *shaderStrings[] = {mTestShader};
305 
306     ShCompileOptions compileOptions              = {};
307     compileOptions.objectCode                    = true;
308     compileOptions.initializeUninitializedLocals = true;
309     compileOptions.initOutputVariables           = true;
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