问题描述
我正在使用NDK编写用于Android的游戏.我的游戏使用vulkan(如果可用),否则使用OpenGL.
I am writing a game for Android using the NDK. My game uses vulkan if it is available and otherwise uses OpenGL.
我有一个问题,如果您将游戏保持在纵向屏幕上,然后将游戏置于分屏模式,然后将游戏调整为全屏模式,则旧视图上的游戏残像仍然可见.注意:在游戏中执行此操作会触发SurfaceHolder.Callback.surfaceDestroyed(在Java中)被调用,从而关闭C ++中的渲染线程.我对surfaceDestroyed的回调告诉C ++渲染线程停止,然后加入它.
I have a problem where if you put the game in split screen mode with the device held in portrait orientation, then resize the game to full screen mode, an after image of the game on the old view is still visible. Note: doing this with the game triggers SurfaceHolder.Callback.surfaceDestroyed (in Java) to be called, which in turn shuts down my render thread in C++. My callback for surfaceDestroyed tells the C++ render thread to stop, then joins it.
我可以在OpenGL中解决此问题,方法是使用任意颜色调用glClearColor,然后在渲染线程关闭之前立即调用eglSwapBuffers.
I can fix this in OpenGL by calling glClearColor with any color, then calling eglSwapBuffers right before the render thread shuts down.
这是OpenGL的有效修复程序吗?我还应该采取其他措施清除旧表面吗?一世在退出渲染线程之前,已验证在从ANativeWindow_fromSurface获取的窗口上调用了ANativeWindow_release.
Is this a valid fix for OpenGL? Is there something else I should be doing to clean out the old surface? Iverified that ANativeWindow_release is called on the window I get from ANativeWindow_fromSurface before I exit the render thread.
然后我尝试在vulkan中执行相同的操作,然后再次遇到问题...我使用了do的vkCmdClearColorImage如下:
Then I tried to do the same thing in vulkan and ran into problems again... I used vkCmdClearColorImage by doing the following:
(1)vkQueueWaitIdle(presentQueue)
(1) vkQueueWaitIdle(presentQueue)
(2)vkAquireNextImageKHR
(2) vkAquireNextImageKHR
(3)使用以下命令初始化相应的命令缓冲区:
(3) initialize the corresponding command buffer with:
(3a)图像内存屏障VK_IMAGE_LAYOUT_UNDEFINED-> VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,0-> VK_ACCESS_TRANSFER_WRITE_BIT
(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
(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
(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 ...)
(4) vkQueueSubmit(graphicsQueue...)
(5)vkQueuePresentKHR(presentQueue ...)
(5) vkQueuePresentKHR(presentQueue...)
(6)vkQueueWaitIdle(presentQueue)
(6) vkQueueWaitIdle(presentQueue)
我到达3a,然后在验证层收到一个错误,说该图像不是使用VK_IMAGE_USAGE_TRANSFER_DST_BIT使用标志创建的.我该如何使用此使用位创建交换链图像?
I got to 3a, and then I got an error in the validation layer saying that the image was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT usage flag. How do I cause the swapchain images to be created with this usage bit?
请让我知道是否需要其他信息.谢谢!
Please let me know if additional information is needed. Thanks!
推荐答案
Vulkan部分很容易解释.有一个imageUsage
成员.让我给你代码:
The Vulkan part is pretty self explanatory; there's a imageUsage
member. Let me just give you code:
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
.
Though you should probably not be doing it anyway. There is no reason to do vkCmdClearColorImage
. Use render pass to clear color images before you intend to write them (VkAttachmentDescription::loadOp
). It is more efficient and as a bonus it counts as a render and does not need TRANSFER
usage.
似乎 windowBackgroundFallback 应该是通用的假设您的应用无法及时提供新图像,则可以解决此问题.
It seems windowBackgroundFallback is supposed to be the general solution to this assuming your app cannot provide a new image in time.
摆脱幻影图像的最佳解决方案是告诉Android如果发生屏幕调整大小,请不要关闭应用程序.这样,可以通过重新创建交换链并重新绘制游戏来处理屏幕调整大小.此文章讨论了设置 android:configChanges .当屏幕从分屏更改为全屏时,以下设置可阻止android关闭应用程序:
The best solution to get rid of the phantom image is to tell android not to shutdown the app if a screen resize occurs. This way, the screen resize can be handled by recreating the swapchain and redrawing the game. This article talks setting android:configChanges in the manifests file. The following setting stops android from shutting down the app when a screen resize from split screen to full screen occurs:
android:configChanges="screenSize|orientation|screenLayout"
这篇关于从分屏到全屏后的幻像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!