【问题标题】:Optimizing a huge VBO drawing on Android/iOS devices优化 Android/iOS 设备上的巨大 VBO 绘图
【发布时间】:2014-08-07 01:49:07
【问题描述】:

我需要做的是在移动设备(OpenGL ES2.0,Android 4.2)上渲染一个比较大的等轴测图。我将 1 个 VBO 用于地形,1 个 VBO 用于阴影层,1 个 VBO 用于对象层。 性能是问题,即使是第一个 VBO。

这里,我有填充VBO的数据类型:

typedef struct _ovlndVertex
{
    GLshort x;
    GLshort y;
} ovlndVertex;

typedef struct _ovlndTexture {
    GLfloat u;
    GLfloat v;
} ovlndTexture;


typedef struct _TexturedVertex
{
    ovlndVertex        vertices;
    ovlndTexture       texCoords;
    GLshort textureId;
} TexturedVertex;

假设我们正在渲染一个 256x256 大小的地图,每个图块 4 个顶点,这在 VBO 中为我们提供了 256x256x4 = 262144 个顶点。给定 sizeof(TexturedVertex) == 16,这是 4194304 字节的原始 VBO 数据(大约 4MB)。

主要的渲染工作在着色器中完成。这是他们的代码:

顶点着色器:

attribute vec4 a_position;                            
attribute vec2 a_texCoord;                            
//attribute vec4 a_color;
attribute vec2 a_textureId;                              

uniform        mat4 u_MVPMatrix;                        

#ifdef GL_ES                                        
//varying lowp vec4 v_fragmentColor;                    
varying lowp vec2 v_texCoord;
#else                                                
//varying vec4 v_fragmentColor;                        
varying vec2 v_texCoord;
#endif                                                

varying float v_textureId;

void main()                                            
{                                                    
    gl_Position = u_MVPMatrix * a_position;            
//  v_fragmentColor = a_color;
    v_texCoord = a_texCoord;                        
    v_textureId = a_textureId.x;
}                                                    

片段着色器:

#ifdef GL_ES                                
precision lowp float;
precision lowp int;
precision lowp sampler2D;
#endif                                        

//varying vec4 v_fragmentColor;                
varying vec2 v_texCoord;
//uniform sampler2D u_texture0, u_texture1, u_texture2;
uniform sampler2D u_textures[16];
varying float v_textureId;
uniform int u_idxOffset;

void main()                                    
{                                  
    // strange enough, but binary search below works WAY faster than
    // plain texture array referencing by index like:
//    int idx = int(v_textureId) - u_idxOffset;
//    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[idx], v_texCoord);

    int index = int(v_textureId) - u_idxOffset;
    if(index < 8) //0-7
    {
        if(index < 4) // 0-4
        {
            if(index < 2) //0-1
            {
                if(index < 1)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[0], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[1], v_texCoord);
                }
            } else // 2-3
            {
                if(index < 3)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[2], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[3], v_texCoord);
                }
            }
        } else //4-7
        {
            if(index < 6) //4-5
            {
                if(index < 5)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[4], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[5], v_texCoord);
                }
            } else // 6-7
            {
                if(index < 7)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[6], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[7], v_texCoord);
                }
            }
        }
    } else //8-15
    {
        if(index < 12) //8-11
        {
            if(index < 10) //8-9
            {
                if(index < 9)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[8], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[9], v_texCoord);
                }
            } else // 10-11
            {
                if(index < 11)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[10], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[11], v_texCoord);
                }
            }
        } else //12-15
        {
            if(index < 14) //12-13
            {
                if(index < 13)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[12], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[13], v_texCoord);
                }
            } else // 14-15
            {
                if(index < 15)
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[14], v_texCoord);
                }
                else
                {
                    gl_FragColor = /*v_fragmentColor * */texture2D(u_textures[15], v_texCoord);
                }
            }
        }
    }
}

是的,我知道 OpenGL ES 剔除视口外的顶点,而且效果很好。在高缩放级别上,它可以流畅地在设备上显示 60FPS,但是,如果我缩小以查看所有地图(这是主要点),即使没有对象渲染,FPS 也会下降到 20-30,而使用对象时下降到 4-5渲染(另外 2 个类似的 VBO)。

以下是典型渲染缓慢帧的 ADT OpenGL ES Tracer 输出: (挂钟时间:0.49 毫秒,线程时间 0.37 毫秒)

