【OpenGL ES】不用GLSurfaceView,如何渲染图像

1 前言

​ Android 中,GLSurfaceView 封装了 EGL 环境,使得我们省去了复杂的 EGL 环境搭建。如果我们不用 GLSurfaceView,该如何渲染 OpenGL ES 图像?在回答此问题前,我们先了解下 EGL。

​ EGL 是 Khronos Group 定义的平台无关接口,作为 OpenGL ES 和本地窗口系统之间的桥梁,主要功能如下。

  • 管理图形上下文
  • 创建和管理渲染表面 (surface)
  • 同步渲染与平台显示系统

​ EGL 提供了两种渲染方式,分别是离屏渲染和窗口渲染,分别对应 eglCreatePbufferSurface 和 eglCreateWindowSurface。对于离屏渲染方案,详见 → EGL+FBO离屏渲染。eglCreateWindowSurface 函数的源码如下。

public static EGLSurface eglCreateWindowSurface(EGLDisplay dpy,     EGLConfig config, Object win, int[] attrib_list, int offset){     Surface sur = null;     if (win instanceof SurfaceView) {         SurfaceView surfaceView = (SurfaceView)win;         sur = surfaceView.getHolder().getSurface();     } else if (win instanceof SurfaceHolder) {         SurfaceHolder holder = (SurfaceHolder)win;         sur = holder.getSurface();     } else if (win instanceof Surface) {         sur = (Surface) win;     }      EGLSurface surface;     if (sur != null) {         surface = _eglCreateWindowSurface(dpy, config, sur, attrib_list, offset);     } else if (win instanceof SurfaceTexture) {         surface = _eglCreateWindowSurfaceTexture(dpy, config,                 win, attrib_list, offset);     } else {         throw new java.lang.UnsupportedOperationException(             "eglCreateWindowSurface() can only be called with an instance of " +             "Surface, SurfaceView, SurfaceTexture or SurfaceHolder at the moment, " +             "this will be fixed later.");     }      return surface; } 

​ 主要留意 win 参数,可以看到它可以是 SurfaceView、SurfaceHolder、Surface,本质都是为了获取 Surface。因此我们提供了以下两种渲染图像的方案。

  • 继承 SurfaceView 方案:自定义一个 View 继承 SurfaceView,并实现 SurfaceHolder.Callback 接口,在 surfaceCreated 方法中将 this 或 getHolder() 传给 eglCreateWindowSurface 函数。
  • 继承 TextureView 方案:自定义一个 View 继承 TextureView,并实现 TextureView.SurfaceTextureListener 接口,在 onSurfaceTextureAvailable 方法中会提供 SurfaceTexture,我们可以创建一个 Surface,并将 SurfaceTexture 传给 Surface,然后将创建的 Surface 传给 eglCreateWindowSurface 函数。

​ 本文完整代码详见 → 不用GLSurfaceView,如何渲染图像

2 继承 SurfaceView 方案

​ 自定义一个 View 继承 SurfaceView,并实现 SurfaceHolder.Callback 接口,在 surfaceCreated 方法中将 this 或 getHolder() 传给 eglCreateWindowSurface 函数。

​ 由于 GLSurfaceView 继承 SurfaceView,所以该方案很容易想到,只需要将 GLSurfaceView 的核心代码扣出来就行。

​ MainActivity.java

