How to retrieve a struct from Renderscript kernel [duplicate] - java

This question already has answers here:
Returning a Renderscript struct from a Renderscript kernel
(2 answers)
Closed 6 years ago.
I have a problem. I would like to retrieve a struct from a renderscript kernel. What I wanted was that I would get an input a struct element... I would modify it and then return it modified. But there is no such a way in the reflected layer. I tryied to manually deserialize the data from the buffer but I am not even able to copy the buffer to a ByteBuffer because the Allocation has validation in the copyTo on a type so I have no idea what am I supposed to do...

RenderScript supports custom elements. To create one, declare a custom typedef struct like the following one, inside a RS script:
typedef struct MyElement {
int x;
int y;
bool simpleBool;
} MyElement_t;
After the build process, a ScriptField_MyElement Java class will appear, mirroring the RS struct. You will be able to use this class to create a custom Allocation that uses your own Element:
// 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();
You can find an example of this process inside the CustomElementExample sample project.
Also, inside the SurfaceRenderExample sample project you can see how a custom element can be used to model a mathematical structure (in this case a particle, falling with some acceleration).
Inside RenderScript scripts:
To get a custom element from an allocation:
MyElement_t el = * (MyElement_t *) rsGetElementAt(aIn, index);
To change a custom element member:
el.x = 10;
To set a custom element in an allocation:
rsSetElementAt(myAlloc, (void *)&el);
Reference: RenderScript: parallel computing on Android, the easy way
Edit:
For now, there is no direct way to copy a custom struct element to the Java side.
The CustomStructElementCopyToJava sample project provides an example of the process.
Short explanation of the example
Note: the following process is EXPERIMENTAL and not performant at all! If you plan to heavily use this process, please use the Android NDK to access the allocation.
Also, in future versions of the Android SDK, this code may break because it relies on Java reflection; some normally hidden methods can change without any notice in the Android SDK.
Let's assume using the following custom struct element:
typedef struct Point {
int x;
int y;
} Point_t;
When looking at the generated code of the struct (which can be seen, in Android Studio, by pressing CTRL+B while focusing on a ScriptField_Point element on the Java side), the following elements can be seen:
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();
}
You can map the contents of the custom struct in a hacky way:
1) Define the destination byte array:
byte destinationArray[] = new byte[allocationGrayPointOrdered.getBytesSize()];
2) Use Java reflection to access the hidden Allocation.copyTo method:
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) Perform the copy:
// 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) Once the array is filled with source data, it is then possible to map its content to a human-readable struct.
// 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;
}
}
For the complete explanation, please refer to the book.

Related

How to get list of all window handles in Java (Using JNA) on MacOS?

