1.java层使用EGL和OpengLES的两种方式
第一种:使用GLES类,这些类会通过jni 的方式调用到c/c++层的EGL和OpenGLES(这种方式程序编写方式复杂)
第二种:GLSurfaceView
GLSurfaceView继承自SurfaceView,也就意味着它有所有view类的功能和属性,特别是处理事件的能力,同时GLSurfaceView也拥有OpenGlES所提供的图形处理能力
GLSurfaceView的功能
- 管理EGLDisplay,它表示一个显示屏
- 管理Surface(本质是一块内存区域)
- GLSurfaceView会创建新的线程,以使整个渲染过程不会阻塞UI主线程
- 用户可以自定义渲染方式,如通过setRenderer设置一个Renderer
2.GLSurfaceView的使用步骤
第一步:创建GLSurfaceView
GLSurfaceView也是View,可以通过布局文件的方式将它加入整棵view树中
第二步:初始化OpenGLES环境
GLSurfaceView默认情况下已经为开发人员搭建好了OpenGLES的运行环境,因而如果没有特别的要求,并不需要做额外的工作。开发人员可以更改一些默认的设置
setEGLConfigChooser(boolean);
setGLWrraper(GLWrapper);
第三步:设置Renderer
渲染是OpenGLES的核心工作,setRenderer可以将用户自定义的一个Renderer加入实际的渲染流程中。
第四步:设置RenderingMode
GLSurfaceView默认采用的是连续渲染的方式,如有需要可以通过这个方法更改渲染方式
第五步:状态处理
使用GLSurfaceView需要注意程序的声明周期,Activity会有暂停和恢复等状态,为了达到最优效果,GLSurfaceView也需根据这些状态来做相应的处理,比如Activity暂停时需要GLSurfaceView的onPause,恢复时需要GLSurfaceView的onResume等,这样能使OpenGLES的内部线程做出正确的判断,从而保证应用程序的稳定性
开发基于GLSurfaceView的程序,主要的工作就是设置Renderer,其他过程,例如EGL的创建,Surface的分配以及OpenGLES的调用都被隐藏起来了。
3.GLSurfaceView的创建过程
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public GLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed
SurfaceHolder holder = getHolder();
holder.addCallback(this); //添加回调,这样surface有变化的时候就能收到通知了
}
//..........
}
3.1 Callback
public interface Callback {
/**当成功申请到一个Surface的时候被调用,一般情况下只会发生一次
* This is called immediately after the surface is first created.
* Implementations of this should start up whatever rendering code
* they desire. Note that only one thread can ever draw into
* a Surface, so you should not draw into the Surface here
* if your normal rendering will be in another thread.
*/
public void surfaceCreated(SurfaceHolder holder);
/**当Surface改变时调用,如format和size的更动
* This is called immediately after any structural changes (format or
* size) have been made to the surface. You should at this point update
* the imagery in the surface. This method is always called at least
* once, after surfaceCreated
*/
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height);
/**当Surface销毁时调用
* This is called immediately before a surface is being destroyed. After
* returning from this call, you should no longer try to access this
* surface. If you have a rendering thread that directly accesses
* the surface, you must ensure that thread is no longer touching the
* Surface before returning from this function
*/
public void surfaceDestroyed(SurfaceHolder holder);
}
3.2SurfaceHolder的创建
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
//....
public void addCallback(Callback callback) {
synchronized (mCallbacks) {
if (mCallbacks.contains(callback) == false) {
mCallbacks.add(callback);
}
}
}
//....
}
SurfaceView中,mSurfaceHolder 是一个全局变量,addCallback用于将接受回调通知的类加入到mCallbacks队列中,如GLSurfaceView在构造方法中调用addCallback方法,这样当SurfaceHolder有变化的时候就能通知到GLSurfaceView。
3.3 SurfaceView中surface的申请(与一般的View不同)
TU 17-11SurfaceView中Surface的申请过程
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
//mSession是ViewRoot与WMS的通信中介
mSession = getWindowSession();
mLayout.token = getWindowToken();
mLayout.setTitle("SurfaceView");
//...
}
private void updateWindow(boolean force, boolean redrawNeeded) {
ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE,
WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mContentInsets,
mVisibleInsets, mConfiguration, mNewSurface);
mSurface.transferFrom(mNewSurface);
}
1.一般情况下,SurfaceView是布局在某个ViewGroup中的,当ViewRoot成功AttachToWindow之后,它需要将这一事件告诉View树中的所有成员
2.SurfaceView收到AttachToWindow成功的消息后,会通过getWindowSession方法获取一个IWindowSession,IWindowSession是ViewRoot与WMS的通信中介。
3.SurfaceView在updateWindow的时候,利用IWindowSession.relayout()来重新申请一个Surface,其中最后一个参数就是WMS新生成的Surface。
4.SurfaceView获取到新的Surface之后,会Transfer到mSurface变量中,然后再通知所有注册了Callback的对象,如GLSurfaceView。这样SurfaceView的Surface就创建成功了。
3.4Surface申请成功之后,GLSurfaceView的操作
public void surfaceCreated(SurfaceHolder holder) {
mGLThread.surfaceCreated();
}
public void surfaceCreated() {
synchronized(sGLThreadManager) {
mHasSurface = true;
mFinishedCreatingEglSurface = false;
sGLThreadManager.notifyAll();
while (mWaitingForSurface
&& !mFinishedCreatingEglSurface
&& !mExited) {
sGLThreadManager.wait();
}
}
}
GLSurfaceView会启动一个工作线程来完成渲染,避免阻塞UI主线程,这个工作线程就是mGLThread,这个线程在应用程序setRederer的时候启动,然后不停地等待和处理事件,同时还负责开展Render工作。
public void setRenderer(Renderer renderer) {
checkRenderThreadState();
mRenderer = renderer;
//mGLThread在setRenderer时初始化并启动
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
static class GLThread extends Thread {
@Override
public void run() {
guardedRun();
}
}
3.5 guardedRun
private void guardedRun() throws InterruptedException {
while (true) {//死循环,除非主动跳出
synchronized (sGLThreadManager) {
while (true) {
if (mShouldExit) {//是否需要结束循环
return;
}
//从EventQueue中取出消息
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
// When pausing, release the EGL surface:
if (pausing && mHaveEglSurface) {
//如果acitivity已经暂停,释放surface
stopEglSurfaceLocked();
}
// When pausing, optionally release the EGL Context:
// Have we lost the SurfaceView surface?
//判断Surface是否丢失
if ((! mHasSurface) && (! mWaitingForSurface)) {
//如果当前没有Surface,而且也不再等待Surface的创建,说明已经失去了Surface
if (mHaveEglSurface) {
stopEglSurfaceLocked();
}
mWaitingForSurface = true;
mSurfaceIsBad = false;
sGLThreadManager.notifyAll();
}
// Have we acquired the surface view surface?
if (mHasSurface && mWaitingForSurface) {
//如果已经成功获取到Surface,那就重新设置相应的全局变量
mWaitingForSurface = false;
//通知任何在等待的线程
sGLThreadManager.notifyAll();
}
// Ready to draw?
if (readyToDraw()) {
//这里是最核心的工作,根据应用程序设置的Renderer来进行图形渲染
}
sGLThreadManager.wait();
}
} // end of synchronized(sGLThreadManager)
if (event != null) {
event.run();
event = null;
continue;
}
if (createEglSurface) {//EglSurface需要被创建
//.....创建
//创建成功之后设置标志位
createEglSurface = false;
}
if (sizeChanged) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {//通知应用程序发生了变化
view.mRenderer.onSurfaceChanged(gl, w, h);
}
sizeChanged = false;
}
{
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {//调用应用程序的Renderer
view.mRenderer.onDrawFrame(gl);
}
}
//通过swap把渲染结果显示到屏幕上
int swapError = mEglHelper.swap();
}
}
第一步:判断事件队列是否为空,如果有事件需要处理,则直接跳出内循环,否则依然在内循环运行
第二步:1.判断是否需要释放EGLSurface,2.判断是否丢失了Surface,mHasSurface表示当前有没有可用的Surface,mWaitingForSurface表示是否在申请Surface的过程中,3.是否需要放弃EGLContext
第三步:经过以上的判断之后,程序进入图形渲染前的准备工作,也就是readyToDraw之间的代码
第四步:一旦程序执行到这里也就是跳出了内循环,有两种可能,第一是EventQueue中有需要处理的事件,第二是需要执行渲染工作
3.6 readyToDraw
// Ready to draw?
if (readyToDraw()) {
// If we don't have an EGL context, try to acquire one.
if (! mHaveEglContext) {//没有EGLContext的情况下
//判断是否要建立EGLContext
if (askedToReleaseEglContext) {
askedToReleaseEglContext = false;
} else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
try {
mEglHelper.start();
} catch (RuntimeException t) {
sGLThreadManager.releaseEglContextLocked(this);
throw t;
}
mHaveEglContext = true;
createEglContext = true;
sGLThreadManager.notifyAll();
}
}
if (mHaveEglSurface) {//有EGLSurface
mRequestRender = false;
sGLThreadManager.notifyAll();
break;
}
}
判断两个关键因素:EGLContext和EGLSurface是否存在并有效,如果没有EGLContext,就需要获取一个,如果当前有EGLSurface但尺寸发生了变化,那么就需要销毁他并重新申请Surface
可以渲染图形的条件是:1.程序当前不处于pause状态2.已经成功获得Surface3.有合适的尺寸4.处于自动持续渲染状态,或者用户发起了渲染请求
3.7 执行渲染工作的处理流程
- 是否需要重新申请EGLSurface,如果尺寸发生了变化,此时createEGLSurface为true
- 是否需要申请GLObject,此时createGLinterface为true
- 是否需要生成EGLContext,此时createEGLContext为true
- 尺寸是否变化,sizeChanged为true,此时需要通知观察者
- 一切准备好之后,调用view.mRenderer.onDrawFrame进行真正的渲染
- 最后通过swap把渲染结果显示到屏幕
3.8 EGLHelper
readyToDraw中调用了start方法,然后跳出readyToDraw后调用了createSurface方法
第一步:
public void start() {
mEgl = (EGL10) EGLContext.getEGL();//获取一个EGL实例
//获取一个EGLDisplay
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
//初始化EGL并返回版本号
if(!mEgl.eglInitialize(mEglDisplay, version)) {
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
//选取一个配置
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
//创建EGLContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
mEglSurface = null;
}
第二步:mEglHelper.createSurface()
public boolean createSurface() {
if (LOG_EGL) {
Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
}
/*
* Check preconditions.
*/
if (mEgl == null) {
throw new RuntimeException("egl not initialized");
}
if (mEglDisplay == null) {
throw new RuntimeException("eglDisplay not initialized");
}
if (mEglConfig == null) {
throw new RuntimeException("mEglConfig not initialized");
}
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
mEglDisplay, mEglConfig, view.getHolder());
return true;
}
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;
}
}
第三步:
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}
4.总结
GLSurfaceView使用EGL的流程
1.生成一个EGL实例
mEgl = (EGL10) EGLContext.getEGL();
2.获取一个EGL Display
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
3.初始化EGL并返回版本号
if(!mEgl.eglInitialize(mEglDisplay, version)) {
}
4.选取一个配置
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
5.创建一个EGLContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
6.创建EGLSurface
egl.eglCreateWindowSurface(display, config, nativeWindow, null);
7.通过swap将渲染内容显示到屏幕
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)
wms2
http://blog.csdn.net/xuesen_lin/article/details/8954748
网友评论