與SSE

2017-06-23 31 views
1

條件語句我想爲我的遊戲做了一些計算,我試圖來計算兩個點之間的距離。實質上,我使用圓的方程來查看點是否在我定義的半徑內。與SSE

(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); 

一旦我得到結果變量,我迷路了。我如何使用剛剛得到的結果變量?我的計劃是,如果條件評估結果是真的,則進行一些照明計算,然後在屏幕上繪製像素。在這種情況下,我如何解釋真與假?

朝着正確方向邁出的任何幫助,非常感謝!

+1

我不知道我完全理解你的問題;例如,您可以執行'_mm_and_ps(距離,結果)'來清除超出範圍的值。 –

+3

順便說一句,也許它只是爲了簡潔,但你爲什麼不在SSE中做'(x - x1)^ 2 +(y - y1)^ 2'? –

回答

5

我的計劃是,如果條件評估結果是真的,做一些照明計算,然後在屏幕上繪製像素。

那麼你真的別無選擇,只能分支。

做使用SSE條件測試的一大優點是,它允許你寫網點代碼,這可能會導致大規模的速度提升。但是,在你的情況,你很可能分支,因爲,如果我理解正確,你從未如果條件評估爲假想在屏幕上輸出任何東西。

我的意思是,我想你可以無條件地(推測性地)完成所有的計算,然後使用像素值中的條件旋轉位的結果,本質上會導致你從屏幕上拖出。這會給你無編碼的代碼,但它非常愚蠢。分支預測錯誤有一個懲罰,但它不會像所有的計算和繪圖代碼那樣昂貴。

換句話說,一旦你有最終結果,你正在使用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塊的中的某些照明計算進行並行化。我無法確定這是否可行,因爲我沒有足夠的關於算法/設計的細節。否則,如果你看不到任何方式來從繪圖代碼中獲得更多的並行性,那麼在這裏使用顯式的SSE內在函數並不會給你帶來太多的收益。你可以並行一個比較(_mm_cmple_ps),但是爲比較而設置的開銷(_mm_set_ps,可能編譯成vinsertpsunpcklps + movlhps指令,假設輸入已經在XMM寄存器中)將不止取消取得你可能得到的微不足道的收穫。你可以說寫代碼就像這樣:

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); 
}