找回密码
 立即注册
首页 业界区 业界 【OpenGL ES】不用GLSurfaceView,如何渲染图像 ...

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

坡琨 昨天 14:12
1 前言

​    Android 中,GLSurfaceView 封装了 EGL 环境,使得我们省去了复杂的 EGL 环境搭建。如果我们不用 GLSurfaceView,该如何渲染 OpenGL ES 图像?在回答此问题前,我们先了解下 EGL。
​    EGL 是 Khronos Group 定义的平台无关接口,作为 OpenGL ES 和本地窗口系统之间的桥梁,主要功能如下。

  • 管理图形上下文
  • 创建和管理渲染表面 (surface)
  • 同步渲染与平台显示系统
​    EGL 提供了两种渲染方式,分别是离屏渲染和窗口渲染,分别对应 eglCreatePbufferSurface 和 eglCreateWindowSurface。对于离屏渲染方案,详见 → EGL+FBO离屏渲染。eglCreateWindowSurface 函数的源码如下。
  1. public static EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
  2.     EGLConfig config, Object win, int[] attrib_list, int offset){
  3.     Surface sur = null;
  4.     if (win instanceof SurfaceView) {
  5.         SurfaceView surfaceView = (SurfaceView)win;
  6.         sur = surfaceView.getHolder().getSurface();
  7.     } else if (win instanceof SurfaceHolder) {
  8.         SurfaceHolder holder = (SurfaceHolder)win;
  9.         sur = holder.getSurface();
  10.     } else if (win instanceof Surface) {
  11.         sur = (Surface) win;
  12.     }
  13.     EGLSurface surface;
  14.     if (sur != null) {
  15.         surface = _eglCreateWindowSurface(dpy, config, sur, attrib_list, offset);
  16.     } else if (win instanceof SurfaceTexture) {
  17.         surface = _eglCreateWindowSurfaceTexture(dpy, config,
  18.                 win, attrib_list, offset);
  19.     } else {
  20.         throw new java.lang.UnsupportedOperationException(
  21.             "eglCreateWindowSurface() can only be called with an instance of " +
  22.             "Surface, SurfaceView, SurfaceTexture or SurfaceHolder at the moment, " +
  23.             "this will be fixed later.");
  24.     }
  25.     return surface;
  26. }
复制代码
​    主要留意 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
  1. package com.zhyan8.egldemo;
  2. import android.os.Bundle;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. public class MainActivity extends AppCompatActivity {
  5.     private EGLSurfaceView mEglSurfaceView;
  6.     protected void onCreate(Bundle savedInstanceState) {
  7.         super.onCreate(savedInstanceState);
  8.         mEglSurfaceView = new EGLSurfaceView(this);
  9.         setContentView(mEglSurfaceView);
  10.         mEglSurfaceView.setRenderer(new MyRenderer(this));
  11.     }
  12.     @Override
  13.     protected void onResume() {
  14.         super.onResume();
  15.         mEglSurfaceView.requestRender();
  16.         //mEglSurfaceView.startRender();
  17.     }
  18.     @Override
  19.     protected void onPause() {
  20.         super.onPause();
  21.         mEglSurfaceView.stopRender();
  22.     }
  23. }
复制代码
​    EGLSurfaceView.java
  1. package com.zhyan8.egldemo;
  2. import android.content.Context;
  3. import android.opengl.EGL14;
  4. import android.opengl.EGLConfig;
  5. import android.opengl.EGLContext;
  6. import android.opengl.EGLDisplay;
  7. import android.opengl.EGLExt;
  8. import android.opengl.EGLSurface;
  9. import android.util.Log;
  10. import android.view.Choreographer;
  11. import android.view.SurfaceHolder;
  12. import android.view.SurfaceView;
  13. import androidx.annotation.NonNull;
  14. /**
  15. * @author little fat sheep
  16. * 承载EGL环境的View, 类比GLSurfaceView
  17. */
  18. public class EGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
  19.     private static final String TAG = "EGLSurfaceView";
  20.     protected EGLDisplay mEGLDisplay;
  21.     protected EGLConfig mEGLConfig;
  22.     protected EGLContext mEGLContext;
  23.     protected EGLSurface mEGLSurface;
  24.     protected Context mContext;
  25.     protected Renderer mRenderer;
  26.     protected boolean mFirstCreateSurface = true;
  27.     private Choreographer mChoreographer = Choreographer.getInstance();
  28.     public EGLSurfaceView(Context context) {
  29.         super(context);
  30.         mContext = context;
  31.         getHolder().addCallback(this);
  32.     }
  33.     // 设置渲染器
  34.     public void setRenderer(Renderer renderer) {
  35.         mRenderer = renderer;
  36.     }
  37.     // 开始持续渲染
  38.     public void startRender() {
  39.         Log.i(TAG, "startRender");
  40.         mChoreographer.removeFrameCallback(mFrameCallback);
  41.         mChoreographer.postFrameCallback(mFrameCallback);
  42.     }
  43.     // 暂停持续渲染
  44.     public void stopRender() {
  45.         Log.i(TAG, "stopRender");
  46.         mChoreographer.removeFrameCallback(mFrameCallback);
  47.     }
  48.     // 请求渲染一帧
  49.     public void requestRender() {
  50.         mFrameCallback.doFrame(System.nanoTime());
  51.     }
  52.     @Override
  53.     protected void onAttachedToWindow() {
  54.         super.onAttachedToWindow();
  55.         createDisplay();
  56.         createConfig();
  57.         createContext();
  58.     }
  59.     @Override
  60.     public void surfaceCreated(@NonNull SurfaceHolder holder) { // 每次activity resume都会调用一次
  61.         Log.i(TAG, "surfaceCreated, surface=" + holder.getSurface());
  62.         createSurface();
  63.         makeCurrent();
  64.         if (mFirstCreateSurface) {
  65.             mRenderer.onSurfaceCreated();
  66.             mFirstCreateSurface = false;
  67.         }
  68.     }
  69.     @Override
  70.     public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
  71.         Log.i(TAG, "surfaceChanged, width=" + width + ", height=" + height);
  72.         mRenderer.onSurfaceChanged(width, height);
  73.     }
  74.     @Override
  75.     public void surfaceDestroyed(@NonNull SurfaceHolder holder) { // 每次activity pause都会调用一次
  76.         Log.i(TAG, "surfaceDestroyed");
  77.         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
  78.             // 与显示设备解绑
  79.             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
  80.             // 销毁 EGLSurface
  81.             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {
  82.                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
  83.                 checkoutConfig("eglDestroySurface");
  84.                 mEGLSurface = null;
  85.             }
  86.         }
  87.     }
  88.     @Override
  89.     public void onDetachedFromWindow() {
  90.         super.onDetachedFromWindow();
  91.         Log.i(TAG, "onDetachedFromWindow");
  92.         stopRender();
  93.         getHolder().removeCallback(this);
  94.         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
  95.             // 与显示设备解绑
  96.             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
  97.             // 销毁 EGLSurface
  98.             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {
  99.                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
  100.                 checkoutConfig("eglDestroySurface");
  101.                 mEGLSurface = null;
  102.             }
  103.             // 销毁 EGLContext
  104.             if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {
  105.                 EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
  106.                 checkoutConfig("eglDestroyContext");
  107.                 mEGLContext = null;
  108.             }
  109.             // 销毁 EGLDisplay (显示设备)
  110.             EGL14.eglTerminate(mEGLDisplay);
  111.             checkoutConfig("eglTerminate");
  112.             mEGLDisplay = null;
  113.         }
  114.     }
  115.     // 1.创建EGLDisplay
  116.     private void createDisplay() {
  117.         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
  118.         int[] versions = new int[2];
  119.         EGL14.eglInitialize(mEGLDisplay, versions,0, versions, 1);
  120.         checkoutConfig("eglInitialize");
  121.     }
  122.     // 2.创建EGLConfig
  123.     private void createConfig() {
  124.         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
  125.             EGLConfig[] configs = new EGLConfig[1];
  126.             int[] configNum = new int[1];
  127.             EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,  configNum, 0);
  128.             if (configNum[0] > 0) {
  129.                 mEGLConfig = configs[0];
  130.             }
  131.             checkoutConfig("eglChooseConfig");
  132.         }
  133.     }
  134.     // 3.创建EGLContext
  135.     private void createContext() {
  136.         if (mEGLConfig != null) {
  137.             mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mEGLConfig, EGL14.EGL_NO_CONTEXT, mEGLContextAttrs, 0);
  138.             checkoutConfig("eglCreateContext");
  139.         }
  140.     }
  141.     // 4.创建EGLSurface
  142.     private void createSurface() {
  143.         if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {
  144.             int[] eglSurfaceAttrs = { EGL14.EGL_NONE };
  145.             //mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, getHolder(), eglSurfaceAttrs, 0);
  146.             mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, eglSurfaceAttrs, 0);
  147.             checkoutConfig("eglCreateWindowSurface");
  148.         }
  149.     }
  150.     // 5.绑定EGLSurface和EGLContext到显示设备(EGLDisplay)
  151.     private void makeCurrent() {
  152.         if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {
  153.             EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
  154.             checkoutConfig("eglMakeCurrent");
  155.         }
  156.     }
  157.     private void checkoutConfig(String tag) {
  158.         int error = EGL14.eglGetError();
  159.         if (error != EGL14.EGL_SUCCESS) {
  160.             Log.e(TAG, tag + " error=0x" + Integer.toHexString(error));
  161.         }
  162.     }
  163.     // EGLConfig参数
  164.     private int[] mEGLConfigAttrs = {
  165.             EGL14.EGL_RED_SIZE, 8,
  166.             EGL14.EGL_GREEN_SIZE, 8,
  167.             EGL14.EGL_BLUE_SIZE, 8,
  168.             EGL14.EGL_ALPHA_SIZE, 8,
  169.             EGL14.EGL_DEPTH_SIZE, 8,
  170.             //EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
  171.             EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR,
  172.             EGL14.EGL_NONE
  173.     };
  174.     // EGLContext参数
  175.     private int[] mEGLContextAttrs = {
  176.             EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,
  177.             EGL14.EGL_NONE
  178.     };
  179.     Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
  180.         @Override
  181.         public void doFrame(long frameTimeNanos) {
  182.             mChoreographer.postFrameCallback(mFrameCallback);
  183.             if (mEGLSurface != null) {
  184.                 mRenderer.onDrawFrame();
  185.                 EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
  186.                 checkoutConfig("eglSwapBuffers");
  187.             }
  188.         }
  189.     };
  190.     /**
  191.      * @author little fat sheep
  192.      * 渲染器接口, 类比GLSurfaceView.Renderer
  193.      */
  194.     interface Renderer {
  195.         void onSurfaceCreated();
  196.         void onSurfaceChanged(int width, int height);
  197.         void onDrawFrame();
  198.     }
  199. }
