efficient calculation-- Renderscript
Renderscript is a highly efficient computing platform recommended by Google on the Android, which automatically distributes computing tasks to all available compute cores, including CPU,GPU and DSP, providing highly efficient parallel computing capabilities. May be due to the application development needs are not enough, about renderscript related articles very few, just I applied to this platform in the work, made some notes, so decided to organize Cheng Bowen share to everyone. The content is mainly from official documents, StackOverflow and their own understanding, if there are errors, please correct me. This article mainly introduces the basic concept of renderscript.
1 Renderscript Introduction
Renderscript is an efficient computing platform provided by Android. Its notable features are:
- can automatically use a variety of cores, including CPU,GPU and DSP, to carry out parallel computing, can greatly improve the image processing, mathematical models and other fields to provide efficient computing power;
- There is no need to write different code for different core platforms, because Renderscript is compiled on the device while it is running.
Applications that use Renderscript and general Android applications are not much different from code writing. Apps that use Renderscript are still running in VMS like traditional apps, but you need to write the Renderscript code you need for your app, and this part of the code runs on the native layer.
The Renderscript uses a subordinate control architecture: the underlying renderscript is controlled by the upper-level Android system running in the virtual machine. The Android VM is responsible for all memory management and binds it to the renderscript memory binding to the Renderscript runtime, so renderscript code can access the memory. The Android framework makes asynchronous calls to Renderscript, where each call is placed in the message queue and processed as soon as possible.
The Renderscript workflow needs to go through three layers:
- Renderscript Runtime API: provides an API for operations
- reflective layer : equivalent to the JNI glue code in the NDK, it is a class that is automatically generated by the Android compiler tool, wrapping the Renderscript code you write, allowing the Android layer to interact with the Renderscript
- Android Framework : Access to the Renderscript runtime by invoking the reflection layer
Key Benefits of Renderscript:
- Portability: For different architectures, different processors do not need to consider the differentiation of code, because they are compiled on the device at runtime;
- High performance: Provides seamless, parallel computing that leverages all cores
- Ease of use: simplifies coding without the need to write glue code like JNI
Disadvantages:
- Development complexity: Need to learn new APIs
- Debug Visibility: Because Renderscript may be running on a processor other than the main CPU, debugging is difficult
2 Use Renderscript
Using renderscript requires a certain configuration of the compilation or development environment.
Using Renderscript is mainly divided into two steps: writing. rs files and using Renderscript in the Android framework, respectively.
2.1 Environment Configuration
- The Renderscript API can be sourced in two different ways:
For Android 3.0 (API level 11) and above can be obtained in the Android.renderscript package
With the Android.support.v8.renderscript package, which supports platforms with API level 8 and above, it is highly recommended that this support package be used to obtain the API
- Compilation Environment Requirements:
Android SDK Tools revision requires 22.2 and above
Android SDK Build-tools revision requires 18.1.0 and above
- Write the following properties in the Project.Properties file:
Renderscript.target=18Renderscript.support.mode=true
Or add in the defaultconfig of Build.gradle in as
Renderscripttargetapitrue
Note: The value of target should be 11 and above, but 18 is recommended. If the value of MINSDK configured in manifest is not the same as the value of target, then at compile time, the value of target is substituted for the MINSDK value in Mainfest.
2.2 Write Renderscript file
The Renderscript code is placed in a. rs or. rsh file, contains the calculation logic in the Renderscript code, and declares all the necessary variables and pointers, usually an. rs file contains the following sections:
- Compiler declaration: #pragma rs Java_package_name (package.name), such as #pragma rs java_package_name (com.willhua.RenderScript), Used to declare the Java package in which this RS resides. Note: the. rs file can only be in the application package, not in the library project.
- Compilation declaration: #pragma version (1). Declare Renderscript, which is now 1
- The main work function root (). It is called by the Reforeach function of the renderscript layer, which implements the parallel processing of root work by multiprocessor. The root function must return void and accept the following parameters
1. A pointer to the input and output address assigned to the Renderscript. In Android3.2 and earlier, the input and output pointers are required, and in Android4.0 and later versions, one or two of them can be
- 2. The following two parameters are optional, but as long as one is used, two must be provided.
A) A pointer to the user's data. This data will be used in the calculation of Renderscript. The data can point to the original type or to a complex structure type
b) Size of user data
From the official document, the old version of the document is the introduction of root, and the new version is replaced with kernel. The official is weakening the concept of the root function, instead recommending the use of the kernel concept. Essentially, Root is just a special form of kernel.
- The optional init () function. Can be used to do any initialization work, such as initializing variables. It will be executed once each time the Renderscript is started, before any other code
- Some invokable functions. These functions are single-threaded (the work of the kernel function is working in parallel), and you can pass any number of arguments to these functions. These functions will generate the corresponding version in the reflection layer, which can be called from the Android framework. These functions are typically used to do some initialization work or as a serial Compute unit task in a computational task. Note: The invokable function cannot be static.
- Some compute cores (compute kernel). The compute kernel is executed in parallel, and it processes each element in the input allocation in parallel. A simple compute kernel is as follows:
= in ; = 255- in.r; = 255- in.g; = 255-return out ; }
Compute kernel is basically the same as a C function, but has the following characteristics:
A) __attribute__ ((kernel)) logo. The flag indicates that the function is a renderscript kernel function, not a invokable function
b) in parameter and its type. In Renderscript kernel, this parameter is automatically assigned based on the input allocation passed to kernel, and by default the allocation function is executed for each element in kernel
c) The return value and its type. Each time the return value of the kernel function executes is automatically written to the correct location of the output allocation. Renderscript will check the input and output allocation and will throw an exception if they do not match the kernel function declaration.
Each kernel should have an input allocation or an output allocation or both, but cannot have two or more inputs or outputs allocation. If you need to access multiple inputs or outputs in kernel, you need to declare the rs_allocation global variable to act as an extra input or output role, and then kernel the function or invokable function through Rsgetelementat_ Type() or Rssetelementat_type() to access or set the corresponding allocation, where type is the data type corresponding to the element type of the allocation, such as UCHAR4.
In kernel, an optional XYZ parameter can be used to obtain the coordinate value of the current element in the entire allocation, such as the XY coordinate value obtained by XY in the above invert. Note that the parameter name for XYZ cannot be set to a different name, and the type must be uint32_t.
- Any variables, pointers, and structures to be used in the renderscript. These declarations can also be in the. rsh file
- The required script variable. As with global variables in C, these global variables are generally used to pass parameters to the computed kernel.
- Some static variables and functions. The difference between a static variable and a normal global variable is that the static variable is not mapped to the reflection layer, or it cannot be called from the Android framework; a static function is a standard C function, but it is not mapped to the reflection layer and cannot be called from the Android framework. However, it can be called in kernel or invokable in Renderscript. If there are variables or functions that need to be used in renderscript but do not need to be used in Java, it is strongly recommended to set to static.
- Optional precision control configuration with three levels:
A) #pragma rs_fp_full: the default rating. Accuracy required for full compliance with IEEE 754-2008 standard
b) #pragma rs_fp_relaxed: precision requirements for the non-stringent IEEE 754-2008 standard
c) #pragma rs_fp_imprecise: Lower accuracy requirements than relaxed
For most applications, the use of relaxed accuracy requirements can be met without any side effects
Example.rs:
#pragmaVersion (1)#pragmaRS Java_package_name (COM.WILLHUA.RGBTOYUV)#pragmaRs_fp_relaxedtypedefstructpoint_t{intx; inty;} Point;//script Variableuint32_t inw;uint32_t inh;uint32_t incount;rs_allocation outyuv;structPoint point ;//RootvoidRootConstUCHAR4 *inch, uint32_t x, uint32_t y) { structmystruct my; My.x=0; structMyStruct My2 =my; intU =my.x; Uchar R,g,b; inty,u,v; R= (*inch). R; G= (*inch). G; B= (*inch). b; Y= ( ( the* R +129* G + -* B + -) >>8) + -; 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= ( ( - -R About) D + the* B + -) >>8) + -; V= ( ( theR94G -* B + -) >>8) + -; 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 (UCHAR4inch, uint32_t x, uint32_t y) {UCHAR4 out=inch; out. R =255-inch. R; out. G =255-inch. G; out. B =255-inch. b; return out;}//invokable FunctionvoidSetinpara (uint32_t W, uint32_t h) {INW=W; InH=h; Incount= W *h;}//Initvoidinit () {}View Code
2.3 in the Android Framework Layer Invocation Renderscript
While each application uses Renderscript details differently, there is a general pattern:
- initializes the Renderscript context. The Renderscript.create function allows you to create a context in which the context can be used to perform other renderscript actions, and the context allows you to control the life cycle of other Renderscript objects. Because creation of the context requires the creation of resources on different hardware devices, it can be time-consuming. Therefore, it is best not to allow context to be created at a point in time when the response speed requirement is high. In general, an application should have only one context.
- you need to create at least one allocation. The more methods used are createtyped (Renderscript, Type) or Createfrombitmap (Renderscript, Bitmap).
- Create the required scripts. Can be divided into two, one is through the custom. rs file, and then automatically generated in the reflective layer of the SCRIPTC subclass, the name is scriptc_rsfilename; there is a system-defined scripts, such as Gaussian Blur, They are all scriptintrinsic of the class.
- populate the allocation with data . Copy system class method using allocation
- set the necessary script variables . The scriptc_rsfilename will generate a corresponding set method for the script variable, such as a script variable of type int named num will generate the Set_num (int) method in the reflection layer.
- start calculation : The kernel function defined in RS generates the Foreach_kernalname method in the Scriptc_rsfilename class of the reflection layer. The execution of the method is asynchronous and executes in Renderscript in the order of kernel calls. As mentioned earlier, the Foreach_kernalname method performs the calculation by default on all the element in the corresponding allocation, but can be foreach_ The Kernalname parameter is passed to the last scrpit.lunchoptions parameter to specify the subset that needs to be computed in allocation: The invokable function defined in RS is generated in the reflection layer Invoke_ The FunctionName method can also be called on demand
- get the data from the allocation . The data in the allocation can be placed in the Java data by allocation's CopyTo system class method. These CopyTo methods are kept in sync with the Foreach method, and the copy process starts automatically when the foreach calculation is complete. Currently, only basic types of CopyTo are supported, and data such as custom structs are not supported.
- frees resources . Use the Renderscript.destory method to release related resources.
2.4 Renderscript Work Flow
At the very beginning, Renderscript is a master-slave architecture, and the underlying renderscript is controlled by the upper Android framework. And so is its workflow. Start with the context in which the Android framework creates renderscript, and then assign, bind, and initialize the script variable to the RENDERSCRIPT layer, The foreach function is then called to notify the startup Renderscript calculation. Renderscript will automatically assign its computing tasks to the various cores available to complete the compute task (now it can only support the CPU and will support the GPU and DSP in the future, and the code does not need to be changed). Renderscript calculation will automatically put the results into the corresponding allocation memory, and then copy the data from the allocation in the Android framework layer, and finally the Android The framework layer command Renderscript release resources, Process introduction. Demonstrates the Renderscript workflow:
Android Efficient Computing--renderscript (i)