0%

MaliCompiler

引言

在智能手机专用的SoC(处理器)领域,最常见的GPU品牌就是高通Adreno、Imagination PowerVR以及ARM Mali。对于目前市面上主流手机中华为,三星,谷歌等手机较多均使用Mali GPU架构进行研发。

图片来源:https://www.eet-china.com/news/202112160927.html

所以在手游研发中,TA更加关注在Mali GPU架构下材质的性能消耗。

所以本文主要记录自己使用mali compiler 检测 Unity shader的代码逻辑复杂度及mali compiler的相关指数及shader优化建议。

下载arm Developer

Mali Offline Compiler | Mali Offline Compiler Legacy Downloads - Arm Developer

在Unity中导出shader

选择shader,设置GLES3x的格式进行编译

将shader进行拆分为vert frag

将#ifdef VERTEX到#endif之间的代码复制出来保存到vertex,Note:#version 300 es 必须放在第一行。(不要带上def)

vert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#version 300 es

#define HLSLCC_ENABLE_UNIFORM_BUFFERS 1
#if HLSLCC_ENABLE_UNIFORM_BUFFERS
#define UNITY_UNIFORM
#else
#define UNITY_UNIFORM uniform
#endif
#define UNITY_SUPPORTS_UNIFORM_LOCATION 1
#if UNITY_SUPPORTS_UNIFORM_LOCATION
#define UNITY_LOCATION(x) layout(location = x)
#define UNITY_BINDING(x) layout(binding = x, std140)
#else
#define UNITY_LOCATION(x)
#define UNITY_BINDING(x) layout(std140)
#endif
uniform vec3 _WorldSpaceCameraPos;
uniform vec4 hlslcc_mtx4x4unity_ObjectToWorld[4];
uniform vec4 hlslcc_mtx4x4unity_WorldToObject[4];
uniform vec4 hlslcc_mtx4x4unity_MatrixVP[4];
uniform vec4 _MainTex_ST;
uniform vec4 _DetailAlbedoMap_ST;
uniform mediump float _UVSec;
in highp vec4 in_POSITION0;
in mediump vec3 in_NORMAL0;
in highp vec2 in_TEXCOORD0;
in highp vec2 in_TEXCOORD1;
out highp vec4 vs_TEXCOORD0;
out highp vec4 vs_TEXCOORD1;
out highp vec4 vs_TEXCOORD2;
out highp vec4 vs_TEXCOORD3;
out highp vec4 vs_TEXCOORD4;
out mediump vec4 vs_TEXCOORD5;
out highp vec4 vs_TEXCOORD7;
out highp vec3 vs_TEXCOORD8;
vec4 u_xlat0;
bool u_xlatb0;
vec4 u_xlat1;
float u_xlat6;
void main()
{
u_xlat0 = in_POSITION0.yyyy * hlslcc_mtx4x4unity_ObjectToWorld[1];
u_xlat0 = hlslcc_mtx4x4unity_ObjectToWorld[0] * in_POSITION0.xxxx + u_xlat0;
u_xlat0 = hlslcc_mtx4x4unity_ObjectToWorld[2] * in_POSITION0.zzzz + u_xlat0;
u_xlat0 = u_xlat0 + hlslcc_mtx4x4unity_ObjectToWorld[3];
u_xlat1 = u_xlat0.yyyy * hlslcc_mtx4x4unity_MatrixVP[1];
u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[0] * u_xlat0.xxxx + u_xlat1;
u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[2] * u_xlat0.zzzz + u_xlat1;
gl_Position = hlslcc_mtx4x4unity_MatrixVP[3] * u_xlat0.wwww + u_xlat1;
#ifdef UNITY_ADRENO_ES3
u_xlatb0 = !!(_UVSec==0.0);
#else
u_xlatb0 = _UVSec==0.0;
#endif
u_xlat0.xy = (bool(u_xlatb0)) ? in_TEXCOORD0.xy : in_TEXCOORD1.xy;
vs_TEXCOORD0.zw = u_xlat0.xy * _DetailAlbedoMap_ST.xy + _DetailAlbedoMap_ST.zw;
vs_TEXCOORD0.xy = in_TEXCOORD0.xy * _MainTex_ST.xy + _MainTex_ST.zw;
u_xlat0.xyz = in_POSITION0.yyy * hlslcc_mtx4x4unity_ObjectToWorld[1].xyz;
u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[0].xyz * in_POSITION0.xxx + u_xlat0.xyz;
u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[2].xyz * in_POSITION0.zzz + u_xlat0.xyz;
u_xlat0.xyz = hlslcc_mtx4x4unity_ObjectToWorld[3].xyz * in_POSITION0.www + u_xlat0.xyz;
vs_TEXCOORD1.xyz = u_xlat0.xyz + (-_WorldSpaceCameraPos.xyz);
vs_TEXCOORD8.xyz = u_xlat0.xyz;
vs_TEXCOORD1.w = 0.0;
vs_TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0);
vs_TEXCOORD3 = vec4(0.0, 0.0, 0.0, 0.0);
u_xlat0.x = dot(in_NORMAL0.xyz, hlslcc_mtx4x4unity_WorldToObject[0].xyz);
u_xlat0.y = dot(in_NORMAL0.xyz, hlslcc_mtx4x4unity_WorldToObject[1].xyz);
u_xlat0.z = dot(in_NORMAL0.xyz, hlslcc_mtx4x4unity_WorldToObject[2].xyz);
u_xlat6 = dot(u_xlat0.xyz, u_xlat0.xyz);
u_xlat6 = inversesqrt(u_xlat6);
vs_TEXCOORD4.xyz = vec3(u_xlat6) * u_xlat0.xyz;
vs_TEXCOORD4.w = 0.0;
vs_TEXCOORD5 = vec4(0.0, 0.0, 0.0, 0.0);
vs_TEXCOORD7 = vec4(0.0, 0.0, 0.0, 0.0);
return;
}

