gpt4 book ai didi

c++ - SSE 的条件语句

转载 作者:行者123 更新时间:2023-11-30 00:45:06 24 4
gpt4 key购买 nike

我正在尝试为我的游戏做一些计算,我正在尝试计算两点之间的距离。本质上,我使用圆的方程来查看这些点是否在我定义的半径内。

(x - x1)^2 + (y - y1)^2 <= r^2

我的问题是:如何使用 SSE 评估条件语句并解释结果?到目前为止我有这个:

float distSqr4 = (pow(x4 - k->getPosition().x, 2) + pow(y4 - k->getPosition().y, 2));
float distSqr3 = (pow(x3 - k->getPosition().x, 2) + pow(y3 - k->getPosition().y, 2));
float distSqr2 = (pow(x2 - k->getPosition().x, 2) + pow(y2 - k->getPosition().y, 2));
float distSqr1 = (pow(x1 - k->getPosition().x, 2) + pow(y1 - k->getPosition().y, 2));

__m128 distances = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);

一旦我得到结果变量,我就迷路了。如何使用刚刚得到的结果变量?我的计划是,如果评估的条件为真,则进行一些照明计算,然后在屏幕上绘制像素。在这种情况下,我该如何解释 true 与 false?

非常感谢任何朝着正确方向提供的帮助!

最佳答案

My plan was, if the condition evaluated turned out to be true, to do some lighting calculations and then draw the pixel on the screen.

那你真的别无选择,只能分支。

使用 SSE 进行条件测试的一大优势是它允许您编写无分支代码,这可以显着提高速度。但在您的情况下,您几乎必须分支,因为如果我对您的理解正确,您永远如果条件评估为 false,则不想在屏幕上输出任何内容。

我的意思是,我猜你可以无条件地(推测性地)进行所有计算,然后只使用条件的结果来旋转像素值中的位,从根本上让你离开屏幕。那会给你无分支的代码,但它很傻。分支预测错误会受到惩罚,但它不会像所有计算和绘图代码那样昂贵。

换句话说,一旦您获得最终结果,您使用 SIMD 所利用的并行性就会耗尽。这只是一个简单的标量比较和分支。首先,您测试条件评估是否为真。如果没有,您将跳过执行光照计算和像素绘制的代码。否则,您将无法执行该代码。

棘手的部分是编译器不允许您在常规的旧if 语句中使用__m128 变量,因此您需要“转换” result 为一个整数,您可以将其用作条件的基础。最简单的方法是使用 _mm_movemask_epi8 内在函数。

所以你基本上会这样做:

__m128 distances  = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);

if (_mm_movemask_epi8(result) == (unsigned)-1)
{
// All distances were less-than-or-equal-to the maximum, so
// go ahead and calculate the lighting and draw the pixels.
CalcLightingAndDraw(…);
}

这是有效的,因为如果比较为真,_mm_cmple_ps 将每个压缩双字设置为全 1,如果比较为假,则设置为全 0。 _mm_movemask_epi8 然后将其折叠成一个整数大小的掩码并将其移动到一个整数值。然后,您可以在普通条件语句中使用该整数值。

注意:使用 Clang 和 ICC,您可以将 __m128 值传递给 _mm_movemask_epi8 内在函数。在 GCC 上,它坚持 __m128i 值。您可以通过强制转换处理此问题:_mm_movemask_epi8((__m128i)result)

当然,我在这里假设您只在所有 距离小于或等于最大距离时才进行绘图。如果您想独立处理四个距离中的每一个,那么您需要在掩码上添加更多条件测试:

__m128   distances  = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);
unsigned condition = _mm_movemask_epi8(result);

if (condition != 0)
{
// One or more of the distances were less-than-or-equal-to the maximum,
// so we have something to draw.

if ((condition & 0x000F) != 0)
{
// distSqr1 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr1);
}
if ((condition & 0x00F0) != 0)
{
// distSqr2 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr2);
}
if ((condition & 0x0F00) != 0)
{
// distSqr3 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr3);
}
if ((condition & 0xF000) != 0)
{
// distSqr4 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr4);
}
}

这不会产生非常高效的代码,因为您必须执行很多条件测试和分支操作。您可以继续并行化主要 if block 内部的一些光照计算。我不能确定这是否可行,因为我没有足够的关于您的算法/设计的详细信息。

否则,如果您看不到从绘图代码中获得更多并行性的任何方法,那么显式 SSE 内在函数的使用在这里不会给您带来太多好处。您能够并行化一个比较(_mm_cmple_ps),但是为该比较设置的开销(_mm_set_ps,它可能会编译成vinsertpsunpcklps+movlhps 指令,假设输入已经在 XMM 寄存器中)将抵消您可能获得的任何微不足道的 yield 。可以说,您也可以像这样编写代码:

float maxDistSqr = k->getMaxDistance() * k->getMaxDistance();
if (distSqr1 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr1);
}
if (distSqr2 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr2);
}
if (distSqr3 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr3);
}
if (distSqr4 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr4);
}

关于c++ - SSE 的条件语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44711516/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com