2012-03-20 59 views
4

我希望有人可以帮我指明了一些纹理基准我做的OpenGL ES 2.0的一些进展和iPhone 4优化OpenGL ES 2.0的2D纹理输出和帧率

我有一个包含精灵的数组对象。渲染循环遍历每个纹理的所有精灵,并检索其所有纹理坐标和顶点坐标。它使用退化的顶点和索引将它们添加到一个巨大的交织阵列中,并将它们发送给GPU(我嵌入的代码是底部)。这一切都是按照纹理完成的,所以我将纹理绑定一次,然后创建我的交错数组,然后绘制它。一切都很好,屏幕上的结果正是他们应该做的。

因此,我的基准测试是通过在不同的不透明度下添加25个新的精灵,并在更新上更改它们的顶点,以便在应用程序上旋转并运行OpenGL ES分析器时,它们在屏幕周围弹跳。

继承人,我希望有一些帮助.... 我可以达到约275个32x32精灵与不同的不透明度在60 fps的屏幕上跳动。到400我下降到40帧/秒。当我运行OpenGL ES Performance Detective时,它会告诉我...

应用程序渲染受三角形栅格化的限制 - 将三角形转换为像素的过程。所有正在渲染的三角形的总面积(以像素为单位)太大。要以更快的帧率绘制,请通过减少三角形的数量,其大小或两者的大小来简化场景。

的是我刚刮起了测试在cocos2d使用CCSpriteBatchNode使用相同的纹理和创建800个透明精灵和帧率为60fps的容易。

下面是一些代码,可能是中肯......

Shader.vsh(矩阵在成立伊始一次)

void main() 
{ 
    gl_Position = projectionMatrix * modelViewMatrix * position; 
    texCoordOut = texCoordIn; 
    colorOut = colorIn; 
} 

Shader.fsh(colorOut用于calc下不透明度)

void main() 
{ 
    lowp vec4 fColor = texture2D(texture, texCoordOut); 
    gl_FragColor = vec4(fColor.xyz, fColor.w * colorOut.a); 
} 

VBO设置

glGenBuffers(1, &_vertexBuf); 
    glGenBuffers(1, &_indiciesBuf); 
    glGenVertexArraysOES(1, &_vertexArray); 

    glBindVertexArrayOES(_vertexArray); 

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuf); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(TDSEVertex)*12000, &vertices[0].x, GL_DYNAMIC_DRAW); 
    glEnableVertexAttribArray(GLKVertexAttribPosition); 
    glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(0)); 

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0); 
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(8)); 

    glEnableVertexAttribArray(GLKVertexAttribColor); 
    glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(16)); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indiciesBuf); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort)*12000, indicies, GL_STATIC_DRAW); 

    glBindVertexArrayOES(0); 

更新代码

/* 

     Here it cycles through all the sprites, gets their vert info (includes coords, texture coords, and color) and adds them to this giant array 
     The array is of... 
     typedef struct{ 
      float x, y; 
      float tx, ty; 
      float r, g, b, a; 
     }TDSEVertex; 
    */ 

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuf); 
    //glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices[0])*(start), sizeof(TDSEVertex)*(indicesCount), &vertices[start]); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(TDSEVertex)*indicesCount, &vertices[start].x, GL_DYNAMIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

渲染代码

GLKTextureInfo* textureInfo = [[TDSETextureManager sharedTextureManager].textures objectForKey:textureName]; 
    glBindTexture(GL_TEXTURE_2D, textureInfo.name); 

    glBindVertexArrayOES(_vertexArray); 
    glDrawElements(GL_TRIANGLE_STRIP, indicesCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(start)); 
    glBindVertexArrayOES(0); 

下面有在400只小精灵(三角形800 800 +退化三角形)的屏幕截图,得到不透明分层作为纹理被移动的一个想法... 再次,我应该注意的是,一个VBO正在创建和发送每个纹理,所以我绑定,然后每帧只绘制两次(因为只有两个纹理)。

screenshot showing layering of sprites

很抱歉,如果这是压倒性的,但在这里它的我的第一篇,想彻底。 任何帮助将不胜感激。

PS,我知道我可以使用Cocos2D而不是从头开始编写所有的东西,但是在那儿玩的乐趣(和学习)?!

UPDATE#1 当我我的片段着色器切换到仅是

gl_FragColor = texture2D(texture, texCoordOut); 

它到达802个在精灵50fps的(4804三角形包括退化三角形),尽管设置子画面不透明度丢失..任何建议到如何仍然可以在我的着色器中处理不透明度而不以1/4的速度运行?

UPDATE#2 因此,我放弃了GLKit的View和View控制器,并编写了一个从AppDelegate加载的自定义视图。 902不透明的精灵& 60fps的透明度。

+0

