Android OpenGL ES 十一.MediaCodec錄制視頻之EglHelper(轉(zhuǎn)載整理)

前言

這篇文章簡單介紹一下在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)境配置整體流程

  1. 獲取默認的EGLDisplay
  2. EGLDisplay進行初始化蒜哀。
  3. 輸入預設置的參數(shù)獲取EGL支持的EGLConfig斩箫。
  4. 通過EGLDisplayEGLConfig創(chuàng)建一個EGLContext上下文環(huán)境。
  5. 創(chuàng)建一個EGLSurface來連接EGL和設備的屏幕撵儿。
  6. 在渲染線程綁定EGLSurfaceEGLContext乘客。
  7. 【進行OpenGL ES的API渲染步驟】(與EGL無關(guān))
  8. 調(diào)用SwapBuffer進行雙緩沖切換顯示渲染畫面。
  9. 釋放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ù)代表MajorMinor的版本奴饮,比如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)境

當拿到EGLDisplayEGLConfig后徘键,就可以開始創(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跟設備的屏幕橋接起來時政恍,我們需要用到EGLSurfaceEGL有一個“橋”的功能汪拥,從而使得OpenGL ES的輸出可以渲染到設備屏幕上;
EGLSurface其實就是一個FrameBuffer篙耗,通過EGL庫提供的eglCreateWindowSurface()可以創(chuàng)建一個可實際顯示的Surface迫筑;也可以通過EGL庫提供的eglCreatePbufferSurface()方法創(chuàng)建一個OffScreenSurface

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中只支持SurfaceSurfaceTexture脯燃,在EGL10中只支持SurfaceHolderSurfaceTexture

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)建一個PBufferSurfacePBufferSurface的保存位置是在顯存中的幀单雾,具體代碼可以參考赚哗。

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來為該線程綁定SurfaceContext,值得注意一點的是一個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)載請注明出處适揉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末留攒,一起剝皮案震驚了整個濱河市煤惩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炼邀,老刑警劉巖魄揉,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拭宁,居然都是意外死亡洛退,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門红淡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來不狮,“玉大人,你說我怎么就攤上這事在旱∫×悖” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵桶蝎,是天一觀的道長驻仅。 經(jīng)常有香客問我,道長登渣,這世上最難降的妖魔是什么噪服? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮胜茧,結(jié)果婚禮上粘优,老公的妹妹穿的比我還像新娘。我一直安慰自己呻顽,他們只是感情好雹顺,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著廊遍,像睡著了一般嬉愧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喉前,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天没酣,我揣著相機與錄音,去河邊找鬼卵迂。 笑死裕便,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的狭握。 我是一名探鬼主播闪金,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哎垦?” 一聲冷哼從身側(cè)響起囱嫩,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漏设,沒想到半個月后墨闲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡郑口,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年鸳碧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犬性。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瞻离,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乒裆,到底是詐尸還是另有隱情套利,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布鹤耍,位于F島的核電站肉迫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏稿黄。R本人自食惡果不足惜喊衫,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杆怕。 院中可真熱鬧族购,春花似錦、人聲如沸陵珍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撑教。三九已至,卻和暖如春醉拓,著一層夾襖步出監(jiān)牢的瞬間伟姐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工亿卤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愤兵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓排吴,卻偏偏與公主長得像秆乳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容