<分区>
我有一个问题。我想从渲染脚本内核中检索一个结构。我想要的是我会得到一个结构元素的输入......我会修改它然后返回修改后的它。但是反射层没有这种方式。我尝试手动反序列化缓冲区中的数据,但我什至无法将缓冲区复制到 ByteBuffer,因为 Allocation 在类型的 copyTo 中进行了验证,所以我不知道我应该做什么......
<分区>
我有一个问题。我想从渲染脚本内核中检索一个结构。我想要的是我会得到一个结构元素的输入......我会修改它然后返回修改后的它。但是反射层没有这种方式。我尝试手动反序列化缓冲区中的数据,但我什至无法将缓冲区复制到 ByteBuffer,因为 Allocation 在类型的 copyTo 中进行了验证,所以我不知道我应该做什么......
最佳答案
RenderScript 支持自定义元素。要创建一个,请在 RS 脚本中声明一个自定义 typedef struct
,如下所示:
typedef struct MyElement {
int x;
int y;
bool simpleBool;
} MyElement_t;
在构建过程之后,将出现一个 ScriptField_MyElement
Java 类,镜像 RS 结构。您将能够使用此类创建使用您自己的元素的自定义分配:
// Declares a new Allocation, based upon the custom struct Element
Element myElement = ScriptField_MyElement.createElement(mRS);
Allocation myElementsAllocation = Allocation.createSized(mRS, myElement, 5);
// Or
Allocation myElementsAllocation = ScriptField_MyElement.create1D(mRS, sizeX).getAllocation();
您可以在 CustomElementExample sample project 中找到此过程的示例. 另外,在 SurfaceRenderExample sample project 里面您可以看到自定义元素如何用于模拟数学结构(在本例中是一个粒子,以一定的加速度下落)。
内部 RenderScript 脚本:
从分配中获取自定义元素:
MyElement_t el = * (MyElement_t *) rsGetElementAt(aIn, index);
更改自定义元素成员:
el.x = 10;
在分配中设置自定义元素:
rsSetElementAt(myAlloc, (void *)&el);
引用:RenderScript: parallel computing on Android, the easy way
编辑:
目前,没有直接的方法可以将自定义结构元素复制到 Java 端。
CustomStructElementCopyToJava sample project提供了该过程的示例。
注意:以下过程是实验性的,根本不是高性能的!如果您计划大量使用此过程,请使用 Android NDK 访问配置。 此外,在 Android SDK 的 future 版本中,这段代码可能会因为依赖 Java 反射而中断;一些通常隐藏的方法可以在 Android SDK 中更改,恕不另行通知。
假设使用以下自定义结构元素:
typedef struct Point {
int x;
int y;
} Point_t;
当查看结构的生成代码时(可以在 Android Studio 中看到,通过按 CTRL+B 同时关注 Java 上的 ScriptField_Point
元素侧),可以看到以下元素:
public static Element createElement(RenderScript rs) {
Element.Builder eb = new Element.Builder(rs);
eb.add(Element.I32(rs), "x");
eb.add(Element.I32(rs), "y");
return eb.create();
}
您可以用一种 hacky 的方式映射自定义结构的内容:
1) 定义目标字节数组:
byte destinationArray[] = new byte[allocationGrayPointOrdered.getBytesSize()];
2)使用Java反射访问隐藏的Allocation.copyTo
方法:
private static Method getCopyToWithoutValidationMethod(){
// private void copyTo(Object array, Element.DataType dt, int arrayLen)
Method allocationHiddenCopyToMethod = null;
try {
allocationHiddenCopyToMethod = Allocation.class.getDeclaredMethod("copyTo", Object.class, Element.DataType.class, int.class);
allocationHiddenCopyToMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not find allocationHiddenCopyToMethod");
}
return allocationHiddenCopyToMethod;
}
3) 执行复制:
// Gets reflected method
Method copyToWithoutValidationMethod = getCopyToWithoutValidationMethod();
// Tries to copy contents
try {
copyToWithoutValidationMethod.invoke(allocationGrayPointOrdered, destinationArray,
Element.DataType.UNSIGNED_8, destinationArray.length);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
4) 一旦数组中充满了源数据,就可以将其内容映射到人类可读的结构。
// Defines the destination array
ScriptField_Point.Item mappedItems[][] = new ScriptField_Point.Item[sizeX][sizeY];
// Wraps array contents
ByteBuffer byteBuffer = ByteBuffer.wrap(destinationArray);
// Sets byte order to be Android-like
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// Iterates on every column and row
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
// Allocates a new item
ScriptField_Point.Item currentItem = new ScriptField_Point.Item();
// Calculate the offset in the source array
int currentOffset = (x + y * sizeX) * ScriptField_Point.Item.sizeof;
// Gets data from the byte array
currentItem.x = byteBuffer.getInt(currentOffset);
currentItem.y = byteBuffer.getInt(currentOffset + 4);
mappedItems[x][y] = currentItem;
}
}
完整解释请引用book .
关于java - 如何从 Renderscript 内核中检索结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38533844/