Why does mipmapping give me barely any performance increases?

668 views Asked by At

I am rendering grass with 8 vertices per piece of grass (per object). This brought my game down from 50+ FPS to exactly 31FPS.

Trying to find a solution to this, I stumbled across a Mipmapping tutorial, a way to make the texture less detailed. "Great", I thought! Since the grass is just two flat surfaces with a texture on, it looked like it would solve the issue!

The grass model looks like this (Obviously I then just apply a texture to it and make certain parts transparent using shaders):

enter image description here

However, when I enabled mipmapping, I got 32 FPS - Only 1 more FPS than without mipmapping! I also get some sort of blue tinge on the grass? enter image description here

Without mipmapping, the grass looks like this: enter image description here

Why is my Mipmapping not giving me any sort of performance enhancements? Considering my grass is mostly just texture, then why would degrading the texture not increase performance?

And also, why is there a blue tinge being created on the grass? Is it something to do with how mipmapping is lowering the texture resolution?

I currently use this code to generate:

texture = TextureLoader.getTexture("PNG",
                new FileInputStream("res/" + fileName + ".png"));
        GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0);

And I use this code to actually render the grass:

public void render(){
    Main.TerrainDemo.shader.start();
    glPushMatrix();
    glTranslatef(location.x, location.y, location.z);
    TexturedModel texturedModel = TerrainDemo.texModel;
    RawModel model = texturedModel.getRawModel();
    GL30.glBindVertexArray(model.getVaoID());
    GL20.glEnableVertexAttribArray(0);
    GL20.glEnableVertexAttribArray(1);
    GL13.glActiveTexture(GL13.GL_TEXTURE0);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getTexture().getID());
    glScalef(10f, 10f, 10f);
    glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
    GL20.glDisableVertexAttribArray(0);
    GL20.glDisableVertexAttribArray(1);
    GL30.glBindVertexArray(0);
    glPopMatrix();
    Main.TerrainDemo.shader.stop();
}
2

There are 2 answers

6
Tim B On BEST ANSWER

The mip-mapping modifies the texture, but the grass doesn't really do much work in the texture anyway as it is a small object.

Most of the work to render the grass comes in processing all of the vertices, and most especially if the grass are lots of small objects then in processing these objects.

You should combine the grass together into one mesh and then let that be rendered. Graphics cards are great at handling objects with huge numbers of vertices, not so great at huge numbers of objects.

If you were using jMonkeyEngine I could recommend some classes that provides to do the batching for you (most obviously BatchNode although there are some other options too). It might still be worth looking at how jMonkeyEngine does it for ideas.

0
Reto Koradi On

@TimB already covered the possibility that your bottleneck is somewhere else in the rendering pipeline, e.g. in vertex processing or draw call overhead. Which is quite likely. There's one crude but quite useful method for narrowing down where the bottleneck is. You can make the window smaller/larger, and see if you framerate increases/decreases.

  • If the framerate increases when you make the window smaller, this suggests that your main bottleneck is in fragment processing, which includes texturing.
  • If the framerate remains constant independent of the window size, your main bottleneck is not in fragment processing. Could be vertex processing, or you're not GPU limited at all.

You can also look at CPU usage. If the CPU is pegged close to 100%, chances are that you're not GPU limited, and you need to reduce CPU overhead. Many platforms/vendors offer CPU and GPU performance analysis tools, which can give you much more conclusive data.

Let's for a moment assume that you actually are limited by texture sampling. Mipmapping is not an automatic win there. The number of fragments you process depends on the number and sizes of the triangles you draw, and the window size. So with mipmapping you still process the same number of fragments in your fragment shader, and call the same number of texture sampling operations.

When you use mipmapping, a few things happen:

  1. Each sampling operation needs to read 8 texels for LINEAR_MIPMAP_LINEAR mode, compared to 4 for LINEAR in the non-mipmap case.
  2. The interpolation gets more complex (trilinear vs. bilinear).
  3. Since you're accessing smaller texture levels, memory access becomes more local, improving cache hit rates.

The performance gain you're targeting comes from item 3 in this list. Cache hit rates are important. But if you already got high cache hit rates without mipmapping (e.g. if your textures are small, and the access patterns favorable), you might not actually gain much here.

The other two items can potentially counteract these gains. It's possible that GPUs could to trilinear interpolation in the same time as bilinear interpolation, so that might be a non-issue. Item 1 could hurt. Since the texel access is more local, you will hopefully get an overall gain. But that's not guaranteed.