私は問題があります。renderscript カーネルから構造体を取得したいと思います。私が欲しかったのは、構造体要素の入力を取得することでした...それを変更してから、変更して返します。しかし、反射層にはそのような方法はありません。バッファーからデータを手動で逆シリアル化しようとしましたが、割り当てには型の copyTo で検証があるため、バッファーを ByteBuffer にコピーすることさえできないため、何をすべきかわかりません...
1 に答える
RenderScript はカスタム要素をサポートしています。typedef struct
カスタムを作成するには、RS スクリプト内で次のようなカスタムを宣言します。
typedef struct MyElement {
int x;
int y;
bool simpleBool;
} MyElement_t;
ビルド プロセスの後、ScriptField_MyElement
RS 構造体を反映した Java クラスが表示されます。このクラスを使用して、独自の要素を使用するカスタム割り当てを作成できます。
// 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 サンプル プロジェクト内にあります。また、SurfaceRenderExample サンプル プロジェクト内では、カスタム要素を使用して数学的構造をモデル化する方法を確認できます (この場合は、何らかの加速度で落下する粒子)。
RenderScript スクリプトの内部:
割り当てからカスタム要素を取得するには:
MyElement_t el = * (MyElement_t *) rsGetElementAt(aIn, index);
カスタム要素メンバーを変更するには:
el.x = 10;
割り当てにカスタム要素を設定するには:
rsSetElementAt(myAlloc, (void *)&el);
リファレンス: RenderScript: Android での並列計算、簡単な方法
編集:
今のところ、カスタム struct 要素を Java 側に直接コピーする方法はありません。
CustomStructElementCopyToJava サンプル プロジェクトは、プロセスの例を提供します。
例の簡単な説明
注:次のプロセスは実験的であり、まったくパフォーマンスがありません! このプロセスを頻繁に使用する場合は、Android NDK を使用して割り当てにアクセスしてください。また、Android SDK の将来のバージョンでは、このコードは Java リフレクションに依存しているため、壊れる可能性があります。Android SDK では、通常は非表示のメソッドの一部が予告なしに変更される可能性があります。
次のカスタム struct 要素を使用するとします。
typedef struct Point {
int x;
int y;
} Point_t;
生成された構造体のコード (Android Studio では、Java 側の要素にフォーカスしてCTRL+Bを押すと表示されます) を見ると、次の要素が表示されます。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();
}
カスタム構造体の内容をハックな方法でマップできます。
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;
}
}
完全な説明については、書籍を参照してください。