編輯:關於android開發
高效計算——RenderScript
RenderScript是安卓平台上很受谷歌推薦的一個高效計算平台,它能夠自動把計算任務分配到各個可用的計算核心上,包括CPU,GPU以及DSP等,提供十分高效的並行計算能力。可能是由於應用開發時的需求不夠,關於RenderScript的相關文章很少,剛好我在工作中應用到此平台,做了一些筆記,因此決定整理成博文分享給大家。內容主要來源於官方文檔、StackOverflow以及自己的理解,如有錯誤,請大家指正。本篇主要介紹RenderScript的基本概念。
1 RenderScript簡介
RenderScript是安卓提供的一個高效計算平台。它顯著的特點在於:
使用了RenderScript的應用與一般的安卓應用在代碼編寫上與並沒有太大區別。使用了RenderScript的應用依然像傳統應用一樣運行在VM中,但是你需要給你的應用編寫你所需要的RenderScript代碼,且這部分代碼運行在native層。
RenderScript采用從屬控制架構:底層RenderScript被運行在虛擬機中的上層安卓系統所控制。安卓VM負責所有內存管理並把它分配給RenderScript的內存綁定到RenderScript運行時,所以RenderScript代碼能夠訪問這些內存。安卓框架對RenderScript進行異步調用,每個調用都放在消息隊列中,並且會被盡快處理。
RenderScript工作流程需要經歷三層:
RenderScript的主要優點:
缺點:
2 使用RenderScript
使用RenderScript需要對編譯或者開發環境進行一定的配置。
使用RenderScript主要分為兩個步驟:編寫.rs文件以及在Android framework中使用RenderScript,下面分別介紹。
2.1 環境配置
對於Android 3.0 (API level 11)及以上的可以在android.renderscript包中獲取
通過android.support.v8.renderscript包獲取,可以支持API level 8及以上的平台,官方強烈建議使用此支持包的方式來獲取API
Android SDK Tools revision 需要22.2及以上
Android SDK Build-tools revision 需要18.1.0及以上
renderscript.target=18 renderscript.support.mode=true
或者在AS中的build.gradle的defaultConfig中添加
renderscriptTargetApi 18 renderscriptSupportModeEnabled true
注意:target的值應該為11及以上,但推薦使用18.如果在Manifest中配置的minSDK的值與target的值不相同,那麼在編譯的時候,將使用target的值替代Mainfest中的minSDK值。
2.2 編寫RenderScript文件
RenderScript代碼放在.rs或者.rsh文件中,在RenderScript代碼中包含計算邏輯以及聲明所有必須的變量和指針,通常一個.rs文件包含如下幾個部分:
1.分配給RenderScript的輸入輸出地址的指針。在Android3.2以及更低版本中,輸入輸出的指針都需要,在Android4.0及以後的版本中,給出其中一個或者兩個都可以
a) 指向用戶數據的指針。該數據會在RenderScript的計算中用到。該數據可以指向原始類型或者復雜結構類型
b) 用戶數據的大小
從官方文檔來看,老版本的文檔中有介紹root,而新版本的則用kernel替代。官方在弱化root函數的概念,而是推薦使用kernel概念。本質上來說,root僅僅是一個寫法形式上特殊的kernel而已。
uchar4 __attribute__((kernel)) invert(uchar4 in, uint32_t x, uint32_t y) { uchar4 out = in; out.r = 255 - in.r; out.g = 255 - in.g; out.b = 255 - in.b; return out; }
compute kernel基本與一個C函數一樣,但是有如下特征:
a) __attribute__((kernel))標志。該標志表示該函數是一個RenderScript kernel函數,而不是一個invokable函數
b) in參數及其類型。在RenderScript kernel中,這個參數將會基於傳給kernel的輸入Allocation而自動賦值,且默認情況下,對於Allocation中每一個Element都將會執行一遍kernel函數
c) 返回值及其類型。每次kernel函數執行的返回值將會自動寫入到輸出Allocation的正確位置。RenderScript將會對輸入輸出Allocation進行檢查,如果他們與kernel函數聲明不匹配則將拋出異常。
每個kernel都應該有一個輸入Allocation或者一個輸出Allocation或者二者都有,但不能有兩個及以上的輸入或者輸出Allocation。如果需要在kernel中訪問多個輸入或者輸出,則需要聲明rs_allocation全局變量來擔任多余一個的輸入或者輸出角色,然後再kernel函數或者invokable函數中通過rsGetElementAt_type()或者rsSetElementAt_type()來訪問或者設置相應的Allocation,其中type為對應Allocation的Element類型對應的數據類型,比如uchar4。
在kernel中,可以通過可選的xyz參數來獲取當前Element在整個Allocation中的坐標值,比如上面的invert中就通過xy來獲取了xy坐標值。注意xyz的參數名不能設置為其他名稱,且類型必須為uint32_t。
a) #pragma rs_fp_full:默認的等級。表示的完全遵守IEEE 754-2008 standard的精度要求
b) #pragma rs_fp_relaxed:不嚴格的IEEE 754-2008 standard的精度要求
c) #pragma rs_fp_imprecise:比relaxed更低的精度要求
對於大部分應用來說,使用relaxed精度要求都可以滿足要求而無任何副作用
example.rs :
#pragma version(1) #pragma rs java_package_name(com.willhua.rgbtoyuv) #pragma rs_fp_relaxed typedef struct Point_T{ int x; int y; }Point; //script variable uint32_t inW; uint32_t inH; uint32_t inCount; rs_allocation outYUV; struct Point point; //root void root(const uchar4 *in, uint32_t x, uint32_t y){ struct myStruct my; my.x = 0; struct myStruct my2 = my; int u = my.x; uchar R,G,B; int Y,U,V; R = (*in).r; G = (*in).g; B = (*in).b; Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16; uint32_t yIndex = y * inW + x; Y = ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y)); rsSetElementAt_uchar(outYUV, ((uchar)Y), yIndex); if((x & 1) == 0 && (y & 1) == 0) { U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128; V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128; uint32_t index = (y >> 1) * inW + x + inCount; U = ((U < 0) ? 0 : ((U > 255) ? 255 : U)); V = ((V < 0) ? 0 : ((V > 255) ? 255 : V)); rsSetElementAt_uchar(outYUV, ((uchar)U), index + 1); rsSetElementAt_uchar(outYUV, ((uchar)V), index ); } } //compute kernel __attribute__((kernel)) invert(uchar4 in, uint32_t x, uint32_t y) { uchar4 out = in; out.r = 255 - in.r; out.g = 255 - in.g; out.b = 255 - in.b; return out; } //invokable function void setInPara(uint32_t w, uint32_t h){ inW = w; inH = h; inCount = w * h; } //init void init(){ } View Code
2.3 在Android framework層調用RenderScript
雖然各個應用使用RenderScript細節各不相同,但大體有著這樣的模式:
2.4 RenderScript工作流程
最開始就提到,RenderScript是一個主從架構,底層的RenderScript被上層的Android framework所控制。其工作流程也正是如此。從在Android framework創建RenderScript的context開始,然後給RenderScript層分配、綁定相關內存,對script變量進行初始化,然後調用forEach函數通知啟動RenderScript計算。RenderScript將會自動把它的計算任務分配到各個可用的核心上來完成計算任務(現在還只能支持CPU,以後將會支持到GPU以及DSP,且代碼不需要變動)。RenderScript計算完成以後將會自動把計算結果放到相應的Allocation內存,然後在Android framework層再從Allocation中copy出數據,最後Android framework層命令RenderScript釋放資源,流程介紹。下圖展示了RenderScript的工作流程:
RecyclerView 結合 CardView 使用,recyclerview使用准備工作:導入 1.activity_mian.xml <android.sup
Android 手機衛士--設置界面&功能列表界面跳轉邏輯處理,android衛士--界面在《Android 手機衛士--md5加密過程》中已經實現了加密類,這裡
Android中Activity的四大啟動模式實驗簡述,androidactivity作為Android四大組件之一,Activity可以說是最基本也是最常見的組件,它提
Greenplum(GPDB)開源啦!~ Greenplum 數據庫(GPDB)是一個無共享的大規模並行處理數據庫,主要用來處理大規模的數據分析任務,包括數據倉庫、商務
解決 Could not find com.android.tools.