2016-07-22 110 views
0

我遇到問題。我想從renderscript內核中檢索一個結構體。我想要的是我會得到一個結構元素的輸入...我會修改它,然後返回它修改。但是反射層沒有這樣的方法。我嘗試手動反序列化緩衝區中的數據,但我甚至無法將緩衝區複製到ByteBuffer,因爲Allocation在copyTo類型中進行了驗證,因此我不知道該怎麼做......如何從Renderscript內核檢索結構

+0

嗯......在「重複」的答案是不正確的。答案是,您可以使用分配的copy1DRangeToUnchecked方法將其複製到ByteBuffer中並自行反序列化它。我後來意識到,後來在 –

回答

0

RenderScript支持自定義元素。要創建一個,申報一個自定義typedef struct像下面的一個,一個RS腳本中:

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中,此代碼可能會因爲它依賴於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(); 
    } 

您可以自定義結構的內容,在哈克的方式映射:

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

+0

嗯,但你指定如何使用反射層創建分配。我的問題是如何在內核運行(和修改)後在java中讀取結構 –

+0

我添加了進程:) – cmaster11