2012-02-26 55 views
1

我試圖圍繞霓虹內在環繞我的頭,並認爲我可以從一個例子開始,並提出一些問題。ARM霓虹內在深度轉換

在這個實驗中,我想將32位RGB轉換爲16位BGR。將以下代碼轉換爲使用NEON內部函數將會是一個好的開始?我在這裏遇到的問題是16bit與我看不到的內在匹配。有16x4 16x8等,但我只是有點運氣包裝我的想法,我需要如何處理這個問題。有小費嗎?

這是我想要轉換的代碼。

typedef struct { 
    uint16_t b:5, g:6, r:5; 
} _color16; 

static int depth_transform_32_to_16_c (VisVideo *dest, VisVideo *src) 
{ 
    int x, y; 
    int w; 
    int h; 

    _color16 *dbuf = visual_video_get_pixels (dest); 
    uint8_t *sbuf = visual_video_get_pixels (src); 

    uint16x8 

    int ddiff; 
    int sdiff; 

    depth_transform_get_smallest (dest, src, &w, &h); 

    ddiff = (dest->pitch/dest->bpp) - w; 
    sdiff = src->pitch - (w * src->bpp); 

    for (y = 0; y < h; y++) { 
     for (x = 0; x < w; x++) { 
      dbuf->b = *(sbuf++) >> 3; 
      dbuf->g = *(sbuf++) >> 2; 
      dbuf->r = *(sbuf++) >> 3; 

      dbuf++; 
      sbuf++; 
     } 

     dbuf += ddiff; 
     sbuf += sdiff; 
    } 

    return VISUAL_OK; 
} 

編輯:哦,由於某種原因,我一直在尋找這個考慮16×3位,但我們正在尋找5,6,5- = 16位。我意識到我需要輪班。嗯。

回答

4

NEON使用128位寬的寄存器,因此概念上你想要做的是讀取四個像素的32位RGB,對這些像素使用按位運算,最後寫出你的16位像素。一個觀察結果是,爲獲得最佳性能,您可能需要組合兩個128位輸入(8個32位像素)並生成一個128個輸出。這將使您的內存訪問更加高效。

另一種考慮這種方式的方法是,你正在採取你的內循環內容,並行做四個像素。使用原始代碼有點困難的原因在於某些「魔法」隱藏,因爲您使用的是位域。如果您重新編寫了C代碼,使其能夠從32位工作到16位,並且使用shift /和/或該代碼會更自然地轉換爲SIMD,並且您可以直觀地看到如何在該上下文中處理多個數據。

如果你只是看每個32位組件 - > 16位的轉換:

00000000RRRRRRRRGGGGGGGGBBBBBBBB 
0000000000000000BBBBBGGGGGGRRRRR 

這可以幫助您可視需要在平行的四個像素做什麼。移位,提取和合並。對於寄存器寬度無關的一些位操作(例如,或者4個32位寄存器或8個16位寄存器是相同的),您可以將其看作4個32位通道。

粗糙僞代碼:

  • 讀取(矢量負載)128位寄存器= 4的32位的像素。
  • Shift綠色(全部四個組件)進入右位位置。
  • 將綠色遮蓋(使用遮罩)到另一個寄存器中。 (概念上仍然處於4×32比特「模式」)
  • 移位紅色(全部四個分量)進入右邊的比特位置。
  • 將紅色遮蔽到另一個寄存器中。
  • Shift藍色變成正確的位位置。
  • 將藍色遮擋到另一個寄存器中。
  • Shift紅色和藍色到右邊的位置。
  • 使用按位進行組合。
  • 現在你將有32位對齊的4個16位值。 (到目前爲止仍然在概念上爲4×32比特)
  • 用另一組4個像素重複。
  • 將這兩個組合與一個NEON解壓縮(VUZP)以生成一個128位/ 8像素寄存器。
  • 寫入(向量存儲)這些像素。