EGL的创建是这样的。
/*** Creates an EGL rendering context and all associated elements*/
void CreateEGL(EGLNativeWindowType window, EGLDisplay* outDisplay, EGLContext* outContext, EGLSurface* outSurface, EGLConfig* outConfig)
{*outDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);if (*outDisplay == EGL_NO_DISPLAY){ALog_A(0, "CreateEGL failed EGL unable to eglGetDisplay");}if (!eglInitialize(*outDisplay, NULL/*major*/, NULL/*minor*/)){ALog_A(0, "CreateEGL failed EGL unable to eglInitialize");}EGLint numConfigs;// Here specify the attributes of the desired configuration.// Below, we select an EGLConfig with at least 8 bits per color// component compatible with on-screen windowsconst EGLint configAttribs[] ={EGL_DEPTH_SIZE, 16,EGL_RED_SIZE, 8, // 5,EGL_GREEN_SIZE, 8, // 6,EGL_BLUE_SIZE, 8, // 5,EGL_ALPHA_SIZE, 8, // 0,EGL_STENCIL_SIZE, 8,EGL_SURFACE_TYPE, EGL_WINDOW_BIT,EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,EGL_NONE};/* Here, the application chooses the configuration it desires. In this* sample, we have a very simplified selection process, where we pick* the first EGLConfig that matches our criteria*/eglChooseConfig(*outDisplay, configAttribs, outConfig, 1, &numConfigs);if (numConfigs < 1){ALog_A(0, "CreateEGL failed no config match eglChooseConfig");}const EGLint surfaceAttrs[] ={EGL_RENDER_BUFFER,EGL_BACK_BUFFER,EGL_NONE};*outSurface = eglCreateWindowSurface(*outDisplay, *outConfig, window, surfaceAttrs);if (*outSurface == EGL_NO_SURFACE){ALog_A(0, "CreateEGL failed EGL unable to eglCreateWindowSurface");}const EGLint contextAttribs[] ={EGL_CONTEXT_CLIENT_VERSION, 2,EGL_NONE};*outContext = eglCreateContext(*outDisplay, *outConfig, EGL_NO_CONTEXT, contextAttribs);if (*outContext == EGL_NO_CONTEXT){ALog_A(0, "CreateEGL failed EGL unable to eglCreateContext");}if (!eglMakeCurrent(*outDisplay, *outSurface, *outSurface, *outContext)){ALog_A(0, "CreateEGL failed EGL unable to eglMakeCurrent");}// eglSwapInterval(*display, 1);
}
我们可以看到,我们需要一个EGLNativeWindowType window,然后我们会创建display,context,config,surface。其中,display是和显示器相关的。context和config相关,surface是和window相关的。最为关键的是最后一句eglMakeCurrent就整合了这一切。以后的OpenGL指令才能正确生效。
当android应用被切换到后台的时候,会执行一系列的回调函数,onWindowDestroyed,onPause,onStop,恢复的时候又会执行onResume,onWindowCreated,onResized等等。期间在后台的时候,EGLNativeWindowType window会被销毁掉,也就会导致eglMakeCurrent失效,OpenGL不可用状态。恢复的时候我们需要重建EGL这个初始化的过程。
通过阅读源码,我们会看到NDK提供的native-activity中,会在onWindowDestroyed销毁整个EGL也就是包括了display,context,config,surface。然后在onWindowCreated时候再次创建EGL相关的所有元素。还可以阅读GLSurfaceView.java为我们封装EGL生命周期的view层。会发现同样的处理流程,就是系统的window发生变化的时候,选择了销毁EGL相关的一切。然后甚至在resized时候,对,window又发生变化了都会销毁EGL。然后在重建。
从EGL相关的几个元素display,context,config,surface,我们会发现似乎之后surface是和系统的window密切相关的。也就是eglCreateWindowSurface和ANativeWindow_setBuffersGeometry函数使用了window变量。其它的display,context,config都是不相关的。尤其是context,存放了OpenGL当前的状态。如果销毁,那么我们就丢失了OpenGL所有的状态,在恢复的时候我们需要重新恢复这些状态。否则就会造成绘制错误各种问题。
所以,我们确定去实现2点。第一,在resized之后也就是当window稳定之后再去初始化EGL,防止window的变化导致需要修正EGL。我们看到resized回调总是在windowCreated之后调用的。第二,就是当window变化的时候,我们选择只销毁surface,其他的都保持不变,在恢复的时候重建surface,然后EGL使用新的surface即可。经过测试,这个思路是可以的。并且程序切换前后台速度要快了很多。因为context没有被销毁,OpenGL的绘制状态全部都被保存了。我们需要增加一个ResetSurface函数,在恢复的时候调用。用来删除旧的surface并设置新的surface。如下:
static void ResetSurface(EGLNativeWindowType window, EGLDisplay display, EGLContext context, EGLConfig config, EGLSurface* surface)
{if (*surface != EGL_NO_SURFACE){eglDestroySurface(display, *surface);}const EGLint surfaceAttrs[] ={EGL_RENDER_BUFFER,EGL_BACK_BUFFER,EGL_NONE};*surface = eglCreateWindowSurface(display, config, window, surfaceAttrs);if (!eglMakeCurrent(display, *surface, *surface, context)){ALog_A(0, "ResetSurface failed EGL unable to eglMakeCurrent");}
}
本文发布于:2024-01-30 18:32:39,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170661076221994.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |