[英]Framerate dropping when drawing multiple textures in OpenGL ES iOS
基本上,我正在做的是制作一个简单的手指绘制应用程序。 我有一个单一的类,它接受输入的接触点,并完成将这些接触点转换为贝塞尔曲线,从这些接触点计算顶点等所有有趣的工作。一切都很好。
我正在使用的唯一有趣的约束条件是,我需要笔触在彼此之上进行融合,但不能彼此融合。 想象一下,有一条划线横穿自己并具有50%的不透明度。 线相交的地方应该没有可见的混合(看起来应该都是相同的颜色)。 但是,该线应与它下面的其余图形融合。
为此,我使用了两个纹理。 背部纹理和划痕纹理。 在动态更新线条时(在笔画过程中),我禁用混合,在暂存纹理上绘制顶点,然后启用混合,并将后部纹理和暂存纹理绘制到我的帧缓冲区中。 笔划完成后,我将划痕纹理绘制到背面纹理中,我们准备开始下一个笔划。
在较新的设备上,这一切都非常顺利,但是在较旧的设备上,帧频会受到严重影响。 从一些测试来看,似乎最大的性能影响在于将纹理绘制到帧缓冲区,因为它们是相对较大的纹理(由于iPhone的视网膜分辨率)。 有人对解决此问题的策略有任何暗示吗? 我很乐意提供更多细节或代码,只是不确定从哪里开始。
我正在使用面向iOS 7.0的OpenGL ES 2.0,但是在iPhone 4S上进行了测试
以下是我用来画入帧缓冲区的代码:
- (void)drawRect:(CGRect)rect
{
[self drawRect:rect
ofTexture:_backTex
withOpacity:1.0];
if (_activeSpriteStroke)
{
[self drawStroke:_activeSpriteStroke
intoFrameBuffer:0];
}
}
这些依赖于以下几种方法:
- (void)drawRect:(CGRect)rect
ofTexture:(GLuint)tex
withOpacity:(CGFloat)opacity
{
_texShader.color = GLKVector4Make(1.0, 1.0, 1.0, opacity);
[_texShader prepareToDraw];
glBindTexture(GL_TEXTURE_2D, tex);
glBindVertexArrayOES(_texVertexVAO);
glBindBuffer(GL_ARRAY_BUFFER, _texVertexVBO);
[self bufferTexCoordsForRect:rect];
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArrayOES(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, tex);
}
- (void)drawStroke:(AHSpriteStroke *)stroke
intoFrameBuffer:(GLuint)frameBuffer
{
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
[self renderStroke:stroke
ontoTexture:_scratchTex
inFrameBuffer:_scratchFrameBuffer];
if (frameBuffer == 0)
{
[self bindDrawable];
}
else
{
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
}
[self setScissorRect:_activeSpriteStroke.boundingRect];
glEnable(GL_SCISSOR_TEST);
[self drawRect:self.bounds
ofTexture:_scratchTex
withOpacity:stroke.lineOpacity];
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
}
- (void)renderStroke:(AHSpriteStroke *)stroke
ontoTexture:(GLuint)tex
inFrameBuffer:(GLuint)framebuffer
{
glBindFramebuffer(GL_FRAMEBUFFER, _msFrameBuffer);
glBindTexture(GL_TEXTURE_2D, tex);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
[stroke render];
glBindFramebuffer(GL_DRAW_FRAMEBUFFER_APPLE, framebuffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER_APPLE, _msFrameBuffer);
glResolveMultisampleFramebufferAPPLE();
const GLenum discards[] = { GL_COLOR_ATTACHMENT0 };
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 1, discards);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
还有一些辅助方法只是为了保持完整性,因此您可以按照以下说明进行操作:
- (void)bufferTexCoordsForRect:(CGRect)rect
{
AHTextureMap textureMaps[4] =
{
[self textureMapForPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect))
inRect:self.bounds],
[self textureMapForPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect))
inRect:self.bounds],
[self textureMapForPoint:CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect))
inRect:self.bounds],
[self textureMapForPoint:CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect))
inRect:self.bounds]
};
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(AHTextureMap), textureMaps, GL_DYNAMIC_DRAW);
}
- (AHTextureMap)textureMapForPoint:(CGPoint)point
inRect:(CGRect)outerRect
{
CGPoint pt = CGPointApplyAffineTransform(point, CGAffineTransformMakeScale(self.contentScaleFactor, self.contentScaleFactor));
return (AHTextureMap) { { pt.x, pt.y }, { point.x / outerRect.size.width, 1.0 - (point.y / outerRect.size.height) } };
}
据我了解,您是在单独的绘制调用中绘制每个四边形。 如果笔划包含很多四边形(对贝塞尔曲线进行采样),则您的代码将每帧进行多次绘制调用。
在较旧的iOS设备上的OpenGL ES 2中进行多次绘制调用可能会在CPU上产生瓶颈。 原因是OpenGL ES 2中的绘图调用可能会在驱动程序中产生大量开销。 驱动程序尝试将您进行的绘图调用组织成GPU可以消化的内容,并使用CPU进行这种组织。
如果打算绘制多个四边形以模拟笔刷笔触,则应更新一个顶点缓冲区以包含多个四边形,然后使用一个绘制调用对其进行绘制,而不是每个四边形进行绘制调用。
您可以使用Time Profiler仪器验证瓶颈在CPU中。 然后,您可以检查CPU是否将大部分时间都花在了OpenGL draw调用方法上,或者是在您自己的函数上。
如果CPU将大部分时间都花在OpenGL绘图调用方法上,则可能是因为每帧进行的绘图调用过多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.