与context的关系_你还不知道 OpenGL ES 和 EGL 的关系?
什么是 EGL
EGL 是 OpenGL ES 和本地窗口系統(Native Window System)之間的通信接口,它的主要作用:與設備的原生窗口系統通信;
查詢繪圖表面的可用類型和配置;
創建繪圖表面;
在OpenGL ES 和其他圖形渲染API之間同步渲染;
管理紋理貼圖等渲染資源。
OpenGL ES 的平臺無關性正是借助 EGL 實現的,EGL 屏蔽了不同平臺的差異(Apple 提供了自己的 EGL API 的 iOS 實現,自稱 EAGL)。
本地窗口相關的 API 提供了訪問本地窗口系統的接口,而 EGL 可以創建渲染表面 EGLSurface ,同時提供了圖形渲染上下文 EGLContext,用來進行狀態管理,接下來 OpenGL ES 就可以在這個渲染表面上繪制。
egl、opengles 和設備之間的關系
圖片中:
Display(EGLDisplay) 是對實際顯示設備的抽象;
Surface(EGLSurface)是對用來存儲圖像的內存區域 FrameBuffer 的抽象,包括 Color Buffer(顏色緩沖區), Stencil Buffer(模板緩沖區) ,Depth Buffer(深度緩沖區);
Context (EGLContext) 存儲 OpenGL ES 繪圖的一些狀態信息;
在 Android 平臺上開發 OpenGL ES 應用時,類 GLSurfaceView 已經為我們提供了對 Display , Surface , Context 的管理,即 GLSurfaceView 內部實現了對 EGL 的封裝,可以很方便地利用接口 GLSurfaceView.Renderer 的實現,使用 OpenGL ES API 進行渲染繪制,很大程度上提升了 OpenGLES 開發的便利性。
當然我們也可以自己實現對 EGL 的封裝,本文就是在 Native 層對 EGL 進行封裝,不借助于 GLSurfaceView ,實現圖片后臺渲染,利用 GPU 完成對圖像的高效處理。
EGL 的應用
EGL 后臺渲染實現效果圖
使用 EGL 渲染的一般步驟:
- 獲取 EGLDisplay 對象,建立與本地窗口系統的連接調用 eglGetDisplay 方法得到 EGLDisplay。
- 初始化 EGL 方法打開連接之后,調用 eglInitialize 方法初始化。
- 獲取 EGLConfig 對象,確定渲染表面的配置信息調用 eglChooseConfig 方法得到 EGLConfig。
- 創建渲染表面 EGLSurface通過 EGLDisplay 和 EGLConfig ,調用 eglCreateWindowSurface 或 eglCreatePbufferSurface 方法創建渲染表面,得到 EGLSurface,其中 eglCreateWindowSurface 用于創建屏幕上渲染區域,eglCreatePbufferSurface 用于創建屏幕外渲染區域。
- 創建渲染上下文 EGLContext?通過 EGLDisplay 和 EGLConfig ,調用 eglCreateContext 方法創建渲染上下文,得到 EGLContext。
- 綁定上下文通過 eglMakeCurrent 方法將 EGLSurface、EGLContext、EGLDisplay 三者綁定,綁定成功之后 OpenGLES 環境就創建好了,接下來便可以進行渲染。
- 交換緩沖OpenGLES 繪制結束后,使用 eglSwapBuffers 方法交換前后緩沖,將繪制內容顯示到屏幕上,而屏幕外的渲染不需要調用此方法。
- 釋放 EGL 環境繪制結束后,不再需要使用 EGL 時,需要取消 eglMakeCurrent 的綁定,銷毀 ?EGLDisplay、EGLSurface、EGLContext 三個對象。
代碼實現:
//?創建?GLES?環境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.?獲取?EGLDisplay?對象,建立與本地窗口系統的連接
????????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.?初始化?EGL?方法
????????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.?獲取?EGLConfig?對象,確定渲染表面的配置信息
????????if(!eglChooseConfig(m_eglDisplay,?confAttr,?&m_eglConf,?1,?&numConfigs))
????????{
????????????LOGCATE("BgRender::CreateGlesEnv?some?config?is?wrong");
????????????resultCode?=?-1;
????????????break;
????????}
????????//4.?創建渲染表面?EGLSurface,?使用?eglCreatePbufferSurface?創建屏幕外渲染區域
????????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.?創建渲染上下文?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.?綁定上下文
????????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;
}
//渲染
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.?渲染
????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);
????//一旦解綁?FBO?后面就不能調用?readPixels
????//glBindFramebuffer(GL_FRAMEBUFFER,?GL_NONE);
}
//釋放?GLES?環境
void?BgRender::DestroyGlesEnv()
{
????//8.?釋放?EGL?環境
????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;
}
Java 層的代碼,主要是一個 ImageView 用于展示渲染前后的圖像。
//?創建渲染對象NativeBgRender?mBgRender?=?new?NativeBgRender();
//?初始化創建?GLES?環境
mBgRender.native_BgRenderInit();
//?加載圖片數據到紋理
loadRGBAImage(R.drawable.java,?mBgRender);
//?離屏渲染
mBgRender.native_BgRenderDraw();
//?從緩沖區讀出渲染后的圖像數據,加載到?ImageView
mImageView.setImageBitmap(createBitmapFromGLSurface(0,?0,?421,?586));
//?釋放?GLES?環境
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?????????????offset1?=?i?*?w;????????????offset2?=?(h?-?i?-?1)?*?w;????????????for?(int?j?=?0;?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);}
技術交流,歡迎加我微信:ezglumes ,拉你入技術交流群。
推薦閱讀:
音視頻面試基礎題
OpenGL ES 學習資源分享
一文讀懂 YUV 的采樣與格式
OpenGL 之 GPUImage 源碼分析
推薦幾個堪稱教科書級別的 Android 音視頻入門項目
覺得不錯,點個在看唄~
總結
以上是生活随笔為你收集整理的与context的关系_你还不知道 OpenGL ES 和 EGL 的关系?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux设置swap分区为128g,s
- 下一篇: lrange是取出所有值并移除么_部落冲