复制代码
​    MyRenderer.java
  1. package com.zhyan8.egldemo;
  2. import android.content.Context;
  3. import android.opengl.GLES30;
  4. import java.nio.FloatBuffer;
  5. public class MyRenderer implements EGLSurfaceView.Renderer {
  6.     private FloatBuffer vertexBuffer;
  7.     private FloatBuffer textureBuffer;
  8.     private MyGLUtils mGLUtils;
  9.     private int mTextureId;
  10.     public MyRenderer(Context context) {
  11.         mGLUtils = new MyGLUtils(context);
  12.         getFloatBuffer();
  13.     }
  14.     @Override
  15.     public void onSurfaceCreated() {
  16.         //设置背景颜色
  17.         GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f);
  18.         //编译着色器
  19.         final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader);
  20.         final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader);
  21.         //链接程序片段
  22.         int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId);
  23.         GLES30.glUseProgram(programId);
  24.         mTextureId = mGLUtils.loadTexture(R.raw.girl);
  25.     }
  26.     @Override
  27.     public void onSurfaceChanged(int width, int height) {
  28.         //设置视图窗口
  29.         GLES30.glViewport(0, 0, width, height);
  30.     }
  31.     @Override
  32.     public void onDrawFrame() {
  33.         //将颜色缓冲区设置为预设的颜色
  34.         GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
  35.         //启用顶点的数组句柄
  36.         GLES30.glEnableVertexAttribArray(0);
  37.         GLES30.glEnableVertexAttribArray(1);
  38.         //准备顶点坐标和纹理坐标
  39.         GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer);
  40.         GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, textureBuffer);
  41.         //激活纹理
  42.         GLES30.glActiveTexture(GLES30.GL_TEXTURE);
  43.         //绑定纹理
  44.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId);
  45.         //绘制贴图
  46.         GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4);
  47.         //禁止顶点数组句柄
  48.         GLES30.glDisableVertexAttribArray(0);
  49.         GLES30.glDisableVertexAttribArray(1);
  50.     }
  51.     private void getFloatBuffer() {
  52.         float[] vertex = new float[] {
  53.                 1f, 1f, 0f,     //V0
  54.                 -1f, 1f, 0f,    //V1
  55.                 -1f, -1f, 0f,   //V2
  56.                 1f, -1f, 0f     //V3
  57.         };
  58.         float[] texture = {
  59.                 1f, 0f,     //V0
  60.                 0f, 0f,     //V1
  61.                 0f, 1.0f,   //V2
  62.                 1f, 1.0f    //V3
  63.         };
  64.         vertexBuffer = mGLUtils.getFloatBuffer(vertex);
  65.         textureBuffer = mGLUtils.getFloatBuffer(texture);
  66.     }
  67. }
