【问题标题】:OpenGL ES 2.0 + Cairo: HUDOpenGL ES 2.0 + 开罗:HUD
【发布时间】:2015-11-27 11:45:44
【问题描述】:

我正在尝试在 ARM Linux 平台上用 C 语言编写的 OpenGL ES 2.0 应用程序渲染 HUD。

我目前正在使用 2 个三角形,它们位于靠近剪裁平面的位置,并将纹理平铺在它们上面。纹理是屏幕的大小,除了我渲染文本的部分外,大部分都是透明的。使用 Pango/Cairo 生成纹理

如果我打开 HUD(取消对 render_ui 调用的注释),我目前会受到 50% 的性能影响(从 60fps 到 30fps)。

这里是渲染HUD的代码:

void render_ui(OGL_STATE_T *state) {

    glUseProgram(state->uiHandle);

    matIdentity(modelViewMatrix);
    matTranslate(modelViewMatrix, 0, 0, -0.51);

    const GLfloat *mvMat2 = modelViewMatrix;

    glViewport(0,0,state->screen_width, state->screen_height);

    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glBindBuffer(GL_ARRAY_BUFFER, state->uiVB);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state->uiIB);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, state->uiTex);
    glUniform1i(_uiTexUniform, 0);

    glUniformMatrix4fv(_uiProjectionUniform, 1, 0, pMat);
    glUniformMatrix4fv(_uiModelViewUniform, 1, 0, mvMat2);

    glVertexAttribPointer(_uiPositionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
    glVertexAttribPointer(_uiColorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
            (GLvoid *) (sizeof(GLfloat) * 3));
    glVertexAttribPointer(_uiTexCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
            (GLvoid *) (sizeof(GLfloat) * 7));

    glEnableVertexAttribArray(_uiPositionSlot);
    glEnableVertexAttribArray(_uiColorSlot);
    glEnableVertexAttribArray(_uiTexCoordSlot);

    glDrawElements(GL_TRIANGLES, uiIndicesArraySize / uiIndicesElementSize,
            GL_UNSIGNED_BYTE, 0);   

    glDisableVertexAttribArray(_uiTexCoordSlot);
    glDisable(GL_BLEND);

    GLenum err;

    if ((err = glGetError()) != GL_NO_ERROR)
        printf("There was an error");
}

必须有一种更明智的方式来做到这一点。

【问题讨论】:

  • 您平台上的 GPU 是什么(PowerVr、Adreno、Mali、Nvidia Tegra ...)?还有分辨率是多少?
  • @VB_overflow Vivante GPU / 飞思卡尔 iMX6 板。分辨率为 1920x1080。

标签: c opengl-es-2.0 hud


【解决方案1】:

在移动设备上,GPU 对混合非常敏感,这有多种原因:

  • 混合会消耗更多带宽(需要读取当前像素以将其与新像素混合)
  • 混合会破坏隐藏的表面去除优化
  • 混合还会破坏基于图块的延迟渲染优化

简而言之,移动 GPU 喜欢不透明的多边形而讨厌透明的多边形

请注意,屏幕上透明多边形占据的总表面也非常重要,因为大多数移动 GPU 具有“基于图块”的特性(当图块/bin 被透明多边形覆盖时,您可以失去一些 GPU 优化)。

另外,既然你说你从 60fps 急剧下降到 30fps,我会得出结论,你的设备 GPU 正在阻塞,等待屏幕 60Hz 垂直同步交换,所以这意味着你的帧 DT 只能是16 毫秒,因此您可能只能获得 fps 值,例如:60、30、15、7.5、...

因此,如果您的速度为 60fps,但在您的应用程序主循环中添加一些东西,这会使 理论 fps 降至仅 57fps,那么由于垂直同步等待,您将突然变为 30fps。可以禁用垂直同步,或者可以使用三重缓冲之类的技术来缓解这种情况,但是使用 OpenGLES,这样做的方式特定于您正在使用的操作系统和硬件......没有“官方的方式来做这件事”在所有设备上”。

因此,了解所有这些后,我们有一些建议可以恢复到 60fps:

  1. 使用降低的分辨率,例如:1280x720 而不是 1920x1080,这将减少带宽使用和片段处理。当然不理想,但这可以用来确认您有带宽或碎片问题(如果您在降低分辨率后恢复到 60fps,那么您就有这种问题)
  2. 使用 16 位 (R5G6B5) 后备缓冲区而不是 32 位后备缓冲区 (R8G8B8A8),这样可以减少带宽使用,但会损失一些视觉质量
  3. 减少混合表面的面积:在你的情况下,这意味着你应该用“块”来组织你的文本,每个块尽可能地适合这个图片中的文本,来自 IOS docs :
  4. 找到一种方法在您的设备上禁用垂直同步/使用三重缓冲。如果您可以访问 Vivante GPU 文档(我没有),这可能会在内部进行描述。

第 3 点是最好的做法(这是我参与的大多数手机游戏中的做法),但这需要一些不可忽略的额外工作。第 1、2 和 3 点更直接,但只是“半解”。

【讨论】:

  • 谢谢,这是一个非常详细的答案。通过删除许多正在发生且不必要的 glDisable 和 glEnable 调用,我能够将我的 fps 备份到 48fps。 gpu 似乎以 30、48 和 60fps 同步。我想尝试探索的一种途径是我当前使用的内核上没有 KMS 支持,因此没有实现零拷贝,这可以节省大量的 memcpy 调用。但是干得好,赏金!
  • 谢谢!附加说明:如果您因为文本的全屏透明四边形而受到 GPU 限制,那么在某些时候,无论您添加什么 cpu 端优化,您都不会获得更多的 fps 改进,然后唯一的解决方案是将这个大四边形分开适合文本区域的子四边形或降低分辨率。您可以通过将四边形切换为不透明而不是透明或降低分辨率来轻松测试您是否因混合而受 GPU 限制,如果您通过这样做获得 fps,则您受 GPU 限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 2011-06-14
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
相关资源
最近更新 更多