Search This Blog

7/23/16

開始在 Intel® Architecture 的 Android* 作業系統上使用 RenderScript

STANISLAV P. (Intel) 發佈於 2014 年 3 月 25 日星期二

產品介紹

RenderScript 是 Android 上的腳本語言。可用來編寫高效能的圖形渲染程式碼和原始的運算程式碼。
RenderScript API 包含高效能的 2D/3D 渲染和數學運算功能,可讓使用者以同類型的大量資料獨立運算來描述一個任務,並將其分割為相似的子任務,以便在執行 Android 的多核心平台上迅速並同步執行。
該技術可改善許多影像處理、影像辨識、物體模型等相關的 Dalvik 應用程式的效能,以此保持機器的獨立度。

Android 之中的 RenderScript 技術

RenderScript 離線編譯
RenderScript 首次現身是在 Honeycomb/Android 3.0 (API 11) 上。在 Android SDK 目錄的平台工具裡可以找到 llvm-rs-cc (離線編譯器),能夠將 RenderScript (*.rs 檔案) 編譯為位元組碼 (*.bc 檔案) 並產生 Java* 類別物件 (*.java 檔案),以供 RenderScript 內的結構和總體變數以及 RenderScript 自身使用。llvm-rs-cc 是以 Clang 編譯器為基礎,再加上一些針對 Android 的改變,是 LLVM 編譯器的前端。下圖可說明離線編譯的運作方式。
RenderScript 執行階段編譯
新的 Android 框架是建立在 LLVM 的後端之上,負責進行位元組碼的執行階段編譯、連結至正確的程式庫、以及 RenderScript 的啟動和控制。該框架由下列元件組成:libbcc 負責處理 LLVM 文本初始化、解析 pragma 和位元組碼內的其他元數據、位元組碼的編譯,以及來自 libRS 的所需程式庫動態連結。libRS 內含程式庫 (數學、時間、製圖、引用計數等)、結構、資料類型 (Script、Type、Element、Allocation、Mesh、各種矩陣等)。執行階段編譯即如下圖所示。
RenderScript 的優點:
  • 由於應用程序包 (APK) 內的 RenderScript 位元組碼在運行時,會被編譯為即將啟動的平台的 CPU 的原生碼,導致編譯器生成無關機器的應用程式。
  • 藉由平行運算、執行階段編譯器優化與原生碼執行,能夠達到極快的執行速度。
缺點:
  • RenderScript 缺乏詳細的說明文件,導致應用程式開發的複雜度較高。RenderScript 執行階段 API 的執行階段限制文件請見此處。或參閱此處的詳細「入門介紹」。
  • 不支援在 GPU 或 DSP 上執行 RenderScript 執行緒。平衡異構運行 (heterogeneous runs) 中執行緒的執行階段以及使用共享記憶體時可能會遭遇問題。

RenderScript 使用範例:將 RGB 色彩轉為單色影像

RenderScript 是以 C 語言為基礎。若對 C 語言有認識很快就能學會,使用原則和 OpenGL* 大致相同。
在 Intel 我們通常會利用 RenderScript 或是 OpenGL 來促進 Dalvik 的函式。
以下為 Dalvik 函式之一的範例,Dalvik_MonoChromeFilter 的作用是將 RGB 色彩的影像轉為單色影像。
private void DalvikFilter() {
    float MonoMult[] = {0.299f, 0.587f, 0.114f};
    int mInPixels[] = new int[mBitmapIn.getHeight() * mBitmapIn.getWidth()];
    int mOutPixels[] = new int[mBitmapOut.getHeight() * mBitmapOut.getWidth()];
    mBitmapIn.getPixels(mInPixels, 0, mBitmapIn.getWidth(), 0, 0,
            mBitmapIn.getWidth(), mBitmapIn.getHeight());
    for(int i = 0;i < mInPixels.length;i++) {
        float r = (float)(mInPixels[i] & 0xff);
        float g = (float)((mInPixels[i] >> 8) & 0xff);
        float b = (float)((mInPixels[i] >> 16) & 0xff);
 
        int mono = (int)(r * MonoMult[0] + g * MonoMult[1] + b * MonoMult[2]);
 
        mOutPixels[i] = mono + (mono << 8) + (mono << 16) + (mInPixels[i] & 0xff000000);
        }
    mBitmapOut.setPixels(mOutPixels, 0, mBitmapOut.getWidth(), 0, 0,
            mBitmapOut.getWidth(), mBitmapOut.getHeight());
}
可以看到該程式碼有一個簡單迴圈,獨立疊代處理像素的串流。
作為實驗,我們使用搭載了 Intel® Atom™ 處理器的 Lenovo K900,在一張解析度為 600x1024、手上捧著一推聖誕禮物的樂高* 怪物照片上執行該程式碼。
此為 RS_MonoChromeFilter 函式 (RenderScript 的實作是取自 Apache 2.0 授權條款 下的 Android SDK) 將 RGB 色彩的影像轉為單色影像的範例:
 private RenderScript mRS;
private Allocation mInAllocation;
private Allocation mOutAllocation;
private ScriptC_mono mScript;
…
private void RS_MonoChromeFilter() {
mRS = RenderScript.create(this);//RenderScript context creating
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
            Allocation.MipmapControl.MIPMAP_NONE,
                Allocation.USAGE_SCRIPT);/*allocation and initialization of shared memory */
        mOutAllocation = Allocation.createTyped(mRS,
mInAllocation.getType());
        mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono); /*creating and binding RenderScript to the context */      
        mScript.forEach_root(mInAllocation, mOutAllocation);/*Call root function by two SMP threads */
         
        mOutAllocation.copyTo(mBitmapOut);
}
 
//mono.rs
//or our small RenderScript
#pragma version(1)
#pragma rs java_package_name(com.example.hellocompute)
 
//multipliers to convert a RGB colors to black and white
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
 
void root(const uchar4 *v_in, uchar4 *v_out) {
  //unpack a color to a float4
  float4 f4 = rsUnpackColor8888(*v_in);
  //take the dot product of the color and the multiplier
  float3 mono = dot(f4.rgb, gMonoMult);
  //repack the float to a color
  *v_out = rsPackColorTo8888(mono);
}

RenderScript 優化範例

可利用更加積極的浮點運算優化來改善 RenderScript 的效能。在下一個程式碼片段中,我們將 rs_fp_imprecise pragma 加入至 RenderScript 以加速運算,同時不會降低圖片品質。
//mono.rs
//or our small RenderScript
#pragma version(1)
#pragma rs java_package_name(com.example.hellocompute)
#pragma rs_fp_imprecise
//multipliers to convert a RGB colors to black and white
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
 
void root(const uchar4 *v_in, uchar4 *v_out) {
  //unpack a color to a float4
  float4 f4 = rsUnpackColor8888(*v_in);
  //take the dot product of the color and the multiplier
  float3 mono = dot(f4.rgb, gMonoMult);
  //repack the float to a color
  *v_out = rsPackColorTo8888(mono);
}
優化後的程式碼會產生相同品質的單色影像,不會出現假影或是失真的情況。和 NDK 不同,由於編譯器旗標之前是在各平台 (x86、ARM 等) 的 Android 內部宣告,因此沒有機制可明確地控制執行階段編譯器優化 RenderScript。


No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...