前言
這篇文章簡單介紹一下在Android平臺下的EGL
環(huán)境的相關(guān)內(nèi)容,由于OpenGL ES
并不負責窗口管理以及上下文管理,該職責由各個平臺自行完成往扔;在Android平臺下OpenGL ES
的上下文環(huán)境是依賴EGL
的API進行搭建的远豺。
對于EGL
這個框架,谷歌已經(jīng)提供了GLSurfaceView
飞几,是一個已經(jīng)封裝EGL
相關(guān)處理的工具類,但是不夠靈活独撇;對于更加核心的OpengGL ES
的用法(例如多線程共享紋理)則需要開發(fā)者自行搭建EGL
開發(fā)環(huán)境屑墨。
前置知識
Java層實現(xiàn)
在Java層,EGL
封裝了兩套框架纷铣,分別是:
- 位于
javax.microedition.khronos.egl
包下的EGL10
卵史。 - 位于
android.opengl
包下的EGL14
。
其主要區(qū)別是:
-
EGL14
是在Android 4.2(API 17)引入的搜立,換言之API 17以下的版本不支持EGL14
以躯。 -
EGL10
不支持OpenGL ES 2.x
,因此在EGL10
中某些相關(guān)常量參數(shù)只能用手寫硬編碼代替儒拂,例如EGL14.EGL_CONTEXT_CLIENT_VERSION
以及EGL14.EGL_OPENGL_ES2_BIT
等等寸潦。
PS:由于主體流程基本一致,所以本篇以EGL10
的代碼進行示例社痛。
Native層實現(xiàn)
程序在Native層使用EGL
環(huán)境時见转。
需要引入EGL
的so庫:
Android.mk:
LOCAL_LDLIBS += -lEGL
CMake:
find_library( EGL-lib
EGL )
需要包含頭文件:
#include <EGL/egl.h>
#include <EGL/eglext.h>
EGL環(huán)境配置整體流程
- 獲取默認的
EGLDisplay
。 - 對
EGLDisplay
進行初始化蒜哀。 - 輸入預設置的參數(shù)獲取
EGL
支持的EGLConfig
斩箫。 - 通過
EGLDisplay
和EGLConfig
創(chuàng)建一個EGLContext
上下文環(huán)境。 - 創(chuàng)建一個
EGLSurface
來連接EGL
和設備的屏幕撵儿。 - 在渲染線程綁定
EGLSurface
和EGLContext
乘客。 - 【進行
OpenGL ES
的API渲染步驟】(與EGL
無關(guān)) - 調(diào)用
SwapBuffer
進行雙緩沖切換顯示渲染畫面。 - 釋放
EGL
相關(guān)資源EGLSurface
淀歇、EGLContext
易核、EGLDisplay
。
獲取顯示設備
首先浪默,EGL
是需要知道繪制內(nèi)容的目標在哪里牡直,EGLDisplay
是一個封裝了物理屏幕的數(shù)據(jù)類型缀匕,也可以理解為繪制目標的一個抽象。
通常通過eglGetDisplay()
方法返回EGLDisplay
來作為OpenGL ES
的渲染目標碰逸,在該方法中乡小,一般來說都會將常量EGL_DEFAULT_DISPLAY
傳進方法中,而各個手機廠商則會返回默認的顯示設備饵史。
java代碼:
mEgl = (EGL10) EGLContext.getEGL();
// 返回默認的顯示設備.
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// 需判斷是否成功獲取EGLDisplay
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
c代碼:
EGLDisplay egl_display;
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
//需判斷是否成功獲取EGLDisplay
if (egl_display == EGL_NO_DISPLAY)
return error;
一般來說满钟,我們需要驗證eglGetDisplay()
的返回值,如果是EGL_NO_DISPLAY
的話胳喷,那么就是沒有獲取默認顯示設備湃番,需要返回給客戶端上層處理異常。
當我們獲取到了EGLDisplay
厌蔽,我們需要調(diào)用eglInitialize()
對其進行初始化牵辣,該方法會返回一個bool變量代表執(zhí)行是否成功。
java代碼:
int version[] = new int[2];
if (!EGL10.eglInitialize(eglDisplay, version, 0, version, 1)) {
throw new RuntimeException("eglInitialize failed");
}
c代碼:
EGLint major, minor;
if (!eglInitialize(egl_display, &major, &minor))
return error;
方法的后面參數(shù)代表Major
和Minor
的版本奴饮,比如EGL
的版本號是1.0,那么Major
將返回1择浊,Minor
返回0戴卜。
如果不關(guān)心版本號,這兩個參數(shù)可以傳入NULL
琢岩。
配置輸出格式
當我們獲取到EGLDisplay
后投剥,其實已經(jīng)可以將OpenGL ES
的輸出與設備的屏幕橋接起來了,但是還是需要指定一些配置項担孔,例如色彩格式江锨、像素格式、RGBA的表示以及SurfaceType等糕篇,實際上也就是指FrameBuffer的配置參數(shù)啄育。
一般來說不同平臺的EGL
標準是不同的,以下是Android平臺一個比較通用的配置參數(shù)(Java的就不列舉了):
const EGLint config_attribs[] = {
EGL_BUFFER_SIZE, 32, //顏色緩沖區(qū)中所有組成顏色的位數(shù)
EGL_ALPHA_SIZE, 8, //顏色緩沖區(qū)中透明度位數(shù)
EGL_BLUE_SIZE, 8, //顏色緩沖區(qū)中藍色位數(shù)
EGL_GREEN_SIZE, 8, //顏色緩沖區(qū)中綠色位數(shù)
EGL_RED_SIZE, 8, //顏色緩沖區(qū)中紅色位數(shù)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //egl版本 2.0
EGL_NONE
};
PS:EGL
的參數(shù)配置一般都以 id拌消,value 依次存放挑豌,對于個別的屬性可以只有 id 沒有 value ,并以EGL_NONE
標識結(jié)尾信息墩崩。
最終可以通過調(diào)用eglChooseConfig()
方法得到配置選項信息:
java代碼:
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
// eglChooseConfig()方法得到配置選項信息
if(!mEgl.eglChooseConfig(mEglDisplay, attribList, configs, configs.length, numConfigs))
throw new IllegalArgumentException("eglChooseConfig failed");
// 如果沒有配置的Config
if (numConfigs[0] < 0)
throw new RuntimeException("Unable to find any matching EGL config");
EGLConfig eglConfig = configs[0];
// 對應的Config不存在
if (eglConfig == null)
throw new RuntimeException("eglChooseConfig returned null");
c代碼:
EGLint num_config;
EGLConfig egl_config;
//檢測返回值是否成功
if (!eglChooseConfig(egl_display, config_attribs, &egl_config, 1, &num_config))
return error;
//如果沒有配置的Config
if (num_config < 0)
return error;
//對應的Config不存在
if (_egl_config == NULL)
return error;
簡單看一下函數(shù)原型:eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,EGLint *num_config)
可以知道:
第2個參數(shù)attrib_list
指的是配置參數(shù)列表氓英,也就是上面的config_attribs[]
;
第3個參數(shù)configs
返回輸出的EGLConfigs
數(shù)據(jù)鹦筹,可能有多個铝阐;
第4個參數(shù)config_size
則表示最多需要輸出多少個EGLConfig
;
第5個參數(shù)num_config
則代表滿足配置參數(shù)的EGLConfig
的個數(shù)铐拐。
附帶一個EGLConfig屬性表格:
屬性 | 描述 | 默認值 |
---|---|---|
EGL_BUFFER_SIZE | 顏色緩沖區(qū)中所有組成顏色的位數(shù) | 0 |
EGL_RED_SIZE | 顏色緩沖區(qū)中紅色位數(shù) | 0 |
EGL_GREEN_SIZE | 顏色緩沖區(qū)中綠色位數(shù) | 0 |
EGL_BLUE_SIZE | 顏色緩沖區(qū)中藍色位數(shù) | 0 |
EGL_LUMINANCE_SIZE | 顏色緩沖區(qū)中亮度位數(shù) | 0 |
EGL_ALPHA_SIZE | 顏色緩沖區(qū)中透明度位數(shù) | 0 |
EGL_ALPHA_MASK_SIZE | 遮擋緩沖區(qū)透明度掩碼位數(shù) | 0 |
EGL_BIND_TO_TEXTURE_RGB | 綁定到 RGB 貼圖使能為真 | EGL_DONT_CARE |
EGL_BIND_TO_TEXTURE_RGBA | 綁定到 RGBA 貼圖使能為真 | EGL_DONT_CARE |
EGL_COLOR_BUFFER_TYPE | 顏色緩沖區(qū)類型 EGL_RGB_BUFFER, 或者EGL_LUMINANCE_BUFFER | EGL_RGB_BUFFER |
EGL_CONFIG_CAVEAT | 配置有關(guān)的警告信息 | EGL_DONT_CARE |
EGL_CONFIG_ID | 唯一的 EGLConfig 標示值 | EGL_DONT_CARE |
EGL_CONFORMANT | 使用EGLConfig 創(chuàng)建的上下文符合要求時為真 | — |
EGL_DEPTH_SIZE | 深度緩沖區(qū)位數(shù) | 0 |
EGL_LEVEL | 幀緩沖區(qū)水平 | 0 |
EGL_MAX_PBUFFER_WIDTH | 使用EGLConfig 創(chuàng)建的PBuffer的最大寬度 | — |
EGL_MAX_PBUFFER_HEIGHT | 使用EGLConfig 創(chuàng)建的PBuffer最大高度 | — |
EGL_MAX_PBUFFER_PIXELS | 使用EGLConfig 創(chuàng)建的PBuffer最大尺寸 | — |
EGL_MAX_SWAP_INTERVAL | 最大緩沖區(qū)交換間隔 | EGL_DONT_CARE |
EGL_MIN_SWAP_INTERVAL | 最小緩沖區(qū)交換間隔 | EGL_DONT_CARE |
EGL_NATIVE_RENDERABLE | 如果操作系統(tǒng)渲染庫能夠使用EGLConfig 創(chuàng)建渲染渲染窗口 | EGL_DONT_CARE |
EGL_NATIVE_VISUAL_ID | 與操作系統(tǒng)通訊的可視ID句柄 | EGL_DONT_CARE |
EGL_NATIVE_VISUAL_TYPE | 與操作系統(tǒng)通訊的可視ID類型 | EGL_DONT_CARE |
EGL_RENDERABLE_TYPE | 渲染窗口支持的布局組成標示符的遮擋位EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, orEGL_OPENVG_BIT that | EGL_OPENGL_ES_BIT |
EGL_SAMPLE_BUFFERS | 可用的多重采樣緩沖區(qū)位數(shù) | 0 |
EGL_SAMPLES | 每像素多重采樣數(shù) | 0 |
EGL_S TENCIL_SIZE | 模板緩沖區(qū)位數(shù) | 0 |
EGL_SURFACE_TYPE | EGL 窗口支持的類型EGL_WINDOW_BIT, EGL_PIXMAP_BIT,或EGL_PBUFFER_BIT | EGL_WINDOW_BIT |
EGL_TRANSPARENT_TYPE | 支持的透明度類型 | EGL_NONE |
EGL_TRANSPARENT_RED_VALUE | 透明度的紅色解釋 | EGL_DONT_CARE |
EGL_TRANSPARENT_GRE EN_VALUE | 透明度的綠色解釋 | EGL_DONT_CARE |
EGL_TRANSPARENT_BLUE_VALUE | 透明度的蘭色解釋 | EGL_DONT_CARE |
創(chuàng)建EGL上下文環(huán)境
當拿到EGLDisplay
和EGLConfig
后徘键,就可以開始創(chuàng)建EGL
的上下文環(huán)境EGLContext
了练对。
EGLContext
的存在是因為OpenGL ES
所創(chuàng)建的資源對于開發(fā)者來說可見的僅僅只是一個 ID 而已,而其實際內(nèi)容依賴于這個上下文啊鸭。
一個EGLContext
只能在一個線程中使用锹淌,如果將EGLContext
所持有的OpengGL
資源在多線程間共享,那么需要用到共享上下文(share context)赠制。
簡單看下EGLContext
的創(chuàng)建代碼:
java代碼:
// 指定OpenGL ES2版本
int[] attrib_list = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
// 創(chuàng)建EGLContext上下文
if(mEGLContext != null)
mEGLContext = mEgl.eglCreateContext(mEglDisplay, configs[0], null,attrib_list);
else
mEGLContext = mEgl.eglCreateContext(mEglDisplay, configs[0], EGL10.EGL_NO_CONTEXT,attrib_list);
//需要檢測Context是否存在
if (mEGLContext == EGL10.EGL_NO_CONTEXT) {
throw new RuntimeException("Failed to create EGL context");
}
c代碼:
EGLContext egl_context;
//指定OpenGL ES2版本
const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
//創(chuàng)建EGLContext上下文
egl_context = eglCreateContext(egl_display, egl_config, NULL, context_attribs);
//需要檢測Context是否存在
if (egl_context == EGL_NO_CONTEXT)
return error;
函數(shù)eglCreateContext()
的第三個參數(shù)可以傳入一個EGLContext
的變量赂摆,該變量的意義是指可以與正在創(chuàng)建的上下文環(huán)境共享OpenGL ES
資源,包括紋理钟些、FrameBuffer
以及其他的Buffer
等資源烟号。
如果傳入NULL
代表不需要與其他的OpenGL ES
上下文共享任何資源。
連接EGL和設備屏幕
當我們需要將EGL
跟設備的屏幕橋接起來時政恍,我們需要用到EGLSurface
讓EGL
有一個“橋”的功能汪拥,從而使得OpenGL ES
的輸出可以渲染到設備屏幕上;
EGLSurface
其實就是一個FrameBuffer
篙耗,通過EGL
庫提供的eglCreateWindowSurface()
可以創(chuàng)建一個可實際顯示的Surface
迫筑;也可以通過EGL庫提供的eglCreatePbufferSurface()
方法創(chuàng)建一個OffScreen
的Surface
。
java代碼:
// 創(chuàng)建可顯示的Surface
// 第三個參數(shù)在EGL10中只支持SurfaceHolder和SurfaceTexture
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], surface,null);
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
}
這里需要強調(diào)一點的是eglCreateWindowSurface()
的第三個入?yún)?code>surface雖然可以傳入Object
宗弯;但是在EGL14
中只支持Surface
和SurfaceTexture
脯燃,在EGL10中只支持SurfaceHolder
和SurfaceTexture
。
c代碼:
//創(chuàng)建可顯示的Surface
EGLSurface egl_surface;
const EGLint attribs[] = { EGL_NONE };
egl_surface = eglCreateWindowSurface(egl_display, egl_config, window, attribs);
if (egl_surface == EGL_NO_SURFACE)
return error;
在Native層蒙保,eglCreateWindowSurface()
的第三個入?yún)?code>window是需要傳入一個ANativeWindow
對象辕棚,也就是本地設備屏幕的表示。
我們可以通過Surface
(由SurfaceView
或者TextureView
獲得或者構(gòu)建出來的Surface
對象)來構(gòu)建ANativeWindow
邓厕。
需要引入頭文件:
#include <android/native_window.h>
#include <android/native_window_jni.h>
獲取ANativeWindow
的代碼如下:
//surface也就是一個jobject逝嚎,對應java層的Surface。
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
如果我們要做離屏渲染的話详恼,就需要用到離屏處理的Surface
补君,也就是創(chuàng)建一個PBufferSurface
,PBufferSurface
的保存位置是在顯存中的幀单雾,具體代碼可以參考赚哗。
java代碼:
//創(chuàng)建離屏Surface
EGLSurface eglSurface;
int[] surfaceAttribs = {
EGL14.EGL_WIDTH, width,
EGL14.EGL_HEIGHT, height,
EGL14.EGL_NONE
};
eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0);
if (eglSurface == EGL14.EGL_NO_SURFACE) {
throw new RuntimeException("Failed to create pixel buffer surface");
}
c代碼:
//創(chuàng)建離屏Surface
EGLSurface egl_surface;
const EGLint attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE
};
egl_surface = eglCreatePbufferSurface(egl_display, egl_config, attribs);
if (egl_surface == EGL_NO_SURFACE)
return error;
另外說一點,EGLSurface
還支持參數(shù)的查詢與設置硅堆,例如我們想知道新創(chuàng)建的Surface
的寬高屿储,那么可以用到下面的方法。
java代碼:
//查詢Surface的width
int[] array = new int[1];
EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, array, 0);
//設置Surface的width
if (!EGL14.eglSurfaceAttrib(eglDisplay, eglSurface, EGL14.EGL_WIDTH, 600))
throw new RuntimeException("eglSurfaceAttrib fail");
c代碼:
//查詢Surface的width
EGLint value;
eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &value);
//設置Surface的width
if (!eglSurfaceAttrib(_egl_display, _egl_surface, EGL_WIDTH, 600))
return error;
EGL變量與線程的綁定
一般來說渐逃,開發(fā)者需要為OpenGL ES
開辟一個新的線程够掠,來執(zhí)行渲染操作,并且需要為該線程綁定顯示設備EGLSurface
和上下文環(huán)境EGLContext
茄菊。
每個線程都需要綁定一個上下文疯潭,才可以開始執(zhí)行OpenGL ES
指令赊堪,我們可以通過eglMakeCurrent
來為該線程綁定Surface
和Context
,值得注意一點的是一個EGLContext
只能綁定到一個線程上面竖哩。
java代碼:
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
c代碼:
if (!eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context))
return error;
可以通過返回值來判斷eglMakeCurrent()
是否成功哭廉,這個也是必要的。
OpenGL的渲染
涉及到OpenGl ES
的繪圖API和紋理相關(guān)方面的知識相叁,本篇這里不做介紹遵绰,請關(guān)注后續(xù)相關(guān)文章。
雙緩沖機制
EGL
在初始化的時候默認設置的是雙緩沖模式增淹,也就是兩份FrameBuffer
;
即一份緩沖用于繪制圖像椿访,一份緩沖用于顯示圖像,每次顯示時需要交換兩份緩沖虑润。
我們需要在OpenGL ES
繪制完畢后成玫,調(diào)用
eglSwapBuffers(egl_display, egl_surface);
將前臺的FrameBuffer
和后臺FrameBuffer
進行交換。
EGL的資源釋放
當然拳喻,EGL
在我們不需要的時候也是需要進行釋放的哭当。
我們需要將線程跟EGL
環(huán)境解除綁定:
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
然后要銷毀EGLSurface
:
eglDestroySurface(egl_display, egl_surface);
接著清理掉上下文環(huán)境:
eglDestroyContext(egl_display, egl_context);
最終關(guān)閉掉顯示設備:
eglTerminate(egl_display);
通過上面也就是完成了一個EGL
的資源釋放工作。
整體java代碼如下:
package com.sjy.livepushmine.opengl;
import android.util.Log;
import android.view.Surface;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
/**
* An EGL helper class.
* 可參照:http://www.reibang.com/p/d5ff1ff4ee2a冗澈,比較詳細
*/
public class EglHelper {
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
private EGLConfig mEGLConfig;
// /**
// * 用給的mEGLContext和mEGLSurface創(chuàng)建egl
// */
public void eglSetup( Surface surface,EGLContext eglContext) {
try {
// mEglContext = mEGLContext;
// 獲取egl實例
mEgl = (EGL10) EGLContext.getEGL();
// 返回默認的顯示設備.
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
// 需判斷是否成功獲取EGLDisplay
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
// mEglDisplay進行初始化
int[] version = new int[2];
if(!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
// 已經(jīng)將OpenGL ES的輸出與設備的屏幕橋接起來荣病,需指定一些配置項
int[] attributes = new int[]{
EGL10.EGL_RED_SIZE, 8,//顏色緩沖區(qū)紅色分量的位數(shù)為8
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,//模板緩沖區(qū)
EGL10.EGL_RENDERABLE_TYPE, 4,//egl版本 2.0
EGL10.EGL_NONE //并以EGL_NONE標識結(jié)尾信息
};
/*
* EGL_RENDERABLE_TYPE注釋:
* android不支持OpenGL ES 2.x,因此在EGL10中某些相關(guān)常量參數(shù)只能用手寫硬編碼代替渗柿,
* 例如EGL14.EGL_CONTEXT_CLIENT_VERSION以及EGL14.EGL_OPENGL_ES2_BIT等等
* public static final int EGL14.EGL_OPENGL_ES2_BIT = 0x0004;
*/
int[] num_config = new int[1];
// eglChooseConfig()方法得到配置選項信息
if(!mEgl.eglChooseConfig(mEglDisplay, attributes, null, 1, num_config)){
throw new IllegalArgumentException("eglChooseConfig failed");
}
int numConfigs = num_config[0];
if (numConfigs <= 0) {
throw new IllegalArgumentException(
"No configs match configSpec");
}
EGLConfig[] configs = new EGLConfig[numConfigs];
if (!mEgl.eglChooseConfig(mEglDisplay, attributes, configs, numConfigs, num_config)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
mEGLConfig = configs[0];
// 對應的Config不存在
if (mEGLConfig == null) {
throw new RuntimeException("eglChooseConfig returned null");
}
// 指定OpenGL ES2版本
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2,EGL10.EGL_NONE};
// 創(chuàng)建EGLContext上下文
if(eglContext != null)
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEGLConfig, eglContext,attrib_list);
else
mEglContext = mEgl.eglCreateContext(mEglDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT,attrib_list);
// 創(chuàng)建可顯示的Surface
// 第三個參數(shù)在EGL10中只支持SurfaceHolder和SurfaceTexture
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], surface,null);
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
throw new RuntimeException("createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
}
/*
每個線程都需要綁定一個上下文,才可以開始執(zhí)行OpenGL ES指令脖岛,
我們可以通過eglMakeCurrent來為該線程綁定Surface和Context
*/
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
Log.e("Egl", "eglSetup: " + Integer.toHexString(mEgl.eglGetError()));
throw new RuntimeException("egl makeCurrent failed");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean swapBuffers() {
if (mEgl != null) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
}
Log.e("TAG", "egl is null");
return false;
}
/**
* 銷毀mEglDisplay和當前線程綁定
*/
public void destroySurface() {
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
// 需要將線程跟EGL環(huán)境解除綁定
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
// 要銷毀EGLSurface
mEgl.eglDestroySurface(mEglDisplay,mEglSurface);
mEglSurface = null;
// 接著清理掉上下文環(huán)境
mEgl.eglDestroyContext(mEglDisplay,mEglContext);
mEglContext = null;
// 最終關(guān)閉掉顯示設備
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
}
}
public EGLConfig getEglConfig() {
return mEGLConfig;
}
public EGLSurface getEglSurface() {
return mEglSurface;
}
public EGLContext getEGLContext() {
return mEglContext;
}
}
最后說一些
在Android平臺上面朵栖,當程序切到后臺的時候,需要釋放EGL
環(huán)境柴梆,在應用挪回前臺時陨溅,重新初始化相關(guān)環(huán)境。
不過谷歌提供了一個已經(jīng)封裝完善的GLSurfaceView
提供OpenGL ES
的繪制環(huán)境绍在,普通需求下采用GLSurfaceView
進行繪制也是一個不錯的選擇门扇。
有興趣可以讀讀這篇文章:源碼解析:Android源碼GLSurfaceView源碼解析。
最后放一個EGL的官方文檔地址偿渡。
結(jié)語
這篇文章簡單介紹了一下Android平臺下的EGL
環(huán)境的相關(guān)內(nèi)容臼寄,并提供了基于java層EGL10
和native層的EGL
相關(guān)API的使用示例。
后續(xù)文章將介紹怎么在EGL
環(huán)境下進行OpenGL ES
相關(guān) API的一些使用溜宽。
End!
轉(zhuǎn)自作者:碼農(nóng)叔叔
轉(zhuǎn)自鏈接:http://www.reibang.com/p/d5ff1ff4ee2a
來源:簡書
著作權(quán)歸作者所有吉拳。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處适揉。