Nick
Nick

Reputation: 2682

glDrawArrays() slow on iPad?

I was wondering how to speed up my iPad application using OpenGLES 2.0. At the moment we have every drawable object draw itself with a call to glDrawArrays(). Blend mode is on, we really need it. Without disabling blendmode, how would we improve performance for this app?

For instances, if we now draw 3 textures (1024x1024, 256x512, 256x512) across the whole screen, the app only gets 15FPS, which is really slow I think? Are we doing something terribly wrong? Our drawing code (for each drawable), is as follows:

- (void) draw {
    GLuint textureAvailable = 0;
    if(texture != nil){
        textureAvailable = 1;
    }

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture.name);

    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);

    glVertexAttribPointer(ATTRIB_COLOR, 4, GL_FLOAT, 1, 0, colorsWithMultipliedAlpha);
    glEnableVertexAttribArray(ATTRIB_COLOR);

    glVertexAttribPointer(ATTRIB_TEXTUREMAP, 2, GL_FLOAT, 1, 0, textureMapping);
    glEnableVertexAttribArray(ATTRIB_TEXTUREMAP);

    //Note that we are NOT using position.z here because that is only used to determine drawing order
    int *jnUniforms = JNOpenGLConstants::getInstance().uniforms;
    glUniform4f(jnUniforms[UNIFORM_TRANSLATE], position.x, position.y, 0.0, 0.0);
    glUniform4f(jnUniforms[UNIFORM_SCALE], scale.x, scale.y, 1.0, 1.0);
    glUniform1f(jnUniforms[UNIFORM_ROTATION], rotation);
    glUniform1i(jnUniforms[UNIFORM_TEXTURE_SAMPLE], 0);
    glUniform2f(jnUniforms[UNIFORM_TEXTURE_REPEAT], textureRepeat.x, textureRepeat.y);
    glUniform1i(jnUniforms[UNIFORM_TEXTURE_AVAILABLE], textureAvailable);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

Possible optimizations I think won't work:

But please tell me if I'm wrong, I'm happy to hear any ideas.

Proposed solutions

Mipmapped textures

Loading mipmapped textures, doing it like this:

- (id) initWithUIImage: (UIImage * const) image {
    glGenTextures(1, &name);
    //JNLogString(@"Recieved name(%d), binding texture", name);
    glBindTexture(GL_TEXTURE_2D, name);

    //Set the needed parameters for the texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //Load the image data into the texture

    glGenerateMipmap(GL_TEXTURE_2D);

    return self;
}

This doesn't seem to do anything for our FPS, I think this is because our textures are already roughly at the size they are rendered to on the screen, in most cases even 1:1.

Other solutions are welcome! I will try them out and post the results here

Upvotes: 1

Views: 1753

Answers (2)

Nick
Nick

Reputation: 2682

I had a branch in my fragment shader. I though that didn't put a lot of strain on it, but it did! Anyhow, that was the whole problem, I removed the branch and now my FPS has almost doubled.

Upvotes: 2

epatel
epatel

Reputation: 46051

If you are using very large textures, try to create mipmap textures. The cost is basically 1/3 of the original texture memory. I think they can be created with this call when setting up the textures.

glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

Some calculations: If you have 3 textures 2048x2048 (max size) at 15 Hz you will have a texel throughput (if they are fully shown, ie downscaled to screen resolution) of 2048x2048x3x15 = 188,743,680 / sec which is around the value we see at glbenchmark.com for single fill rate (173 Mtexel/sec). But if you are using mipmap textures the texel throughput should be closer to the screen size resolution (1024x768) which should be something like 1/4 of the previous throughput.

Upvotes: 2

Related Questions