I have been using the JNA library to get all visible window handles in Windows. I need to do something similar in macOS using JNA.
Here is code to get all window handles in Windows:
public static List<HWND> findAll() {
final List<HWND> windows = new LinkedList<>();
User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
#Override
public boolean callback(HWND hWnd, Pointer arg) {
if (User32.INSTANCE.IsWindowVisible(hWnd)) {
windows.add(hWnd);
}
return true;
}
}, null);
return windows;
}
What is the equivalent code in macOS?
You'll need to map portions of the Core Graphics Framework. You can list windows using the CGWindowListCopyWindowInfo() function.
To load the framework you'll need to map a CoreGraphics interface extending JNA's Library class, and map the function you need:
public interface CoreGraphics extends Library {
CoreGraphics INSTANCE = Native.load("CoreGraphics", CoreGraphics.class);
CFArrayRef CGWindowListCopyWindowInfo(int option, int relativeToWindow);
}
The CFArrayRef type is already mapped in JNA in the CoreFoundation class. Pick the appropriate Window List Option (probably kCGWindowListOptionAll = 0). If you already had a window number you could use relative reerences, otherwise you'll use kCGNullWindowID (0) for the second parameter. Calling it from your code should be simple:
CFArrayRef windowInfo = CoreGraphics.INSTANCE.CGWindowListCopyWindowInfo(0, 0);
That will give you an array of CFDictionaryRef objects representing the windows. You can iterate the array and then use further methods in the CFDictionaryRef class to explore these dictionary objects: you'll create a CFString for the keys. A list of required keys is documented here and optional keys are here. The constant strings match the variable name.
This should get you a CFNumberRef for each window number (the "handle" equivalent):
// Set up keys for dictionary lookup
CFStringRef kCGWindowNumber = CFStringRef.createCFString("kCGWindowNumber");
CFStringRef kCGWindowOwnerPID = CFStringRef.createCFString("kCGWindowOwnerPID");
// Note: the Quartz name is rarely used
CFStringRef kCGWindowName = CFStringRef.createCFString("kCGWindowName");
CFStringRef kCGWindowOwnerName = CFStringRef.createCFString("kCGWindowOwnerName");
// Iterate the array
int numWindows = windowInfo.getCount();
for (int i = 0; i < numWindows; i++) {
// For each array element, get the dictionary
Pointer result = windowInfo.getValueAtIndex(i);
CFDictionaryRef windowRef = new CFDictionaryRef(result);
// Now get information from the dictionary.
// Get a pointer to the result, in this case a CFNumber
result = windowRef.getValue(kCGWindowNumber);
// "Cast" the pointer to the appropriate type
CFNumberRef windowNumber = new CFNumberRef(result);
// CoreFoundation.INSTANCE.CFNumberGetType(windowNumber)
// --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
// Get a pointer to the result, in this case a CFNumber
result = windowRef.getValue(kCGWindowOwnerPID);
// "Cast" the pointer to the appropriate type
CFNumberRef windowOwnerPID = new CFNumberRef(result);
// CoreFoundation.INSTANCE.CFNumberGetType(windowOwnerPID)
// --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
// Get a pointer to the result, in this case a CFString
result = windowRef.getValue(kCGWindowName);
// "Cast" the pointer to the appropriate type
// Optional key, check for null
String windowName = result == null ? "" : new CFStringRef(result).stringValue();
// Get a pointer to the result, in this case a CFString
result = windowRef.getValue(kCGWindowOwnerName);
// "Cast" the pointer to the appropriate type
// Optional key, check for null
String windowOwnerName = result == null ? "" : new CFStringRef(result).stringValue();
// ... look up other keys if needed ...
// use ProcessHandle with the PID to get start time
// Output or add to List, etc.
System.out.println(windowNumber.longValue()
+ " (" + windowOwnerName + ", pid="
+ windowOwnerPID.longValue()
+ "): " + windowName);
}
// CF references from "Copy" or "Create" must be released
// release the created key references
kCGWindowNumber.release();
kCGWindowOwnerPID.release();
kCGWindowName.release();
kCGWindowOwnerName.release();
// release the array
windowInfo.release();

JNA: Set struct pointer to NULL

I am starting to use JNA to communicate with a device on the RS485 interface of a computer. Suprisingly to me I came to good results very quickly. But now I am stuck by a simple problem. The library I use accepts a pointer to a pointer of struct. The actual signature is
func(Struct1 **, Struct2 **, Struct3 *, Struct4 *, long)
Now to indicate the size of the first parameter the library expects the last pointer to be a NULL pointer. This is what fails. Following code is what I tried so far:
Struct1.ByReference[] s = (Struct1.ByReference[]) new Struct1.ByReference().toArray(size);
int pos = 0;
// ...
// for loop to set the s[pos] struture values
for(pos = 0; pos < size - 1; pos++)
// ...
// Now set the last array element to a null pointer to indicate end-of-list
s[pos].getPointer().setPointer(0, null);// Following does not work: results in zero memoried structure
s[pos] = null; // Following does not work wither: NullPointerException at com.sun.jna.Structure.autoWrite
EDIT 1
s[pos] = new Struct1.ByReference(Pointer.NULL); // results in zero memoried structure as well
EDIT 2
According to technomage's question. If I were to write C code it would probably look something like that:
Struct1 **s = malloc(n * sizeof(Struct1*));
for(int i=0; i<n; i++)
{
if(i == n -1)
{
s[i] = NULL;
}
else
{
s[i] = malloc(sizeof(Struct1));
s[i].bla = value;
....
}
}
But be warned: I am not very skilled in C/C++. I consider Java to be my domain.
Has anyone had a similar problem? Maybe I am just not seeing the wood for the trees...
Thanks in advance.
Structures in JNA are pointers, so what you really need here is a pointer to a (pointer to a) Structure, which is a PointerByReference -- in your case, an array of them.
Given the code example above, you'll create your array of Structures, one less than n:
Struct1[] struct1Array = new Struct1[n-1];
This only allocates the Java memory for the array.
Next you'll instantiate and write the changes you make to native memory:
for (int i = 0; i < n-1; i++) {
struct1Array[i] = new Struct1();
struct1Array[i].bla = value;
struct1Array[i].write();
}
The new Struct1() allocates native side memory for these structures. It's possible to use the Structure.toArray() method to do this as well; I'm intentionally doing this a bit more manual and low-level to try to make clear what's happening.
Then you'll create a corresponding PointerByReference array to hold the pointers to these structures. You'll add an extra element for the null:
PointerByReference[] pbrArray = new PointerByReference[n];
Again, this is only java-side allocation. And then you fill it with pointers to the pointers to the structure, obtained from the Structure.getPointer() method:
for (int i = 0; i < n-1; i++) {
pbrArray[i] = new PointerByReference(struct1Array[i].getPointer());
}
pbrArray[n - 1] = new PointerByReference(Pointer.NULL);
The new PointerByReference() here allocates the native side memory for the pointer itself, which points to the native-side structure you allocated earlier.
From how I understand your initial question, you will pass this PointerByReference array to your function, which presumably updates your structures.
Since you created the two arrays in this fashion, you can keep track of their correspondence by array index. You may have to iterate through the structure array and read() the native memory into the Java-side structure to do further processing with it. Typically when you work directly with Structures being passed to methods they autowrite and autoread, but when using a PointerByReference to indirectly reference the Structure, JNA isn't as friendly.
As an alternative to tracking the two arrays by corresponding indices, you could "forget" the initial Structure assignment and recover it later using the PointerByReference.getValue() method on your array to recover a pointer to the memory for the structure, and then instantiate a new structure using that Pointer in its constructor (e.g. new Struct1(pbr.getValue()) which calls super() with that pointer).