复制代码
​    MyGLUtils.java
  1. package com.zhyan8.egldemo;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.opengl.GLES30;
  6. import android.opengl.GLUtils;
  7. import java.io.BufferedReader;
  8. import java.io.InputStream;
  9. import java.io.InputStreamReader;
  10. import java.nio.ByteBuffer;
  11. import java.nio.ByteOrder;
  12. import java.nio.FloatBuffer;
  13. public class MyGLUtils {
  14.     private Context mContext;
  15.     private Bitmap mBitmap;
  16.     public MyGLUtils(Context context) {
  17.         mContext = context;
  18.     }
  19.     public FloatBuffer getFloatBuffer(float[] floatArr) {
  20.         FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES)
  21.                 .order(ByteOrder.nativeOrder())
  22.                 .asFloatBuffer();
  23.         fb.put(floatArr);
  24.         fb.position(0);
  25.         return fb;
  26.     }
  27.     //通过代码片段编译着色器
  28.     public int compileShader(int type, String shaderCode){
  29.         int shader = GLES30.glCreateShader(type);
  30.         GLES30.glShaderSource(shader, shaderCode);
  31.         GLES30.glCompileShader(shader);
  32.         return shader;
  33.     }
  34.     //通过外部资源编译着色器
  35.     public int compileShader(int type, int shaderId){
  36.         String shaderCode = readShaderFromResource(shaderId);
  37.         return compileShader(type, shaderCode);
  38.     }
  39.     //链接到着色器
  40.     public int linkProgram(int vertexShaderId, int fragmentShaderId) {
  41.         final int programId = GLES30.glCreateProgram();
  42.         //将顶点着色器加入到程序
  43.         GLES30.glAttachShader(programId, vertexShaderId);
  44.         //将片元着色器加入到程序
  45.         GLES30.glAttachShader(programId, fragmentShaderId);
  46.         //链接着色器程序
  47.         GLES30.glLinkProgram(programId);
  48.         return programId;
  49.     }
  50.     //从shader文件读出字符串
  51.     private String readShaderFromResource(int shaderId) {
  52.         InputStream is = mContext.getResources().openRawResource(shaderId);
  53.         BufferedReader br = new BufferedReader(new InputStreamReader(is));
  54.         String line;
  55.         StringBuilder sb = new StringBuilder();
  56.         try {
  57.             while ((line = br.readLine()) != null) {
  58.                 sb.append(line);
  59.                 sb.append("\n");
  60.             }
  61.             br.close();
  62.         } catch (Exception e) {
  63.             e.printStackTrace();
  64.         }
  65.         return sb.toString();
  66.     }
  67.     //加载纹理贴图
  68.     public int loadTexture(int resourceId) {
  69.         BitmapFactory.Options options = new BitmapFactory.Options();
  70.         options.inScaled = false;
  71.         mBitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId, options);
  72.         final int[] textureIds = new int[1];
  73.         // 生成纹理id
  74.         GLES30.glGenTextures(1, textureIds, 0);
  75.         // 绑定纹理到OpenGL
  76.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]);
  77.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR);
  78.         GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
  79.         // 加载bitmap到纹理中
  80.         GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, mBitmap, 0);
  81.         // 生成MIP贴图
  82.         GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D);
  83.         // 取消绑定纹理
  84.         GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
  85.         return textureIds[0];
  86.     }
  87. }
