We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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