glClear(mask = 16640)
glUseProgram(program = 22)
glBindTexture(target = GL_TEXTURE_2D, texture = 2)
glActiveTexture(texture = GL_TEXTURE1)
glActiveTexture(texture = GL_TEXTURE2)
glActiveTexture(texture = GL_TEXTURE3)
glActiveTexture(texture = GL_TEXTURE4)
glActiveTexture(texture = GL_TEXTURE5)
glActiveTexture(texture = GL_TEXTURE6)
glActiveTexture(texture = GL_TEXTURE7)
glActiveTexture(texture = GL_TEXTURE8)
glActiveTexture(texture = GL_TEXTURE9)
glActiveTexture(texture = GL_TEXTURE10)
glActiveTexture(texture = GL_TEXTURE11)
glActiveTexture(texture = GL_TEXTURE12)
glUniform1i(location = 1, x = 0)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 123)
glVertexAttribPointer(indx = 0, size = 2, type = GL_SHORT, normalized = false, stride = 16, ptr = 0x0)
glEnableVertexAttribArray(index = 1)
glEnableVertexAttribArray(index = 2)
glEnableVertexAttribArray(index = 0)
glEnableVertexAttribArray(index = 3)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 16, ptr = 0x0)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 16, ptr = 0x4)
glVertexAttribPointer(indx = 3, size = 1, type = GL_SHORT, normalized = false, stride = 16, ptr = 0xc)
glBindBuffer(target = GL_ELEMENT_ARRAY_BUFFER, buffer = 124)
glDrawElements(mode = GL_TRIANGLES, count = 469374, type = GL_UNSIGNED_INT, indices = 0x0)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
glBindBuffer(target = GL_ELEMENT_ARRAY_BUFFER, buffer = 0)
glActiveTexture(texture = GL_TEXTURE0)
glUseProgram(program = 7)
glDisableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x775470c0)
glVertexAttribPointer(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x775470e0)
glVertexAttribPointerData(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 8, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 16, ptr = 0x??, minIndex = 0, maxIndex = 4)
glBlendFunc(sfactor = GL_SRC_ALPHA, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUseProgram(program = 1)
glBlendFunc(sfactor = GL_LINES, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glBindTexture(target = GL_TEXTURE_2D, texture = 0)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77530800)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77530810)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x7753080c)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x775295f8)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529608)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77529604)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529878)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529888)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77529884)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
eglSwapBuffers

仅供参考,这是典型的快速渲染 GUI 框架(实际上是主菜单,它给了我 60FPS): (挂钟时间:1.10MS,线程时间0.70MS)

