2014-08-28 53 views
2

我有一個32位RGBA圖像緩衝區。讓我們假設它是,比如1920x1080 - 典型的從左到右,從上到下的RAW緩衝區。需要使用英特爾內核來驅動32位Alpha通道

這是我想很快做真的是什麼:創建源於這一個代碼緩衝了兩個新的緩衝區...

  1. 「補」緩衝...... RGB值匹配原始緩衝區。 Alpha值將變爲不透明(0xff)
  2. 「KEY」Buffer ...每個RGB值都與原始緩衝區的Alpha值匹配。 α值將是不透明的(0xff的)

我(慢)的解決方案是用於將輸入緩衝器中的每個像素,如下所示:

u_int32_t pixel = *srcPtr++; // grab the source 32-bit pixel value 
*fillPtr++ = pixel | 0xff; // FILL: keep only the RGB channels (alpha = 0xff) 
pixel &= 0xff;    // KEY: grab just the alpha value 
*keyPtr++ = (pixel<<24) | (pixel<<16) | (pixel<<8) | 0xff; // KEY: xfer alpha to RGB, alpha = 0xff 

人們可以假設源緩衝器是16字節對齊。

一些初步測試在1920x1080圖像 - 英特爾至強E5,六核,12MB三級緩存,3.5Ghz,時鐘約爲8ms。

有人可以提供他們的SSE3 instrinics專業知識,讓這一些加速?

+0

科裏..我沒試過從SSE-土地作爲東西我只有它存在的一個粗略的認識。 – zzyzy 2014-08-28 14:12:05

回答

2

聽起來這是您想要的基礎 - 它一次處理四個像素。

void split_pixels(__m128i src, __m128i *fill, __m128i *key) 
{ 
    __m128i const alphamask = _mm_set_epi8(-1, 0, 0, 0, -1, 0, 0, 0, 
              -1, 0, 0, 0, -1, 0, 0, 0); 
    __m128i const fillmask = _mm_set_epi8(-1, 15, 15, 15, -1, 12, 12, 12, 
              -1, 7, 7, 7, -1, 3, 3, 3); 

    _mm_stream_si128(fill, _mm_or_si128(src, alphamask)); 
    _mm_stream_si128(key, _mm_or_si128(_mm_shuffle_epi8(src, fillmask), alphamask)); 
} 

它利用了SSE shuffle指令,它通過它們在寄存器中的索引對字節進行混洗。它也使用流媒體存儲,因爲您無法在緩存中安裝三個1080p緩衝區。流媒體商店是挑剔的,可能會或可能不會幫助取決於你在做什麼,所以我會基準這些。

請注意,這個問題是高度瓶頸的內存帶寬,所以雖然它可能比你的普通C版本運行得更快,它可能不會運行速度加快4倍。在商店之前可以捆綁的處理越多,執行速度就越快。

+0

你爲什麼說流媒體商店「挑剔」? – 2014-08-28 07:03:26

+0

Dang it ...我知道我應該已經獲得了帶有25MB緩存的8核心;-)真的,非常感謝你 - 我會給它一個旋轉和報告。 – zzyzy 2014-08-28 14:07:10

0

除了科裏的答案,你可以嘗試多個線程。儘管這是使用多線程can increase the throughput for a single socket system by up to a factor of two(甚至在多套接字系統上更多)的內存綁定。

你可以做這樣的事情使用OpenMP

#pragma omp parallel for 
for(int i=0; i<height; i++) { 
    for(int j=0; <width; j+=4) { 
     split_pixels(&src[i*width+j], &fill[i*width+j], &key[i*width+j]) 
    } 
} 
+0

如果我使用多線程,我將在Mac上使用dispatch_apply和GCD(Grand Central Dispatch)。我的經驗是,除非L3緩存對於源/目標緩衝區足夠大,否則在多個內核之間剝離工作將導致最小的增益。 – zzyzy 2014-08-28 14:10:22