欢迎关注公众号:sumsmile /专注图像处理的移动开发老兵~~
EGL简介
EGL全称:Embedded-System Graphics Library。
显示设备的参数设置有十多种,不同硬件系统之间差异很大,比如有的不支持RGB_565,所以维护OpenGLES的khronos组织专门抽出一层,以适配各平台的差异,这个抽象层即EGL。
OpenGLES定义了平台无关的GL绘图指令,EGL则定义了控制 displays、contexts 以及 surfaces 的统一的平台接口。
java是跨平台的,是因为java虚拟机打平了各平台的差异。同理,EGL打平了各平台底层图形硬件的差异,所以openGL ES才能跨平台。类似的功能库有SDL、GLFW、GLUT等。
下文中GL指的OpenGL ES,不再说明。
为什么要用到EGL
基于GLSurfaceView,就可以很简单的继成GL,Android平台替开发者屏蔽了复杂的EGL,懂一点GL就可以渲染酷炫的效果,在图像、视频处理中有广泛的应用。
弊端是,如果有比较复杂的定制,GLSurfaceView就不够用了。比如应用中有多个GL环境,需要动态切换,或多个GL环境需要共享GLContext(context保存了GL的状态、资源),而GLSurfaceView中EGL的实现是默认写死的。
GLSurfaceView源码中,有一个EglHelper类处理了EGL初始化配置的逻辑,后面还会讲到。
Java层配置EGL,自定义GLSurfaceView,参考
继成SurfaceView,完整实现一个GLSurfaceView,就很清楚的了解GLSurfaceView替我们干了啥。
把最核心的逻辑抠出来,画了张流程图:
GLSurfaceView的工作流程:
- 设置Renderer
- addCallback(SurfaceView方法)
- 实现EGLThread(常说的渲染线程)
- 初始化EGL
- while(true)中循环调用onSurfaceCreated()、onSurfaceChanged()、onDrawFrame()
从实现EglHelper.java开始,仿照GLSurfaceView自己实现一遍
实现EglHelper,封装EGL初始化逻辑
EGL像个中介,把Display、Surface、Context绑到一起,让这三者结合到一起,紧密配合,碰撞出爱的火花。初始化及绑定的工作封装在EglHelper中。
上图用代码实现,流程如下:
EGL实例
- 得到Egl实例
Display
- 得到默认的显示设备(就是窗口)
- 初始化默认显示设备
- 设置显示设备的属性
- 从系统中获取对应属性的配置
Context
- 创建EglContext
Surface
- 创建渲染的Surface
绑定
- 绑定EglContext和Surface到显示设备中
渲染到屏幕
- 刷新数据,显示渲染场景
EGL设置略繁琐,但是逻辑并不复杂,详细参考github代码
GLSurfaceView实现
GLSurfaceView最核心的逻辑是实现了GLThread,该线程中处理了EGL初始化,以及drawFrame等重要回调
GLThread run()函数实现比较重要单独拿出来看看,完整代码参考
重点关注:
- EGLHelper初始化
- 不同的RenderMode,如何处理
- onCreate() onChange(width, height) onDraw()回调时机
@Override
public void run() {
super.run();
try {
guardedRun();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void guardedRun() throws InterruptedException {
isExit = false;
isStart = false;
object = new Object();
mEglHelper = new EglHelper();
mEglHelper.initEgl(mEGLSurfaceViewWeakRef.get().mSurface, mEGLSurfaceViewWeakRef.get().mEglContext);
while (true) {
if (isExit) {
// 释放资源
release();
break;
}
if (isStart) {
if (mEGLSurfaceViewWeakRef.get().mRenderMode == RENDERMODE_WHEN_DIRTY) {
synchronized(object) {
// 自动绘制模式下,等待数据更新通知
object.wait();
}
} else if (mEGLSurfaceViewWeakRef.get().mRenderMode == RENDERMODE_CONTINUOUSLY) {
// 近似1秒绘制60次
Thread.sleep(1000 / 60);
} else {
throw new IllegalArgumentException("renderMode");
}
}
// 三个重要的回调,回调里有判断是否需要执行
onCreate();
onChange(width, height);
onDraw();
isStart = true;
}
}
Activity中使用自定义的GLSurfaceView
demo很简单,点击GLSurfaceView,触发更改颜色。重要的是把整个流程串起来,弄明白了,可以使用OpenGL定义更有意思的效果。
实现效果:
完成Demo:
public class EglMainActivity extends AppCompatActivity implements EglSurfaceView.Renderer{
public static final String TAG = "EglMainActivity";
private EglSurfaceView eglSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
eglSurfaceView = new EglSurfaceView(this);
setContentView(eglSurfaceView);
eglSurfaceView.setRenderer(this);
eglSurfaceView.setRendererMode(EglSurfaceView.RENDERMODE_WHEN_DIRTY);
eglSurfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
eglSurfaceView.requestRender();
}
});
}
@Override
public void onSurfaceCreated() {
Log.e(TAG, "onSurfaceCreated");
}
@Override
public void onSurfaceChanged(int width, int height) {
Log.e(TAG, "onSurfaceChanged");
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame() {
Log.e(TAG, "onDrawFrame");
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
float r = (float) Math.random();
float g = (float) Math.random();
float b = (float) Math.random();
GLES20.glClearColor(r, g, b, 1.0f);
}
}
补充:
-
GL线程分析,这篇文章讲的非常好,建议认真阅读
Native层配置EGL
开发复杂的渲染功能时,opengl egl相关的代码放到C++层更方便,比如搭建一个渲染引擎,大多数库都是c++版本的。另一方面,C++层执行逻辑效率会高一些。
需要对NDK、C++开发有一定的了解。
接下来,我们讲讲Native方式配置EGL,逻辑和Java层的差不多。
完整工程:
重点讲不一样的地方:
Android Studio 新建C++工程
工程目录:
代码逻辑:
CMakeLists.txt配置
# cmake最小版本
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
SHARED
native-lib.cpp
egl/EglHelper.cpp
egl/EglThread.cpp
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
EGL
GLESv2
android
)
实现EglHelper.cpp EglThread.cpp
逻辑与java层差不多,换成c++实现而已,详细参考工程代码
封装jni
jni逻辑放在native-lib.cpp,是C++工程自动创建的文件,名字我也懒得改,就在里面造了。比较简单:
...
EglThread *eglThread = NULL;
// surfaceCreate回调
void callBackOnCreate(){
LOGE("callBackOnCreate");
}
// surface size change回调
void callBackOnChange(int width, int height){
LOGE("callBackOnChange");
}
// 最重要的draw回调
void callBackOnDraw(){
glClearColor(0.0, 1.0, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
LOGE("callBackOnDraw");
}
// native接口,surfaceCreate
// 设置好三个重要的回调指针,设置渲染模式
// 从SurfaceView中获取ANativeWindow
extern "C"
JNIEXPORT void JNICALL
Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceCreate(JNIEnv *env,jobject thiz,jobject surface) {
eglThread = new EglThread();
eglThread->callBackOnCreate(callBackOnCreate);
eglThread->callBackOnChange(callBackOnChange);
eglThread->callBackOnDraw(callBackOnDraw);
eglThread->setRenderModule(RENDER_MODULE_MANUAL);
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
eglThread->onSurfaceCreate(nativeWindow);
}
// 调用surfaceChange
extern "C"
JNIEXPORT void JNICALL
Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceChanged(JNIEnv *env, jobject thiz,jint width,jint height) {
if(eglThread){
eglThread->onSurfaceChange(width, height);
}
}
// 调用SurfaceDestroyed
extern "C"
JNIEXPORT void JNICALL
Java_com_android_samples_nativeegl_opengl_NativeOpenGL_nativeSurfaceDestroyed(JNIEnv *env,jobject thiz) {
if(eglThread){
eglThread->isExit = true;
//等待线程结束
pthread_join(eglThread->mEglThread, NULL);
delete eglThread;
eglThread = NULL;
}
}
NativeGLSurfaceView实现
NativeGLSurfaceView继承SurfaceView,几乎是个壳子,关键方法里调到Native方法
class NativeGLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private NativeOpenGL mNativeOpenGL;
public NativeGLSurfaceView(Context context) {
this(context, null);
}
public NativeGLSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NativeGLSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mNativeOpenGL = new NativeOpenGL();
getHolder().addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mNativeOpenGL.nativeSurfaceCreate(holder.getSurface());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mNativeOpenGL.nativeSurfaceChanged(width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mNativeOpenGL.nativeSurfaceDestroyed();
}
}
NativeOpenGL封装Native方法 java层接口 so easy
class NativeOpenGL {
static {
System.loadLibrary("native-lib");
}
public native void nativeSurfaceCreate(Surface surface);
public native void nativeSurfaceChanged(int width, int height);
public native void nativeSurfaceDestroyed();
}
最后在Activity中调用NativeGLSurfaceView
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
SurfaceView写在布局中
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.android.samples.nativeegl.opengl.NativeGLSurfaceView
android:id="@+id/sample_text"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
实现效果很简单,随便画个颜色
你也可以改成自己喜欢的颜色 修改native-lib.cpp callBackOnDraw方法
void callBackOnDraw(){
glClearColor(0.0, 1.0, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
LOGE("callBackOnDraw");
}
开发一个完整的demo,涉及到不少细节,无法在一篇文章中详细阐述,读者朋友们有时间,可以读读文末附录的参考
欢迎关注公众号:sumsmile /专注图像处理的移动开发老兵~~
参考
[1] Android配置EGL环境: www.jianshu.com/p/ce3496ab9…
[2] Android自定义GLSurfaceView: www.jianshu.com/p/08f9338ae…
[3] EglHelper实现: github.com/summer-go/A…
[4] EglSurfaceView实现: github.com/summer-go/A…
[5] 剖析EGL及GL线程源码: cloud.tencent.com/developer/a…
[6] EGL OpenGLES版本选择: www.cnblogs.com/kiffa/archi…
[7] eglmakeCurrent api: www.khronos.org/registry/EG…;
[8] makeCurrent、eglSwapBuffers: www.zybuluo.com/SR1s/note/6…
[9] 非常棒的EGL opengl示意图: www.icode9.com/content-4-6…
[10] c++ lock使用: blog.csdn.net/u012109245/…
[11] android c++ EGL环境实现: www.jianshu.com/p/cb34f965a…
今天的文章Android Camera开发实践(3)EGL原理及使用分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19590.html