2016-11-08 39 views
2

我想知道是否有一個SSE2/AVX2整數指令或指令(或內在)序列:C++ SSE2或AVX2內在灰度到ARGB轉換

給定一個的形式的8個字節的像素行:

A = {a, b, c, d, e, f, g, h} 

是否有任何方式來加載在包含8個32位ARGB像素,使得初始灰度值被廣播到其它各2個字節的YMM寄存器這些像素對應的32位像素?結果應該是這樣的:(0是Alpha值)

B = {0aaa, 0bbb, 0ccc, 0ddd, 0eee, 0fff, 0ggg, 0hhh} 

我在矢量擴展一個完整的初學者,所以我甚至不知道如何處理這一點,或者如果它是在所有可能的。

任何幫助,將不勝感激。謝謝!

UPDATE1

謝謝您的回答。我仍然有一個問題,但:

我把這個小例子放在一起,並編譯與VS2015在x64上。

int main() 
{ 
    unsigned char* pixels = (unsigned char*)_aligned_malloc(64, 32); 
    memset(pixels, 0, 64); 

    for (unsigned char i = 0; i < 8; i++) 
     pixels[i] = 0xaa + i; 

    __m128i grayscalePix = _mm_load_si128((const __m128i*)pixels); 
    __m256i rgba = _mm256_cvtepu8_epi32(grayscalePix); 
    __m256i mulOperand = _mm256_set1_epi32(0x00010101); 

    __m256i result = _mm256_mullo_epi32(rgba, mulOperand); 

    _aligned_free(pixels); 
    return 0; 
} 

的問題是,這樣做

__m256i rgba = mm256_cvtepu8_epi32(grayscalePix) 

RGBA後只有第一四個雙設定。最後四個均爲0

英特爾開發者手冊說:

VPMOVZXBD YMM1,XMM2/M64
零擴展8封裝8位整數的低8個 字節XMM2的/ m64到8個打包的32位整數,在 ymm1。

我不確定這是意向行爲還是我仍然缺少某些東西。

謝謝。

+0

您的代碼看起來正確。你確定你不只是測試錯誤?或者,由於結果未被使用,編譯器沒有優化它的全部或部分功能? [關於Godbolt](https://godbolt.org/g/TR15E9),我不得不使用'-O0'來使編譯器保持向量操作。即使'-Og'或'-O1'優化了除malloc/free之外的所有內容。嘗試將矢量存儲到'uint32_t'數組中,並用'printf'或者C++ ish來打印。 –

+0

優化器不是一個問題,因爲我在調試模式下測試了這一點,但你仍然是正確的:)但顯然,VS調試器不會正確顯示_m256i值。它幾乎感覺像是在'_m128i'邊界截斷它們。另外,寄存器窗口也沒有太大的幫助。 在將矢量存儲到內存並做了一個'printf'後,一切看起來都很好,所以我想謝謝:) – redeye

+0

哦,哇,當你不能相信調試器的時候,事情就變得很糟糕!當您使用結果時,調試器會更好嗎? –

回答

3

開始與PMOVZX像馬克暗示。

但之後,PSHUFB(_mm256_shuffle_epi8)將比PMULLD快得多,除了它與PMOVZX競爭洗牌端口。 (它在車道上運行,所以你仍然需要PMOVZX)。

所以,如果你只關心吞吐量,而不是延遲,那麼_mm256_mullo_epi32是好的。但是如果延遲很重要,或者如果吞吐量瓶頸超出每個向量2個shuffle-port指令,那麼PSHUFB在每個像素內複製字節應該是最好的。

實際上,即使對於吞吐量,_mm256_mullo_epi32在HSW和BDW上也是不好的:它對於p0來說是2個uops(10c延遲),所以對於一個端口是2個uops。

在SKL上,p01是2 uops(10c延遲),所以它可以維持與VPMOVZXBD相同的每時鐘吞吐量。但是這是一個額外的1UOP,使它更容易出現瓶頸。

(VPSHUFB爲1個UOP,1C延遲,端口5,在支持AVX2所有的英特爾CPU。)