Передача функции java.nio.IntBuffer в C в игре для Android - PullRequest
3 голосов
/ 26 февраля 2011

Я бы хотел добавить немного собственного кода на C в свое приложение для Android. У меня есть IntBuffer, который я использую в качестве параметра для метода OpenGL glColorPointer. Это заполнено / используется примерно так:

private IntBuffer mColourBuffer;
int[] colours = new int[10 * 4];   // 10 dots, 4 colour components per dot


ByteBuffer vbb3 = ByteBuffer.allocateDirect(10 * 4 * 4);   
vbb3.order(ByteOrder.nativeOrder());
mColourBuffer = vbb3.asIntBuffer();
mColourBuffer.put(colours);
mColourBuffer.position(0);

gl.glColorPointer(4, GL10.GL_FIXED, 0, mColourBuffer); 

Я бы хотел внести изменения в этот буфер, но он слишком медленный по сравнению с Java, поэтому я хотел бы сделать это с собственным кодом. Я искал простой пример, но я не могу найти ничего, что я мог бы понять, или который работает. Много документации, которую я видел, говорит о передаче элементов, но, конечно, все, что я хочу, это указатель. Передача указателя и работа с памятью, на которую он указывает, должна быть чрезвычайно эффективной; передача нагрузки между Java и C убила бы любые улучшения скорости, возможно, благодаря возможности работать с памятью из C.

До сих пор я придумал это:

void Java_com_poldie_myTouch2_myclass_mymethod( JNIEnv* env, jobject thiz, jintArray arr, int n )
{
    jint *c_array;

    c_array = (*env)->GetIntArrayElements(env, arr, NULL);

    (*env)->ReleaseIntArrayElements(env, arr, c_array, 0);


 return;


}

Который я могу назвать так:

public native void  mymethod(IntBuffer intbuf, int n);

mymethod(mColourBuffer , n);

Который, по крайней мере, работает и, кажется, выполняет вызов, но любая попытка оперировать с c_array (либо как разыменованный указатель, либо как массив) заставляет программу немедленно завершиться.

Я на правильном пути? Могу ли я передать указатель на память, стоящую за mColourBuffer, в мой C-код и работать с ним по возвращении в мой Java-код?

1 Ответ

2 голосов
/ 28 февраля 2011

Отвечая на мой собственный вопрос здесь, кажется, что ответ состоит в том, чтобы взять ваш массив вершин (которым вы манипулируете каждый кадр с помощью Java) и записать их в прямой буфер.

В моем примере выше, я бы хотел как-то заполнить Direct Buffer mColourBuffer для каждого кадра тем, что находится в локальном массиве 'colors'. Оказывается, вы хотите что-то вроде:

JNIfastPutf(mfColourBuffer, colours, nCount); 

где nCount - количество байтов для копирования. Функция (Native, C) JNIfastPutf выглядит следующим образом:

void Java_com_a_b_c_JNIfastPutf(JNIEnv* env, jobject thiz, jobject jo, jfloatArray jfa, int n)
{
    float* pDst = (float*) (*env)->GetDirectBufferAddress(env, jo);
    float* pSrc = (float*) (*env)->GetPrimitiveArrayCritical(env, jfa, 0);              
    memcpy( pDst, pSrc, n  );

   (*env)->ReleasePrimitiveArrayCritical(env, jfa, pSrc, 0);
}

Я нашел следующую ссылку очень полезной (моя функция - слегка модифицированная C-версия их примера C ++):

http://www.badlogicgames.com/wiki/index.php/Direct_Bulk_FloatBuffer.put_is_slow

Они объясняют, что вам действительно нужен такой подход, если вы работаете с поплавками; использование ints предположительно намного быстрее, хотя именно с этого я и начал, и в любом случае их собственный код показывает увеличение скорости примерно на 20 -> 100% по сравнению с «быстрой» int-версией, поэтому причин, по-видимому, мало не делать этого!

...