简体   繁体   English

如何使用Allocations将数组值传入和传出Android RenderScript

[英]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. 我最近一直在使用RenderScript,目的是创建一个程序员可以轻松使用的API,类似于Microsoft Accelerator的工作方式。

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: 我现在遇到的麻烦是因为我想要在RenderScript层中传递值并让所有内容以最有效的方式运行,这是我的源代码的摘录到目前为止:

    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. 这只是创建两个基本数组并用值填充它们并调用将它们发送到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: 这将向以下RenderScript代码发送一对值:

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. 但是这有两个问题,第一个是RenderScript的异步性质意味着当Java层请求值时,脚本还没有完成操作,或者它已经完成了它,破坏了输出的值并开始下一个。 And thanks to the low debugging visibility of RenderScript there's no way of telling. 由于RenderScript的低调试可见性,无法说明。

The other problem is that it's not very efficient, the code is constantly calling the RenderScript function to add two numbers together. 另一个问题是它效率不高,代码不断调用RenderScript函数将两个数字加在一起。 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. 理想情况下,我想将数组传递给RenderScript并将其存储在结构中,并在一个脚本调用中完成整个操作,而不是很多。 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. 但是为了得到它我认为我需要使用rsSendtoClient函数,但我没有找到任何关于如何使用它的材料。 And preferably I'd like to use the rsForEach strategy, but again information is scare. 最好是我想使用rsForEach策略,但信息又是恐慌。

If anyone has any ideas I'd be very grateful. 如果有人有任何想法我会非常感激。 Thanks. 谢谢。

Will Scott-Jackson 威尔斯 - 杰克逊

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. 我不确定这对你来说是否有帮助,但是因为我知道通过RenderScript可以解决多少痛苦,所以我可以提供帮助。 In order to use the rsSendToClient function, you need to instruct the RenderScript instance you created where to send messages to. 要使用rsSendToClient函数,您需要指示您创建的RenderScript实例将消息发送到的位置。 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. 有必要继承RenderScript.RSMessageHandler并覆盖run()方法。 See http://developer.android.com/reference/android/renderscript/RenderScript.RSMessageHandler.html if you havn't already. 如果您还没有,请参阅http://developer.android.com/reference/android/renderscript/RenderScript.RSMessageHandler.html 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). 至于效率低下,我会考虑创建一个RenderScript实例,让它保持运行(你可以在不需要时暂停它,将停留在内存中但停止线程,因此每次调用函数时都不会产生建设成本)。 From here you can have your structures and then use invoke_myFunction(some arguments here) from the reflected Java layer. 从这里你可以拥有你的结构,然后从反射的Java层使用invoke_myFunction(这里的一些参数)。

Hopefully this helps at least a little bit. 希望这至少有一点帮助。

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 您的程序的问题是,不知道rs文件中的add函数何时应该运行,尝试它应该工作

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

}

I had the same problem with you. 我和你有同样的问题。 I think rsSendtoClient function is not useful and creates many bugs. 我认为rsSendtoClient函数没用,会产生很多错误。 Instead, using a pointer and allocate it a memory to bring result back to you is much easier. 相反,使用指针并为其分配内存以将结果返回给您更容易。

I recommend the solution of your problem like this: 我推荐你的问题解决方案如下:

In rsintadd.rs use this snippet: 在rsintadd.rs中使用此代码段:

int32_t *a;
int32_t *b;
int32_t *c;

void intAdd() {
    for(int i = 0; i<10;i++){
    c[i] = a[i] + b[i];
}

In your JAVA code use this snippet: 在您的JAVA代码中使用此代码段:

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

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

    // provide memory for b using data in B
    Allocation b = Allocation.createSized(rs, Element.I32(rs), B.length);
    b.copyFrom(B);
    inv.bind_b(b);

    // provide memory for a using data in A
    Allocation a = Allocation.createSized(rs, Element.I32(rs), A.length);
    a.copyFrom(A);
    inv.bind_a(a);

    // create blank memory for c
    inv.bind_c(Allocation.createSized(rs, Element.I32(rs), 10));

    // call intAdd function
    inv.invoke_intAdd();

    // get result
    int[] C = new int[10];
    inv.get_c().copyTo(C);
    for (int i = 0; i < C.length; i++) {
        System.out.println(C[i]);
    }

And this is your result on Logcat: 这是你在Logcat上的结果:

C的结果

Your first question is about Asynchronous, you can use thread to wait result. 您的第一个问题是关于异步,您可以使用线程等待结果。 In this example, the function is fast enough and instantly gives the output to C array so result can show on logcat. 在这个例子中,函数足够快,并立即将输出提供给C数组,因此结果可以显示在logcat上。

Your second question is about implement intAdd() function without recalling it. 你的第二个问题是关于实现intAdd()函数而不回忆它。 The code above is the answer. 上面的代码就是答案。 You can access any part of int array in Java until the method is done ( different from root() function ). 您可以在Java中访问int数组的任何部分,直到方法完成(与root()函数不同)。

Hope this can help someone :) 希望这可以帮助别人:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM