【发布时间】:2019-06-21 03:04:32
【问题描述】:
我研究了很多平台供应商(Qucomm Adreno SDK、PowerVR SDK、ARM Mali SDK 和 Google 的 android NDK 示例)提供的 Vulkan 示例应用程序有一段时间了。我注意到所有示例都在以下代码模式中执行 Vulkan 初始化和反初始化:
void android_main(struct android_app* androidApp)
{
...
androidApp->onAppCmd = [](struct android_app* androidApp, int32_t cmd) -> void //Event handle (Lambda)
{
VulkanApp* app = (VulkanApp*)androidApp->userData;
switch (cmd)
{
case APP_CMD_INIT_WINDOW:
initVulkan(...); //Initialize vulkan: layers, extension, instance, surface, device, swapchain, ...
break;
case APP_CMD_TERM_WINDOW:
deinitVulkan(...); //Deinitialize vulkan: in reversed order...
break;
...
}
...
}
...
}
基本上应用程序在 NDK 事件 APP_CMD_INIT_WINDOW 中初始化 Vulkan 组件,并在事件 APP_CMD_TERM_WINDOW 中销毁它们。这段代码在用户启动应用,运行一段时间后被用户退出的情况下是相当合理的。
但是,当用户将android应用切换到后台(通过主页或菜单按钮)并多次将其带回来时,将触发配对事件APP_CMD_TERM_WINDOW和APP_CMD_INIT_WINDOW多次,因此函数 initVulkan() 和 deinitVulkan() 将被调用多次。
在这种情况下,代码对我来说似乎是不合理的:由于应用程序只是暂时推到后台并回到前台,我们为什么要销毁所有 Vulkan 组件,如层、扩展、实例、设备、表面、交换链、管道……然后重新创建它们?最多,可能唯一需要重新创建的组件是交换链和管道。但是为什么所有 SDK 的示例应用程序都执行如此繁重的操作呢?
顺便说一句,当我与 Windows、Linux、macOS 和 iOS 等其他平台上的 Vulkan 示例源代码进行比较时,它们都没有进行如此繁重的娱乐。
我曾尝试使用“初始化一次” 解决方案,但是当它从后台返回到前台时,android 应用程序崩溃了。
所以可能的问题是: 当 Android 应用在后台和前台之间切换时,我们是否必须销毁并重新创建所有 Vulkan 组件?如果没有,我们该怎么做?
-----
更新: 我收到的关于我的问题的建议很少,我理解在 Android 应用程序的“交换”期间,我们最好限制应用程序占用的系统资源(特别是在收到低内存警告时),同时,细粒度的暂停Vulkan 组件上的 /resume 机制有助于在轻量内存使用和快速恢复应用之间保持良好的平衡。
我查看了 Google NDK OpenGL ES“茶壶”示例,我注意到这个 NDK gl 示例使用高度查找调整机制来暂停/恢复 OpenGL 上下文: 在事件处理部分,代码如下:
switch (cmd)
{
case APP_CMD_INIT_WINDOW:
// The window is being shown, get it ready.
if (app->window != NULL)
eng->InitDisplay(app);
break;
case APP_CMD_TERM_WINDOW:
// The window is being hidden or closed, clean it up.
eng->TermDisplay();
break;
case APP_CMD_LOW_MEMORY:
// Free up GL resources
eng->TrimMemory();
break;
这是函数 InitDisplay() 的代码:
int Engine::InitDisplay(android_app *app)
{
if (!initialized_resources_) // THIS IS FIRST TIME THE EVENT IS TRIGGERED WHEN APP IS LAUNCHED
{
gl_context_->Init(app_->window); //Initialize OpenGL
LoadResources();
...
}
else // TRIGGERED WHEN APP IS BROUGHT BACK FROM BACKGROUND TO FOREGROUND
{
// On some devices, ANativeWindow is re-created when the app is resumed
if (app->window != gl_context_->GetANativeWindow())
{
// Re-initialize ANativeWindow.
assert(gl_context_->GetANativeWindow());
UnloadResources();
gl_context_->Invalidate();
gl_context_->Init(app->window); //Initialize OpenGL again
LoadResources();
...
}
// Normal case, only need to resume OpenGL
else
{
// initialize OpenGL ES and EGL
if (EGL_SUCCESS == gl_context_->Resume(app_->window))//Resume OpenGL
{
UnloadResources();
LoadResources();
}
...
}
}
...
从代码中我们可以看出,在大多数“好的情况”下,只有一小部分 OpenGL 资源被卸载和重新加载;只有在“坏情况”下,OpenGL上下文才会被完全销毁并重新创建,这可以产生快速的应用恢复。
所以我的问题可以扩展到: 有没有人知道使用这种 find-grind Vulkan 暂停/恢复机制的优秀 Vulkan/Android 模板应用程序?或者想分享你自己的代码来做到这一点?我目前正在做这件事,但进展并不顺利。
【问题讨论】: