我正在尝试使用NEON(ios,> arm7)优化视锥中的aabb框,我只是对基准测试结果感到困惑。
NEON版本(使用NEON的GLKVector4DotProduct):
FORCE_INLINE bool box_in_view1(const GLKVector4& min, const GLKVector4& max)
{
#define test_plane(i) { \
const GLKVector4& fp = frustum_plane[i]; \
if (GLKVector4DotProduct(fp, GLKVector4Make(min.x, min.y, min.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(max.x, min.y, min.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(min.x, max.y, min.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(max.x, max.y, min.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(min.x, min.y, max.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(max.x, min.y, max.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(min.x, max.y, max.z, 1.0f)) <= 0.0f && \
GLKVector4DotProduct(fp, GLKVector4Make(max.x, max.y, max.z, 1.0f)) <= 0.0f) { \
return false; \
} \
}
test_plane(0);
test_plane(1);
test_plane(2);
test_plane(3);
test_plane(4);
test_plane(5);
return true;
}
没有NEON:
FORCE_INLINE bool box_in_view2(const GLKVector4& min, const GLKVector4& max)
{
#define test_plane(i) { \
const GLKVector4& fp = frustum_plane[i]; \
float negw = -fp.w; \
if (fp.x * min.x + fp.y * min.y + fp.z * min.z <= negw && \
fp.x * max.x + fp.y * min.y + fp.z * min.z <= negw && \
fp.x * min.x + fp.y * max.y + fp.z * min.z <= negw && \
fp.x * max.x + fp.y * max.y + fp.z * min.z <= negw && \
fp.x * min.x + fp.y * min.y + fp.z * max.z <= negw && \
fp.x * max.x + fp.y * min.y + fp.z * max.z <= negw && \
fp.x * min.x + fp.y * max.y + fp.z * max.z <= negw && \
fp.x * max.x + fp.y * max.y + fp.z * max.z <= negw) { \
return false; \
} \
}
test_plane(0);
test_plane(1);
test_plane(2);
test_plane(3);
test_plane(4);
test_plane(5);
return true;
}
在简单的基准时间中为:
box_in_view1: 1.9704s
box_in_view2: 0.0013s
这是使用静态aabb框和静态视锥的1000万次测试(多维数据集在内部,因此所有测试均返回true)。
在ipad3,ios7和编译器opt标志上进行了测试:-Ofast -ffast-math
我确定GLKVector4DotProduct()确实在 ARM_NEON 路径中使用NEON度量标准。为什么NEON的结果这么慢?为什么?
最佳答案
以下是完全优化的版本,该版本必须比当前版本快得多:
/*
fanicBoxInView
Copyright (C) 2014 Jake Lee
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// int fanicBoxInView(void *pMin, void *pMax, void *pFp, unsigned int count);
// assert : count >= 4
.text
.arm
.global fanicBoxInView
pMin .req r0
pMax .req r1
pFp .req r2
count .req r3
.align 5
.func
fanicBoxInView:
vld1.32 {q12}, [pMin]
vld1.32 {q13}, [pMax]
subs count, count, #4
vmov.i32 q14, #0
vmov.i32 q15, #0
bxmi lr
vpush {q6-q7}
vzip.32 q12, q13
1:
vld1.32 {q0,q1}, [pFp]!
vld1.32 {q2,q3}, [pFp]!
pld [pFp, #64*3]
subs count, count, #4
vdup.32 d20, d1[1]
vdup.32 d21, d3[1]
vdup.32 d22, d5[1]
vdup.32 d23, d7[1]
vmul.f32 d12, d25, d0[1]
vmul.f32 d13, d25, d2[1]
vmul.f32 d14, d25, d4[1]
vmul.f32 d15, d25, d6[1]
vneg.f32 q10, q10
vneg.f32 q11, q11
vmul.f32 d16, d26, d1[0]
vmul.f32 d17, d26, d3[0]
vmul.f32 d18, d26, d5[0]
vmul.f32 d19, d26, d7[0]
vmls.f32 d20, d24, d0[0]
vmls.f32 d21, d24, d2[0]
vmls.f32 d22, d24, d4[0]
vmls.f32 d23, d24, d6[0]
vrev64.32 q0, q6
vrev64.32 q1, q7
vadd.f32 q6, q6, q8
vadd.f32 q7, q7, q9
vadd.f32 q8, q8, q0
vadd.f32 q9, q9, q1
vrev64.32 q0, q6
vrev64.32 q1, q7
vrev64.32 q2, q8
vrev64.32 q3, q9
vcgt.f32 q6, q6, q10
vcgt.f32 q7, q7, q11
vcgt.f32 q8, q8, q10
vcgt.f32 q9, q9, q11
vcgt.f32 q0, q0, q10
vcgt.f32 q1, q1, q11
vcgt.f32 q2, q2, q10
vcgt.f32 q3, q3, q11
vorr q6, q7, q6
vorr q8, q9, q8
vorr q0, q1, q0
vorr q2, q3, q2
vorr q14, q6, q14
vorr q15, q8, q15
vorr q14, q14, q0
vorr q15, q15, q2
bpl 1b
cmp count, #-4
add pFp, pFp, count, lsl #2
bgt 1b
vorr q14, q15, q14
vpop {q6-q7}
vmov r0, r1, d28
vmov r2, r3, d29
orr r0, r1, r0
orr r2, r3, r2
orr r0, r2, r0
bx lr
.endfunc
.end
上面的语法适用于Linaro GCC。您必须对XCode进行一些更改:
How do I use the ARM assembler in XCode?
注意,您必须断言(计数> = 4);
另请注意,当(count%4 == 0);时,代码运行效率最高。
玩得开心。
PS:我是采用“按需优化”实践的专业优化器,我的客户对我最近在这里免费提供完全优化的代码的 Activity 并不满意。因此,我被迫使其成为GPL。
关于ios - 使用NEON的aabb截锥体剔除,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25036257/