简体   繁体   English

OpenGL ES 2.0 +开罗:HUD

[英]OpenGL ES 2.0 + Cairo: HUD

I am trying to render a HUD over an OpenGL ES 2.0 application written in C on an ARM Linux platform. 我试图在ARM Linux平台上用C语言编写的OpenGL ES 2.0应用程序上呈现HUD。

I am currently using 2 triangles positioned close to the near clipping plane and tiling the texture onto them. 我目前正在使用靠近近剪裁平面放置的2个三角形,并将纹理平铺到它们上面。 The texture is the size of the screen and is mostly transparent except for the parts where I have text rendered. 纹理是屏幕的大小,除了我有文本渲染的部分之外,它们大多是透明的。 The texture is generated using Pango/Cairo 使用Pango / Cairo生成纹理

If I turn on the HUD (uncommenting the call to render_ui), I currently take a 50% performance hit (Goes from 60fps to 30fps). 如果我打开HUD(取消对render_ui的调用),我目前的性能达到50%(从60fps到30fps)。

Here is the code to render the HUD: 这是渲染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");
}

There has to be a more sensible way of doing this. 必须有一种更明智的方法来做到这一点。

On mobile devices GPUs are very sensitive to blending, this for multiple reasons : 在移动设备上,GPU对混合非常敏感,原因有多种:

  • Blending consumes more bandwidth (need to read current pixel to mix it with new one) 混合消耗更多带宽(需要读取当前像素以将其与新的像素混合)
  • Blending can break hidden surface removal optimizations 混合可以破坏隐藏的表面移除优化
  • Blending can also break tile based defered rendering optimizations 混合还可以破坏基于图块的延迟渲染优化

So in short mobile GPUs love opaque polygons and hate transparent ones . 因此,简而言之, 移动GPU喜欢不透明的多边形并且讨厌透明的多边形

Note that the total surface occupied by transparent polygons on screen is also very important due to the "tile based" nature of most mobile GPUs (when a tile/bin is covered by transparent polygons you can lose some GPU optimizations for it). 请注意,由于大多数移动GPU的“基于图块”的特性, 屏幕上透明多边形占据的总面积也非常重要 (当图块/区域被透明多边形覆盖时,您可能会丢失一些GPU优化)。

Also, since you say you get a sharp drop from 60fps to 30fps, I would conclude that your device GPU is blocking, waiting for the screen 60Hz vertical sync to swap, so this means that your frame DT can only be multiples of 16ms, so you probably only can get fps values like : 60, 30, 15, 7.5, ... 此外,既然你说你从60fps急剧下降到30fps,我会得出结论你的设备GPU正在阻塞,等待屏幕60Hz垂直同步交换,所以这意味着你的帧DT只能是16ms的倍数,所以你可能只能获得fps值,如:60,30,15,7.5,......

So if you were at 60fps, but add something in your app main loop which would drop the theorical fps to only 57fps, then because of the vertical sync wait, you will abruptly go to 30fps. 因此,如果您的速度为60fps,但在app主循环中添加一些内容会使理论 fps降至仅为57fps,那么由于垂直同步等待,您将突然达到30fps。 VSync can be disabled, or techniques like triple buffering can be used to mitigate this, but with OpenGLES the way of doing this is specific to the OS & hardware you are working with ... there is no "official way of doing it which works on all devices". 可以禁用VSync,或者可以使用三重缓冲等技术来缓解这种情况,但使用OpenGLES,这样做的方式特定于您正在使用的操作系统和硬件......没有“官方的方法可以使用它在所有设备上“。

So, knowing all this here are some propositions to get back to 60fps : 所以,知道所有这些是一些回到60fps的命题:

  1. Use a reduced resolution, ex: 1280x720 instead of 1920x1080, this will reduce bandwith usage & fragment processing. 使用降低分辨率,例如:1280x720而不是1920x1080,这将减少带宽使用和片段处理。 Not ideal of course, but this could be used as a test to confirm that you have a bandwith or fragment issue (if you get 60fps back after reducing resolution, then you have this kind of issue) 当然不理想,但这可以用作测试来确认你有带宽或片段问题(如果你在降低分辨率后得到60fps,那么你有这种问题)
  2. Use 16bit (R5G6B5) backbuffer instead of 32bits backbuffer (R8G8B8A8), this can reduce bandwith usage, but with some visual quality loss 使用16位(R5G6B5)后置缓冲器而不是32位后置缓冲器(R8G8B8A8),这可以减少带宽使用,但会有一些视觉质量损失
  3. Reduce area of blended surfaces: in your case this would mean that you should organize your texts by "blocks", each block fitting as much as possible the text like in this picture from IOS docs : 减少混合曲面的面积:在您的情况下,这意味着您应该按“块”组织文本,每个块尽可能地拟合IOS 文档中此图片中的文本: 在此输入图像描述
  4. Find a way to disable Vsync on your device / use triple buffering. 找到一种方法来禁用设备上的Vsync /使用三重缓冲。 If you have access to Vivante GPU docs (I do not) this may be described inside. 如果您可以访问Vivante GPU文档(我没有),可以在里面进行描述。

Point 3 is the best thing to do (this is what was done in most mobile games I worked on), however this will need some non negligible extra work. 第3点是最好的事情(这是我在大多数手机游戏中所做的事情),但这需要一些不可忽视的额外工作。 Points 1, 2 and 3 are more straightforward but are only "half solutions". 第1,2和3点更简单,但只是“半解决方案”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM