本文將介紹NEON提供的移位運算,,并顯示如何利用移位運算在常用顏色深度之間轉(zhuǎn)換影像數(shù)據(jù)。
向量移位
NEON上的移位與標(biāo)量ARM編碼中可能用到的移位非常相似,,即每個向量元素的位數(shù)均向左或向右移位,,出現(xiàn)在每個元素左側(cè)或右側(cè)的位將被刪除;它們不能移位至相鄰的元素,。
移位的數(shù)量可通過指令中編碼的文字或附加的移位向量來指定,。使用移位向量時,應(yīng)用到輸入向量每個元素的移位取決于移位向量中對應(yīng)元素的值,。移位向量中的元素被當(dāng)作帶符號的值來處理,,因此按元素分配,左移位,、右移位和零移位都有可能發(fā)生,。
帶符號元素的向量上發(fā)生的右移位由指令附加的類型指定,,并會將符號擴展至每一個元素。這與ARM編碼中可能用到的算術(shù)移位相同,。應(yīng)用到無符號向量的移位不會發(fā)生符號擴展,。
移位與插入NEON也支持通過插入產(chǎn)生移位,使兩個不同向量的位相結(jié)合,。例如,,左移位與插入(VSLI)可使源向量的每一個元素均向左移位。每個元素右側(cè)新插入的位就是目標(biāo)向量中的對應(yīng)位,。
移位與計算最后,,NEON還支持向量元素向右移位,并將結(jié)果計入到另一個向量中,。這種方法對于先在高精度條件下進(jìn)行臨時計算,,然后再將結(jié)果與低精度計算器相結(jié)合的情況非常有用。
指令修改器每個移位指令都能擁有一個或多個修改器,。這些修改器并不改變移位運算本身,,而是通過調(diào)整輸入值或輸出值,消除偏差或飽和狀況,,保持一定的范圍,。共有五種移位修改器:
- 舍位修改器 (Rounding),以R前綴表示,,可以糾正右移時舍位導(dǎo)致的偏差,。
- 窄修改器 (Narrow),以N后綴表示,,可以讓結(jié)果中每個元素的位數(shù)減半,。它代表Q(128位)源和D(64位)目標(biāo)寄存器。
- 長修改器 (Long),,以L后綴表示,,可以讓結(jié)果中每個元素的位數(shù)加倍。它代表D源和Q目標(biāo)寄存器,。 飽和修改器 (Saturating),以Q前綴表示,,可以在最大和最小可表范圍內(nèi)設(shè)置每個結(jié)果元素,,前提是結(jié)果未超出該范圍。向量的位數(shù)和符號類型可用于確定飽和范圍,。
- 無符號飽和修改器 (Unsigned Saturating),,以Q前綴和U后綴表示,與飽和修改器類似,,但在進(jìn)行帶符號或無符號輸入時,,結(jié)果將在無符號范圍內(nèi)表現(xiàn)為飽和,。
這些修改器的部分組合并未表現(xiàn)出有用的運算,因此NEON也沒有提供相應(yīng)指令,。例如,,飽和右移位(應(yīng)稱為VQSHR)其實就毫無必要,因為右移位只會讓結(jié)果變得更小,,因而值根本無法超出有效范圍,。
可用移位表NEON提供的所有移位指令均在下表中列出。它們根據(jù)先前提到的修改器進(jìn)行排列,。如果你還是不太確定修改器各個字母代表的含義,,請利用下表選擇需要的指令。
示例:轉(zhuǎn)換顏色深度顏色深度之間的轉(zhuǎn)換是圖形處理中經(jīng)常需要的運算,。通常,,輸入或輸出數(shù)據(jù)都是RGB565 16位顏色格式,但RGB888格式的數(shù)據(jù)處理起來更為方便,。對于NEON而言尤其如此,,因為它無法為RGB565這樣的數(shù)據(jù)類型提供本機支持。
但是,,NEON仍然可以有效地處理RGB565數(shù)據(jù),,上文中介紹的向量移位便提供了處理方法。
從565到888首先,,我們來看如何將RGB565轉(zhuǎn)換為RGB888,。假設(shè)寄存器q0中有8個16位像素,我們想要在d2,、d3和d4這三個寄存器中將紅色,、綠色和藍(lán)色分離成8位的元素。
每個指令的效果都在上面?zhèn)渥⒅凶隽嗣枋?,但總而言之,,每個通道上執(zhí)行的運算為:
- 利用移位推掉元素任意一端的位數(shù),清除相鄰?fù)ǖ赖念伾珨?shù)據(jù),。
- 使用第二次移位將顏色數(shù)據(jù)放置到每個元素最重要的位上,,并縮短位數(shù)將元素大小從16位減至8位。
請注意在這個順序中使用元素大小來確定8位和16位元素的位置,,以進(jìn)行部分掩碼運算,。
一個小問題你可能會注意到,如果使用上述代碼轉(zhuǎn)換到RGB888格式,,白色顯得不夠白,。這是因為,對于每個通道而言,最低的2或3位是零,,而不是1,;白色在RGB565中表示為(0x1F, 0x3F, 0x1F),而在RGB888中,,卻變成了 (0xF8, 0xFC, 0xF8),。這可以通過移位來解決,將部分最重要的位插入到低位,。
從888到565現(xiàn)在,,我們來看反向運算,即從RGB888轉(zhuǎn)換為RGB565,。這里,,我們假設(shè)RGB888數(shù)據(jù)為上述代碼產(chǎn)生的格式;在d0,、d1和d2這三個寄存器上,,每個寄存器均包含每種顏色的8個元素。結(jié)果將存儲為q2格式的8個16位RGB565元素,。
同樣,,每個指令的詳細(xì)說明在備注中列出,但總而言之,,對于每個通道而言:
- 將每個元素的長度擴展至16位,,并將顏色數(shù)據(jù)移至最重要的位上。
- 使用插入右移位,,將每個顏色通道放置到結(jié)果寄存器中,。
結(jié)論NEON提供的強大的移位指令范圍讓你能夠:
- 利用舍入和飽和,通過二次冪快速進(jìn)行向量的除法和乘法運算,。
- 通過移位將一個向量位復(fù)制到另一個向量位,。
- 在高精度條件下進(jìn)行臨時計算,并在低精度條件下計算結(jié)果,。
Martyn是處理器領(lǐng)域的資深軟件工程師,,已在ARM工作了近10年。他主要負(fù)責(zé)改善ARM平臺上軟件的性能和體驗,。他對使用匯編語言和SIMD實現(xiàn)軟件優(yōu)化非常感興趣,,尤其是在圖形和多媒體領(lǐng)域。