Передача java.nio.IntBuffer в функцию C в игре для Android

Я хотел бы иметь возможность добавить немного собственного кода 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?


person Community    schedule 25.02.2011    source источник


Ответы (1)


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

В моем примере выше я хотел бы каким-то образом заполнить mColourBuffer прямого буфера для каждого кадра тем, что находится в локальном массиве «цвета». Оказывается, вам нужно что-то вроде:

JNIfastPutf(mfColourBuffer, colours, nCount); 

где nCount — количество копируемых байтов. (Собственная, 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

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

person Community    schedule 27.02.2011
comment
Скорость зависит от версии Android. Более поздние версии основных библиотек Dalvik имеют гораздо лучшую производительность. - person fadden; 01.03.2011