为什么POT纹理比非锅效果慢?

时间:2016-10-24 12:30:55

标签: android textures opengl-es-2.0

我使用以下函数来加载纹理

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];
}

我得到14-17 fps的代码。如果我直接加载我的位图(非POT)而不适应POT.FPS跳转到28-30.Hovever我认为POT纹理应该比非POT工作更快。对此有解释吗?

UPD:渲染代码:

@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);
}

2 个答案:

答案 0 :(得分:0)

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

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

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

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

答案 1 :(得分:0)

如果没有详细的绩效分析,那么除了推测之外,其实不可能做得更多。

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

或者,与上述内容非常相关,如果采样的纹理像素在内存中展开得更远,则纹理采样的缓存命中率会下降,这会在您对纹理进行放大时发生。降低缓存命中率意味着性能降低。

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