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

1 前言

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

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

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

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

cpp 复制代码
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

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

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

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

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

cpp 复制代码
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

cpp 复制代码
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

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,如何渲染图像

相关推荐
CHPCWWHSU2 天前
osg中相机矩阵到vsg相机矩阵的转换
opengl·osg·投影矩阵·vulkan·vsg
农场主er9 天前
Metal - 5.深入剖析 3D 变换
3d·opengl·transform·matrix·metal
♡すぎ♡24 天前
创建GLFW窗口,开启OpenGL之路
opengl
AJi25 天前
EGL使用记录
前端·opengl
华溢澄1 个月前
macOS下基于Qt/C++的OpenGL开发环境的搭建
c++·qt·macos·opengl
Kapaseker1 个月前
大师级 Compose 图形编程—AGSL 入门
android·kotlin·opengl
onthewaying2 个月前
详解 Android GLSurfaceView 与 Renderer:开启你的 OpenGL ES 之旅
android·opengl
灿烂阳光g2 个月前
OpenGL Camera
opengl
用户619533334172 个月前
为ChatGPT和API集成构建MCP服务器
openai·opengl