OpenGL ES Android screenshot question

Hi all,
I am struggling for some time with the topic. Bottom line is that for one proprietary Android application we need to capture screenshots of the entire screen (not our activity) and push those images to VNC server. Now, I read various topics about (ab)using OpenGL ES for this cause but never found complete code with initialization (in C++). What I tried basically are some variants of the following code:


const EGLint attribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //important
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_NONE
};

EGLint attribList[] =
{
        EGL_CONTEXT_CLIENT_VERSION, 3,
        EGL_NONE
};

EGLint w, h, dummy, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;

EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

EGLBoolean res = eglInitialize(display, 0, 0);
log << "eglInitialize: " << (res ? "yes": "no") << " " << eglGetError() << "
";

EGLint pi32ConfigAttribs[] =
{
    EGL_SURFACE_TYPE,
    EGL_PBUFFER_BIT,
    EGL_RENDERABLE_TYPE,
    EGL_OPENGL_BIT,
    EGL_CONFORMANT,
    EGL_OPENGL_BIT,
    EGL_COLOR_BUFFER_TYPE,
    EGL_RGB_BUFFER,
    EGL_LUMINANCE_SIZE,
    0,
    EGL_RED_SIZE,
    8,
    EGL_GREEN_SIZE,
    8,
    EGL_BLUE_SIZE,
    8,
    EGL_ALPHA_SIZE,
    8,
    EGL_DEPTH_SIZE,
    8,
    EGL_LEVEL,
    0,
    EGL_BUFFER_SIZE,
    24,
    EGL_NONE
};

res = eglChooseConfig(display, pi32ConfigAttribs, &config, 1, &numConfigs);
log << "eglChooseConfig: " << (res ? "yes" : "no") << " " << eglGetError() << "
";

//        res = eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
//        log << "eglGetConfigAttrib: " << (res ? "yes" : "no") << " " << eglGetError() << "
";


//        ANativeWindow* window;

//        ANativeWindow_setBuffersGeometry(window, 0, 0, format);
//        log << "window: " << (window != 0 ? "yes": "no") << "
";



EGLint pbufferAttribs[5];
pbufferAttribs[0] = EGL_WIDTH;
pbufferAttribs[1] = 200;
pbufferAttribs[2] = EGL_HEIGHT;
pbufferAttribs[3] = 200;
pbufferAttribs[4] = EGL_NONE;

surface = eglCreatePbufferSurface(display, config, pbufferAttribs);

log << "surface: " << (surface ? "yes" : "no") << " " << eglGetError() << "
";

context = eglCreateContext(display, config, NULL, attribList);
log << "context: " << (context ? "yes" : "no") << " " << eglGetError() << "
";

res = eglMakeCurrent(display, surface, surface, context);
log << "eglMakeCurrent: " << (res ? "yes": "no") << " " << eglGetError() << "
";

GLubyte *texture = new GLubyte[screenSize.width() * screenSize.height() * bpp]; // 3 for RGB, 4 for RGBA

glReadBuffer(GL_FRONT);
glReadPixels(0, 0, screenSize.width(), screenSize.height(), GL_RGB, GL_UNSIGNED_BYTE, texture);

On Linux I had no such troubles at all, and simply used:

Display *dpy = XOpenDisplay(nullptr);
Display *dpy = XOpenDisplay(nullptr);
Window root = DefaultRootWindow(dpy);
GLint att[] = {GLX_RGBA, 0};
XVisualInfo *vis = glXChooseVisual(dpy, 0, att);
GLXContext glc = glXCreateContext(dpy, vis, nullptr, true);

GLubyte *texture = new GLubyte[screenSize.width() * screenSize.height() * bpp]; // 3 for RGB, 4 for RGBA


glXMakeCurrent(dpy, root, glc);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, screenSize.width(), screenSize.height(), GL_RGB, GL_UNSIGNED_BYTE, texture);

So in short - is this possible to do? I also considered using the framebuffer, but as I understood it is not always available and possibly you need to have rooted phone.

Thank you all in advance

With an Android app, you’re writing to an offscreen framebuffer (whether it looks like you are or not). As far as I know, you don’t really have direct access to the entire composited display or the display hardware. SurfaceFlinger and the Hardware Compositor (HWC) do though.

Look at creating a Virtual Display for what you want (see the above link).

A few more related pages:

Take screenshot programmatically of the whole screen (Android)
How to CORRECTLY take a screenshot using Android MediaProjection API

Thank you, I will try this. Do you maybe know how fast(slow) is this SurfaceFlinger is? I must have at least 15 FPS

You should easily be able to get that with a well-behaved OpenGL ES application on most mobile platforms.