目录
1 GLsurfaceview 的定义和作用
2 GLsurfaceview 使用
3 GLsurfaceview 源码分析
正文
1 GLsurfaceview定义&作用:
GLSurfaceView继承于SurfaceView,主要用于配合OpenGL ES的接口执行渲染窗口的任务。
GLsurfaceview=surfaceview+surfaceTexture+opengl+eglhelper.
(surface,surfaceview,surfaceTexture说明请点这里).
2 GLsurfaceview 使用:
下面是标准使用流程,引用自:https://blog.csdn.net/MarRn/article/details/100897530
1)、在layout文件中使用android.opengl.GLSurfaceView,代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.opengl.GLSurfaceView
android:id="@+id/surfaceview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
2)、自定义Renderer
其中onDrawframe 编写glsl脚本(shader)
public class TestRenderer implements GLSurfaceView.Renderer{
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
...
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置窗口大小
GLES20.glViewport(0, 0, width, height);
}
public void onDrawFrame(GL10 gl) {
//执行清屏
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(0.0f, 0.1f, 0.0f, 1.0f);
}
}
3)、给GLSurfaceView设置Renderer
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
glSurfaceView = (GLSurfaceView)findViewById(R.id.surfaceview);
TestRenderer renderer = new TestRenderer();
glSurfaceView.setRenderer(renderer);
}
小结:camera 采集-->回调到surface(buffer)-->render渲染输出到屏幕(surfaceview在xml中config的.)
3 GLsurfaceview类的组成 :
GLThread内部类:OpenGL ES的运行线程。包含创建EGL环境、调用GLRender的onSurfaceCreated、onSurfaceChanged和onDrawFrame方法以及生命周期的管理。
EglHelper内部类:负责创建EGL环境。包括start,createSurface,swap等.
GLSurfaceView:负责提供Surface和状态改变。
4 源码分析
4.1 Init
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {
//1=================================
private static final GLThreadManager sGLThreadManager = new GLThreadManager();//多个GLthread共享
private GLThread mGLThread; // GL 线程
private Renderer mRenderer; // GLSurfaceView 的回调接口
public void setRenderer(Renderer renderer) { // 设置渲染接口
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
mEGLContextFactory = new DefaultContextFactory();
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
mRenderer = renderer;
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
//2===GLsurfaceview接口仅仅是个wrapper,真正执行的是GLthread对应函数=================
//set mHasSurface=true
public void surfaceCreated(SurfaceHolder holder) {
mGLThread.surfaceCreated();
}
//set width&height
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mGLThread.onWindowResize(w, h);
}
public void requestRender() {
mGLThread.requestRender();
}
public void queueEvent(Runnable r) {
mGLThread.queueEvent(r);
}
//3=========================
private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,EGLConfig config, Object nativeWindow) {
EGLSurface result = null;
result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
return result;
}
}
}
4.2 EglHelper内部类: wrapper egl 操作,负责创建EGL环境
/*An EGL helper class.*///egl=display+context+surface
//create egl surface&context&opengl,swap surface to target
private static class EglHelper {
public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
}
//1===========
public void start() {
/*Get an EGL instance */
mEgl = (EGL10) EGLContext.getEGL();
/*Get to the default display.*/
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
/*We can now initialize EGL for that display */
int[] version = new int[2];
mEgl.eglInitialize(mEglDisplay, version)
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);//颜色、深度、模板等等设置
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
mEglSurface = null;
}
//2=============
public boolean createSurface() {
/*Create an EGL surface we can render into. */
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglSurface=view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,mEglDisplay, mEglConfig,view.getHolder());
//绑定context和surface
mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
}
//3============
GL createGL() {
GL gl = mEglContext.getGL();
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
return gl;
}
//4 /*Display the current render surface.*/
public int swap() {
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)
}
private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
}
4.3 GLthread
Render框架:onSurfaceCreated(),onSurfaceChanged(),onDrawFrame()。
onSurfaceCreated() :在开始渲染的时候被调用,无论什么时候OpenGL ES 渲染不得不重新被创建.
onSurfaceChanged():该方法在surface大小改变时被调用。
onDrawFrame():每帧的时候该方法都会被调用.
1 ) 调用guardedRun
static class GLThread extends Thread {
private EglHelper mEglHelper; // EGL环境的帮助类
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();//event queue是每个GLthread 私有
private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
// 构造函数
GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
......
mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
}
public void run() {
//最最最重要的逻辑
guardedRun();
}
2 ) guardedRun() 函数
处理两种情况:
scenario1: camera 采集自动回调.frameAvailale新来一帧: GLsurfaceview.requestrender--- onDrawFrame.
scenario2: GLsurfaceView手动执行opengl(filter)操作: GLsurfaceview.queueEvent.add(r)--- GLsurfaceview.queueEvent.remove(r)&r.run
流程图:
image
a) ReadyToDraw: 当发送GLsurfaceview.requestRender的时候,mRequestRender=true,
// 判断是否准备好开始 draw
private boolean readyToDraw() {
return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
&& (mWidth > 0) && (mHeight > 0)
// 如果是 RENDERMODE_CONTINUOUSLY 渲染模式,则不需要调用 requestRender() 也会一直调用onDrawFrame() 进行渲染
&& (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
}
b) 两个线程同步实现 (重点)
发送端:
requestRender:收到camera采集数据,设置画图开关&唤醒线程。
/*Request that the renderer render a frame. *///设置开关&唤醒线程
public void requestRender() {
synchronized(sGLThreadManager) {
mRequestRender = true;
sGLThreadManager.notifyAll();
}
}
QueueEvent: 由于操作 OpenGL 环境只能通过 GL线程,所以GLSurfaceView 提供了 queueEvent() 函数,将待执行的 runnable 添加到 GLThread 中的队列中。
/*Queue a runnable to be run on GL rendering thread.Renderer communicate with it on the rendering thread*/
//入参就是一个runnable 线程实体
//向queue添加runnable task&唤醒线程
public void queueEvent(Runnable r) {
synchronized(sGLThreadManager) {
mEventQueue.add(r);
sGLThreadManager.notifyAll();
}
}
UI线程运行上面两个函数之后,任务完成。后面画图工作是另一个线程GLthread处理.
接收端:
核心内容: 双循环
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);//创建Eglhelper类
while (true) {//外循环处理业务逻辑event.run和ondrawframe
synchronized (sGLThreadManager) {
while (true) {//内循环两种消息路由
//scenario1: step1 读取GLsurfaceview.queueevent发送的task,然后退出内循环
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
if (readyToDraw()) {//requestRender
// If we don't have an EGL context, try to acquire one.
if (! mHaveEglContext) {//只第一次执行
mEglHelper.start();//
mHaveEglContext = true;
createEglContext = true;
sGLThreadManager.notifyAll();
}
if (mHaveEglContext && !mHaveEglSurface) {//只第一次执行
mHaveEglSurface = true;
createEglSurface = true;
createGlInterface = true;
sizeChanged = true;
}
//scenario2的情况每次都会执行
if (mHaveEglSurface) {
......
//===scenario2:requestRender--onDrawFrame.
//==step1 退出内循环&唤醒GLsurfaceView所有GLthread
mRequestRender = false;
sGLThreadManager.notifyAll();
break;
}
}
//==scenario1: step3 阻塞,线程同步:等待queueevent;==
sGLThreadManager.wait();
}//内循环end
} // end of synchronized(sGLThreadManager)
//===scenario1: step2 运行GLsurfaceview.queueevent (runnable)===
if (event != null) {
event.run();
event = null;
continue;
}
if (createEglSurface) {//只第一次执行
mEglHelper.createSurface()
createEglSurface = false;
}
if (createGlInterface) {//只第一次执行
gl = (GL10) mEglHelper.createGL();
createGlInterface = false;
}
if (createEglContext) {//只第一次执行
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
createEglContext = false;
}
//==scenario2: step2 外循环的时候每次都执行。
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
view.mRenderer.onDrawFrame(gl);
//scenario2: step3 onDrawFrame中opengl将数据画到suface,这句是将surface上数据画到display(双缓冲surface,是前后surface交换,前端surface即是display)
int swapError = mEglHelper.swap();
switch (swapError) {
case EGL10.EGL_SUCCESS:
break;
......
}
}
附录:GLsurfaceview 源码
参考:
Android Camera开发:使用GLSurfaceView预览Camera 基础拍照:https://blog.csdn.net/yanzi1225627/article/details/33339965
Android Camera使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜):https://blog.csdn.net/lb377463323/article/details/77071054
[-综合篇-] 相机、OpenGL、视频、Flutter和SurfaceView:https://www.imooc.com/article/293406
Android: Camera相机开发详解(中) ——实现预览、拍照、保存照片等功能 https://www.jianshu.com/p/e20a2ad6ad9a
GLSurfaceView 源码分析 & EGL 创建过程 https://www.pianshen.com/article/8421310032/
网友评论