为什么 iPhone 上的点精灵 glClear() 如此慢?

发布于 2024-09-12 01:49:50 字数 2894 浏览 1 评论 0原文

我正在尝试在 iPhone 上使用 OpenGL ES 绘制点精灵。它们可能有很多(1000)并且宽度最多为 64 像素(也许这就是我的问题 - 是否有限制或者我是否使用了太多内存?)

我正在使用 CADisplayLink 来对帧进行计时。发生的情况是,当点数太高或点大小太大时,第一个 gl 绘图函数往往会延迟或停止。在下面的示例中,glClear() 是第一个绘图函数,运行时间可能为 0.02 秒到 0.2 秒。如果我简单地注释掉 glClear,glDrawArrays 就会变成慢速函数(否则它运行得非常快)。

这个示例是我为了隔离问题而精简的代码。它只是在同一个位置绘制一堆没有纹理的点精灵。我使用 VBO 来存储所有精灵数据(位置、颜色、大小)。对于这个例子来说,这似乎有点矫枉过正,但我​​当然打算稍后修改这些数据。

这是视图的初始化函数(减去样板 gl 设置):

glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);

glDisable(GL_LIGHTING);
glDisable(GL_FOG);

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND); 

glBlendEquationOES(GL_FUNC_ADD_OES);

glClearColor(0.0, 0.0, 0.0, 0.0);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glEnable(GL_POINT_SPRITE_OES);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
glEnableClientState(GL_COLOR_ARRAY);

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

glEnable(GL_POINT_SMOOTH);

glGenBuffers(1, &vbo);                   // vbo is an instance variable
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glMatrixMode(GL_PROJECTION);
glOrthof(0.0, [self frame].size.width, 0.0, [self frame].size.height, 1.0f, -1.0f);
glViewport(0, 0, [self frame].size.width, [self frame].size.height);  
glMatrixMode(GL_MODELVIEW);

glTranslatef(0.0f, [self frame].size.height, 0.0f);
glScalef(1.0f, -1.0f, 1.0f);  

这是渲染函数:

- (void)render
{
    glClear(GL_COLOR_BUFFER_BIT);    // This function runs slowly!

    int pointCount = 1000;

    // fyi...
    // typedef struct {
    // CGPoint point;
    // CFTimeInterval time;
    // GLubyte r, g, b, a;
    // GLfloat size;
    // } MyPoint;

    glBufferData(GL_ARRAY_BUFFER, sizeof(MyPoint)*pointCount, NULL, GL_DYNAMIC_DRAW);
    MyPoint * vboBuffer = (MyPoint *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);

    for (int i = 0; i < pointCount; i++) {
        vboBuffer[i].a = (GLubyte)0xFF;
        vboBuffer[i].r = (GLubyte)0xFF;
        vboBuffer[i].g = (GLubyte)0xFF;
        vboBuffer[i].b = (GLubyte)0xFF;
        vboBuffer[i].size = 64.0;
        vboBuffer[i].point = CGPointMake(200.0, 200.0);
    }

    glUnmapBufferOES(GL_ARRAY_BUFFER);

    glPointSizePointerOES(GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, size));
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyPoint), (void *)offsetof(MyPoint, r));
    glVertexPointer(2, GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, point));

    glDrawArrays(GL_POINTS, 0, pointCount);

    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

为什么 glClear 函数停滞?它不只是随机延迟 - 根据点数或大小,它往往会以相同的间隔(例如 0.015 秒、0.030 秒、0.045 秒等)随机延迟。我注意到的另外一件奇怪的事情是,如果我切换到 glBlendMode(GL_ZERO, GL_ONE),它运行得很好(尽管这不会是我想要的视觉效果)。其他 glBlendMode 值也会改变速度 - 通常会变得更好。这让我认为这不是内存问题,因为这与 VBO 无关(对吗?)。

我承认我对 OpenGL 有点陌生,可能误解了有关 VBO 或其他事物的基本概念。非常感谢任何帮助或指导!

I am trying to draw point sprites with OpenGL ES on iPhone. It's possible there could be very many of them (1000) and up to 64 pixels wide (maybe that's my problem right there - is there a limit or could I be using too much memory?)

I am using CADisplayLink to time the frames. What happens is that the first gl drawing function tends to delay or stall when either the point count is too high or when the point size is too big. In my example below, glClear() is the first drawing function, and it can take anywhere from 0.02 seconds to 0.2 seconds to run. If I simply comment out glClear, glDrawArrays becomes the slow function (it runs very fast otherwise).

