如何提高float lerp功能的速度
How to improve the speed of the float lerp function?
最近我正在编写一个软光栅渲染器,但它的速度真的很慢。通过性能测试,我发现float lerp函数是瓶颈。如何提高此功能的速度?使用simd?知道吗?
inline float MathUtil::Lerp(float x1, float x2, float t)
{
return x1 + (x2 - x1)*t;
}
//lerp vector
ZCVector MathUtil::Lerp(const ZCVector& v1, const ZCVector& v2, float t)
{
return ZCVector(
Lerp(v1.x, v2.x, t),
Lerp(v1.y, v2.y, t),
Lerp(v1.z, v2.z, t),
v1.w
);
}
//lerp ZCFLOAT2
ZCFLOAT2 MathUtil::Lerp(const ZCFLOAT2& v1, const ZCFLOAT2& v2, float t)
{
return ZCFLOAT2(
Lerp(v1.u, v2.u, t),
Lerp(v1.v, v2.v, t)
);
}
//lerp ZCFLOAT3
ZCFLOAT3 MathUtil::Lerp(const ZCFLOAT3& v1, const ZCFLOAT3& v2, float t)
{
return ZCFLOAT3(
Lerp(v1.x, v2.x, t),
Lerp(v1.y, v2.y, t),
Lerp(v1.z, v2.z, t)
);
}
//lerp VertexOut
VertexOut MathUtil::Lerp(const VertexOut& v1, const VertexOut& v2, float t)
{
return VertexOut(
Lerp(v1.posTrans, v2.posTrans, t),
Lerp(v1.posH, v2.posH, t),
Lerp(v1.tex, v2.tex, t),
Lerp(v1.normal, v2.normal, t),
Lerp(v1.color, v2.color, t),
Lerp(v1.oneDivZ, v2.oneDivZ, t)
);
}
VertexOut的结构:
class VertexOut
{
public:
ZCVector posTrans;
ZCVector posH;
ZCFLOAT2 tex;
ZCVector normal;
ZCFLOAT3 color;
float oneDivZ;
}
scanlinefill
函数来填充三角形,每个顶点都需要使用lerp函数,所以它会被调用很多次。
void Tiny3DDeviceContext::ScanlineFill(const VertexOut& left, const VertexOut& right, int yIndex)
{
float dx = right.posH.x - left.posH.x;
for (float x = left.posH.x; x <= right.posH.x; x += 0.5f)
{
int xIndex = static_cast<int>(x + .5f);
if(xIndex >= 0 && xIndex < m_pDevice->GetClientWidth())
{
float lerpFactor = 0;
if (dx != 0)
{
lerpFactor = (x - left.posH.x) / dx;
}
float oneDivZ = MathUtil::Lerp(left.oneDivZ, right.oneDivZ, lerpFactor);
if (oneDivZ >= m_pDevice->GetZ(xIndex,yIndex))
{
m_pDevice->SetZ(xIndex, yIndex, oneDivZ);
//lerp get vertex
VertexOut out = MathUtil::Lerp(left, right, lerpFactor);
out.posH.y = yIndex;
m_pDevice->DrawPixel(xIndex, yIndex, m_pShader->PS(out));
}
}
}
}
此循环结构可能运行lerp
的次数是所需次数的两倍:
for (float x = left.posH.x; x <= right.posH.x; x += 0.5f) {
int xIndex = static_cast<int>(x + .5f);
...
}
相反,(更准确地说(,通过递增整数xIndex
进行循环,并为每个xIndex
计算正确的float x
。
这可能会自动向量化,但您必须检查编译器输出,看看发生了什么。希望用out.posH.y = yIndex;
覆盖的Lerp在丢弃结果后得到优化。如果没有,您可能会通过制作一个不做Lerp的包装器函数来获得加速。
通过使用数组结构方法,而不是保持结构的所有内容连续的AoS方法,可以使它对SIMD更友好。然而,您以相同的方式排列多个元素,因此它可能会使用两个标量和一个向量Lerp自动向量化。
有关SIMD内容的一些指南,请参阅sse标签wiki,其中包括一个指向这组非常好的初学者/中级幻灯片的链接。
你可能还可以改变其他事情,特别是对代码进行更大的重组,以减少整体工作。这种优化通常比使用SIMD来有效地应用现代CPU的暴力更能给你带来更大的加速。
同时做这两件事来增加加速是真正让事情变得快速的原因。
缓存未命中和内存带宽瓶颈通常是一个巨大的因素,因此优化访问模式可以产生很大的影响。
如果您想了解更多底层细节,请参阅Agner Fog的优化指南。他有一个C++优化指南,但大多数好东西都是关于x86 asm的。(另请参阅x86标记wiki(。但请记住,在寻找高级优化之后,这种低级优化只是一个好主意。
- 在执行其他功能的同时播放动画(LED矩阵和Arduino/ESP8266)
- 多态性和功能结合
- 带内存和隔离功能的SQLite
- 在CMakeLists.txt的安装功能中使用.cmake文件有什么用
- 类模板的成员功能的定义在单独的TU中完全专业化
- 为什么在读取文件大小时文件IO速度会发生变化
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++中获得"静态纯虚拟"功能?
- 两个文件使用彼此的功能-如何解决
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 文件系统:复制功能的速度秘诀是什么
- 在鼠标按下时移动 SDL2 窗口的功能闪烁窗口并且移动速度不够快
- 如何准确测量和比较opencl速度以实现循环功能的简单速度
- 辅助功能级别对性能或速度的影响
- CPP 中速度性能的测试功能
- 相同的功能?使用 GMP(C++) 时运行速度慢约 10 倍
- 'if'功能在C++中具有可读性是否存在速度差异?
- 如何提高float lerp功能的速度
- OpenCV:C++API和C API在功能或速度上是否不同
- 从功能返回容器:优化速度和现代风格