SWIG java: releasing memory allocated in c++

I'm using SWIG 2.0.10 in Ubuntu to call C++ code in Java.
My C++ code is:
//ImgPro.h:
#include <vector>
typedef struct _bin
{
char* name;
float value;
} Bin;
typedef struct imgprops
{
std::vector<Bin> color;
int width;
int height;
char *print;
} ImageProperties;
class ImgPro
{
public:
ImgPro();
ImageProperties *processImage(char* imagePath);
};
The processImage function definition is:
ImageProperties* ImgPro::processImage(char *imagePath)
{
ImageProperties* imgProp = new ImageProperties();
imgProp->width = 200;
imgProp->height = 200;
char* fp = new char(5);
strcpy(fp, "abc!");
imgProp->print = fp;
Bin outputBin1;
char *name1 = new char(strlen("red")+1);
strcpy(name1, "red");
outputBin1.name = name1;
outputBin1.value = 0.125;
Bin outputBin2;
char *name2 = new char(strlen("blue")+1);
strcpy(name2, "blue");
outputBin2.name = name1;
outputBin2.value = 0.27;
vector<Bin> tempVec;
tempVec.push_back(outputBin1);
tempVec.push_back(outputBin2);
imgProp->color = tempVec;
return imgProp;
}
So, to generate the jni code using swig, i've used the following swig file (note: the vector.i file was created using this example ) :
%module CBIR
// to handle char** has String_Array in Java
%include <various.i>
%include "vector.i"
%{
#include "ImgPro.h"
%}
// to handle char** has String_Array in Java
%apply char **STRING_ARRAY { char ** };
// memory release
%extend imgprops {
~imgprops(){
if($self != NULL)
{
// releasing print element
if($self->print != NULL)
delete[] $self->print;
// releasing vector elements
for(uint x = 0; x < $self->color.size(); x++)
{
Bin currentBin = $self->color[x];
if(currentBin.name != NULL)
delete[] currentBin.name;
}
// releasing stuct Pointer
delete $self;
}
}
}
%include "ImgPro.h"
%template(BinVec) std::vector<Bin>;
And this generates in the swig_wrap file the next function:
SWIGINTERN void delete_imgprops(imgprops *self){
if(self != NULL)
{
// releasing print element
if(self->print != NULL)
delete[] self->print;
// releasing vector elements
for(uint x = 0; x < self->color.size(); x++)
{
Bin currentBin = self->color[x];
if(currentBin.name != NULL)
delete[] currentBin.name;
}
// releasing stuct Pointer
delete self;
}
}
which is called in the delete ImageProperties c++ function.
However, running the following code in Java never releases the memory (calling the function delete_imgprops) allocated in C++:
ImgPro imgObject = new ImgPro();
ImageProperties propObject = imgObject.processImage("imagem123-jpg");
int width = propObject.getWidth();
int height = propObject.getHeight();
String fingerPrint = propObject.getPrint();
propObject.delete();
imgObject.delete();
So, after analyzing the code flow, i found the reason why the memory isn't released. The ImageProperties.Java file generated by SWIG contains, among others, the delete function:
public synchronized void delete() {
if (swigCPtr != 0) {
if (swigCMemOwn) {
swigCMemOwn = false;
CBIRJNI.delete_ImageProperties(swigCPtr);
}
swigCPtr = 0;
}
}
The line "CBIRJNI.delete_ImageProperties(swigCPtr);" is never called because the var swigCMemOwn is always false.
I understand that because the Java side doesn't alloc memory so it also doesn't release it, so what can i do to ensure that java releases memory without any modification on java files generated by swig?
The solution that i found to release the memory is to comment the if(swigCMemOwn) test on delete() function, but i don't think that it's the best way of do it!
Thanks, Sérgio
You could check out the
%newobject
directive (in swig 2.0) with a factory method. It tells swig that a particular function will return a new object and that the java proxy class should be responsible for cleaning up the c++ memory as well. The generated code will set swigCMemOwn to true resulting in the c++ destructor being called.
If you do call the delete method yourself, that's fine - you just have to change your style of programming to think of the swig'ed object as something like a file handle or a db connection. You call close() on those objects when you're done because you don't want to wait for java's GC to kick in at some unknown later point and collect this expensive resource- you want to manage it manually.
But you also obviously must remember to exercise good code discipline to make sure you don't use the java object anywhere after calling delete()
You should never call delete() manually. If you correctly implemented C++ destructor (or wherever you memory is freed) the memory will be released as soon as the Java wrapper object is released, SWIG wrapper code then will call appropriate method automatically. Read more at SWIG doc for Java.