This example is what I've stripped my code down to in order to isolate the problem. It simply draws a bunch of point sprites, with no texture, all in the same spot. I am using VBOs to store all the sprite data (position, color, size). It may seem like overkill for the example but of course I have intentions to modify this data later.

This is the view's init function (minus the boilerplate gl setup):

glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);

glDisable(GL_LIGHTING);
glDisable(GL_FOG);

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND); 

glBlendEquationOES(GL_FUNC_ADD_OES);

glClearColor(0.0, 0.0, 0.0, 0.0);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glEnable(GL_POINT_SPRITE_OES);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_POINT_SIZE_ARRAY_OES);
glEnableClientState(GL_COLOR_ARRAY);

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

glEnable(GL_POINT_SMOOTH);

glGenBuffers(1, &vbo);                   // vbo is an instance variable
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glMatrixMode(GL_PROJECTION);
glOrthof(0.0, [self frame].size.width, 0.0, [self frame].size.height, 1.0f, -1.0f);
glViewport(0, 0, [self frame].size.width, [self frame].size.height);  
glMatrixMode(GL_MODELVIEW);

glTranslatef(0.0f, [self frame].size.height, 0.0f);
glScalef(1.0f, -1.0f, 1.0f);  

And this is the rendering function:

- (void)render
{
    glClear(GL_COLOR_BUFFER_BIT);    // This function runs slowly!

    int pointCount = 1000;

    // fyi...
    // typedef struct {
    // CGPoint point;
    // CFTimeInterval time;
    // GLubyte r, g, b, a;
    // GLfloat size;
    // } MyPoint;

    glBufferData(GL_ARRAY_BUFFER, sizeof(MyPoint)*pointCount, NULL, GL_DYNAMIC_DRAW);
    MyPoint * vboBuffer = (MyPoint *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);

    for (int i = 0; i < pointCount; i++) {
        vboBuffer[i].a = (GLubyte)0xFF;
        vboBuffer[i].r = (GLubyte)0xFF;
        vboBuffer[i].g = (GLubyte)0xFF;
        vboBuffer[i].b = (GLubyte)0xFF;
        vboBuffer[i].size = 64.0;
        vboBuffer[i].point = CGPointMake(200.0, 200.0);
    }

    glUnmapBufferOES(GL_ARRAY_BUFFER);

    glPointSizePointerOES(GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, size));
    glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyPoint), (void *)offsetof(MyPoint, r));
    glVertexPointer(2, GL_FLOAT, sizeof(MyPoint), (void *)offsetof(MyPoint, point));

    glDrawArrays(GL_POINTS, 0, pointCount);

    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

Why is the glClear function stalling? It doesn't just delay in random amounts - depending on the point count or size, it tends to randomly delay in the same intevals (eg. 0.015 sec, 0.030 sec, 0.045 sec, etc). Also something strange I noticed is that if I switch to glBlendMode(GL_ZERO, GL_ONE), it runs just fine (although this is will not be the visual effect I'm after). Other glBlendMode values change the speed as well - usually for the better. That makes me think it is not a memory issue because that has nothing to do with the VBO (right?).

I admit I am a bit new at OpenGL and may be misunderstanding basic concepts about VBOs or other things. Any help or guidance is greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜唯美灬不弃 2024-09-19 01:49:50

如果glClear()很慢,您可以尝试绘制一个完全覆盖视口区域的大空白四边形。

If glClear() is slow you might try drawing a large blank quad that completely covers the viewport area.

〃安静 2024-09-19 01:49:50

您是否正在使用同步(或者是否已启用?)。您看到的延迟可能与 CPU 和 GPU 并行运行有关,因此测量各个 GL 调用的时间没有意义。

如果您使用 VSync(或 GPU 负载较重),则 SwapBuffers 调用可能会出现一些延迟,因为某些驱动程序会进行繁忙循环来等待 VBlank。

但首先要考虑的是,您不应该对各个 GL 调用进行计时,因为大多数 GL 调用只是设置 GPU 的某些状态或写入命令缓冲区,因此命令执行是异步发生的。

Are you using sync (or is it enabled?). The delay you're seeing might be related to the fact that CPU and GPU run in parallel, so measuring time of individual GL calls has no meaning.

If you're using VSync (or the GPU is heavily loaded), there might be some latency in the SwapBuffers call, since some drivers make busy loops to wait for VBlank.

But first consider that you should NOT time individual GL calls, since most GL calls just set some state of the GPU or write to a command buffer, the command execution happens asynchronously.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文