glClear(mask = 16640)
glUseProgram(program = 7)
glDisableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x77538880)
glVertexAttribPointer(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x775388a0)
glBlendFunc(sfactor = GL_SRC_ALPHA, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glVertexAttribPointerData(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 8, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 16, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUseProgram(program = 1)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, 0.093229175, -0.17300725, 0.0, 1.0])
glBlendFunc(sfactor = GL_LINES, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glBindTexture(target = GL_TEXTURE_2D, texture = 1)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77546f08)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77546f18)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77546f14)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.23489577, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538cb0)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538cc0)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77538cbc)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.20677078, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538f00)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538f10)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77538f0c)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.15572912, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77539150)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77539160)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x7753915c)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.1057291, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x775393a0)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x775393b0)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x775393ac)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.0567708, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77537bc0)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77537bd0)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77537bcc)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -0.020312428, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77537e10)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77537e20)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77537e1c)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, 0.02239585, -0.17300725, 0.0, 1.0])
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538060)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77538070)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x7753806c)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUseProgram(program = 7)
glDisableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x77533090)
glVertexAttribPointerData(indx = 0, size = 2, type = GL_FLOAT, normalized = false, stride = 8, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 16, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_FLOAT, normalized = false, stride = 0, ptr = 0x775330b0)
glBlendFunc(sfactor = GL_SRC_ALPHA, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glUseProgram(program = 1)
glUniformMatrix4fv(location = 0, count = 1, transpose = false, value = [0.0010416667, 0.0, 0.0, 0.0, 0.0, 0.0018115942, 0.0, 0.0, 0.0, 0.0, -9.765625E-4, 0.0, -1.0, -1.0, 0.0, 1.0])
glBlendFunc(sfactor = GL_LINES, dfactor = GL_ONE_MINUS_SRC_ALPHA)
glBindTexture(target = GL_TEXTURE_2D, texture = 0)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77530800)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77530810)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x7753080c)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x775295f8)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529608)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77529604)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
glVertexAttribPointer(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529878)
glVertexAttribPointer(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x77529888)
glVertexAttribPointer(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x77529884)
glVertexAttribPointerData(indx = 0, size = 3, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 1, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glVertexAttribPointerData(indx = 2, size = 2, type = GL_FLOAT, normalized = false, stride = 24, ptr = 0x??, minIndex = 0, maxIndex = 4)
glDrawArrays(mode = GL_TRIANGLE_STRIP, first = 0, count = 4)
eglSwapBuffers

这使得 OpenGL Tracers 对我来说毫无用处,因为更快的渲染帧显示的时间(包括挂钟和线程)比慢速帧更多。这是否意味着问题隐藏在着色器的某个地方?我如何分析他们?

到目前为止我尝试了什么:

  • 将所有 GLuint 更改为 GLshort 以最小化缓冲区大小(给了我 28 到 16 字节的顶点结构 sizeof 优化)
  • 使用 GL_DYNAMIC_DRAW/GL_STATIC_DRAW 方法将数据发送到 VBO(对我来说没有区别)
  • 尽我所能尝试使用 lowp
  • 尝试了单纹理渲染(没有区别,这让我觉得着色器做得很好)
  • 将 OpenGL 调用降至最低(您可以查看上面的 OGL 调用日志)
  • 删除了所有可能破坏管道渲染的 glGet* 函数

有什么建议可以优化吗?

【问题讨论】:

  • 缩小时无法“mip map”(下采样)?即,创建(重复)低至 1x1 的半比例版本。从底部到顶部渲染,直到时间用完,然后停止。如果您有足够的时间,这会使渲染的 VBO 总数增加 1/3 (1+1/4+1/4*1/4+1/4*1/4*1/4+... = 1+ 1/3),否则会给你快速的帧......可能会弹出一些,不知道。
  • 从片段着色器的角度缩小时神奇地选择mipmap的技术是什么? OpenGL ES 不支持 textureLod() 函数。
  • 我认为你需要优化你的片段着色器。你有大量的分支,着色器中的分支可能对性能非常不利。
  • 我完全同意 Niklas。 SIMD 操作不能很好地处理分歧,因为同一 warp 中的单独并行任务不能同时执行不同的语句。为了避免这种情况,warp 中的每个实例都将执行片段着色器的每个分支(无论结果如何),并在事后选择正确的分支结果。我看到二进制搜索方法更快的唯一方法是由于一些编译器优化删除了您的分支语句并用便宜的算术运算替换它们,这比您以前的方法更快。

标签: android c++ optimization opengl-es-2.0 vbo


【解决方案1】:

你已经做得很好了。可能没有更多的空间进行更多的微优化。

因为 drawcalls 的数量很少,使用 VAO/VertexArrays 从渲染循环中删除 glVertexAttribPointer 应该没有多大帮助。

每个图块 4 个顶点

你为什么使用 GL_TRIANGLE_STRIP 和 glDrawArrays ?带索引的 glDrawElements 将为您提供更大的灵活性(见后...)。

20-30 即使没有对象渲染,也可以达到 4-5 对象渲染(另外 2 个类似的 VBO)。

好的。所以你最终会得到大约 800k 个顶点。正确的 ? 去年我遇到了类似的问题(1000k 个顶点)。我最终选择发送更多的绘制调用而不是使用复杂的着色器。是的,绑定大量数据(16 个纹理绑定!)会减慢此类设备上的一切。

如果我缩小以查看所有地图(这是主要点),FPS 会下降

在 iPad 2 上,屏幕上的 1000k 个顶点(每个顶点的数据比您多得多)应该渲染得更快:超过 20 fps。

您的大部分数据似乎都是静态的。 您可以尝试为每个纹理构建一个 vbo 或索引列表(我不知道哪个更快),大大简化您的片段着色器。

  • 将 vbo 与所有“静态数据”(顶点位置、纹理坐标)绑定
  • 对于每个纹理
    1. 绑定纹理
    2. 将 glDrawElements 与“纹理特定”索引列表一起使用。

您可以将索引存储在缓冲区中:glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...) 或者,如果它们是动态的,您可以将索引直接传递给 glBindBuffer。它可能比您想象的要快。

最后一个细节:lowp 到处都是危险的。试试mediump。

祝你好运,你正在触及设备限制!

【讨论】:

  • 我需要复杂的片段着色器来混合来自不同纹理(建筑物、树木等)的对象的 z 顺序。这就是为什么我不能像你建议的那样简单地用几个 VBO(每个纹理一个)替换它。对象纹理的最终选择是在片段着色器中完成的。不过,感谢您的回复,我今天将尝试 iPad 3 及其 OpenGL ES 分析器,因为我找不到任何适合 Android 的工具。
【解决方案2】:

由于快速帧显示图形跟踪的时间较长,因此很可能是其他原因导致速度变慢。您应该分析 CPU 并查看您的主线程和渲染线程在做什么。希望它能显示出瓶颈。

在渲染放大视图和缩小视图时分析 CPU 会很有用,并查看两者之间的主要区别是否有任何突出之处。

【讨论】:

  • 我做到了。问题是填充率,正如我所说,CPU 几乎是空闲的。缩小时,渲染器利用率始终为 99%-100%。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
相关资源
最近更新 更多