日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【genius_platform软件平台开发】第四点:ARM NEON Intrinsics 使用详解

發布時間:2023/12/8 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【genius_platform软件平台开发】第四点:ARM NEON Intrinsics 使用详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

前言

SIMD簡介

ARM NEON Intrinsics簡介

函數改寫示例

結語


前言

最近公司在視頻直播項目中要使用H.265/HEVC,具體的是使用HW硬件編碼H.264/AVC,云端轉碼成H.265/HEVC并推流的解決方案。方案中使用的解碼器是FFMpeg中的H.265解碼器,該解碼器是從OpenHEVC直接獲取的,比起備受好評的H.264/AVC解碼器,這個解碼器目前優化不足,在手機上占用資源較高。因此一個工作就是優化該解碼器在手機上的性能表現,主要使用ARM提供的SIMD指令進行優化。

SIMD簡介

Single Instruction Multiple Data (SIMD),單指令多數據。從字面理解,就是在CPU執行中,一條操作指令可以同時操作多個寄存器,從而在物理上倍數的加速運行。我理解范疇內的X86平臺上最早的SIMD指令應該是奔騰MMX上自帶的MMX指令,其寄存器寬度是64位,可以同時操作8個字節。MultiMedia eXtensions (MMX)是多媒體擴展的意思,其最初的設計目的就是為了加速圖像/視頻等高并行數據的處理速度。

  • 一個簡單的SIMD示意圖如下所示:

    ?

    SIMD 8x8加法示意圖

在這里,一條SIMD加法指令可以同時得到8個加法結果。就計算步驟本身而言,比單獨使用8條加法指令能夠獲得8倍的加速比。從該示例也可以看出,隨著寄存器長度的變長,單指令能夠處理的數據量也越來越大,從而獲得更高的加速性能。在Intel最新的AVX2指令集中,寄存器最大長度已經達到512位。

ARM NEON Intrinsics簡介

NEON指令是從Armv7架構開始引入的SIMD指令,其共有16個128位寄存器。發展到最新的Arm64架構,其寄存器數量增加到32個,但是其長度仍然為最大128位,因此操作上并沒有發生顯著的變化。對于這樣的寄存器,因為可以同時存儲并處理多組數據,稱之為向量寄存器。Intrinsics是使用C語言的方式對NEON寄存器進行操作,因為相比于傳統的使用純匯編語言,具有可讀性強,開發速度快等優勢。如果需要在代碼中調用NEON Intrinsics函數,需要加入頭文件"arm_neon.h"。

數據類型

NEON Intrinsics內置的整數數據類型主要包括以下幾種:

  • (u)int8x8_t;
  • (u)int8x16_t;
  • (u)int16x4_t;
  • (u)int16x8_t;
  • (u)int32x2_t;
  • (u)int32x4_t;
  • (u)int64x1_t;

其中,第一個數字代表的是數據類型寬度為8/16/32/64位,第二個數字代表的是一個寄存器中該類型數據的數量。如int16x8_t代表16位有符號數,寄存器中共有8個數據。

常用指令

NEON Intrinsics支持的所有指令可參看ARM NEON Intrinsics,其包含了常用的arm匯編指令類型,如數學運算,邏輯運算等。另外,其引入了有針對性的加載/存儲/轉置/交叉存取等指令。部分常見的指令在會下面的示例環節中予以說明。需要注意的是,指令中的助記符與arm匯編是相同的。

示例1:

  • int16x8_t vqaddq_s16 (int16x8_t, int16x8_t)
  • int16x4_t vqadd_s16 (int16x4_t, int16x4_t)
  • 第一個字母'v'指明是vector向量指令,也就是NEON指令;
  • 第二個字母'q'指明是飽和指令,即后續的加法結果會自動飽和;
  • 第三個字段'add'指明是加法指令;
  • 第四個字段'q'指明操作寄存器寬度,為'q'時操作QWORD, 為128位;未指明時操作寄存器為DWORD,為64位;
  • 第五個字段's16'指明操作的基本單元為有符號16位整數,其最大表示范圍為-32768 ~ 32767;
  • 形參和返回值類型約定與C語言一致。
  • 其它可能用到的助記符包括:

    • l 長指令,數據擴展
    • w 寬指令,數據對齊
    • n 窄指令, 數據壓縮

    示例2

    • uint8x8_t vld1_u8 (const uint8_t *)
  • 第二個字段'ld'表示加載指令
  • 第三個字段'1'(注意是1,不是l)表示順次加載。如果需要處理圖像的RGB分量,可能會用到vld3。關于vld/vst指令更詳細的說明,請自己參閱arm官方文檔。
  • 函數改寫示例

    1. 簡單示例

    原始代碼

    // uint8_t *_dst, uint8_t *_src, int16_t *src2 // int height, int width for (y = 0; y < height; y++) {for (x = 0; x < width; x++) {dst[x] = av_clip_pixel(((src[x] << 6) + src2[x] + offset) >> shift);}src += srcstride;dst += dststride;src2 += MAX_PB_SIZE; }

    改寫代碼

    int16x8_t result_16x8; int16x8_t offset_16x8 = vmovq_n_s16(offset); int16x8_t minusshift_16x8 = vmovq_n_s16(-1 * shift); int16x8_t min_16x8 = vmovq_n_s16(0); int16x8_t max_16x8 = vmovq_n_s16(255);for (y = 0; y < height; y++) {for (x = 0; x < width; x+=8) {result_16x8 = vshlq_n_s16(vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x]))), 6);result_16x8 = vshlq_s16(vqaddq_s16(vqaddq_s16(result_16x8, vld1q_s16(&src2[x])), offset_16x8), minusshift_16x8);vst1_u8(&dst[x], vqmovn_u16(vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(result_16x8, max_16x8), min_16x8))));}src += srcstride;dst += dststride;src2 += MAX_PB_SIZE; }

    說明:

    • 這里只針對寬度為8的倍數進行了改寫,實際代碼中需要對傳入參數進行判斷
    • vld1_u8讀取8字節數據,vmovl_u8對讀取的uint8x8進行寬度擴展
    • vreinterpretq_s16_u16對數據類型進行強制轉換
    • vshlq_n_s16對數據進行左移處理(P.S. NEON提供了右移指令,但是只能使用整數常量。需要根據變量進行右移時,只能使用左移負數位的方法。)
    • vqmovn_u16對處理結果進行寬度壓縮
    • vst1_u8將處理后的int16x8_t數據寫回內存

    2.進階示例

    原始代碼

    /* #define QPEL_FILTER(src, stride) \ (filter[0] * src[x - 3 * stride] + \filter[1] * src[x - 2 * stride] + \filter[2] * src[x - stride] + \filter[3] * src[x ] + \filter[4] * src[x + stride] + \filter[5] * src[x + 2 * stride] + \filter[6] * src[x + 3 * stride] + \filter[7] * src[x + 4 * stride])DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters[3][16]) = {{ -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0},{ -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1},{ 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1} }; */ filter = ff_hevc_qpel_filters[mx - 1]; for (y = 0; y < height + QPEL_EXTRA; y++) {for (x = 0; x < width; x++)tmp[x] = QPEL_FILTER(src, 1);src += srcstride;tmp += MAX_PB_SIZE; }

    改寫代碼

    /* DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filtersT[3][64]) = {{ -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, 4, 4, 4, 4, 4, 4,//(0)-10,-10,-10,-10,-10,-10,-10,-10, 58, 58, 58, 58, 58, 58, 58, 58,17, 17, 17, 17, 17, 17, 17, 17, -5, -5, -5, -5, -5, -5, -5, -5,1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},{ -1, -1, -1, -1, -1, -1, -1, -1, 4, 4, 4, 4, 4, 4, 4, 4,//(1)-11,-11,-11,-11,-11,-11,-11,-11, 40, 40, 40, 40, 40, 40, 40, 40,40, 40, 40, 40, 40, 40, 40, 40,-11,-11,-11,-11,-11,-11,-11,-11,4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1},{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,//(2)-5, -5, -5, -5, -5, -5, -5, -5, 17, 17, 17, 17, 17, 17, 17, 17,58, 58, 58, 58, 58, 58, 58, 58,-10,-10,-10,-10,-10,-10,-10,-10,4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1} }; */ int16x8_t filteT_16x8_0, filteT_16x8_1, filteT_16x8_2, filteT_16x8_3, filteT_16x8_4, filteT_16x8_5, filteT_16x8_6, filteT_16x8_7; int16x8_t result_16x8;filter = ff_hevc_qpel_filtersT[mx - 1];filteT_16x8_0 = vmovl_s8(vld1_s8(&filter[0])); filteT_16x8_1 = vmovl_s8(vld1_s8(&filter[8])); filteT_16x8_2 = vmovl_s8(vld1_s8(&filter[16])); filteT_16x8_3 = vmovl_s8(vld1_s8(&filter[24])); filteT_16x8_4 = vmovl_s8(vld1_s8(&filter[32])); filteT_16x8_5 = vmovl_s8(vld1_s8(&filter[40])); filteT_16x8_6 = vmovl_s8(vld1_s8(&filter[48])); filteT_16x8_7 = vmovl_s8(vld1_s8(&filter[56]));for (y = 0; y < height + QPEL_EXTRA; y++) {for ( x = 0; x < width; x += 8 ) {// init the output regresult_16x8 = vmovq_n_s16(0);// (0)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x-3]))), filteT_16x8_0);// (1)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x-2]))), filteT_16x8_1);// (2)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x-1]))), filteT_16x8_2);// (3)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x]))), filteT_16x8_3);// (4)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x+1]))), filteT_16x8_4);// (5)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x+2]))), filteT_16x8_5);// (6)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x+3]))), filteT_16x8_6);// (7)result_16x8 = vmlaq_s16(result_16x8, vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x+4]))), filteT_16x8_7);// store the output datavst1q_s16(&tmp[x], result_16x8);}src += srcstride;tmp += MAX_PB_SIZE; }

    說明:
    在C實現中,每個結果需要讀取包括自身在內的8個輸入,乘以相應的系數并累加。最簡單直觀的實現方法是

    output_16x8 = vmulq_s16( vreinterpretq_s16_u16(vmovl_u8(vld1_u8(&src[x-3]))), vmovl_s8(vld1_s8(ff_hevc_qpel_filters[mx - 1])));

    這樣實現,會使得8個乘積分布在同一個向量寄存器中,需要通過取寄存器的不同元素實現累加,加法部分無法并行。
    在C實現中,其數學表示為兩個1x8和8x1的矩陣之間的乘法。分析數據間的關系,將矩陣乘法轉換為矩陣轉置乘法,可以得出前文改寫代碼的實現。在該實現中,由于濾波器系統固定,因此預先定義了其轉置矩陣并擴展。在進行'乘加'操作的過程中,一個循環將8個結果全部計算完畢,使得乘法/加法均實現了并行化。
    P.S. 這里,單獨設置了8個向量寄存器變量并展開使得代碼較長,使用循環+數組的方式也可以得到同樣的結果,且代碼較短。但是在底層高頻函數中,盡量展開循環可以最大化的提升效率。

    結語

    本文只介紹了使用ARM NEON Intrinsics的原理和基本應用。實際中需要對待優化的函數原理及能使用的資源了解清楚才能使用最有效的方法并行化程序。

    總結

    以上是生活随笔為你收集整理的【genius_platform软件平台开发】第四点:ARM NEON Intrinsics 使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 中文字幕在线播放av | 精品久久久无码中文字幕边打电话 | 欧美日韩八区 | 青青草视频播放器 | 欧美36p| 激情网久久 | chinese xxxx videos andvr | 久久夜视频 | 夜夜精品一区二区无码 | 99热欧美| 少妇极品熟妇人妻无码 | 成人网免费 | 爽爽影院免费观看 | av片手机在线观看 | 欧美激情啪啪 | 色乱码一区二区三区网站 | 久久女女| 亚洲精品午夜国产va久久成人 | 波多野结衣伦理 | 精品一区二区三区四区五区六区 | 日日碰狠狠添天天爽无码 | 91无打码| 91免费高清视频 | 农村妇女一区二区 | 精品探花 | 韩国bj大尺度vip福利网站 | 中文字幕乱码人妻无码久久95 | 中文字幕一区二区在线播放 | 亚洲欧美日韩精品久久亚洲区 | 国产一区二区三区视频 | 成人福利网站在线观看 | 沈樵精品国产成av片 | 精品中出| 激情国产一区 | 永久免费看mv网站入口亚洲 | 日本不卡视频在线观看 | 国产不卡视频在线播放 | 亚洲av成人片色在线观看高潮 | 黄色成人在线观看 | 超碰caopeng | 最近2019中文字幕大全第二页 | 久久久久久久久久久久久久av | 日本一二区视频 | 看看黄色片 | 欧美国产日韩在线观看成人 | 中国久久久 | 超碰在线成人 | 亚洲欧美激情在线 | 天天操导航| 一区二区三区 欧美 | www.伊人.com| 久久久嫩草 | 美国一级特黄 | 性xxx法国hd极品 | 亚洲天堂网在线视频 | 99热精品久久 | 精品无码久久久久久久久果冻 | 中国一级特黄毛片 | 欧美性猛交xxxx免费看 | 天天干夜夜爱 | 亚洲一区二区免费电影 | 正在播放一区二区 | 亚洲天堂欧美在线 | 成年人视频在线看 | 一区二区三区久久久久 | 琪琪色在线视频 | 欧美xxxx少妇 | 精品成人免费视频 | 91免费看.| 一起操在线 | 日操夜操天天操 | 在线免费观看国产视频 | 久草成人 | 日韩成人性视频 | 久久国产亚洲精品无码 | 免费av网站在线观看 | 山村淫强伦寡妇 | 欲色av| 中文字字幕第183页 欧美特级一级片 | 啪啪网站免费 | 欧美亚洲精品在线 | 快乐激情网| 黄色录像三级 | av片手机在线观看 | 日韩av在线一区 | 欧美日韩国产综合网 | 天天摸天天操天天爽 | 超碰66 | 亚洲无吗在线观看 | 国产一区二区久久 | 华人在线视频 | 亚洲熟女一区二区三区 | 在线观看视频91 | 老色鬼av | 国产精品嫩草影院av蜜臀 | 国产奶头好大揉着好爽视频 | 午夜污片| 娇小6一8小毛片 | 精品国产一区二区不卡 |