我正在为Java编写游戏,使用Java作为用户界面,使用C ++和NDK作为渲染线程。如果可用,它将使用Vulkan,否则将使用OpenGL ES。此错误发生在OpenGL ES和Vulkan中。
如果我暂停应用程序并在onPause,onStop或SurfaceHolder.Callback.surfaceDestroyed完成之前快速恢复它,则在渲染线程停止之前,表面上将显示残影。残像的行为就像我绘制的任何新事物的背景一样。执行渲染过程时,我将透明颜色设置为:黑色,alpha为0.0。我这样做是为了使应用程序的背景成为游戏的背景。如果我将alpha值设置为1.0,则此错误的症状将不会出现。
此问题可以看作是对以下问题的概括: phantom images after going from split screen to full screen 但是解决该问题(即避免关闭应用程序)的解决方案不适用于这种更常见的情况。
我在onPause或SurfaceHolder.Callback.surfaceDestroyed期间停止渲染线程,无论哪种情况先发生。这些功能只有在渲染线程加入后才会返回(如果有的话)。
如果我使用空的渲染通道(透明颜色为黑色,alpha值为0.0,在Vulkan中)或通过在渲染线程关闭之前调用glClear(在OpenGL ES中)来清除屏幕,则该错误不会显现。但是,这冒出表面做错了某些东西(或某种竞赛条件)的恶臭。我担心此解决方案只是隐藏该错误,而不是通过释放与残像相关的资源来修复它。我还需要做其他事情以确保正确重置表面吗?
开始渲染阶段(vulkan):
std::array<VkClearValue, 2> clearValues = {};
clearValues[0].color = {0.0f, 0.0f, 0.0f, 0.0f};
clearValues[1].depthStencil = {1.0, 0};
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
renderPassInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
在OpenGL ES中初始化期间:
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
在绘图循环(OpenGL)中清除屏幕:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
在渲染线程中,这是ANativeWindow的设置和拆卸。我在调试器中检查了共享指针删除器的实际调用位置:
ANativeWindow *window = ANativeWindow_fromSurface(env, jsurface);
if (window == nullptr) {
notify->sendError("Unable to acquire window from surface.");
return;
}
auto deleter = [](WindowType *windowRaw) {
/* release the java window object */
if (windowRaw != nullptr) {
ANativeWindow_release(windowRaw);
}
};
std::shared_ptr<WindowType> surface(window, deleter);
在onPause和SurfaceHolder.Callback.surfaceDestroyed中
if (drawer == null) {
return;
}
try {
Draw.tellDrawerStop();
drawer.join();
} catch (InterruptedException e) {
}
drawer = null;
在onCreate中执行以下操作以使SurfaceView透明:
SurfaceView drawSurfaceView = findViewById(R.id.drawingSurface);
drawSurfaceView.setZOrderOnTop(true);
SurfaceHolder drawSurfaceHolder = drawSurfaceView.getHolder();
drawSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
drawSurfaceHolder.addCallback(new MySurfaceCallback(this));