PDA

View Full Version : Vulkan window on Android



MaB76
21st April 2017, 12:58
Hello,

I am trying to create Qt Vulkan window on Android. I use QWindow as application main window. Without vulkan it works just great. When trying to add vulkan rendering, I encountered the following problem. How to obtain ANativeWindow pointer needed for vkCreateAndroidSurfaceKHR()? QWindow::winId() does seem to return anything useful on android (in fact it always return value 1 in Qt 5.8 I use).

Googling I found some JNI black magic to get ANativeWindow:


ANativeWindow* awindow = nullptr;
QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface();
// the JNI black magic to get ANativeWindow*
jobject activity = (jobject)nativeInterface->nativeResourceForIntegration("QtActivity");
QAndroidJniEnvironment *qjniEnv;
JNIEnv * jniEnv;
JavaVM * jvm = qjniEnv->javaVM();
jvm->GetEnv(reinterpret_cast<void**>(&qjniEnv), JNI_VERSION_1_6);
jvm->AttachCurrentThread(&jniEnv,NULL);
jint r_id_content = QAndroidJniObject::getStaticField<jint>("android/R$id", "content");
QAndroidJniObject view = ((QAndroidJniObject) activity).callObjectMethod("findViewById", "(I)Landroid/view/View;", r_id_content);
if (view.isValid()) {
QAndroidJniObject child1 = view.callObjectMethod("getChildAt", "(I)Landroid/view/View;", 0);
if (child1.isValid()) {
jint cnt = child1.callMethod<jint>("getChildCount");
if (cnt > 0) {
QAndroidJniObject child2 = child1.callObjectMethod("getChildAt", "(I)Landroid/view/View;", 0);
if (child2.isValid()) {
QAndroidJniObject sHolder = child2.callObjectMethod("getHolder","()Landroid/view/SurfaceHolder;");
if (sHolder.isValid()) {
QAndroidJniObject theSurface = sHolder.callObjectMethod("getSurface","()Landroid/view/Surface;");
if (theSurface.isValid()) {
awindow = ANativeWindow_fromSurface(jniEnv, theSurface.object());
qDebug() <<"Got native window " << awindow;
WId wid = winId();
qDebug() << "winid returned " << wid;
}
}
}
}
}
}
if (awindow != nullptr) {
// and now try to create vulkan surface
VkAndroidSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.window = awindow;
VkResult res = vkInstance->vkCreateAndroidSurfaceKHR(&createInfo, NULL, &m_surface);
if (res != VK_SUCCESS) qDebug() << "Could not create Vulkan surface, err: " << res;
else qDebug() << "Vulkan surface creaated!";
}

Well, it partially works. When called during application startup, the code does not work, probably because the java views are not created yet (even when called in showEvent()). When called later when application is already running (I called it in keyPressEvent()), it finds the surface and ANativeWindow_fromSurface return something what seems to be sensible pointer. But when passed to vkCreateAndroidSurfaceKHR() I got error.

This is the application output I got:



D libVkWindow.so: ../VkWindow/vkwindow.cpp:440 (virtual void QVkWindow::keyPressEvent(QKeyEvent*)): Got native window 0x9ebf3808
D libVkWindow.so: ../VkWindow/vkwindow.cpp:442 (virtual void QVkWindow::keyPressEvent(QKeyEvent*)): winid returned 1
E vulkan : native_window_api_connect() failed: Invalid argument (-22)
D libVkWindow.so: ../VkWindow/vkwindow.cpp:456 (virtual void QVkWindow::keyPressEvent(QKeyEvent*)): Could not create Vulkan surface, err: -3

I am not sure whether the reason for error is that returned ANativeWindow * is not correct or it is caused by the fact, that I am trying to create vulkan surface for window too late (application already paited into this window in QWindow::exposeEvent()). Anyway I am stuck and do not know how to obtain proper ANativeWindow * in time to initialize vulkan surface.

Does anybody know how it should be done correctly? Some simple example would be just great.

Thanks in advance

wysota
21st April 2017, 22:00
It might not be doable at present. I know Qt devs are experimenting with Vulkan but appropriate native handles might not be available right now. Probably you should dive into "native" Android APIs instead.

fernnando
25th April 2017, 20:44
Hi MaB76! I'd like to ask if you could explain me a little bit more about how to get the surface. I think that I'm still missing something because I cannot get my native window. Where should I call that part of the code? Do you have a minimum project example that you could share with me?

I'm trying to create a Qt application for Android that uses OGRE but I have a few problems with "winId()" that makes a segmentation fault.

This line returns a zero in my application :/

jint cnt = child1.callMethod<jint>("getChildCount");