Я пишу игру для Android, используя NDK. Моя игра использует vulkan, если он доступен, и в противном случае использует OpenGL.
У меня проблема, когда вы переводите игру в режим разделенного экрана, когда устройство находится в портретной ориентации, а затем изменяете размер игры до полноэкранного режима, после чего изображение игры на старом экране все еще отображается. Примечание: выполнение этого с игрой вызывает триггер SurfaceHolder.Callback.surfaceDestroyed (на Java), который, в свою очередь, закрывает мой поток рендеринга в C++. Мой обратный вызов для SurfaceDestroyed указывает [Ren10] прервать поток рендеринга, а затем присоединяется к нему.
Я могу исправить это в OpenGL, вызвав glClearColor любым цветом, а затем вызвав eglSwapBuffers непосредственно перед тем, как завершится поток рендеринга.
Это действительное исправление для OpenGL? Есть ли что-то еще, что я должен сделать, чтобы очистить старую поверхность? Я проверил, что ANativeWindow_release вызывается в окне, которое я получаю из ANativeWindow_fromSurface, прежде чем выйти из потока рендеринга.
Затем я попытался сделать то же самое в vulkan и снова столкнулся с проблемами... Я использовал vkCmdClearColorImage, выполнив следующее:
(1) vkQueueWaitIdle (presentQueue)
(2) vkAquireNextImageKHR
(3) инициализировать соответствующий буфер команд с помощью:
(3a) ImageMemoryBarrier VK_IMAGE_LAYOUT_UNDEFINED → VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0 → VK_ACCESS_TRANSFER_WRITE_BIT
(3b) vkCmdClearColor VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
(3c) ImageMemoryBarrier VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL → VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_ACCESS_TRANSFER_WRITE_BIT → VK_ACCESS_MEMORY_READ_BIT
(4) vkQueueSubmit (graphicsQueue...)
(5) vkQueuePresentKHR (настоящее время...)
(6) vkQueueWaitIdle (presentQueue)
Я добрался до 3a, а затем получил ошибку в слое проверки, говорящую, что изображение не было создано с флагом использования VK_IMAGE_USAGE_TRANSFER_DST_BIT. Как сделать так, чтобы образы swapchain создавались с этим битом использования?
Пожалуйста, дайте мне знать, если нужна дополнительная информация. Спасибо!
Вулканская часть говорит сама за себя; там член imageUsage
. Позвольте мне дать вам код:
VkSurfaceCapabilitiesKHR caps;
errco = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( pdev, mySurface, &caps ); if(errco) panic();
if( !(caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) ) panic();
VkSwapchainCreateInfoKHR sci = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};
sci.surface = mySurface;
sci.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; // !
// etc
VkSwapchainKHR mySwapchain;
errco = vkCreateSwapchainKHR( dev, &sci, nullptr, &mySwapchain ); if(errco) panic();
Хотя вы, вероятно, не должны делать это в любом случае. Нет причин делать vkCmdClearColorImage
. Используйте проход рендеринга для очистки цветных изображений перед тем, как вы собираетесь их записать (VkAttachmentDescription::loadOp
). Он более эффективен и в качестве бонуса считается рендером и не требует использования TRANSFER
.
Похоже, что windowBackgroundFallback является общим решением этой проблемы, если ваше приложение не может своевременно предоставить новое изображение.
Лучшее решение, чтобы избавиться от фантомного изображения, это сказать Android не закрывать приложение, если происходит изменение размера экрана. Таким образом, изменение размера экрана может быть выполнено путем воссоздания swapchain и перерисовки игры. В этой статье рассказывается о настройке android: configChanges в файле манифеста. Следующая настройка не позволяет Android выключать приложение при изменении размера экрана с разделенного на полный экран:
android:configChanges="screenSize|orientation|screenLayout"
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#00000000" /> <size android:width="500dp" android:height="500dp"/> </shape>
В нем все еще есть фантомные изображения