坡琨 发表于 5 天前

【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;
      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;
            int[] configNum = new int;
            EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,configNum, 0);
            if (configNum > 0) {
                mEGLConfig = configs;
            }
            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;
      // 生成纹理id
      GLES30.glGenTextures(1, textureIds, 0);
      // 绑定纹理到OpenGL
      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds);
      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;
    }
}​    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);
}​    运行效果如下。

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;
      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;
            int[] configNum = new int;
            EGL14.eglChooseConfig(mEGLDisplay, mEGLConfigAttrs, 0, configs, 0,1,configNum, 0);
            if (configNum > 0) {
                mEGLConfig = configs;
            }
            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,如何渲染图像。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 【OpenGL ES】不用GLSurfaceView,如何渲染图像