为什么 POT 纹理比非 POT 纹理工作得慢?

Why POT textures work slower than non-pot?

我使用以下函数加载纹理

public static int loadTexture(Bitmap bmp)
{
    final int[] textureHandle = new int[1];

    GLES20.glGenTextures(1, textureHandle, 0);
    if (textureHandle[0] != 0)
    {

        // Bind to the texture in OpenGL
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

        // Set filtering
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        //GLES20.glGenerateMipmap(textureHandle[0]);
        //adapt texture to POT
        int adaptedWidth= (int) Math.pow(2,Math.ceil(Math.log(bmp.getWidth())/Math.log(2d)));
        int adaptedHeight= (int) Math.pow(2,Math.ceil(Math.log(bmp.getHeight())/Math.log(2d)));
        Log.d("texture",adaptedWidth+","+adaptedHeight);

        Bitmap tmp = Bitmap.createScaledBitmap(bmp, adaptedWidth, adaptedHeight, false);
        Log.d("asize",tmp.getWidth()+","+tmp.getHeight());
        // Load the bitmap into the bound texture.
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, tmp, 0);
        //GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
        tmp.recycle();
        // Recycle the bitmap, since its data has been loaded into OpenGL.
        //bmp.recycle();
    }

    if (textureHandle[0] == 0)
    {
        throw new RuntimeException("Error loading texture.");
    }
    return textureHandle[0];
}

如果我直接加载我的位图(非 POT)而不适应 POT.FPS 跳转到 28-30.I thought POT 纹理,我得到 14-17 fps code.Hovever应该比非POT.Is工作得更快?有解释吗?

更新:渲染代码:

@Override
public void onDrawFrame(GL10 gl) {
    //curScale=modelMatrix[SCALE_X];
    TimeMeasurer.reset();
    long curTS= SystemClock.uptimeMillis();
    long frameRenderTime=curTS-ts;
    //Log.d("renderer","FPS:"+1000.0/frameRenderTime);
    Log.d("renderer","frame render time:"+frameRenderTime);
    ts=curTS;
    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
    if (piecesMesh!=null) {
        Matrix.setIdentityM(MVPMatrix,0);
        Matrix.multiplyMM(MVPMatrix,0,projMatrix,0,modelMatrix,0);
        drawPassivePieces();
        drawActivePieces();
        if (helper!=null) {
            drawHelper();
        }
    }
    TimeMeasurer.measure("onDrawFrame execution time:");
}
private void drawPassivePieces() {
    //shadows
    shadowProgram.useProgram();
    shadowProgram.setUniforms(MVPMatrix,textureMaskId);
    shadowMesh.bindPieceData(shadowProgram,false);
    shadowMesh.drawPieces(false);
    shadowMesh.disableAttributes(shadowProgram);
    //pieces
    piecesProgram.useProgram();
    piecesProgram.setUniforms(MVPMatrix, textureImageId, textureMaskId);
    piecesMesh.bindPieceData(piecesProgram,false);
    piecesMesh.drawPieces(false);
    piecesMesh.disableAttributes(piecesProgram);

}
private void drawActivePieces() {
    //shadows
    shadowProgram.useProgram();
    shadowProgram.setUniforms(MVPMatrix,textureMaskId);
    shadowMesh.bindPieceData(shadowProgram,true);
    shadowMesh.drawPieces(true);
    shadowMesh.disableAttributes(shadowProgram);
    //pieces
    piecesProgram.useProgram();
    piecesProgram.setUniforms(MVPMatrix, textureImageId, textureMaskId);
    piecesMesh.bindPieceData(piecesProgram,true);
    piecesMesh.drawPieces(true);
    piecesMesh.disableAttributes(piecesProgram);
}
public void drawHelper() {
    helperProgram.useProgram();
    helper.bindData(helperProgram);
    helper.draw();
    helper.disableAttributes(helperProgram);
}

使用 POT 纹理有很大的优势。在 OpenGLES 2.0 中,它们允许您使用 mipmap 和有用的纹理寻址模式,如重复。您还可以更有效地利用内存,因为许多实现分配内存就像您的纹理无论如何都是 POT 一样。

但是,在这种情况下,您只是采用非 POT 纹理并将其放大,因此我预计性能会稍微差一些。你错过了巨大的潜在胜利,因为你没有使用 mipmaps。通过使用更大的纹理,您只是要求更多的 GPU 纹理缓存,因为图像的有用部分现在比以前更分散在内存中。

另一种看待它的方式是,在没有 mipmapping 的情况下,大纹理的性能会比小纹理差,而你的重新缩放过程只会让你的纹理变大。

我很惊讶差异如此明显 - 您确定您的重新缩放代码路径没有做任何意外的事情,例如调整太大,或者选择不同的纹理格式或过滤器模式?

如果没有详细的性能分析,除了推测之外真的不可能做更多的事情。

一个可能的原因是您的渲染受到纹理采样内存带宽的限制。如果纹理变大,访问的内存总量就会变大,从而导致速度变慢。

或者,与上述情况非常相关,如果采样的纹素在内存中分布得更远,纹理采样的缓存命中率会下降,这在您放大纹理时会发生。较低的缓存命中率意味着较慢的性能。

你真的不应该人为地使纹理比必要的更大,除非由于 ES 2.0 中有限的 NPOT 支持而需要它,并且你使用的硬件不会宣传 OES_texture_npot 扩展。我怀疑长期以来是否有人制作过更喜欢 POT 纹理的硬件。