1. 通过提供“暗示”,让编译器自动优化。
近日在研究Unity可编程渲染管线源码时,在Core库的[email protected]\CoreRP\ShaderLibrary\Common.hlsl(446)发现了这样一个小技巧,看一下下面这两个例子:
struct VertexInput
{
float4 vertex : POSITION;
};
struct VertexOutput
{
half4 pos : SV_POSITION;
};
half Pow4(half x)
{
return (x * x) * (x * x);
}
VertexOutput Vertex(VertexInput i)
{
VertexOutput o;
o.pos = Pow4(i.vertex.x);
return o;
}
上述Shader源代码在编译后实际只有2次乘法,编译器自动执行了优化:
0: mul r0.x, v0.x, v0.x
1: mul o0.xyzw, r0.xxxx, r0.xxxx
2: ret
struct VertexInput
{
float4 vertex : POSITION;
};
struct VertexOutput
{
half4 pos : SV_POSITION;
};
half Pow4(half x)
{
return x * x * x * x;
}
VertexOutput Vertex(VertexInput i)
{
VertexOutput o;
o.pos = Pow4(i.vertex.x);
return o;
}
如果Pow4中的3连乘不加括号,编译器不会执行优化,编译后会执行3次乘法。
0: mul r0.x, v0.x, v0.x
1: mul r0.x, r0.x, v0.x
2: mul o0.xyzw, r0.xxxx, v0.xxxx
3: ret
说明在编码时给编译器提供一些“暗示”,可以帮助编译器执行自动优化,既保持了良好的可读性,也达到了性能最优的目的。没有必要按照传统的方式进行手动优化,那样代码的可读性会略差一些:
// 没有必要写成这样,因为结果完全一样,但可读性略差些。
half Pow4(half x)
{
half x2 = x * x;
return x2 * x2;
}