產品介紹
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。
Comments
Post a Comment