前面幾篇文章經過 GLSurfaceView 進行 opengles 的渲染,使用簡單。可是不夠靈活,一個 opengl 只能渲染一個 GLSurfaceView,一旦 GLSurfaceView 銷燬,對應的 opengl 也會銷燬。php
使用 EGL 能夠避免上述缺點。java
EGL 時渲染 API 和平臺原生窗口系統之間的接口,主要任務是:android
EGL 使用主要步驟很清晰,每一個步驟都有相應的方法進行操做。git
private void createEGL(){
//獲取顯示設備
eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL_NO_DISPLAY){
throw new RuntimeException("egl error:" + eglGetError());
}
//初始化EGL
int[] version = new int[2];
if (!eglInitialize(eglDisplay, version,0,version,1)){
throw new RuntimeException("egl error:" + eglGetError());
}
//EGL選擇配置
int[] configAttribList = {
EGL_BUFFER_SIZE, 32,
EGL_ALPHA_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
int[] numConfig = new int[1];
EGLConfig[] configs = new EGLConfig[1];
if(!eglChooseConfig(eglDisplay,
configAttribList, 0,
configs,0, configs.length,
numConfig,0)){
throw new RuntimeException("egl error:" + eglGetError());
}
eglConfig = configs[0];
//建立ELG上下文
int[] contextAttribList = {
EGL_CONTEXT_CLIENT_VERSION,2,
EGL_NONE
};
eglContext = eglCreateContext(eglDisplay, eglConfig,EGL_NO_CONTEXT,contextAttribList,0);
if (eglContext == EGL_NO_CONTEXT){
throw new RuntimeException("egl error:" + eglGetError());
}
}
public void render(Surface surface, int width, int height){
//建立屏幕上渲染區域:EGL窗口
int[] surfaceAttribList = {EGL_NONE};
EGLSurface eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribList, 0);
//指定當前上下文
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
//獲取着色器
int vertexShader = loadShader(GL_VERTEX_SHADER, VERTEX_SHADER_SOURCE);
int fragmentShader = loadShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
//建立並鏈接程序
int program = createAndLinkProgram(vertexShader, fragmentShader);
//設置清除渲染時的顏色
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
//設置視口
glViewport(0, 0, width, height);
//獲取頂點、顏色數據
FloatBuffer vertexBuffer = getVertextBuffer();
FloatBuffer vertexColorBuffer = getVertexColorBuffer();
//擦除屏幕
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(program);
//綁定頂點、顏色數據到指定屬性位置
int vposition = glGetAttribLocation(program, "vPosition");
glVertexAttribPointer(vposition,3,GL_FLOAT,false,0,vertexBuffer);
glEnableVertexAttribArray(vposition);
int aColor = glGetAttribLocation(program, "aColor");
glEnableVertexAttribArray(aColor);
glVertexAttribPointer(aColor, 4, GL_FLOAT, false, 0, vertexColorBuffer);
//繪製
glDrawArrays(GL_TRIANGLES,0,3);
//交換 surface 和顯示器緩存
eglSwapBuffers(eglDisplay, eglSurface);
//釋放
eglDestroySurface(eglDisplay, eglSurface);
}
複製代碼
opengles 渲染是基於線程的,須要本身實現一個管理 opengles 環境和渲染的線程的渲染器。github
public class EGLRender extends HandlerThread {
private EGLConfig eglConfig;
private EGLDisplay eglDisplay;
private EGLContext eglContext;
public EGLRender() {
super("ELGRender");
}
private void createEGL(){
//代碼在上面
}
private void destroyEGL(){
eglDestroyContext(eglDisplay, eglContext);
eglContext = EGL_NO_CONTEXT;
eglDisplay = EGL_NO_DISPLAY;
}
@Override
public synchronized void start() {
super.start();
new Handler(getLooper()).post(new Runnable() {
@Override
public void run() {
createEGL();
}
});
}
public void release(){
new Handler(getLooper()).post(new Runnable() {
@Override
public void run() {
destroyEGL();
quit();
}
});
}
public void render(Surface surface, int width, int height){
//代碼在上面
}
}
複製代碼
佈局文件緩存
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".fragment.EGLFragment">
<SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" />
</RelativeLayout>
複製代碼
將渲染器與佈局中的 SurfaceView 進行關聯。ide
public class EGLFragment extends Fragment {
private SurfaceView surfaceView;
private EGLRender eglRender;
public EGLFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_egl, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
eglRender = new EGLRender();
eglRender.start();
surfaceView = view.findViewById(R.id.surfaceView);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
eglRender.render(holder.getSurface(), width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
@Override
public void onDestroy() {
eglRender.release();
eglRender = null;
super.onDestroy();
}
}
複製代碼
本文梳理了 EGL 的使用流程,基於線程自定義了 EGL 渲染器,將內容顯示到 SurfaceView。oop
項目地址佈局