blob: 5f466ce0ba1747a17aff8f1a48671a68ce022b93 [file] [log] [blame]
page.title=Renderscript Computation
parent.title=Computation
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#overview">Renderscript System Overview</a></li>
<li><a href="#filterscript">Filterscript</a></li>
<li>
<a href="#creating-renderscript">Creating a Computation Renderscript</a>
<ol>
<li><a href="#creating-rs-file">Creating the Renderscript file</a></li>
<li><a href="#calling">Calling the Renderscript code</a></li>
</ol>
</li>
</ol>
<h2>Related Samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">Hello
Compute</a></li>
</ol>
</div>
</div>
<p>Renderscript offers a high performance computation API at the native
level that you write in C (C99 standard). Renderscript gives your apps the ability to run
operations with automatic parallelization across all available processor cores.
It also supports different types of processors such as the CPU, GPU or DSP. Renderscript
is useful for apps that do image processing, mathematical modeling, or any operations
that require lots of mathematical computation.</p>
<p>In addition, you have access to all of these features without having to write code to
support different architectures or a different amount of processing cores. You also
do not need to recompile your application for different processor types, because Renderscript
code is compiled on the device at runtime.</p>
<p class="note"><strong>Deprecation Notice</strong>: Earlier versions of Renderscript included
an experimental graphics engine component. This component
is now deprecated as of Android 4.1 (most of the APIs in <code>rs_graphics.rsh</code>
and the corresponding APIs in {@link android.renderscript}).
If you have apps that render graphics with Renderscript, we highly
recommend you convert your code to another Android graphics rendering option.</p>
<h2 id="overview">Renderscript System Overview</h2>
<p>The Renderscript runtime operates at the native level and still needs to communicate
with the Android VM, so the way a Renderscript application is set up is different from a pure VM
application. An application that uses Renderscript is still a traditional Android application that
runs in the VM, but you write Renderscript code for the parts of your program that require
it. No matter what you use it for, Renderscript remains platform
independent, so you do not have to target multiple architectures (for example,
ARM v5, ARM v7, x86).</p>
<p>The Renderscript system adopts a control and slave architecture where the low-level Renderscript runtime
code is controlled by the higher level Android system that runs in a virtual machine (VM). The
Android VM still retains all control of memory management and binds memory that it allocates to
the Renderscript runtime, so the Renderscript code can access it. The Android framework makes
asynchronous calls to Renderscript, and the calls are placed in a message queue and processed
as soon as possible. Figure 1 shows how the Renderscript system is structured.</p>
<img id="figure1" src="{@docRoot}images/rs_overview.png" />
<p class="img-caption"><strong>Figure 1.</strong> Renderscript system overview</p>
<p>When using Renderscript, there are three layers of APIs that enable communication between the
Renderscript runtime and Android framework code:</p>
<ul>
<li>The Renderscript runtime APIs allow you to do the computation
that is required by your application.</li>
<li>The reflected layer APIs are a set of classes that are reflected from your Renderscript
runtime code. It is basically a wrapper around the Renderscript code that allows the Android
framework to interact with the Renderscript runtime. The Android build tools automatically generate the
classes for this layer during the build process. These classes eliminate the need to write JNI glue
code, like with the NDK.</li>
<li>The Android framework layer calls the reflected layer to access the Renderscript
runtime.</li>
</ul>
<p>Because of the way Renderscript is structured, the main advantages are:</p>
<ul>
<li>Portability: Renderscript is designed to run on many types of devices with different
processor (CPU, GPU, and DSP for instance) architectures. It supports all of these architectures without
having to target each device, because the code is compiled and cached on the device
at runtime.</li>
<li>Performance: Renderscript provides a high performance computation API with seamless parallelization
across the amount of cores on the device.</li>
<li>Usability: Renderscript simplifies development when possible, such as eliminating JNI glue code.</li>
</ul>
<p>The main disadvantages are:</p>
<ul>
<li>Development complexity: Renderscript introduces a new set of APIs that you have to learn.</li>
<li>Debugging visibility: Renderscript can potentially execute (planned feature for later releases)
on processors other than the main CPU (such as the GPU), so if this occurs, debugging becomes more difficult.
</li>
</ul>
<p>For a more detailed explanation of how all of these layers work together, see
<a href="{@docRoot}guide/topics/renderscript/advanced.html">Advanced Renderscript</a>.<p>
<h2 id="filterscript">Filterscript</h2>
<p>Introduced in Android 4.2 (API Level 17), Filterscript defines a subset of Renderscript
that focuses on image processing operations, such as those
that you would typically write with an OpenGL ES fragment shader. You still write your scripts
using the standard Renderscript runtime APIs, but within stricter
constraints that ensure wider compatibility and improved optimization across
CPUs, GPUs, and DSPs. At compile time, the precompiler evaluates Filterscript files and
applies a more stringent set of warnings and errors than
it does for standard Renderscript files. The following list describes the major constraints
of Filterscript when compared to Renderscript:</p>
<ul>
<li>Inputs and return values of root functions cannot contain pointers. The default root function
signature contains pointers, so you must use the <code>__attribute__((kernel))</code> attribute to declare a custom
root function when using Filterscript.</li>
<li>Built-in types cannot exceed 32-bits.</li>
<li>Filterscript must always use relaxed floating point precision by using the
<code>rs_fp_relaxed</code> pragma.</li>
<li>Filterscript files must end with an <code>.fs</code> extension, instead of an <code>.rs</code> extension.</li>
</ul>
<h2 id="creating-renderscript">Creating a Renderscript</h2>
<p>Renderscript scales to the amount of
processing cores available on the device. This is enabled through a function named
<code>rsForEach()</code> (or the <code>forEach_root()</code> method at the Android framework level).
that automatically partitions work across available processing cores on the device.</p>
<p>Implementing a Renderscript involves creating a <code>.rs</code> file that contains
your Renderscript code and calling it at the Android framework level with the
<code>forEach_root()</code> or at the Renderscript runtime level with the
<code>rsForEach()</code> function. The following diagram describes how a typical
Renderscript is set up:</p><img src="{@docRoot}images/rs_compute.png">
<p class="img-caption"><strong>Figure 1.</strong> Renderscript overview</p>
<p>The following sections describe how to create a simple Renderscript and use it in an
Android application. This example uses the <a href=
"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute Renderscript
sample</a> that is provided in the SDK as a guide (some code has been modified from its original
form for simplicity).</p>
<h3 id="creating-rs-file">Creating the Renderscript file</h3>
<p>Your Renderscript code resides in <code>.rs</code> and <code>.rsh</code> files in the
<code>&lt;project_root&gt;/src/</code> directory. This code contains the computation logic
and declares all necessary variables and pointers.
Every <code>.rs</code> file generally contains the following items:</p>
<ul>
<li>A pragma declaration (<code>#pragma rs java_package_name(<em>package.name</em>)</code>)
that declares the package name of the <code>.java</code> reflection of this Renderscript.</li>
<li>A pragma declaration (<code>#pragma version(1)</code>) that declares the version of
Renderscript that you are using (1 is the only value for now).</li>
<li><p>A root function (or kernel) that is the main entry point to your Renderscript.
The default <code>root()</code> function must return
<code>void</code> and accept the following arguments:</p>
<ul>
<li>Pointers to memory allocations that are used for the input and output of the
Renderscript. Both of these pointers are required for Android 3.2 (API level 13) platform
versions or older. Android 4.0 (API level 14) and later requires one or both of these
allocations.</li>
</ul>
<p>The following arguments are optional, but both must be supplied if you choose to use
them:</p>
<ul>
<li>A pointer for user-defined data that the Renderscript might need to carry out
computations in addition to the necessary allocations. This can be a pointer to a simple
primitive or a more complex struct.</li>
<li>The size of the user-defined data.</li>
</ul>
<p>Starting in Android 4.1 (API Level 16), you can choose to define your own root function arguments
without adhering to the default root function signature described previously. In addition,
you can declare multiple root functions in the same Renderscript. To do this, use the <code>__attribute__((kernel))</code>
attribute to define a custom root function. For example, here's a root function
that returns a <code>uchar4</code> and accepts two <code>uint32_t</code> types: </p>
<pre>
uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
...
}
</pre>
</li>
<li>An optional <code>init()</code> function. This allows you to do any initialization
before the root function runs, such as initializing variables. This
function runs once and is called automatically when the Renderscript starts, before anything
else in your Renderscript.</li>
<li>Any variables, pointers, and structures that you wish to use in your Renderscript code (can
be declared in <code>.rsh</code> files if desired)</li>
</ul>
<p>The following code shows how the <a href=
"{@docRoot}resources/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.html">
mono.rs</a> file is implemented:</p>
<pre>
#pragma version(1)
#pragma rs java_package_name(com.example.android.rs.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);
}
</pre>
<h4>Setting floating point precision</h4>
<p>You can define the floating point precision required by your compute algorithms. This is useful if you
require less precision than the IEEE 754-2008 standard (used by default). You can define
the floating-point precision level of your script with the following pragmas:</p>
<ul>
<li><code>#pragma rs_fp_full</code> (default if nothing is specified): For apps that
require floating point precision as outlined by the IEEE 754-2008 standard.
</li>
<li><code>#pragma rs_fp_relaxed</code> - For apps that don’t require
strict IEEE 754-2008 compliance and can tolerate less precision. This mode enables
flush-to-zero for denorms and round-towards-zero.
</li>
<li><code>#pragma rs_fp_imprecise</code> - For apps that don’t have stringent precision requirements. This mode enables
everything in <code>rs_fp_relaxed</code> along with the following:
<ul>
<li>Operations resulting in -0.0 can return +0.0 instead.</li>
<li>Operations on INF and NAN are undefined.</li>
</ul>
</li>
</ul>
<h4>Script intrinsics</h4>
<p>Renderscript adds support for a set of script intrinsics, which are pre-implemented
filtering primitives that reduce the amount of
code that you need to write. They also are implemented to ensure that your app gets the
maximum performance gain possible.</p>
<p>
Intrinsics are available for the following:
<ul>
<li>{@link android.renderscript.ScriptIntrinsicBlend Blends}</li>
<li>{@link android.renderscript.ScriptIntrinsicBlur Blur}</li>
<li>{@link android.renderscript.ScriptIntrinsicColorMatrix Color matrix}</li>
<li>{@link android.renderscript.ScriptIntrinsicConvolve3x3 3x3 convolve}</li>
<li>{@link android.renderscript.ScriptIntrinsicConvolve5x5 5x5 convolve}</li>
<li>{@link android.renderscript.ScriptIntrinsicLUT Per-channel lookup table}</li>
<li>{@link android.renderscript.ScriptIntrinsicYuvToRGB Converting an Android YUV buffer to RGB}</li>
</ul>
<h3 id="calling">Calling the Renderscript code</h3>
<p>You can call the Renderscript from your Android framework code by
creating a Renderscript object by instantiating the (<code>ScriptC_<em>script_name</em></code>)
class. This class contains a method, <code>forEach_root()</code>, that lets you invoke
<code>rsForEach</code>. You give it the same parameters that you would if you were invoking it
at the Renderscript runtime level. This technique allows your Android application to offload
intensive mathematical calculations to Renderscript. See the <a href=
"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute</a> sample to see
how a simple Android application can utilize Renderscript.</p>
<p>To call Renderscript at the Android framework level:</p>
<ol>
<li>Allocate memory that is needed by the Renderscript in your Android framework code.
You need an input and output {@link android.renderscript.Allocation} for Android 3.2 (API level
13) platform versions and older. The Android 4.0 (API level 14) platform version requires only
one or both {@link android.renderscript.Allocation}s.</li>
<li>Create an instance of the <code>ScriptC_<em>script_name</em></code> class.</li>
<li>Call <code>forEach_root()</code>, passing in the allocations, the
Renderscript, and any optional user-defined data. The output allocation will contain the output
of the Renderscript.</li>
</ol>
<p>The following example, taken from the <a href=
"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute</a> sample, processes
a bitmap and outputs a black and white version of it. The
<code>createScript()</code> method carries out the steps described previously. This method calls the
Renderscript, <code>mono.rs</code>, passing in memory allocations that store the bitmap to be processed
as well as the eventual output bitmap. It then displays the processed bitmap onto the screen:</p>
<pre>
package com.example.android.rs.hellocompute;
import android.app.Activity;
import android.os.Bundle;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
import android.renderscript.RenderScript;
import android.renderscript.Allocation;
import android.widget.ImageView;
public class HelloCompute extends Activity {
private Bitmap mBitmapIn;
private Bitmap mBitmapOut;
private RenderScript mRS;
private Allocation mInAllocation;
private Allocation mOutAllocation;
private ScriptC_mono mScript;
&#064;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mBitmapIn = loadBitmap(R.drawable.data);
mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
mBitmapIn.getConfig());
ImageView in = (ImageView) findViewById(R.id.displayin);
in.setImageBitmap(mBitmapIn);
ImageView out = (ImageView) findViewById(R.id.displayout);
out.setImageBitmap(mBitmapOut);
createScript();
}
private void createScript() {
mRS = RenderScript.create(this);
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);
mScript.forEach_root(mInAllocation, mOutAllocation);
mOutAllocation.copyTo(mBitmapOut);
}
private Bitmap loadBitmap(int resource) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
return BitmapFactory.decodeResource(getResources(), resource, options);
}
}
</pre>
<p>To call Renderscript from another Renderscript file:</p>
<ol>
<li>Allocate memory that is needed by the Renderscript in your Android framework code.
You need an input and output {@link android.renderscript.Allocation} for Android 3.2 (API level
13) platform versions and older. The Android 4.0 (API level 14) platform version requires only
one or both {@link android.renderscript.Allocation}s.</li>
<li>Call <code>rsForEach()</code>, passing in the allocations and any optional user-defined data.
The output allocation will contain the output of the Renderscript.</li>
</ol>
<pre>
rs_script script;
rs_allocation in_allocation;
rs_allocation out_allocation;
UserData_t data;
...
rsForEach(script, in_allocation, out_allocation, &amp;data, sizeof(data));
</pre>
</p>
<p>In this example, assume that the script and memory allocations have already been
allocated and bound at the Android framework level and that <code>UserData_t</code> is a struct
declared previously. Passing a pointer to a struct and the size of the struct to <code>rsForEach</code>
is optional, but useful if your Renderscript requires additional information other than
the necessary memory allocations.</p>
<h4>Script groups</h4>
<p>You can group Renderscript scripts together and execute them all with a single call as though
they were part of a single script. This allows Renderscript to optimize execution of the scripts
in ways that it could not do if the scripts were executed individually.</p>
<p>To build a script groupm, use the {@link android.renderscript.ScriptGroup.Builder} class to create a {@link android.renderscript.ScriptGroup}
defining the operations. At execution time, Renderscript optimizes the run order and the connections between these
operations for best performance.
<p class="note"><strong>Important:</strong> The script group must be a direct acyclic graph for this feature to work.</p>