frag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#version 300 es
#ifdef GL_EXT_shader_texture_lod
#extension GL_EXT_shader_texture_lod : enable
#endif

precision highp float;
precision highp int;
#define HLSLCC_ENABLE_UNIFORM_BUFFERS 1
#if HLSLCC_ENABLE_UNIFORM_BUFFERS
#define UNITY_UNIFORM
#else
#define UNITY_UNIFORM uniform
#endif
#define UNITY_SUPPORTS_UNIFORM_LOCATION 1
#if UNITY_SUPPORTS_UNIFORM_LOCATION
#define UNITY_LOCATION(x) layout(location = x)
#define UNITY_BINDING(x) layout(binding = x, std140)
#else
#define UNITY_LOCATION(x)
#define UNITY_BINDING(x) layout(std140)
#endif
uniform mediump vec4 _WorldSpaceLightPos0;
uniform vec4 unity_SpecCube0_BoxMax;
uniform vec4 unity_SpecCube0_BoxMin;
uniform vec4 unity_SpecCube0_ProbePosition;
uniform mediump vec4 unity_SpecCube0_HDR;
uniform vec4 unity_SpecCube1_BoxMax;
uniform vec4 unity_SpecCube1_BoxMin;
uniform vec4 unity_SpecCube1_ProbePosition;
uniform mediump vec4 unity_SpecCube1_HDR;
uniform mediump vec4 _LightColor0;
uniform mediump vec4 _Color;
uniform mediump float _Metallic;
uniform float _Glossiness;
uniform mediump float _OcclusionStrength;
UNITY_LOCATION(0) uniform mediump sampler2D _MainTex;
UNITY_LOCATION(1) uniform mediump sampler2D _OcclusionMap;
UNITY_LOCATION(2) uniform mediump samplerCube unity_SpecCube0;
UNITY_LOCATION(3) uniform mediump samplerCube unity_SpecCube1;
in highp vec4 vs_TEXCOORD0;
in highp vec4 vs_TEXCOORD1;
in highp vec4 vs_TEXCOORD4;
in highp vec3 vs_TEXCOORD8;
layout(location = 0) out mediump vec4 SV_Target0;
vec3 u_xlat0;
mediump vec3 u_xlat16_0;
vec3 u_xlat1;
bool u_xlatb1;
mediump vec3 u_xlat16_2;
mediump vec3 u_xlat16_3;
mediump vec4 u_xlat16_4;
vec3 u_xlat5;
mediump vec4 u_xlat16_5;
bool u_xlatb5;
vec3 u_xlat6;
vec3 u_xlat7;
vec3 u_xlat8;
bvec3 u_xlatb8;
mediump vec3 u_xlat16_9;
bvec3 u_xlatb10;
mediump vec3 u_xlat16_11;
mediump vec3 u_xlat16_12;
float u_xlat13;
float u_xlat14;
vec3 u_xlat22;
mediump vec3 u_xlat16_22;
mediump vec3 u_xlat16_24;
float u_xlat26;
float u_xlat27;
float u_xlat39;
float u_xlat40;
mediump float u_xlat16_40;
mediump float u_xlat16_41;
mediump float u_xlat16_42;
mediump float u_xlat16_43;
float u_xlat44;
bool u_xlatb44;
mediump float u_xlat16_48;
void main()
{
u_xlat16_0.xyz = texture(_MainTex, vs_TEXCOORD0.xy).xyz;
u_xlat1.xyz = u_xlat16_0.xyz * _Color.xyz;
u_xlat16_2.xyz = _Color.xyz * u_xlat16_0.xyz + vec3(-0.0399999991, -0.0399999991, -0.0399999991);
u_xlat16_2.xyz = vec3(vec3(_Metallic, _Metallic, _Metallic)) * u_xlat16_2.xyz + vec3(0.0399999991, 0.0399999991, 0.0399999991);
u_xlat16_41 = (-_Metallic) * 0.959999979 + 0.959999979;
u_xlat16_3.xyz = u_xlat1.xyz * vec3(u_xlat16_41);
u_xlat0.x = dot(vs_TEXCOORD4.xyz, vs_TEXCOORD4.xyz);
u_xlat0.x = inversesqrt(u_xlat0.x);
u_xlat0.xyz = u_xlat0.xxx * vs_TEXCOORD4.xyz;
u_xlat39 = dot(vs_TEXCOORD1.xyz, vs_TEXCOORD1.xyz);
u_xlat39 = inversesqrt(u_xlat39);
u_xlat1.xyz = vec3(u_xlat39) * vs_TEXCOORD1.xyz;
u_xlat16_40 = texture(_OcclusionMap, vs_TEXCOORD0.xy).y;
u_xlat16_42 = (-_OcclusionStrength) + 1.0;
u_xlat16_42 = u_xlat16_40 * _OcclusionStrength + u_xlat16_42;
u_xlat40 = (-_Glossiness) + 1.0;
u_xlat16_4.x = dot(u_xlat1.xyz, u_xlat0.xyz);
u_xlat16_4.x = u_xlat16_4.x + u_xlat16_4.x;
u_xlat16_4.xyz = u_xlat0.xyz * (-u_xlat16_4.xxx) + u_xlat1.xyz;
#ifdef UNITY_ADRENO_ES3
u_xlatb5 = !!(0.0<unity_SpecCube0_ProbePosition.w);
#else
u_xlatb5 = 0.0<unity_SpecCube0_ProbePosition.w;
#endif
if(u_xlatb5){
u_xlat5.x = dot(u_xlat16_4.xyz, u_xlat16_4.xyz);
u_xlat5.x = inversesqrt(u_xlat5.x);
u_xlat5.xyz = u_xlat16_4.xyz * u_xlat5.xxx;
u_xlat6.xyz = (-vs_TEXCOORD8.xyz) + unity_SpecCube0_BoxMax.xyz;
u_xlat6.xyz = u_xlat6.xyz / u_xlat5.xyz;
u_xlat7.xyz = (-vs_TEXCOORD8.xyz) + unity_SpecCube0_BoxMin.xyz;
u_xlat7.xyz = u_xlat7.xyz / u_xlat5.xyz;
u_xlatb8.xyz = lessThan(vec4(0.0, 0.0, 0.0, 0.0), u_xlat5.xyzx).xyz;
{
vec3 hlslcc_movcTemp = u_xlat6;
hlslcc_movcTemp.x = (u_xlatb8.x) ? u_xlat6.x : u_xlat7.x;
hlslcc_movcTemp.y = (u_xlatb8.y) ? u_xlat6.y : u_xlat7.y;
hlslcc_movcTemp.z = (u_xlatb8.z) ? u_xlat6.z : u_xlat7.z;
u_xlat6 = hlslcc_movcTemp;
}
u_xlat44 = min(u_xlat6.y, u_xlat6.x);
u_xlat44 = min(u_xlat6.z, u_xlat44);
u_xlat6.xyz = vs_TEXCOORD8.xyz + (-unity_SpecCube0_ProbePosition.xyz);
u_xlat5.xyz = u_xlat5.xyz * vec3(u_xlat44) + u_xlat6.xyz;
} else {
u_xlat5.xyz = u_xlat16_4.xyz;
}
u_xlat16_43 = (-u_xlat40) * 0.699999988 + 1.70000005;
u_xlat16_43 = u_xlat40 * u_xlat16_43;
u_xlat16_43 = u_xlat16_43 * 6.0;
u_xlat16_5 = textureLod(unity_SpecCube0, u_xlat5.xyz, u_xlat16_43);
u_xlat16_9.x = u_xlat16_5.w + -1.0;
u_xlat16_9.x = unity_SpecCube0_HDR.w * u_xlat16_9.x + 1.0;
u_xlat16_9.x = log2(u_xlat16_9.x);
u_xlat16_9.x = u_xlat16_9.x * unity_SpecCube0_HDR.y;
u_xlat16_9.x = exp2(u_xlat16_9.x);
u_xlat16_9.x = u_xlat16_9.x * unity_SpecCube0_HDR.x;
u_xlat16_22.xyz = u_xlat16_5.xyz * u_xlat16_9.xxx;
#ifdef UNITY_ADRENO_ES3
u_xlatb44 = !!(unity_SpecCube0_BoxMin.w<0.999989986);
#else
u_xlatb44 = unity_SpecCube0_BoxMin.w<0.999989986;
#endif
if(u_xlatb44){
#ifdef UNITY_ADRENO_ES3
u_xlatb44 = !!(0.0<unity_SpecCube1_ProbePosition.w);
#else
u_xlatb44 = 0.0<unity_SpecCube1_ProbePosition.w;
#endif
if(u_xlatb44){
u_xlat44 = dot(u_xlat16_4.xyz, u_xlat16_4.xyz);
u_xlat44 = inversesqrt(u_xlat44);
u_xlat6.xyz = u_xlat16_4.xyz * vec3(u_xlat44);
u_xlat7.xyz = (-vs_TEXCOORD8.xyz) + unity_SpecCube1_BoxMax.xyz;
u_xlat7.xyz = u_xlat7.xyz / u_xlat6.xyz;
u_xlat8.xyz = (-vs_TEXCOORD8.xyz) + unity_SpecCube1_BoxMin.xyz;
u_xlat8.xyz = u_xlat8.xyz / u_xlat6.xyz;
u_xlatb10.xyz = lessThan(vec4(0.0, 0.0, 0.0, 0.0), u_xlat6.xyzx).xyz;
{
vec3 hlslcc_movcTemp = u_xlat7;
hlslcc_movcTemp.x = (u_xlatb10.x) ? u_xlat7.x : u_xlat8.x;
hlslcc_movcTemp.y = (u_xlatb10.y) ? u_xlat7.y : u_xlat8.y;
hlslcc_movcTemp.z = (u_xlatb10.z) ? u_xlat7.z : u_xlat8.z;
u_xlat7 = hlslcc_movcTemp;
}
u_xlat44 = min(u_xlat7.y, u_xlat7.x);
u_xlat44 = min(u_xlat7.z, u_xlat44);
u_xlat7.xyz = vs_TEXCOORD8.xyz + (-unity_SpecCube1_ProbePosition.xyz);
u_xlat6.xyz = u_xlat6.xyz * vec3(u_xlat44) + u_xlat7.xyz;
} else {
u_xlat6.xyz = u_xlat16_4.xyz;
}
u_xlat16_4 = textureLod(unity_SpecCube1, u_xlat6.xyz, u_xlat16_43);
u_xlat16_11.x = u_xlat16_4.w + -1.0;
u_xlat16_11.x = unity_SpecCube1_HDR.w * u_xlat16_11.x + 1.0;
u_xlat16_11.x = log2(u_xlat16_11.x);
u_xlat16_11.x = u_xlat16_11.x * unity_SpecCube1_HDR.y;
u_xlat16_11.x = exp2(u_xlat16_11.x);
u_xlat16_11.x = u_xlat16_11.x * unity_SpecCube1_HDR.x;
u_xlat16_11.xyz = u_xlat16_4.xyz * u_xlat16_11.xxx;
u_xlat5.xyz = u_xlat16_9.xxx * u_xlat16_5.xyz + (-u_xlat16_11.xyz);
u_xlat22.xyz = unity_SpecCube0_BoxMin.www * u_xlat5.xyz + u_xlat16_11.xyz;
u_xlat16_22.xyz = u_xlat22.xyz;
}
u_xlat16_9.xyz = vec3(u_xlat16_42) * u_xlat16_22.xyz;
u_xlat5.xyz = (-vs_TEXCOORD1.xyz) * vec3(u_xlat39) + _WorldSpaceLightPos0.xyz;
u_xlat39 = dot(u_xlat5.xyz, u_xlat5.xyz);
u_xlat39 = max(u_xlat39, 0.00100000005);
u_xlat39 = inversesqrt(u_xlat39);
u_xlat5.xyz = vec3(u_xlat39) * u_xlat5.xyz;
u_xlat39 = dot(u_xlat0.xyz, (-u_xlat1.xyz));
u_xlat1.x = dot(u_xlat0.xyz, _WorldSpaceLightPos0.xyz);
#ifdef UNITY_ADRENO_ES3
u_xlat1.x = min(max(u_xlat1.x, 0.0), 1.0);
#else
u_xlat1.x = clamp(u_xlat1.x, 0.0, 1.0);
#endif
u_xlat0.x = dot(u_xlat0.xyz, u_xlat5.xyz);
#ifdef UNITY_ADRENO_ES3
u_xlat0.x = min(max(u_xlat0.x, 0.0), 1.0);
#else
u_xlat0.x = clamp(u_xlat0.x, 0.0, 1.0);
#endif
u_xlat13 = dot(_WorldSpaceLightPos0.xyz, u_xlat5.xyz);
#ifdef UNITY_ADRENO_ES3
u_xlat13 = min(max(u_xlat13, 0.0), 1.0);
#else
u_xlat13 = clamp(u_xlat13, 0.0, 1.0);
#endif
u_xlat16_42 = u_xlat13 + u_xlat13;
u_xlat16_42 = u_xlat13 * u_xlat16_42;
u_xlat16_42 = u_xlat16_42 * u_xlat40 + -0.5;
u_xlat16_48 = (-u_xlat1.x) + 1.0;
u_xlat16_11.x = u_xlat16_48 * u_xlat16_48;
u_xlat16_11.x = u_xlat16_11.x * u_xlat16_11.x;
u_xlat16_48 = u_xlat16_48 * u_xlat16_11.x;
u_xlat16_48 = u_xlat16_42 * u_xlat16_48 + 1.0;
u_xlat16_11.x = -abs(u_xlat39) + 1.0;
u_xlat16_24.x = u_xlat16_11.x * u_xlat16_11.x;
u_xlat16_24.x = u_xlat16_24.x * u_xlat16_24.x;
u_xlat16_11.x = u_xlat16_11.x * u_xlat16_24.x;
u_xlat16_42 = u_xlat16_42 * u_xlat16_11.x + 1.0;
u_xlat16_42 = u_xlat16_42 * u_xlat16_48;
u_xlat26 = u_xlat1.x * u_xlat16_42;
u_xlat14 = u_xlat40 * u_xlat40;
u_xlat14 = max(u_xlat14, 0.00200000009);
u_xlat27 = (-u_xlat14) + 1.0;
u_xlat40 = abs(u_xlat39) * u_xlat27 + u_xlat14;
u_xlat27 = u_xlat1.x * u_xlat27 + u_xlat14;
u_xlat39 = abs(u_xlat39) * u_xlat27;
u_xlat39 = u_xlat1.x * u_xlat40 + u_xlat39;
u_xlat39 = u_xlat39 + 9.99999975e-06;
u_xlat39 = 0.5 / u_xlat39;
u_xlat27 = u_xlat14 * u_xlat14;
u_xlat40 = u_xlat0.x * u_xlat27 + (-u_xlat0.x);
u_xlat0.x = u_xlat40 * u_xlat0.x + 1.0;
u_xlat27 = u_xlat27 * 0.318309873;
u_xlat0.x = u_xlat0.x * u_xlat0.x + 1.00000001e-07;
u_xlat0.x = u_xlat27 / u_xlat0.x;
u_xlat0.x = u_xlat0.x * u_xlat39;
u_xlat0.x = u_xlat1.x * u_xlat0.x;
u_xlat0.x = u_xlat0.x * 3.14159274;
u_xlat0.x = max(u_xlat0.x, 0.0);
u_xlat39 = u_xlat14 * u_xlat14 + 1.0;
u_xlat39 = float(1.0) / u_xlat39;
u_xlat16_42 = dot(u_xlat16_2.xyz, u_xlat16_2.xyz);
#ifdef UNITY_ADRENO_ES3
u_xlatb1 = !!(u_xlat16_42!=0.0);
#else
u_xlatb1 = u_xlat16_42!=0.0;
#endif
u_xlat1.x = u_xlatb1 ? 1.0 : float(0.0);
u_xlat0.x = u_xlat0.x * u_xlat1.x;
u_xlat16_41 = (-u_xlat16_41) + 1.0;
u_xlat16_41 = u_xlat16_41 + _Glossiness;
#ifdef UNITY_ADRENO_ES3
u_xlat16_41 = min(max(u_xlat16_41, 0.0), 1.0);
#else
u_xlat16_41 = clamp(u_xlat16_41, 0.0, 1.0);
#endif
u_xlat16_24.xyz = vec3(u_xlat26) * _LightColor0.xyz;
u_xlat1.xyz = u_xlat0.xxx * _LightColor0.xyz;
u_xlat16_42 = (-u_xlat13) + 1.0;
u_xlat16_48 = u_xlat16_42 * u_xlat16_42;
u_xlat16_48 = u_xlat16_48 * u_xlat16_48;
u_xlat16_42 = u_xlat16_42 * u_xlat16_48;
u_xlat16_12.xyz = (-u_xlat16_2.xyz) + vec3(1.0, 1.0, 1.0);
u_xlat16_12.xyz = u_xlat16_12.xyz * vec3(u_xlat16_42) + u_xlat16_2.xyz;
u_xlat0.xyz = u_xlat1.xyz * u_xlat16_12.xyz;
u_xlat0.xyz = u_xlat16_3.xyz * u_xlat16_24.xyz + u_xlat0.xyz;
u_xlat16_3.xyz = u_xlat16_9.xyz * vec3(u_xlat39);
u_xlat16_9.xyz = (-u_xlat16_2.xyz) + vec3(u_xlat16_41);
u_xlat16_2.xyz = u_xlat16_11.xxx * u_xlat16_9.xyz + u_xlat16_2.xyz;
u_xlat0.xyz = u_xlat16_3.xyz * u_xlat16_2.xyz + u_xlat0.xyz;
SV_Target0.xyz = u_xlat0.xyz;
SV_Target0.w = 1.0;
return;
}

