如果在onPause完成之前应用再次搁浅,则SurfaceView上的幻像图像

时间:2019-03-22 23:00:37

标签: android opengl-es android-ndk vulkan

我正在为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));

0 个答案:

没有答案