与其使用OpenGL ES Performance Detective,我更喜欢使用带有OpenGL ES分析器和OpenGL ES驱动程序工具的仪器。分析器通常会指出更细微的渲染问题,并且驱动程序可以在Tiler(顶点侧)和Renderer(片段侧)为您提供百分比负载,以验证您的瓶颈位置。另外尝试运行Time Profiler对此。这看起来比应该慢,因为我把A4的基准定为1。使用VBOs和简单的阴影,每秒800万个三角形,或以60 FPS在屏幕上约30000个三角形。 – 2012-03-20 20:07:13

+0

感谢回复@BradLarson。尽管有些事情我不太了解... Renderer Utiliz:99%,Tiler Utilz:8%,Device Utilz:99%,我尽可能使用Analyzer和Driver。思考? Analyzer中唯一突出的是多余的调用,但绝大多数来自glView(绑定帧缓冲区等)。 Time Profilier显示83%来自我绑定和更新VBO(在更新中完成)并绘制。你认为使用glView是问题的一部分吗?我认为这是transp层(即时贴上截图和我更新的代码)。谢谢。 – yiannis 2012-03-20 21:23:27

+0

如果您的渲染器利用率确实为99%,而您的铺砖机为8%,那么显然您的填充率受限,而不是几何形状受限。优化三角形和你的VBO不会对你有什么好处,你需要专注于绘制更少的像素或更快地绘制像素。你已经在上面的场景中进行了很多混合,[来自经验](http://stackoverflow.com/q/6051237/19679)如果一堆混合对象堆积在一起,我知道这是非常昂贵的彼此顶部。您可以渲染不透明区域并写入深度缓冲区,然后在混合半透明区域时从中读取。 – 2012-03-21 14:43:29

回答

1

晴繁杂的思绪......

如果你是三角形的限制,试着从GL_TRIANGLE_STRIP切换到GL_TRIANGLES。您仍然需要指定完全相同数量的索引 - 每个四个索引相同数量 - 但GPU从未发现四边形之间的连接三角形退化(即,从不必将它们转换为零像素)。您需要进行配置以查看您是否最终支付了不再隐式共享边缘的成本。

您还应该缩小顶点的占位面积。我敢想象你可以将x,y,tx和ty指定为16位整数,将你的颜色指定为8位整数,而在渲染时不会有明显变化。这样可以将每个顶点的占用空间从32个字节(八个组件,每个四个字节的大小)减少到12个字节(四个双字节值加上四个单字节值,不需要填充因为所有内容都已经对齐)那里63%的内存带宽成本。

由于你实际上似乎是填充率有限,你也应该考虑你的源纹理。您可以通过修改字节大小来进行任何操作,这将直接帮助纹理提取并填充速率。

它看起来像你使用艺术是有意识的像素,所以切换到PVR可能不是一种选择。也就是说,人们有时并未意识到PVR纹理的全部好处;如果切换到每像素模式4位,那么您可以将图像缩放为宽度的两倍和高度的两倍,以减少压缩伪影,并且仍然只支付每个源像素上的16位,但可能会得到比16 bpp RGB纹理更好的亮度范围。

假设您目前使用32 bpp纹理,至少应该使用任何提供的硬件模式来查看普通16 bpp RGB纹理是否足够(尤其是如果1位alpha和每个颜色通道5位适合您的艺术品,因为这样会减少9位色彩信息,同时将带宽成本降低50%)。

它也看起来像你上传索引每一帧。仅当您向场景中添加额外对象时,或者上次上传的缓冲区比所需的大得多时才上传。您可以将传递给glDrawElements的计数限制为在没有重新上传的情况下削减对象。你还应该检查你是否通过上传顶点到VBO来获得任何东西,然后如果他们只是改变每一帧,就重新使用它们。从客户端内存直接提供它们可能会更快。

+0

谢谢@Tommy。因为这是从iPhone完成的,我不认为我可以直接从我的代码中提供顶点(我假设使用glBegin)。我确实尝试了GL_TRIANGLES方法,虽然它减少了许多三角形,但它并没有做太多的工作。我想使用PVR,但是我一直在使用纹理工具。我确实将纹理尺寸从37k缩小到了9k,但仍然没有区别。我会尝试将这些图像转换为16bpp,但它只是如此痛苦!尽管如此,再次感谢您的努力。 – yiannis 2012-03-21 05:50:10

+0

使用VBO是直接提供数组的可选替代方案。你必须提供偏移量的原因就像它们是一个指向'glVertexAttribPointer'的指针一样,只允许你给它一个指向某些客户端内存的指针。我的建议是,你可以尝试去掉'_vertexBuf' VBO和相应的'glBufferData'调用。您应该能够在运行时转换为16 bpp; Apple曾经在一些示例项目中提供了一个'Texture2D'类,但我猜想现在GLKit已经在现场消失了...... – Tommy 2012-03-21 18:01:55