Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass array values to and from Android RenderScript using Allocations

I've been working with RenderScript recently with the intent of creating an API that a programmer can use with ease, similar to the way that Microsoft Accelerator works.

The trouble I'm stuck with at the moment as that I want to pass values to and from the RenderScript layer and have everything run in the most efficient way possible, this is an extract of my source code so far:

    int[] A = new int[10];
    int[] B = new int[10];

    for (int i = 0; i < 10; i++) {
        A[i] = 2;
        B[i] = i;
    }
    intAdd(A, B);

This just creates two basic arrays and fills them with values and calls the functions that will send them to RenderScript.

 private void intAdd(int[] A, int[] B) {
    RenderScript rs = RenderScript.create(this);
    ScriptC_rsintadd intaddscript = new ScriptC_rsintadd(rs, getResources(), R.raw.rsintadd);
    mScript = intaddscript;

    for(int i = 0; i < A.length; i++) {
    setNewValues(mScript, A[i], B[i]);
    intaddscript.invoke_intAdd();
    int C = getResult(mScript);
    notifyUser.append(" " + C);
    }
}

    public void setNewValues(Script script, int A, int B) {
    mScript.set_numberA(A);
    mScript.set_numberB(B);
}

public int getResult(Script script) {
    int C = mScript.get_numberC();
    return C;
}

This will send a pair of values to the following RenderScript code:

int numberA;
int numberB;
int numberC;

void intAdd() {
/*Add the two together*/
numberC = numberA + numberB;
/*Send their values to the logcat*/
rsDebug("Current Value", numberC);
 }

But there are two problems with this, the first one is the Asynchronous nature of RenderScript means that when the Java layer requests the value, the script either hasn't done the operation yet, or it's already done it, destroyed the value of the output and started on the next one. And thanks to the low debugging visibility of RenderScript there's no way of telling.

The other problem is that it's not very efficient, the code is constantly calling the RenderScript function to add two numbers together. Ideally I'd want to pass the array to RenderScript and store it in a struct and have the entire operation done in one script call rather than many. But in order to get it back I reckon I'll need to user the rsSendtoClient function, but I've not found any material on how to use it. And preferably I'd like to use the rsForEach strategy, but again information is scare.

If anyone has any ideas I'd be very grateful. Thanks.

Will Scott-Jackson

like image 960
Will Scott-Jackson Avatar asked Mar 11 '12 13:03

Will Scott-Jackson


People also ask

What is RenderScript and when should we really use it?

RenderScript framework is basically based on data parallel computation. It distributes your application workload on all the processors available on your device like multi-core CPUs or GPUs.

What is allocation in Android?

This class was deprecated in API level 31. An Allocation provides the backing store for a given Type . An Allocation also contains a set of usage flags that denote how the Allocation could be used.


2 Answers

I'm not sure if this will be of help to you at this point but since I know how much of a pain it can be to work through RenderScript, here is the help I can offer. In order to use the rsSendToClient function, you need to instruct the RenderScript instance you created where to send messages to. This is accomplished by something such as:

private void intAdd(int[] A, int[] B) {
     RenderScript rs = RenderScript.create(this);

     MySubclassedRSMessageHandler handler = new MySubclassedRSMessageHandler();
     rs.setMessageHandler(handler);
     ScriptC_rsintadd intaddscript = new ScriptC_rsintadd(rs, getResources(), R.raw.rsintadd);
     mScript = intaddscript;

     for(int i = 0; i < A.length; i++) {
          setNewValues(mScript, A[i], B[i]);
          intaddscript.invoke_intAdd();
          int C = getResult(mScript);
          notifyUser.append(" " + C);
     }
}

It will be necessary to subclass RenderScript.RSMessageHandler and override the run() method. See http://developer.android.com/reference/android/renderscript/RenderScript.RSMessageHandler.html if you havn't already. Basically there is no way to get around the asynchronous nature which I find to be a double edged sword.

As for the inefficiency, I would consider creating a RenderScript instance, leave it running (you can pause it when not needed, will stay in memory but stop the threads, thus not incurring the construction cost each time you call a function). From here you can have your structures and then use invoke_myFunction(some arguments here) from the reflected Java layer.

Hopefully this helps at least a little bit.

like image 92
Jared Avatar answered Oct 26 '22 15:10

Jared


I had the same problem. The problem with your program is that doesn't know when the add function in rs file should run ,try this it should work

public void setNewValues(Script script, int A, int B) {
mScript.set_numberA(A);
mScript.set_numberB(B);
mscript.invoke_intAdd();

}
like image 32
user1225347 Avatar answered Oct 26 '22 14:10

user1225347