I am trying to save screenshot of a qml quick controls application on a platform (running QT on wayland) by using native opengl functions .What I am doing is that using a RGB color render buffer with eglCreateImageKHR function and then send the EGLImageKHR void pointer to another device through Qt socket communication. I can successfully create EGLImage that means that there is no error from eglGetError function . For testing the EGLImageKHR object correctness, I bind it to another framebuffer by using glEglImageTargetRenderbufferStorageOES on the same process and read the pixel from glReadPixel function , create a png file from read buffer and observed that correct png is created with correct colors.
After that I tried to send this EGLImageKHR void pointer to another device or process and then create some png from the sended EGLImageKHR object and I do not see correct colored png ,only have a noise on the png.
Following is the code sample to create the EGLImageKHR from render buffer and then saving a tga_file from EGLImageKHR.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// create render buffer and bind it to a framebuffer glGenRenderbuffers( 1, &renderBuffer ); glBindRenderbuffer( GL_RENDERBUFFER, renderBuffer ); glRenderbufferStorage( GL_RENDERBUFFER, GL_RGB, mWinWidth, mWinHeight ); glBindRenderbuffer(GL_RENDERBUFFER, 0); //mwindow->openglContext()->defaultFramebufferObject()); if (glGetError()==GL_NO_ERROR) { //qDebug() << "Render buff storage is OK" << glGetError(); } else { qDebug() << "Render buff storage error is " << glGetError(); } glGenFramebuffers( 1, &frameBuffer ); glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer); glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer); //printFramebufferInfo(frameBuffer); if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { qDebug() << "Framebuffer error is " << glGetError(); } else { //qDebug() << "Framebuffer is OK" << glGetError(); } // create EGLImageKHR object mWinWidth = mwindow->width(); mWinHeight = mwindow->height(); glGetIntegerv(GL_PACK_ALIGNMENT, &rowPack); glPixelStorei(GL_PACK_ALIGNMENT, 1); glBindFramebuffer(GL_READ_FRAMEBUFFER,mwindow->openglContext()->defaultFramebufferObject()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER,frameBuffer); glBlitFramebuffer(0, 0, mWinWidth, mWinHeight, 0, 0, mWinWidth, mWinHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); m_display = reinterpret_cast<egldisplay>(reinterpret_cast<void*>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("egldisplay"))); m_context = QGuiApplication::platformNativeInterface()->nativeResourceForContext("eglcontext", mwindow->openglContext()); mImage = CreateImageKHR(m_display,m_context, EGL_GL_RENDERBUFFER_KHR,reinterpret_cast<eglclientbuffer>(renderBuffer), nullptr); if (mImage == EGL_NO_IMAGE_KHR) { qDebug("failed to make image from target buffer: %s", get_egl_error()); return -1; } int size = mWinWidth * mWinHeight * 3; sendEglImage(size); glDeleteRenderbuffers(1,&renderBuffer); renderBuffer = 0; glDeleteFramebuffers(1,&frameBuffer); frameBuffer = 0; // send EGLImageKHR to client sendEglImage(int size) { if (SenderSocket != NULL) { QByteArray data; data.append(reinterpret_cast<const char*="">(mImage),size); //data.append(reinterpret_cast<qbytearray *="">(mImage)); QDataStream out(&data, QIODevice::WriteOnly); out.setDevice(SenderSocket); out << data; //qDebug() << "func " << __FUNCTION__ << "line" << __LINE__; qDebug() << "func " << __FUNCTION__ << "line" << __LINE__ << "data size" << data.size(); } QImage testImg((uchar *)mImage,640,480,QImage::Format_RGB888, nullptr, nullptr); if(testImg.save("server.png")) qDebug() << "Successfully saved image" << testImg; DestroyImageKHR(m_display,mImage); mImage = 0; } // Another approach to create a tga_file from EGLImageKHR is FILE *out = fopen("tga_file", "w"); short TGAhead[] = {0, 2, 0, 0, 0, 0, 640, 480, 24}; fwrite(&TGAhead, sizeof(TGAhead), 1, out); fwrite(mImage, mWinWidth * mWinHeight*3, 1, out); fflush(out); fclose(out); // One more different trial int bufSize = mWinHeight * mWinWidth*3; unsigned char * trialBuff = new unsigned char[bufSize]; memcpy(trialBuff,khrImage,bufSize); FILE *out = fopen("dada.txt", "w"); fwrite(trialBuff, bufSize, 1, out); fflush(out); fsync(fileno(out)); fclose(out); delete [] trialBuff;
So When I try to create a png with QImage or with fwrite from EGLImageKHR object, I do not get a valid png or tga_file.
Note that I do not want to use glReadPixels function since it is causing high cpu load. Is there any idea how I can create some png file from EGLImageKHR and How I can send it to another device ?
Best Regards
Hi Eko,
I'm not sure what you mean by sharing to a different "device", but even at process level this is tricky without the use of glReadPixels
Here's someone trying to do something similar: https://stackoverflow.com/questions/24304953/share-an-eglimage-between-different-applications-processes-on-embedded-linux
Is CreateImageKHR just a wrapper around eglCreateImageKHR?
At any rate the EGLImage is not just a pointer to pixel data, so can't just be copied. Here's an Android implementation trying to attach a texture to the EGLImage, so that it can then have pixel data copied out: https://stackoverflow.com/questions/21151259/replacing-glreadpixels-with-egl-khr-image-base-for-faster-pixel-copy
I hope this helps get you a bit further forward,
Ben
Hello Ben,
It is correct without glReadPixels it may not be possible to transfer pixels between different devices.Now I implemented an asynchronous readback implementation with glReadPixels and currently testing it to see the cpu usages.
Regards