复制代码
​    vertex_shader.glsl
  1. attribute vec4 a_position;
  2. attribute vec2 a_texCoord;
  3. varying vec2 v_texCoord;
  4. void main() {
  5.      gl_Position = a_position;
  6.      v_texCoord = a_texCoord;
  7. }
复制代码
​    fragment_shader.glsl
  1. precision mediump float;
  2. uniform sampler2D u_texture;
  3. varying vec2 v_texCoord;
  4. void main() {
  5.      gl_FragColor = texture2D(u_texture, v_texCoord);
  6. }
复制代码
​    运行效果如下。
1.png

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
  1. package com.zhyan8.egldemo;
  2. import android.content.Context;
  3. import android.graphics.SurfaceTexture;
  4. import android.opengl.EGL14;
  5. import android.opengl.EGLConfig;
  6. import android.opengl.EGLContext;
  7. import android.opengl.EGLDisplay;
  8. import android.opengl.EGLExt;
  9. import android.opengl.EGLSurface;
  10. import android.util.Log;
  11. import android.view.Choreographer;
  12. import android.view.Surface;
  13. import android.view.TextureView;
  14. import androidx.annotation.NonNull;
  15. /**
  16. * @author little fat sheep
  17. * 承载EGL环境的View, 类比GLSurfaceView
  18. */
  19. public class EGLSurfaceView extends TextureView implements TextureView.SurfaceTextureListener {
  20.     private static final String TAG = "EGLSurfaceView";
  21.     protected EGLDisplay mEGLDisplay;
  22.     protected EGLConfig mEGLConfig;
  23.     protected EGLContext mEGLContext;
  24.     protected EGLSurface mEGLSurface;
  25.     protected Context mContext;
  26.     protected Surface mSurface;
  27.     protected Renderer mRenderer;
  28.     private Choreographer mChoreographer = Choreographer.getInstance();
  29.     public EGLSurfaceView(Context context) {
  30.         super(context);
  31.         mContext = context;
  32.         setSurfaceTextureListener(this);
  33.     }
  34.     // 设置渲染器
  35.     public void setRenderer(Renderer renderer) {
  36.         mRenderer = renderer;
  37.     }
  38.     // 开始持续渲染
  39.     public void startRender() {
  40.         Log.i(TAG, "startRender");
  41.         mChoreographer.removeFrameCallback(mFrameCallback);
  42.         mChoreographer.postFrameCallback(mFrameCallback);
  43.     }
  44.     // 暂停持续渲染
  45.     public void stopRender() {
  46.         Log.i(TAG, "stopRender");
  47.         mChoreographer.removeFrameCallback(mFrameCallback);
  48.     }
  49.     // 请求渲染一帧
  50.     public void requestRender() {
  51.         mFrameCallback.doFrame(System.nanoTime());
  52.     }
  53.     @Override
  54.     protected void onAttachedToWindow() {
  55.         super.onAttachedToWindow();
  56.         Log.i(TAG, "onAttachedToWindow");
  57.         createDisplay();
  58.         createConfig();
  59.         createContext();
  60.     }
  61.     @Override
  62.     public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
  63.         Log.i(TAG, "onSurfaceTextureAvailable");
  64.         mSurface = new Surface(surface);
  65.         createSurface();
  66.         makeCurrent();
  67.         mRenderer.onSurfaceCreated();
  68.         mRenderer.onSurfaceChanged(width, height);
  69.     }
  70.     @Override
  71.     public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
  72.         Log.i(TAG, "onSurfaceTextureSizeChanged, width=" + width + ", height=" + height);
  73.         mRenderer.onSurfaceChanged(width, height);
  74.     }
  75.     @Override
  76.     public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
  77.         Log.i(TAG, "onSurfaceTextureDestroyed");
  78.         return false;
  79.     }
  80.     @Override
  81.     public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
  82.     }
  83.     @Override
  84.     protected void onDetachedFromWindow() {
  85.         super.onDetachedFromWindow();
  86.         Log.i(TAG, "onDetachedFromWindow");
  87.         stopRender();
  88.         setSurfaceTextureListener(null);
  89.         mSurface.release();
  90.         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
  91.             // 与显示设备解绑
  92.             EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
  93.             // 销毁 EGLSurface
  94.             if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {
  95.                 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
  96.                 checkoutConfig("eglDestroySurface");
  97.                 mEGLSurface = null;
  98.             }
  99.             // 销毁 EGLContext
  100.             if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {
  101.                 EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
  102.                 checkoutConfig("eglDestroyContext");
  103.                 mEGLContext = null;
  104.             }
  105.             // 销毁 EGLDisplay (显示设备)
  106.             EGL14.eglTerminate(mEGLDisplay);
  107.             checkoutConfig("eglTerminate");
  108.             mEGLDisplay = null;
  109.         }
  110.     }
  111.     // 1.创建EGLDisplay
  112.     private void createDisplay() {
  113.         mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
  114.         int[] versions = new int[2];
  115.         EGL14.eglInitialize(mEGLDisplay, versions,0, versions, 1);
  116.         checkoutConfig("eglInitialize");
  117.     }
  118.     // 2.创建EGLConfig
  119.     private void createConfig() {
  120.         if (mEGLDisplay != null && mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
  121.             EGLConfig[] configs = new EGLConfig[1];
  122.             int[] configNum = new int[1];
  123.             EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,  configNum, 0);
  124.             if (configNum[0] > 0) {
  125.                 mEGLConfig = configs[0];
  126.             }
  127.             checkoutConfig("eglChooseConfig");
  128.         }
  129.     }
  130.     // 3.创建EGLContext
  131.     private void createContext() {
  132.         if (mEGLConfig != null) {
  133.             mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mEGLConfig, EGL14.EGL_NO_CONTEXT, mEGLContextAttrs, 0);
  134.             checkoutConfig("eglCreateContext");
  135.         }
  136.     }
  137.     // 4.创建EGLSurface
  138.     private void createSurface() {
  139.         if (mEGLContext != null && mEGLContext != EGL14.EGL_NO_CONTEXT) {
  140.             int[] eglSurfaceAttrs = { EGL14.EGL_NONE };
  141.             mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mSurface, eglSurfaceAttrs, 0);
  142.             checkoutConfig("eglCreateWindowSurface");
  143.         }
  144.     }
  145.     // 5.绑定EGLSurface和EGLContext到显示设备(EGLDisplay)
  146.     private void makeCurrent() {
  147.         if (mEGLSurface != null && mEGLSurface != EGL14.EGL_NO_SURFACE) {
  148.             EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
  149.             checkoutConfig("eglMakeCurrent");
  150.         }
  151.     }
  152.     private void checkoutConfig(String tag) {
  153.         int error = EGL14.eglGetError();
  154.         if (error != EGL14.EGL_SUCCESS) {
  155.             Log.e(TAG, tag + " error=0x" + Integer.toHexString(error));
  156.         }
  157.     }
  158.     // EGLConfig参数
  159.     private int[] mEGLConfigAttrs = {
  160.             EGL14.EGL_RED_SIZE, 8,
  161.             EGL14.EGL_GREEN_SIZE, 8,
  162.             EGL14.EGL_BLUE_SIZE, 8,
  163.             EGL14.EGL_ALPHA_SIZE, 8,
  164.             EGL14.EGL_DEPTH_SIZE, 8,
  165.             //EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
  166.             EGL14.EGL_RENDERABLE_TYPE, EGLExt.EGL_OPENGL_ES3_BIT_KHR,
  167.             EGL14.EGL_NONE
  168.     };
  169.     // EGLContext参数
  170.     private int[] mEGLContextAttrs = {
  171.             EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,
  172.             EGL14.EGL_NONE
  173.     };
  174.     Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
  175.         @Override
  176.         public void doFrame(long frameTimeNanos) {
  177.             mChoreographer.postFrameCallback(mFrameCallback);
  178.             if (mEGLSurface != null) {
  179.                 mRenderer.onDrawFrame();
  180.                 EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
  181.                 checkoutConfig("eglSwapBuffers");
  182.             }
  183.         }
  184.     };
  185.     /**
  186.      * @author little fat sheep
  187.      * 渲染器接口, 类比GLSurfaceView.Renderer
  188.      */
  189.     interface Renderer {
  190.         void onSurfaceCreated();
  191.         void onSurfaceChanged(int width, int height);
  192.         void onDrawFrame();
  193.     }
  194. }
复制代码
​    运行效果如下。
2.png

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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册