Search code examples
javaandroidperformancelibgdxscreenshot

Java Libgdx get screenshot very slow


I write a game for android using libgdx. If the user opens the pause menu I take a screenshot of the current game, blur it and use it as background for the options menu. This works fine but the code for getting the screenshot is very slow. It takes about 0.8 seconds on average using the code below...

Is there another way to take a screenshot in libgdx which is much faster? If not, when the user opens the options menu I could try to just keep rendering the game, pause the game logic and blur the screen and draw the options on top.. If this is the only fast way, how could one blur the screen? I found this link but I didn't get it to work. If it is possible I prefer the solution with the screenshot because it is much easier...

Code to get the screenshot (from official wiki):

public static Pixmap getScreenshot(){
    long start = TimeUtils.millis();

    byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
    Pixmap pixmap = new Pixmap(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), Pixmap.Format.RGBA8888);
    BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);

    long time = TimeUtils.millis()-start;
    Gdx.app.log("INFO", "Time for screenshot in sec.: " + time);  // about 0.8 seconds

    return pixmap;
}

I use the resulting Pixmap to draw my texture.

EDIT:

My code now with the answer of Deniz Yılmaz for getting the screenshot fast:

public Texture getScreenshot(){

    Texture texture = new Texture(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGB888);

    Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
    Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
    texture.bind();
    Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGB, 0, 0,Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0);
    Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);

    return texture;
}

Solution

  • Actually taking screenshot is not slow. Slow part is data transfer between GPU and CPU so any other way to get pixels wont be faster so much.

    But also there are openGl codes helping us right here. You can use opengl codes via Gdx.gl class.

    void glCopyTexImage2D(  
        GLenum      target,         //Target Opengl Texture
        GLint       level,          //Mipmap level
        GLenum      internalformat, //Color format
        GLint       x,
        GLint       y,
        GLsizei     width,
        GLsizei     height,
        GLint       border);
    

    This function copy pixels into a 2D texture image but not bringing them to CPU. You just belong a FBO at GPU. In libgdx first you must bind texture to openGl's texture with a method. This texture can be empty screen sized texture or you can use old texture you wont use again.

    Texture.bind();
    

    or

    Gdx.gl.glBindTexture(Opengltexture, texture.getTextureObjectHandle());
    

    For bounding and taking screen

    1. Enable GPUtexture type.
    2. Activate for exact GPUtexture
    3. Call texture bind method
    4. Call opengl function for active GPUtexture
    5. Disable GPUtexture type.

    Here is what code look like :

    Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
    Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
    texture.bind();
    Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA,0, 0,width , height, 0);
    Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
    

    Be aware binding is only active in 1 and 5. My fault was here because i tried to bind texture in create method and had got black screen.

    BE AWARE!!!

    • On android, it needs opengl es 2.0 . You can edit manifest to make sure unsupported devices cant download your game.

      < uses-feature android:glEsVersion="0x00020000" android:required="true" >

    • RGBA format color space doesnt supported. So make sure you are using Format.RGB for both opengl function and texture creation.

    • Result texture will be flipped vertically because of openGl matrix system. So you have to fix it manually.

    I also suggest you to look at fragments and shaders. It seems like hard but actually enjoyable.