1

Google の native_app_glue ラッパーを使用したネイティブ Android アプリがあります。GLES をレンダリングするためのフルスクリーン未満のサーフェスを取得したいと考えています。Activity から派生した Java レイヤーを使用する GLES アプリでは、これは Java レイヤーの getWindow().setLayer() によって実現されます。ただし、私のプロジェクトの状況では、このソリューションを使用できません。

nativeActivtiy と native_app_glue レイヤーを使用すると、JNI を使用して Java クラスを取得し、Java にコールバックできますが、View 階層を変更することはできません。JNI 経由で C コードから setLayers() にコールバックすると、NativeActivity が View 階層が作成されたスレッドと同じスレッドにないため、このエラーが発生します。

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**) &env, JNI_VERSION_1_6); 

    if (!env  && result == JNI_EDETACHED)
    {
        JVMAttachArgs.version = JNI_VERSION_1_6;
        JVMAttachArgs.name = "NativeThread";
        JVMAttachArgs.group = NULL;
        if (state->activity->vm->AttachCurrentThread(&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) setContentView() を介して View 階層を作成する Java クラスを NativeActivity から派生させる c) Java と同じスレッドで実行されるネイティブ コードで JNI を使用して setLayout() を呼び出す d) ネイティブ コードの残りの部分は、必要に応じて別のスレッドで実行することができる

上記のアプローチが実行可能かどうか、これで障害に遭遇するかどうかはわかりません。

4

1 に答える 1

0

ピクセル バッファからレンダリングしようとしている場合は、glSubTexImage2D().

于 2013-03-29T16:46:57.547 に答える