Undefined function 'javaaddpath' for input arguments of type 'cell'

I am currently call Matlab object in my java code .
The code of matlab is easy like this
function idx = clustering(W, k)
degs = sum(W, 2);
D = sparse(1:size(W, 1), 1:size(W, 2), degs);
L = D-W;
[V,dummy] = eigs(W,k,'sr');
idx = kmeans(V, k);
end
It is easy to use the object Clustering in Java.
I generate an object with code like this,
Spclustering specClusteringcol = null;
try {
specClusteringcol = new Spclustering();
} catch (MWException e) {
e.printStackTrace();
}
.......do some thing
if(specClusteringcol!=null)
specClusteringcol.dispose();
If I run simple demo in a single thread , this works correctly.
However, if I run some time cost task
the runtime will give out an exception
Undefined function 'javaaddpath' for input arguments of type 'cell'.
Why this happens? How to solve it?

Extracting data from objects using Unsafe (bypassing the Security Manager0

I am fully aware that I am doing is:
1) Unsafe, that I have no more guarantees, type safety, and that the JVM could therefore crash
2) That I could do similar operations using ByteBuffers or JNI
3) That Unsafe is an internal class and could well disappear.
I am doing this for experimentation purposes only and am aware of the consequences.
With this in mind, I am trying to extract the data from an array using Unsafe and reflection:
I first find the field offset of the array:
public long findFieldOffset(Event event) {
try {
Class cl = event.getClass();
Field data_field = cl.getDeclaredField("data");
data_field.setAccessible(true);
long offset = unsafe.objectFieldOffset(data_field);
return offset;
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return 0;
}
I also extract the base location of the array:
int base = unsafe.arrayBaseOffset(byte[].class);
I subsequently try to extract the array from the class Event, and copy it to a buffer (byte_offset is the result of findFieldOffset).
In the code below, the first part is just a test function and prints out the correct string, whilst the second part extracts what should be the array, but when testing returns garbage unicode values:
/* Testing */
active_buffer.getBuffer().position(1);
active_buffer.getBuffer().put(event.getData());
active_buffer.getBuffer().position(1);
active_buffer.getBuffer().get(tuple, 0, (int)tuple_size);
System.out.println("Test1: " + new String(tuple)) ;
/* Test1 prints out the correct string */
unsafe.copyMemory( (Object) event, byte_offset + base, (Object) null, active_buffer.getAddress() + 1, tuple_size);
active_buffer.getBuffer().position(1);
active_buffer.getBuffer().get(tuple, 0, (int)tuple_size);
System.out.println("Test2: " + new String(tuple));
/* Garbage unicode values gets printed*/
Can anyone see anything wrong with this code?
As data is a field, it is either a primitive or a reference, in either case you cannot copy it somewhere and treat it as a byte[]
If data is a byte[] you need to treat this as the true object, not the Event.

Categories

Resources