фантомные изображения после перехода с разделенного экрана на полный экран

1

Я пишу игру для 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 создавались с этим битом использования?

Пожалуйста, дайте мне знать, если нужна дополнительная информация. Спасибо!

Теги:
android-ndk
opengl-es
vulkan

1 ответ

1
Лучший ответ

Вулканская часть говорит сама за себя; там член 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"

  • 0
    Итак, я протестировал решение windowBackgroundFallback, и мне не повезло. Я установил этот атрибут в моем SurfaceView в xml-файле: android: windowBackgroundFallback = "@ drawable / empty_background", а затем создал рисунок, подобный этому: <?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> В нем все еще есть фантомные изображения
  • 0
    Я проверил код вулкана, который вы мне дали (спасибо!), И он сработал. Фантомное изображение после изменения размера исчезло. Но, как вы указали, это плохое решение. Мне не нужно запрашивать функцию, которая используется только при изменении размера приложения. Я также попытался сделать проход рендера без команд рисования. Это также сработало (без претензий от уровня валидации). Нет больше фантомного изображения. Это все еще кажется немного грязным. Что-нибудь еще, что я должен сделать к поверхности прежде, чем нить рендера закроется?
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню