GLSurefaceView继承自SurfaceView,同时也拥有了OpenGL ES所提供的的强大的3D图形处理功能。目前主流的移动游戏引擎都使用该View。
GLSurefaceView的主要特性:
1、管理EGLDisplay,它表示一个显示屏
2、管理Surface(本质上就是一块内存区域)
3、GLSurefaceView会创建新的线程,以使整个渲染过程不至于阻塞UI主线程
4、用户可以自定义渲染方式,如通过setRender()设置一个Render。
使用基本步骤:
1、创建GLSurefaceView
2、初始化OpenGL ES环境
环境可以自己设置,ex:
setEGLConfigChooser(boolean);
setGLWrapper(GLWrapper);
getHolder().setFormat(PixelFormat,TRANSLUCENT)
setDebugFlag(int)
3、设置Renderer,setRender()可以将用户自定义的一个Renderer加入实际的渲染流程中
setRenderer(Renderer renderer);
4、设置Rendering Mode,默认情况下采用的是连续的渲染方式。
setRenderMode(RENDERMODE_WHEN_DIRTY);
5、状态处理
注意处理程序的声明周期,例如Activity的暂停和恢复情况下的处理,在pause触发时,调用GLSurefaceView的onPause(),恢复时再调用onResume。
上述步骤发现,我们主要关注Renderer的实现,而EGL的创建过程,Surface的分配以及OpenGL ES的一些调用细节等都会被隐藏起来了。
实现原理:
其构造函数除了调用了其父类的方法就直接进入了init()方法
private void init() {
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
该方法先通过父类获取当前的SurefaceHolder,然后添加自身为回调函数(自身实现了SurfaceHolder.Callback2,CallBack2继承自SurfaceHolder.Callback),这样每当Surface有变化时,就能收到通知了。
//当成功申请到一个Surface时调用,正常情况下只会发生一次
public void surfaceCreated(SurfaceHolder holder);
//当Surface改变时调用,如format,size的变动
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height);
//当Surface销毁时调用
public void surfaceDestroyed(SurfaceHolder holder);
SurfaceHolder如何被创建
SurfaceView.java
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
....
}
他是一个全局变量,在一开始就已经创建了实例。
Surface如何创建
SurfaceView继承于View,View树在ViewRoot创建时会申请到一个Surface。而SurfaceView的这个SurfaceView并非和ViewRoot的Surface是同一个。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
//SurfaceView没有必要自己在创建一个ViewRoot,直接通过ViewRoot获取一个IWindowSession
mSession = getWindowSession();
mLayout.token = getWindowToken();
mLayout.setTitle("SurfaceView");
mViewVisibility = getVisibility() == VISIBLE;
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnScrollChangedListener(mScrollChangedListener);
observer.addOnPreDrawListener(mDrawListener);
mGlobalListenersAdded = true;
}
}
onAttachedToWindow为updateWindow提供触发 源码链接
/** @hide */
protected void updateWindow(boolean force, boolean redrawNeeded) {
if (!mHaveFrame) {
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
....................
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mLeft != mLocation[0] || mTop != mLocation[1]
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded || layoutSizeChanged) {
try {
final boolean visible = mVisible = mRequestedVisible;
mLeft = mLocation[0];
mTop = mLocation[1];
mWidth = myWidth;
mHeight = myHeight;
mFormat = mRequestedFormat;
mLayout.x = mLeft;
mLayout.y = mTop;
mLayout.width = getWidth();
mLayout.height = getHeight();
if (mTranslator != null) {
mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
}
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
if (mWindow == null) {
Display display = getDisplay();
mWindow = new MyWindow(this);
mLayout.type = mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
mStableInsets);
}
boolean realSizeChanged;
boolean reportDrawNeeded;
int relayoutResult;
mSurfaceLock.lock();
try {
mUpdateWindowNeeded = false;
reportDrawNeeded = mReportDrawNeeded;
mReportDrawNeeded = false;
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, "Cur surface: " + mSurface);
//重新申请一个Surface
relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInsets, mContentInsets,
mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
mNewSurface);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportDrawNeeded = true;
}
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
mSurfaceFrame.right = mWinFrame.width();
mSurfaceFrame.bottom = mWinFrame.height();
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
final int surfaceHeight = mSurfaceFrame.bottom;
realSizeChanged = mLastSurfaceWidth != surfaceWidth
|| mLastSurfaceHeight != surfaceHeight;
mLastSurfaceWidth = surfaceWidth;
mLastSurfaceHeight = surfaceHeight;
} finally {
mSurfaceLock.unlock();
}
try {
redrawNeeded |= creating | reportDrawNeeded;
SurfaceHolder.Callback callbacks[] = null;
final boolean surfaceChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
}
}
mSurface.transferFrom(mNewSurface);
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
if (DEBUG) Log.i(TAG, "visibleChanged -- surfaceCreated");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
if (DEBUG) Log.i(TAG, "surfaceChanged -- format=" + mFormat
+ " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
if (redrawNeeded) {
//申请了全新的Surface后,会通知到所有注册了callback函数的对象。
if (DEBUG) Log.i(TAG, "surfaceRedrawNeeded");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
if (c instanceof SurfaceHolder.Callback2) {
((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
mSurfaceHolder);
}
}
}
}
} finally {
mIsCreating = false;
if (redrawNeeded) {
if (DEBUG) Log.i(TAG, "finishedDrawing");
mSession.finishDrawing(mWindow);
}
mSession.performDeferredDestroy(mWindow);
}
} catch (RemoteException ex) {
}
}
}
GLSurfaceView将会启动一个新线程来完后渲染,以防止程序阻塞UI线程(GLThread),其在setRenderer时启动,然后不断等待和处理事件,同时还负责开展Render工作
public void surfaceCreated() {
synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
mFinishedCreatingEglSurface = false;
sGLThreadManager.notifyAll();
while (mWaitingForSurface
&& !mFinishedCreatingEglSurface
&& !mExited) {
try {
sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
参考:
《深入理解Android内核设计思想》