#android #native-code #egl
#Android #собственный код #egl
Вопрос:
У меня есть родное приложение для Android, использующее оболочку native_app_glue от Google. Я хотел бы получить менее чем полноэкранную поверхность для рендеринга GLES. В приложениях GLES, использующих java layer, полученный из Activity, это достигается с помощью GetWindow().setLayer() в Java layer. Однако ситуация с моим проектом не позволяет мне использовать это решение.
С nativeActivtiy и native_app_glue layer я могу использовать JNI для получения классов Java и обратного вызова в Java, но не изменять иерархию представлений. При обратном вызове setLayers() из моего C-кода через JNI я получаю эту ошибку, поскольку NativeActivity находится не в том потоке, в котором была создана иерархия представлений.
E / AndroidRuntime (21503): android.view.ViewRoot $CalledFromWrongThreadException: только исходный поток, создавший иерархию представлений, может касаться своих представлений.
И вот мой код для этого:
// Call Java to set Window size
//-----------------------------------------------------------------------------
int CallJavaWindowSize(struct android_app* state, jint width, jint height)
//-----------------------------------------------------------------------------
{
JNIEnv *env;
jclass nativeActivityClass;
jobject nativeActivityObj;
jmethodID mid;
jobject windowObj;
bool didAttachment = false;
int ret = -1;
JavaVMAttachArgs JVMAttachArgs;
jint result = state->activity->vm->GetEnv((void**) amp;env, JNI_VERSION_1_6);
if (!env amp;amp; result == JNI_EDETACHED)
{
JVMAttachArgs.version = JNI_VERSION_1_6;
JVMAttachArgs.name = "NativeThread";
JVMAttachArgs.group = NULL;
if (state->activity->vm->AttachCurrentThread(amp;env, NULL) < 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to attach to thread");
return ret;
}
__android_log_print(ANDROID_LOG_DEBUG, "PowerLift", "CallJavaWindowSize() attached to Thread");
didAttachment = true;
}
else if (result < 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to GetEnv()");
return ret;
}
// retrieves NativeActivity class
nativeActivityObj = state->activity->clazz;
//nativeActivityClass = env->FindClass("android/app/NativeActivity");
nativeActivityClass = env->GetObjectClass(nativeActivityObj);
if (!nativeActivityClass)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to Find NativeActivity class");
return ret;
}
//Run getWindow().setLayout(width,height)
mid = env->GetMethodID(nativeActivityClass, "getWindow", "()Landroid/view/Window;");
if (mid == 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to get method getWindow() with signature = ()Landroid/view/Window;");
return ret;
}
windowObj = env->CallObjectMethod(nativeActivityObj, mid);
if (windowObj == 0)
{
__android_log_print(ANDROID_LOG_ERROR, "PowerLift", "CallJavaWindowSize() Failed to CallObjectMethod for mid getWindow()");
return ret;
}
jclass classWindow = env->FindClass("android/view/Window");
mid = env->GetMethodID(classWindow, "setLayout", "(II)V");
env->CallVoidMethod(windowObj, mid, width, height);
if (didAttachment)
state->activity->vm->DetachCurrentThread();
return 0;
}
Решение, которое некоторые из вас могут предложить, — использовать glViewport() для рисования менее, чем на весь экран. Это решение работает визуально, но имеет низкую производительность, поскольку драйвер EGL все еще обрабатывает полноэкранные поверхности.
Мне интересно, является ли этот подход лучшим решением, поскольку он архитектурно сильно отличается от использования родной оболочки приложения: a) отказаться от родной оболочки клея приложения и запустить собственный код (или, по крайней мере, его часть) в том же потоке, что и JVM b) производный от NativeActivity класс Java, который создает иерархию представлений через setContentView() c) в собственном коде, который выполняется в том же потоке, что и Java, используйте JNI для вызова setLayout(). ) d) остальная часть машинного кода может быть запущена в другом потоке по мере необходимости
Я не уверен, возможен ли вышеуказанный подход, если я столкнусь с этим препятствием.
Ответ №1:
В случае, если вы пытаетесь выполнить рендеринг из пиксельного буфера, вы можете использовать glSubTexImage2D()
.