运行编译

默认编译

cmd输入malioc 文件名.frag/vert即可看到编译结果

上图为malioc shader.vert运算结果

上图为malioc shader.frag运算结果

指定型号编译

可以通过 malioc 文件名 -c 硬件型号来指定Mali GPU编译。(frag 和 vert 均可指定型号进行特定编译)

上图为malioc shader.frag -c Mali-G78运算结果

上图为malioc shader.frag -c Mali-G72运算结果

参数详解

从上图可以直观看到shader 的相关属性和模拟硬件的相关信息。

在中间的列表,是对 Mali 着色器核心中的主要功能单元、算法、加载/存储单元、变化单元和纹理单元进行大致的循环成本细分。一般来说,最长的循环和最短的循环是一个很好的优化方向。我们可以先看以Mali-G72运算编译的详细信息:

上图为malioc shader.frag -c Mali-G72运算结果

硬件基础信息

首先可以看到使用Mali -G72 与 Mali -G78 编译后的结果返回结果有些不同。这是由于两个GPU的硬件架构不同所致。

上图为两个GPU编译后提示的架构细节

具体的细节可以参考下这位dalao所写的mali GPU架构演进,这里只讨论两者在性能优化的区别。

ARM Mali GPU架构演进

在Mali Valhall 架构的GPU,所有 Valhall GPU 都实现了两个并行处理引擎。所以前面所看到的在Mali - G72 Bifrost 架构下的Arithmetic 会被拆分为 FMA , CVT , SFU三个数据进行展示。(这三个数据我会在后面Shader信息部分进行解释)

