在OpenGL ES iOS中绘制多个纹理时帧率下降



基本上我正在做的是制作一个简单的手指绘图应用程序。我有一个类,它处理输入的触摸点,并完成所有有趣的工作,将这些触摸点转换为贝塞尔曲线,从中计算顶点,等等。这一切都很好。

我使用的唯一有趣的约束是,我需要笔划在彼此之上混合,但不能与它们本身混合。想象一下,有一条与自己交叉的不透明度为50%的粗线条。在线与自身交叉的地方,不应该有可见的混合(它应该看起来都是相同的颜色)。但是,这条线应该与下面的图纸的其余部分融为一体。

为了实现这一点,我使用了两种纹理。背面纹理和划痕纹理。当线被主动更新时(在笔划过程中),我禁用混合,在划痕纹理上绘制顶点,然后启用混合,并将背面纹理和划痕纹理绘制到帧缓冲区中。笔划完成后,我将划痕纹理绘制到背面纹理中,然后我们就可以开始下一个笔划了。

这一切在较新的设备上运行非常顺利,但在较旧的设备上,帧速率会受到严重影响。从一些测试来看,最大的性能打击似乎是将纹理绘制到帧缓冲区,因为它们是相对较大的纹理(由于iPhone的视网膜分辨率)。有人对此有什么建议吗?我很乐意提供更多的细节或代码,我只是不确定从哪里开始。

我使用OpenGL ES 2.0,目标是iOS 7.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) } };
}

据我所知,您正在单独的draw调用中绘制每个四边形。如果你的笔划由许多四边形组成(来自对贝塞尔曲线的采样),你的代码将在每帧中进行许多绘制调用。

在旧的iOS设备上使用OpenGL ES 2进行多次绘图调用可能会对CPU造成瓶颈。原因是OpenGL ES 2中的draw调用可能会在驱动程序中产生大量开销。驱动程序试图将您进行的绘制调用组织成GPU可以消化的内容,并使用CPU进行组织。

如果要绘制许多四边形以模拟笔刷笔划,则应更新顶点缓冲区以包含许多四边形,然后使用一个绘制调用绘制它,而不是每个四边形进行一个绘图调用。

您可以使用时间档案器仪器验证瓶颈是否在CPU中。然后,您可以检查CPU是否将大部分时间花在OpenGL绘图调用方法上,或者更确切地说,是花在您自己的函数上。

如果CPU将大部分时间花在OpenGL绘制调用方法上,很可能是因为每帧绘制调用过多。

相关内容

  • 没有找到相关文章

最新更新