首页 > 解决方案 > 无法跟踪从另一个线程呈现的帧

问题描述

我们公司为包括Android在内的移动平台开发了几款游戏。我们将 OpenGL 用于所有视觉项目,包括 UI(更多技术细节如下)。

我们在发布前报告中收到了来自 Google Play 控制台的一些奇怪警告,例如“您的应用启动时间为 20764 毫秒”。在此报告提供的视频中,游戏大约需要一秒钟才能开始。

经过一番调查,我们发现 Android Systrace 无法检测到来自另一个线程的 OpenGL 绘图。所以发布前测试(错误地)认为我们的游戏超级慢。

是否有某种方法可以通知系统绘制了框架?似乎 eglSwapBuffers() 还不够。

Cocos2d 有相同问题的链接:https ://discuss.cocos2d-x.org/t/frozen-frames-warnings-by-google-play-pre-launch-report-for-3-17-cocos-演示应用程序/42894

一些细节

当新版本发布到 Google Play 控制台时,会在不同的设备上执行一些自动化测试。这些测试的结果可在 Google Play 管理中心的发布前报告部分中找到。

从 4 月初开始,我们在某些设备上收到了奇怪的性能警告(总是相同的)。两个例子:

这两个问题听起来都很可怕——如果它们是真的。但是当我们查看测试视频时,我们看不到任何问题。所有游戏都开始得很快,运行时没有视觉卡顿。

系统跟踪报告

这是 systrace 的图片,显示了我们游戏开始的 5 秒(矩形是我画的)。

系统跟踪

如您所见,systrace 仅发现渲染了 4 帧(粉红色矩形),这些帧是从 RenderThread 中绘制的。但由于某种原因,Android 无法检测到我们在另一个线程中执行的 GL 绘制调用(蓝色矩形)。

预发布报告也只显示 3 到 4 帧,每帧 300-400 毫秒长。

初始化代码

我们的游戏引擎在单独的线程中运行所有游戏逻辑和渲染代码。这是简化的初始化代码。

工作线程是从我们 Activity 的 onStart() 覆盖方法创建的。

public class MyActivity extends Activity
{
    protected Thread worker = null;

    private native void Run();

    @Override
    protected void onStart()
    {
        super.onStart();

        if(worker == null)
        {
            worker = new Thread()
            {
                public void run()
                {
                    Run();
                }
            };

            worker.start();
        }
    }
}

线程唯一做的就是 Run() 本机函数。这个函数可以解析成这样的:

void MyActivity::Run()
{
    initApp();

    while(!destroyRequested())
    {
        // Process the game logic.
        if (activated && window != NULL)
        {
            time->process();
            input->process();
            sound->process();
            logic->process();
            graphics->draw();
        }
    }

    clearApp();
}

如您所见,工作线程不断地旋转更新和绘制循环。Vsync 可防止循环过度执行。诸如资源加载之类的繁重操作是异步完成的,以避免冻结。

从用户方面来看,这种方法效果很好。游戏加载速度快,运行顺畅。

标签: androidopengl-essystrace

解决方案


推荐阅读