上图为Valhall shader core (截选自Arm Mali GPU Training Series Ep 3.5 : Mali Offline Compiler)

IDVS shader variants

在Bifrost Valhall 家族的 Mali GPU 使用 index-draven vertex shading(IDVS)。它会在两个binaries编译vertex shaders,position shader,它只计算位置并为每个索引顶点执行,varying shader,它计算剩余的非位置顶点属性输出,并且只对作为剔除后幸存下来的可见图元的一部分的顶点执行。所以可以看到在使用mali compiler 编译处理顶点着色器时,会Position variant 和 Varying variant。

上图为malioc shader.vert-c Mali-G78的执行结果

Work registers

该shader工作使用的寄存器数量。可用的物理寄存器池在正在执行的着色器线程之间分配。因此,减少工作寄存器的使用可以增加可以同时执行的线程数,有助于保持 GPU工作忙碌。

上图为malioc shader.frag -c Mali-G72运算结果

Uniform registers

Mali GPU 可以将数据从 API 集统一和统一缓冲区提升到着色器核心寄存器中。然后在每次绘制的基础上加载数据,而不是在每个着色器线程上加载。(比如在shader中Properties声明的常量)

Stack spilling

对于Valhall 和 Bifrost GPUs,可以看到是否有变量被放置到栈内存中。放置到栈中的内存对于GPU读取是性能消耗较大的。(降低才能提高性能)