package com.zhyan8.egldemo;  import android.os.Bundle;  import androidx.appcompat.app.AppCompatActivity;  public class MainActivity extends AppCompatActivity {     private EGLSurfaceView mEglSurfaceView;      protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         mEglSurfaceView = new EGLSurfaceView(this);         setContentView(mEglSurfaceView);         mEglSurfaceView.setRenderer(new MyRenderer(this));     }      @Override     protected void onResume() {         super.onResume();         mEglSurfaceView.requestRender();         //mEglSurfaceView.startRender();     }      @Override     protected void onPause() {         super.onPause();         mEglSurfaceView.stopRender();     } } 

​ EGLSurfaceView.java

package com.zhyan8.egldemo;  import android.content.Context; import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLExt; import android.opengl.EGLSurface; import android.util.Log; import android.view.Choreographer; import android.view.SurfaceHolder; import android.view.SurfaceView;  import androidx.annotation.NonNull;  /**  * @author little fat sheep  * 承载EGL环境的View, 类比GLSurfaceView  */ public class EGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {     private static final String TAG = "EGLSurfaceView";      protected EGLDisplay mEGLDisplay;     protected EGLConfig mEGLConfig;     protected EGLContext mEGLContext;     protected EGLSurface mEGLSurface;     protected Context mContext;     protected Renderer mRenderer;     protected boolean mFirstCreateSurface = true;     private Choreographer mChoreographer = Choreographer.getInstance();      public EGLSurfaceView(Context context) {         super(context);         mContext = context;         getHolder().addCallback(this);     }      // 设置渲染器     public void setRenderer(Renderer renderer) {         mRenderer = renderer;     }      // 开始持续渲染     public void startRender() {         Log.i(TAG, "startRender");         mChoreographer.removeFrameCallback(mFrameCallback);         mChoreographer.postFrameCallback(mFrameCallback);     }      // 暂停持续渲染     public void stopRender() {         Log.i(TAG, "stopRender");         mChoreographer.removeFrameCallback(mFrameCallback);     }      // 请求渲染一帧     public void requestRender() {         mFrameCallback.doFrame(System.nanoTime());     }      @Override     protected void onAttachedToWindow() {         super.onAttachedToWindow();         createDisplay();         createConfig();         createContext();     }      @Override     public void surfaceCreated(@NonNull SurfaceHolder holder) { // 每次activity resume都会调用一次         Log.i(TAG, "surfaceCreated, surface=" + holder.getSurface());         createSurface();         makeCurrent();         if (mFirstCreateSurface) {             mRenderer.onSurfaceCreated();             mFirstCreateSurface = false;         }     }      @Override     public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {         Log.i(TAG, "surfaceChanged, width=" + width + ", height=" + height);         mRenderer.onSurfaceChanged(width, height);     }      @Override     public void surfaceDestroyed(@NonNull SurfaceHolder holder) { // 每次activity pause都会调用一次         Log.i(TAG, "surfaceDestroyed");         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {             // 与显示设备解绑             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);             // 销毁 EGLSurface             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);                 checkoutConfig("eglDestroySurface");                 mEGLSurface = null;             }         }     }      @Override     public void onDetachedFromWindow() {         super.onDetachedFromWindow();         Log.i(TAG, "onDetachedFromWindow");         stopRender();         getHolder().removeCallback(this);         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {             // 与显示设备解绑             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);             // 销毁 EGLSurface             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);                 checkoutConfig("eglDestroySurface");                 mEGLSurface = null;             }             // 销毁 EGLContext             if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {                 EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);                 checkoutConfig("eglDestroyContext");                 mEGLContext = null;             }             // 销毁 EGLDisplay (显示设备)             EGL14.eglTerminate(mEGLDisplay);             checkoutConfig("eglTerminate");             mEGLDisplay = null;         }     }      // 1.创建EGLDisplay     private void createDisplay() {         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);         int[] versions = new int[2];         EGL14.eglInitialize(mEGLDisplay, versions,0, versions, 1);         checkoutConfig("eglInitialize");     }      // 2.创建EGLConfig     private void createConfig() {         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {             EGLConfig[] configs = new EGLConfig[1];             int[] configNum = new int[1];             EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,  configNum, 0);             if (configNum[0] > 0) {                 mEGLConfig = configs[0];             }             checkoutConfig("eglChooseConfig");         }     }      // 3.创建EGLContext     private void createContext() {         if (mEGLConfig != null) {             mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mEGLConfig, EGL14.EGL_NO_CONTEXT, mEGLContextAttrs, 0);             checkoutConfig("eglCreateContext");         }     }      // 4.创建EGLSurface     private void createSurface() {         if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {             int[] eglSurfaceAttrs = { EGL14.EGL_NONE };             //mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, getHolder(), eglSurfaceAttrs, 0);             mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, eglSurfaceAttrs, 0);             checkoutConfig("eglCreateWindowSurface");         }     }      // 5.绑定EGLSurface和EGLContext到显示设备(EGLDisplay)     private void makeCurrent() {         if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {             EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);             checkoutConfig("eglMakeCurrent");         }     }      private void checkoutConfig(String tag) {         int error = EGL14.eglGetError();         if (error != EGL14.EGL_SUCCESS) {             Log.e(TAG, tag + " error=0x" + Integer.toHexString(error));         }     }      // EGLConfig参数     private int[] mEGLConfigAttrs = {             EGL14.EGL_RED_SIZE, 8,             EGL14.EGL_GREEN_SIZE, 8,             EGL14.EGL_BLUE_SIZE, 8,             EGL14.EGL_ALPHA_SIZE, 8,             EGL14.EGL_DEPTH_SIZE, 8,             //EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,             EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR,             EGL14.EGL_NONE     };      // EGLContext参数     private int[] mEGLContextAttrs = {             EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,             EGL14.EGL_NONE     };      Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {         @Override         public void doFrame(long frameTimeNanos) {             mChoreographer.postFrameCallback(mFrameCallback);             if (mEGLSurface != null) {                 mRenderer.onDrawFrame();                 EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);                 checkoutConfig("eglSwapBuffers");             }         }     };      /**      * @author little fat sheep      * 渲染器接口, 类比GLSurfaceView.Renderer      */     interface Renderer {         void onSurfaceCreated();         void onSurfaceChanged(int width, int height);         void onDrawFrame();     } } 

​ MyRenderer.java

package com.zhyan8.egldemo;  import android.content.Context; import android.opengl.GLES30;  import java.nio.FloatBuffer;  public class MyRenderer implements EGLSurfaceView.Renderer {     private FloatBuffer vertexBuffer;     private FloatBuffer textureBuffer;     private MyGLUtils mGLUtils;     private int mTextureId;      public MyRenderer(Context context) {         mGLUtils = new MyGLUtils(context);         getFloatBuffer();     }      @Override     public void onSurfaceCreated() {         //设置背景颜色         GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);         //编译着色器         final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);         final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);         //链接程序片段         int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);         GLES30.glUseProgram(programId);         mTextureId = mGLUtils.loadTexture(R.raw.girl);     }      @Override     public void onSurfaceChanged(int width, int height) {         //设置视图窗口         GLES30.glViewport(0, 0, width, height);     }      @Override     public void onDrawFrame() {         //将颜色缓冲区设置为预设的颜色         GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);         //启用顶点的数组句柄         GLES30.glEnableVertexAttribArray(0);         GLES30.glEnableVertexAttribArray(1);         //准备顶点坐标和纹理坐标         GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);         GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, textureBuffer);         //激活纹理         GLES30.glActiveTexture(GLES30.GL_TEXTURE);         //绑定纹理         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId);         //绘制贴图         GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4);         //禁止顶点数组句柄         GLES30.glDisableVertexAttribArray(0);         GLES30.glDisableVertexAttribArray(1);     }      private void getFloatBuffer() {         float[] vertex = new float[] {                 1f, 1f, 0f,     //V0                 -1f, 1f, 0f,    //V1                 -1f, -1f, 0f,   //V2                 1f, -1f, 0f     //V3         };         float[] texture = {                 1f, 0f,     //V0                 0f, 0f,     //V1                 0f, 1.0f,   //V2                 1f, 1.0f    //V3         };         vertexBuffer = mGLUtils.getFloatBuffer(vertex);         textureBuffer = mGLUtils.getFloatBuffer(texture);     } } 

​ MyGLUtils.java

package com.zhyan8.egldemo;  import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLES30; import android.opengl.GLUtils; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer;  public class MyGLUtils {     private Context mContext;     private Bitmap mBitmap;      public MyGLUtils(Context context) {         mContext = context;     }      public FloatBuffer getFloatBuffer(float[] floatArr) {         FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)                 .order(ByteOrder.nativeOrder())                 .asFloatBuffer();         fb.put(floatArr);         fb.position(0);         return fb;     }      //通过代码片段编译着色器     public int compileShader(int type, String shaderCode){         int shader = GLES30.glCreateShader(type);         GLES30.glShaderSource(shader, shaderCode);         GLES30.glCompileShader(shader);         return shader;     }      //通过外部资源编译着色器     public int compileShader(int type, int shaderId){         String shaderCode = readShaderFromResource(shaderId);         return compileShader(type, shaderCode);     }      //链接到着色器     public int linkProgram(int vertexShaderId, int fragmentShaderId) {         final int programId = GLES30.glCreateProgram();         //将顶点着色器加入到程序         GLES30.glAttachShader(programId, vertexShaderId);         //将片元着色器加入到程序         GLES30.glAttachShader(programId, fragmentShaderId);         //链接着色器程序         GLES30.glLinkProgram(programId);         return programId;     }      //从shader文件读出字符串     private String readShaderFromResource(int shaderId) {         InputStream is = mContext.getResources().openRawResource(shaderId);         BufferedReader br = new BufferedReader(new InputStreamReader(is));         String line;         StringBuilder sb = new StringBuilder();         try {             while ((line = br.readLine()) != null) {                 sb.append(line);                 sb.append("n");             }             br.close();         } catch (Exception e) {             e.printStackTrace();         }         return sb.toString();     }      //加载纹理贴图     public int loadTexture(int resourceId) {         BitmapFactory.Options options = new BitmapFactory.Options();         options.inScaled = false;         mBitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId, options);         final int[] textureIds = new int[1];         // 生成纹理id         GLES30.glGenTextures(1, textureIds, 0);         // 绑定纹理到OpenGL         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]);         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR);         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);         // 加载bitmap到纹理中         GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, mBitmap, 0);         // 生成MIP贴图         GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);         // 取消绑定纹理         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);         return textureIds[0];     } } 

​ vertex_shader.glsl

attribute vec4 a_position; attribute vec2 a_texCoord; varying vec2 v_texCoord; void main() {      gl_Position = a_position;      v_texCoord = a_texCoord; } 

​ fragment_shader.glsl

precision mediump float; uniform sampler2D u_texture; varying vec2 v_texCoord; void main() {      gl_FragColor = texture2D(u_texture, v_texCoord); } 

​ 运行效果如下。

【OpenGL ES】不用GLSurfaceView,如何渲染图像

3 继承 TextureView 方案

​ 自定义一个 View 继承 TextureView,并实现 TextureView.SurfaceTextureListener 接口,在 onSurfaceTextureAvailable 方法中会提供 SurfaceTexture,我们可以创建一个 Surface,并将 SurfaceTexture 传给 Surface,然后将创建的 Surface 传给 eglCreateWindowSurface 函数。

​ 前段时间在看 Rive 的源码,详见 → rive-android源码分析,了解到 Rive 底层是通过 OpenGL ES 渲染图像,并且也没有使用 GLSurfaceView,由此借鉴而来。该方案主要参考 Rive 中 RiveTextureView 的实现,eglCreateWindowSurface 参考 thread_state_egl.cpp

​ 与第二节相比,只有 EGLSurfaceView 类有差异,因此本节仅展示 EGLSurfaceView 的代码。

​ EGLSurfaceView.java

package com.zhyan8.egldemo;  import android.content.Context; import android.graphics.SurfaceTexture; import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLExt; import android.opengl.EGLSurface; import android.util.Log; import android.view.Choreographer; import android.view.Surface; import android.view.TextureView;  import androidx.annotation.NonNull;  /**  * @author little fat sheep  * 承载EGL环境的View, 类比GLSurfaceView  */ public class EGLSurfaceView extends TextureView implements TextureView.SurfaceTextureListener {     private static final String TAG = "EGLSurfaceView";      protected EGLDisplay mEGLDisplay;     protected EGLConfig mEGLConfig;     protected EGLContext mEGLContext;     protected EGLSurface mEGLSurface;     protected Context mContext;     protected Surface mSurface;     protected Renderer mRenderer;     private Choreographer mChoreographer = Choreographer.getInstance();      public EGLSurfaceView(Context context) {         super(context);         mContext = context;         setSurfaceTextureListener(this);     }      // 设置渲染器     public void setRenderer(Renderer renderer) {         mRenderer = renderer;     }      // 开始持续渲染     public void startRender() {         Log.i(TAG, "startRender");         mChoreographer.removeFrameCallback(mFrameCallback);         mChoreographer.postFrameCallback(mFrameCallback);     }      // 暂停持续渲染     public void stopRender() {         Log.i(TAG, "stopRender");         mChoreographer.removeFrameCallback(mFrameCallback);     }      // 请求渲染一帧     public void requestRender() {         mFrameCallback.doFrame(System.nanoTime());     }      @Override     protected void onAttachedToWindow() {         super.onAttachedToWindow();         Log.i(TAG, "onAttachedToWindow");         createDisplay();         createConfig();         createContext();     }      @Override     public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {         Log.i(TAG, "onSurfaceTextureAvailable");         mSurface = new Surface(surface);         createSurface();         makeCurrent();         mRenderer.onSurfaceCreated();         mRenderer.onSurfaceChanged(width, height);     }      @Override     public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {         Log.i(TAG, "onSurfaceTextureSizeChanged, width=" + width + ", height=" + height);         mRenderer.onSurfaceChanged(width, height);     }      @Override     public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {         Log.i(TAG, "onSurfaceTextureDestroyed");         return false;     }      @Override     public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {     }      @Override     protected void onDetachedFromWindow() {         super.onDetachedFromWindow();         Log.i(TAG, "onDetachedFromWindow");         stopRender();         setSurfaceTextureListener(null);         mSurface.release();         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {             // 与显示设备解绑             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);             // 销毁 EGLSurface             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);                 checkoutConfig("eglDestroySurface");                 mEGLSurface = null;             }             // 销毁 EGLContext             if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {                 EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);                 checkoutConfig("eglDestroyContext");                 mEGLContext = null;             }             // 销毁 EGLDisplay (显示设备)             EGL14.eglTerminate(mEGLDisplay);             checkoutConfig("eglTerminate");             mEGLDisplay = null;         }     }      // 1.创建EGLDisplay     private void createDisplay() {         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);         int[] versions = new int[2];         EGL14.eglInitialize(mEGLDisplay, versions,0, versions, 1);         checkoutConfig("eglInitialize");     }      // 2.创建EGLConfig     private void createConfig() {         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {             EGLConfig[] configs = new EGLConfig[1];             int[] configNum = new int[1];             EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,  configNum, 0);             if (configNum[0] > 0) {                 mEGLConfig = configs[0];             }             checkoutConfig("eglChooseConfig");         }     }      // 3.创建EGLContext     private void createContext() {         if (mEGLConfig != null) {             mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mEGLConfig, EGL14.EGL_NO_CONTEXT, mEGLContextAttrs, 0);             checkoutConfig("eglCreateContext");         }     }      // 4.创建EGLSurface     private void createSurface() {         if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {             int[] eglSurfaceAttrs = { EGL14.EGL_NONE };             mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mSurface, eglSurfaceAttrs, 0);             checkoutConfig("eglCreateWindowSurface");         }     }      // 5.绑定EGLSurface和EGLContext到显示设备(EGLDisplay)     private void makeCurrent() {         if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {             EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);             checkoutConfig("eglMakeCurrent");         }     }      private void checkoutConfig(String tag) {         int error = EGL14.eglGetError();         if (error != EGL14.EGL_SUCCESS) {             Log.e(TAG, tag + " error=0x" + Integer.toHexString(error));         }     }      // EGLConfig参数     private int[] mEGLConfigAttrs = {             EGL14.EGL_RED_SIZE, 8,             EGL14.EGL_GREEN_SIZE, 8,             EGL14.EGL_BLUE_SIZE, 8,             EGL14.EGL_ALPHA_SIZE, 8,             EGL14.EGL_DEPTH_SIZE, 8,             //EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,             EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR,             EGL14.EGL_NONE     };      // EGLContext参数     private int[] mEGLContextAttrs = {             EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,             EGL14.EGL_NONE     };      Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {         @Override         public void doFrame(long frameTimeNanos) {             mChoreographer.postFrameCallback(mFrameCallback);             if (mEGLSurface != null) {                 mRenderer.onDrawFrame();                 EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);                 checkoutConfig("eglSwapBuffers");             }         }     };      /**      * @author little fat sheep      * 渲染器接口, 类比GLSurfaceView.Renderer      */     interface Renderer {         void onSurfaceCreated();         void onSurfaceChanged(int width, int height);         void onDrawFrame();     } } 

​ 运行效果如下。

【OpenGL ES】不用GLSurfaceView,如何渲染图像

​ 声明:本文转自【OpenGL ES】不用GLSurfaceView,如何渲染图像

发表评论

评论已关闭。

相关文章