What is EGL
EGL is the communication interface between OpenGL ES and Native Window System. Its main functions include:
- Communicate with the native window system of the device;
- Query the available types and configurations of the drawing surface;
- Create a drawing surface;
- Synchronous rendering between OpenGL ES and other graphics rendering API s;
- Manage rendering resources such as texture maps.
The platform independence of OpenGL ES is realized by EGL, which shields the differences between different platforms (Apple provides its own iOS implementation of EGL API, calling itself EAGL).
The API related to the local window provides an interface to access the local window system. EGL can create the rendering surface EGLSurface and provide the graphics rendering context EGLContext for state management. Next, OpenGL ES can draw on this rendering surface.
Relationship between egl, opengles and devices
In the picture:
- Display (EGL display) is an abstraction of the actual display device;
- Surface (EGLSurface) is an abstraction of the memory area FrameBuffer used to store images, including Color Buffer, Stencil Buffer and Depth Buffer;
- Context (EGLContext) stores some state information of OpenGL ES drawing;
When developing OpenGL ES applications on Android platform, class GLSurfaceView has provided us with the management of display, surface and context, that is, GLSurfaceView internally implements the encapsulation of EGL, which can easily use the implementation of interface GLSurfaceView.Renderer to render and draw using OpenGL ES API, It greatly improves the convenience of OpenGLES development.
Of course, we can also encapsulate EGL by ourselves. This paper encapsulates EGL in the Native layer, realizes image background rendering without the help of GLSurfaceView, and uses GPU to complete efficient image processing.
Application of EGL
Effect drawing of EGL background rendering
General steps for rendering with EGL:
- Obtain the EGLDisplay object and establish a connection with the local window system Call eglGetDisplay method to get EGLDisplay.
- Initialize EGL method After the connection is opened, the eglInitialize method is initialized.
- Get the EGLConfig object and determine the configuration information of the rendered surface Call eglChooseConfig method to get EGLConfig.
- Create a rendered surface EGLSurface Through EGLDisplay and EGLConfig, call eglCreateWindowSurface or eglcreatepuffersurface methods to create a rendered surface to obtain EGLSurface, where eglCreateWindowSurface is used to create on-screen rendering areas and eglcreatepuffersurface is used to create off-screen rendering areas.
- Create rendering context EGLContext Through EGLDisplay and EGLConfig, call eglCreateContext method to create rendering context and get EGLContext.
- Binding context Bind EGLSurface, EGLContext and EGLDisplay through eglMakeCurrent method. After the binding is successful, the OpenGLES environment is created, and then you can render.
- Swap buffer After OpenGLES painting, use the eglSwapBuffers method to exchange the front and back buffers to display the painting content on the screen, but this method does not need to be called for off-screen rendering.
- Release EGL environment After drawing, when EGL is no longer needed, you need to unbind eglMakeCurrent and destroy EGLDisplay, EGLSurface and EGLContext.
Code implementation:
// Create the GLES environment int BgRender::CreateGlesEnv() { // EGL config attributes const EGLint confAttr[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_SURFACE_TYPE,EGL_PBUFFER_BIT,//EGL_WINDOW_BIT EGL_PBUFFER_BIT we will create a pixelbuffer surface EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,// if you need the alpha channel EGL_DEPTH_SIZE, 8,// if you need the depth buffer EGL_STENCIL_SIZE,8, EGL_NONE }; // EGL context attributes const EGLint ctxAttr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; // surface attributes // the surface size is set to the input frame size const EGLint surfaceAttr[] = { EGL_WIDTH, 1, EGL_HEIGHT,1, EGL_NONE }; EGLint eglMajVers, eglMinVers; EGLint numConfigs; int resultCode = 0; do { //1. Obtain the EGLDisplay object and establish a connection with the local window system m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(m_eglDisplay == EGL_NO_DISPLAY) { //Unable to open connection to local windowing system LOGCATE("BgRender::CreateGlesEnv Unable to open connection to local windowing system"); resultCode = -1; break; } //2. Initialize EGL method if(!eglInitialize(m_eglDisplay, &eglMajVers, &eglMinVers)) { // Unable to initialize EGL. Handle and recover LOGCATE("BgRender::CreateGlesEnv Unable to initialize EGL"); resultCode = -1; break; } LOGCATE("BgRender::CreateGlesEnv EGL init with version %d.%d", eglMajVers, eglMinVers); //3. Obtain the EGLConfig object and determine the configuration information of the rendered surface if(!eglChooseConfig(m_eglDisplay, confAttr, &m_eglConf, 1, &numConfigs)) { LOGCATE("BgRender::CreateGlesEnv some config is wrong"); resultCode = -1; break; } //4. Create a rendering surface EGLSurface, and use eglCreatePbufferSurface to create an off screen rendering area m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConf, surfaceAttr); if(m_eglSurface == EGL_NO_SURFACE) { switch(eglGetError()) { case EGL_BAD_ALLOC: // Not enough resources available. Handle and recover LOGCATE("BgRender::CreateGlesEnv Not enough resources available"); break; case EGL_BAD_CONFIG: // Verify that provided EGLConfig is valid LOGCATE("BgRender::CreateGlesEnv provided EGLConfig is invalid"); break; case EGL_BAD_PARAMETER: // Verify that the EGL_WIDTH and EGL_HEIGHT are // non-negative values LOGCATE("BgRender::CreateGlesEnv provided EGL_WIDTH and EGL_HEIGHT is invalid"); break; case EGL_BAD_MATCH: // Check window and EGLConfig attributes to determine // compatibility and pbuffer-texture parameters LOGCATE("BgRender::CreateGlesEnv Check window and EGLConfig attributes"); break; } } //5. Create rendering context EGLContext m_eglCtx = eglCreateContext(m_eglDisplay, m_eglConf, EGL_NO_CONTEXT, ctxAttr); if(m_eglCtx == EGL_NO_CONTEXT) { EGLint error = eglGetError(); if(error == EGL_BAD_CONFIG) { // Handle error and recover LOGCATE("BgRender::CreateGlesEnv EGL_BAD_CONFIG"); resultCode = -1; break; } } //6. Binding context if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglCtx)) { LOGCATE("BgRender::CreateGlesEnv MakeCurrent failed"); resultCode = -1; break; } LOGCATE("BgRender::CreateGlesEnv initialize success!"); } while (false); if (resultCode != 0) { LOGCATE("BgRender::CreateGlesEnv fail"); } return resultCode; } //Render void BgRender::Draw() { LOGCATE("BgRender::Draw"); if (m_ProgramObj == GL_NONE) return; glViewport(0, 0, m_RenderImage.width, m_RenderImage.height); // Do FBO off screen rendering glUseProgram(m_ProgramObj); glBindFramebuffer(GL_FRAMEBUFFER, m_FboId); glBindVertexArray(m_VaoIds[0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_ImageTextureId); glUniform1i(m_SamplerLoc, 0); if (m_TexSizeLoc != GL_NONE) { GLfloat size[2]; size[0] = m_RenderImage.width; size[1] = m_RenderImage.height; glUniform2fv(m_TexSizeLoc, 1, &size[0]); } //7. Rendering GO_CHECK_GL_ERROR(); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0); GO_CHECK_GL_ERROR(); glBindVertexArray(GL_NONE); glBindTexture(GL_TEXTURE_2D, GL_NONE); //Once the FBO is unbound, readPixels cannot be called //glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE); } //Release the GLES environment void BgRender::DestroyGlesEnv() { //8. Release EGL environment if (m_eglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(m_eglDisplay, m_eglCtx); eglDestroySurface(m_eglDisplay, m_eglSurface); eglReleaseThread(); eglTerminate(m_eglDisplay); } m_eglDisplay = EGL_NO_DISPLAY; m_eglSurface = EGL_NO_SURFACE; m_eglCtx = EGL_NO_CONTEXT; }
The code of Java layer is mainly an ImageView, which is used to display the images before and after rendering.
// Create rendered objects NativeBgRender mBgRender = new NativeBgRender(); // Initializing and creating the GLES environment mBgRender.native_BgRenderInit(); // Load picture data to texture loadRGBAImage(R.drawable.java, mBgRender); // offscreen rendering mBgRender.native_BgRenderDraw(); // Read the rendered image data from the buffer and load it into ImageView mImageView.setImageBitmap(createBitmapFromGLSurface(0, 0, 421, 586)); // Release the GLES environment mBgRender.native_BgRenderUnInit(); private void loadRGBAImage(int resId, NativeBgRender render) { InputStream is = this.getResources().openRawResource(resId); Bitmap bitmap; try { bitmap = BitmapFactory.decodeStream(is); if (bitmap != null) { int bytes = bitmap.getByteCount(); ByteBuffer buf = ByteBuffer.allocate(bytes); bitmap.copyPixelsToBuffer(buf); byte[] byteArray = buf.array(); render.native_BgRenderSetImageData(byteArray, bitmap.getWidth(), bitmap.getHeight()); } } finally { try { is.close(); } catch(IOException e) { e.printStackTrace(); } } } private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h) { int bitmapBuffer[] = new int[w * h]; int bitmapSource[] = new int[w * h]; IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer); intBuffer.position(0); try { GLES20.glReadPixels(x, y, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, intBuffer); int offset1, offset2; for (int i = 0; i < h; i++) { offset1 = i * w; offset2 = (h - i - 1) * w; for (int j = 0; j < w; j++) { int texturePixel = bitmapBuffer[offset1 + j]; int blue = (texturePixel >> 16) & 0xff; int red = (texturePixel << 16) & 0x00ff0000; int pixel = (texturePixel & 0xff00ff00) | red | blue; bitmapSource[offset2 + j] = pixel; } } } catch (GLException e) { return null; } return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888); }
See the original text for the implementation code path of EGL background rendering.
recommend:
Master the basic processing of YUV image
Android OpenGL ES from getting started to mastering systematic learning tutorial
FFmpeg + OpenGLES realize audio visual playback
Little sister, is this the thin face and big eyes effect you want?
Hi little sister, is this the slimming effect you want?
To tell you the truth, I was moved by this special effect and cried
Advanced OpenGL ES: EGL and GL threads
I think it's good. Order one and watch it~