16-bit arithmetic

以 16 位或更低精度执行的算术运算的百分比。数值越高代表shader性能越好。因为使用 mediump 选择的 16 位精度是 32 位精度下的 highp 的两倍。

Shader信息

Total Instruction Cycles

为程序生成的所有指令的累积执行周期数,与程序控制流无关。

Shortest Path Cycles

通过着色器程序的最短控制流路径的循环数的估计。该行根据设计中存在的功能单元数量对周期成本进行标准化。

Longest Path Cycles

通过着色器程序的最长控制流路径的循环数的估计。该行根据设计中存在的功能单元数量对周期成本进行标准化。并非总是可以根据静态分析确定最长路径,例如,如果统一变量控制循环迭代限制。所以这一行可能表示一个未知的周期计数(“N/A”)。

报告的统计数据按功能单元细分。在 Shortest Path Cycles 和 Longest Path Cycles 行中的一个或两个行中具有最高周期成本的单位列是一个很好的优化候选者。例如,最高值在 A(算术)列中的着色器是算术边界。通过减少其执行的数学运算的数量或精度来优化着色器。 Bound 列列出了循环计数最高的功能单元,这使您可以快速识别着色器代码中的瓶颈单元。

A = Arithmetic operations

数学运算操作符。具体代表了shader中sum multiply等操作

