From c069ed7f8c3d307c9fed2c8d1a81e28152190b5a Mon Sep 17 00:00:00 2001 From: Yang Ni Date: Wed, 29 Jun 2016 12:44:06 -0700 Subject: Updated user document for Single-Source RenderScript Bug: 29875503 Bug: 29879448 Added a section introducing the new single-source feature. Local staging: http://yangni.mtv.corp.google.com/guide/topics/renderscript/compute.html This updates https://developer.android.com/guide/topics/renderscript/compute.html Change-Id: I62dda3ab60b1678a9580fd2873f64f33d9696e13 --- docs/html/guide/topics/renderscript/compute.jd | 137 +++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 10 deletions(-) diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd index 13880ec6b796..89cfff93514c 100755 --- a/docs/html/guide/topics/renderscript/compute.jd +++ b/docs/html/guide/topics/renderscript/compute.jd @@ -10,12 +10,13 @@ parent.link=index.html
  1. Writing a RenderScript Kernel
  2. -
  3. Accessing RenderScript APIs +
  4. Accessing RenderScript APIs from Java
    1. Setting Up Your Development Environment
  5. Using RenderScript from Java Code
  6. +
  7. Single-Source RenderScript
  8. Reduction Kernels in Depth
    1. Writing a reduction kernel
    2. @@ -45,12 +46,16 @@ computer vision.

      To begin with RenderScript, there are two main concepts you should understand:

        -
      • High-performance compute kernels are written in a C99-derived language. A compute - kernel is a function or collection of functions that you can direct the RenderScript runtime - to execute in parallel across a collection of data.
      • +
      • The language itself is a C99-derived language for writing high-performance compute +code. Writing a RenderScript Kernel describes +how to use it to write compute kernels.
      • -
      • A Java API is used for managing the lifetime of RenderScript resources and controlling kernel -execution.
      • +
      • The control API is used for managing the lifetime of RenderScript resources and +controlling kernel execution. It is available in three different languages: Java, C++ in Android +NDK, and the C99-derived kernel language itself. +Using RenderScript from Java Code and +Single-Source RenderScript describe the first and the third +options, respectively.

      Writing a RenderScript Kernel

      @@ -77,7 +82,9 @@ initial setup or serial computations within a larger processing pipeline. access script globals from Java code, and these are often used for parameter passing to RenderScript kernels.

      -
    3. Zero or more compute kernels. There are two kinds of compute +

    4. Zero or more compute kernels. A compute kernel is a function +or collection of functions that you can direct the RenderScript runtime to execute in parallel +across a collection of data. There are two kinds of compute kernels: mapping kernels (also called foreach kernels) and reduction kernels.

      @@ -243,9 +250,9 @@ beneficial on some architectures due to additional optimizations only available precision (such as SIMD CPU instructions).

      -

      Accessing RenderScript APIs

      +

      Accessing RenderScript APIs from Java

      -

      When developing an Android application that uses RenderScript, you can access its API in +

      When developing an Android application that uses RenderScript, you can access its API from Java in one of two ways:

        @@ -377,7 +384,7 @@ to you when using RenderScript:
        • ScriptC: These are the user-defined scripts as described in Writing a RenderScript Kernel above. Every script has a Java class +href="#writing-an-rs-kernel">Writing a RenderScript Kernel above. Every script has a Java class reflected by the RenderScript compiler in order to make it easy to access the script from Java code; this class has the name ScriptC_filename. For example, if the mapping kernel above were located in invert.rs and a RenderScript context were already located in @@ -448,6 +455,116 @@ context to throw an exception.
    a get() method to obtain the result of a reduction. get() is synchronous, and is serialized with respect to the reduction (which is asynchronous).

    +

    Single-Source RenderScript

    + +

    Android 7.0 (API level 24) introduces a new programming feature called Single-Source +RenderScript, in which kernels are launched from the script where they are defined, rather than +from Java. This approach is currently limited to mapping kernels, which are simply referred to as "kernels" +in this section for conciseness. This new feature also supports creating allocations of type + +rs_allocation from inside the script. It is now possible to +implement a whole algorithm solely within a script, even if multiple kernel launches are required. +The benefit is twofold: more readable code, because it keeps the implementation of an algorithm in +one language; and potentially faster code, because of fewer transitions between Java and +RenderScript across multiple kernel launches.

    + +

    In Single-Source RenderScript, you write kernels as described in +Writing a RenderScript Kernel. You then write an invokable function that calls + +rsForEach() to launch them. That API takes a kernel function as the first +parameter, followed by input and output allocations. A similar API + +rsForEachWithOptions() takes an extra argument of type + +rs_script_call_t, which specifies a subset of the elements from the input and +output allocations for the kernel function to process.

    + +

    To start RenderScript computation, you call the invokable function from Java. +Follow the steps in Using RenderScript from Java Code. +In the step launch the appropriate kernels, call +the invokable function using invoke_function_name(), which will start the +whole computation, including launching kernels.

    + +

    Allocations are often needed to save and pass +intermediate results from one kernel launch to another. You can create them using + +rsCreateAllocation(). One easy-to-use form of that API is +rsCreateAllocation_<T><W>(…), where T is the data type for an +element, and W is the vector width for the element. The API takes the sizes in +dimensions X, Y, and Z as arguments. For 1D or 2D allocations, the size for dimension Y or Z can +be omitted. For example, rsCreateAllocation_uchar4(16384) creates a 1D allocation of +16384 elements, each of which is of type uchar4.

    + +

    Allocations are managed by the system automatically. You +do not have to explicitly release or free them. However, you can call + +rsClearObject(rs_allocation* alloc) to indicate you no longer need the handle +alloc to the underlying allocation, +so that the system can free up resources as early as possible.

    + +

    The Writing a RenderScript Kernel section contains an example +kernel that inverts an image. The example below expands that to apply more than one effect to an image, +using Single-Source RenderScript. It includes another kernel, greyscale, which turns a +color image into black-and-white. An invokable function process() then applies those two kernels +consecutively to an input image, and produces an output image. Allocations for both the input and +the output are passed in as arguments of type + +rs_allocation.

    + +
    +// File: singlesource.rs
    +
    +#pragma version(1)
    +#pragma rs java_package_name(com.android.rssample)
    +
    +static const float4 weight = {0.299f, 0.587f, 0.114f, 0.0f};
    +
    +uchar4 RS_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;
    +}
    +
    +uchar4 RS_KERNEL greyscale(uchar4 in) {
    +  const float4 inF = rsUnpackColor8888(in);
    +  const float4 outF = (float4){ dot(inF, weight) };
    +  return rsPackColorTo8888(outF);
    +}
    +
    +void process(rs_allocation inputImage, rs_allocation outputImage) {
    +  const uint32_t imageWidth = rsAllocationGetDimX(inputImage);
    +  const uint32_t imageHeight = rsAllocationGetDimY(inputImage);
    +  rs_allocation tmp = rsCreateAllocation_uchar4(imageWidth, imageHeight);
    +  rsForEach(invert, inputImage, tmp);
    +  rsForEach(greyscale, tmp, outputImage);
    +}
    +
    + +

    You can call the process() function from Java as follows:

    + +
    +// File SingleSource.java
    +
    +RenderScript RS = RenderScript.create(context);
    +ScriptC_singlesource script = new ScriptC_singlesource(RS);
    +Allocation inputAllocation = Allocation.createFromBitmapResource(
    +    RS, getResources(), R.drawable.image);
    +Allocation outputAllocation = Allocation.createTyped(
    +    RS, inputAllocation.getType(),
    +    Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT);
    +script.invoke_process(inputAllocation, outputAllocation);
    +
    + +

    This example shows how an algorithm that involves two kernel launches can be implemented completely +in the RenderScript language itself. Without Single-Source +RenderScript, you would have to launch both kernels from the Java code, separating kernel launches +from kernel definitions and making it harder to understand the whole algorithm. Not only is the +Single-Source RenderScript code easier to read, it also eliminates the transitioning +between Java and the script across kernel launches. Some iterative algorithms may launch kernels +hundreds of times, making the overhead of such transitioning considerable.

    +

    Reduction Kernels in Depth

    Reduction is the process of combining a collection of data into a single -- cgit v1.2.3-59-g8ed1b