FMA Fused multiply accumulate

加减乘除运算符

CVT Arithmetic conversion

算术转换操作符

SFU Special functions unit

特殊功能单元

LS = Load/Store operation

读取和存储的操作

V = Varying operations

在shader中不同单位插值的消耗

T = Texture operations

采样贴图的消耗

Shader properties

shader 使用了能影响shader执行表现的相关语言特性信息、

Has uniform computation

这显示是否有任何计算仅依赖于文字常量或统一值,因此为绘制调用或计算分派中的每个线程产生相同的结果。mali 驱动能优化,但还有一定的消耗的。所以建议尽量把这系列的计算移植到在CPU上的application logic 。

Has side-effects

这显示此着色器是否具有在固定图形管道之外的内存中可见的副作用。可能由内存写入,图片存储,原子的使用。

Modifies coverage

这显示片段着色器是否具有可以通过着色器执行更改的覆盖掩码,例如,通过使用丢弃语句

具有可修改覆盖率的shader必须使用late ZS update,这会降低early ZS test在同一坐标上的later片段的效率

Uses late ZS test

这个显示片段shader是否包含了强制late ZS test的逻辑。

这禁用了early ZS test和hidden surface removal的使用,这可能会导致显著的效率损失

Uses late ZS update

Reads color buffer

这个显示了fragment shader 是否包含了程序化从color buffer中读取的逻辑 。以这种方式从颜色缓冲区读取的着色器被视为透明的,不能用作hidden surface removal去除遮挡物

优化建议

尽量不要使用if、discard

Discard会使gpu的early-z机制失效,且一般会跟随if语句一起使用,影响gpu的流水线效率。

一般树木等因为实现方式需要使用discard,如果非预期地使用,则需要关注和优化。

减低相关运算量

不要使用反三角函数!不要使用反三角函数!不要使用反三角函数!(重要的事情说三遍!!!)

使用反三角函数等高复杂度三角函数的计算会增加GPU SFU的开销。

减低不必要的运算。

相关shader运算消耗后续我会写相关文章进行性能介绍。(挖个坑……)

避免类型转换

Shader中使用浮点和整形混合运算时,GPU需要先把整形转换浮点,比直接使用浮点要额外多出一条指令,这个是比较容易被忽略的细节。

高精度和浮点数

高精度计算和浮点数计算比中精度或整形数的计算开销明显要高,要尽可能减少使用。

比如将highp(32-bit)精度降低为mediump(16-bit)。这使 GPU 能够为每个寄存器存储两倍的变量,降低消耗和寄存器的压力。

但是在position 和 depth 相关计算方面建议使用highp

避免触发spilling

当shader使用寄存器较多,超过了硬件的寄存器数量,会触发spilling机制,使用内存临时代替寄存器,这样数据交换的速度会大幅下降。早期未优化的shader容易出现这种情况。

遇到此情况时,建议可以减少变量精度,减少变量的有效范围,或者简化shader程序。

纹理指令数

一般来说在vert阶段不会去进行纹理采样,高耗时的操作会阻塞后续frag阶段。

使用纹理的数量最好不要超过4个

Setpass

每次setpass call会刷新gpu内部的渲染状态,造成更多的开销,同样材质的物体排序绘制也无法获得收益。

  • varring尽量使用vec类型
  • uniform应该为常量
  • 避免常量运算
  • 避免在fragment中修改深度
  • set pass的数量应该为1

写在最后

感谢dalao们的指导,本人第一篇博客,如果觉得对您有帮助的话,请多多支持~

API support

Mali™ Offline Compiler supports the following API versions:

  • OpenGL ES 2.0 and 3.0-3.2
  • Vulkan 1.0-1.1
  • OpenCL 1.0-1.2 and 2.0

OpenCL support is only available on Linux and macOS host installations.

参考

https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio/components/mali-offline-compiler

https://www.youtube.com/watch?v=zEybNlwd7SI&list=PLKjl7IFAwc4QUTejaX2vpIwXstbgf8Ik7&index=15