Android GLSurfaceView笔记
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是同一个。
@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();mParent.requestTransparentRegion(this);//SurfaceView没有必要自己在创建一个ViewRoot,直接通过ViewRoot获取一个IWindowSessionmSession = 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);//重新申请一个SurfacerelayoutResult = 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内核设计思想》
Android GLSurfaceView笔记相关推荐
- Android开发笔记(序)写在前面的目录
知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经验教训,与网友互相切磋,从而去芜存菁进一步提升自己的水平.因此博主就想,入门的东西咱就不写了,人不能老停留在入 ...
- Android开发笔记(一百五十六)通过渲染纹理展示地球仪
上一篇文章介绍了如何使用GL10描绘三维物体的线段框架,后面给出的立方体和球体效果图,虽然看起来具备立体的轮廓,可离真实的物体还差得远.因为现实生活中的物体不仅仅有个骨架,还有花纹有光泽(比如衣服), ...
- Android开发笔记(一百五十四)OpenGL的画笔工具GL10
上一篇文章介绍了OpenGL绘制三维图形的流程,其实没有传说中的那么玄乎,只要放平常心把它当作一个普通控件就好了,接下来继续介绍OpenGL具体的绘图操作,这项工作得靠三维图形的画笔GL10来完成了. ...
- Android开发笔记(一百五十三)OpenGL绘制三维图形的流程
从这篇文章开始,接下来会连载一系列的OpenGL相关博文,好好探讨如何在Android中进行OpenGL开发. OpenGL的全称是"Open Graphics Library", ...
- Android开发笔记(序)
本开发笔记,借鉴与其他开发者整理的文章范例与心得体会.在这里作为开发过程中的一个总结与笔记式记录. 如有侵犯作者权益,请及时联系告知删除.俗话说:集百家成一言,去粕成金. ************** ...
- Android学习笔记三
大神博客(必看)http://blog.csdn.net/huachao1001/article/list/1 1.Android校招笔记 http://huachao1001.github.io/i ...
- Android学习笔记:Android基础知识点(不断更新中)
1.Android学习笔记:OkHttp 2.Android学习笔记:更新UI的方法(UI线程和非UI线程) 3.Android学习笔记:Volley 4.Android学习笔记:Handler 5. ...
- Android开发笔记(序)写在前面的目录大全
转自 湖前琴亭 的博客https://blog.csdn.net/aqi00/article/details/50012511 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面 ...
- Andriod开发之二十:Android开发笔记(序)写在前面的目录
https://blog.csdn.net/aqi00/article/details/50038385 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经验教 ...
最新文章
- WEB程序代码优化入手的几方面
- (转载博文)VC++API速查
- python程序多次运行_[Python]在一段Python程序中使用多次事件循环
- uniGUI 实操感受
- Matlab | 数字信号处理:双线性变换法设计IIR数字滤波器
- React state和props使用场景
- 手机qq2008触屏版_[进行中]数码手机周年庆
- WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器
- python形参中的:*args和**kwargs区别
- 使用ajax获取后台数据怎么打印,我用ajax获取后台数据并展示在前端页面的方法【源码】...
- 三个 CSS 预处理器(框架):Sass、LESS 和 Stylus
- 将.sql文件导入数据库
- C语言题目:平均成绩,已知某个同学的语文、数学、英语成绩,计算该同学的平均分
- 辣椒app软件测试,testflight辣椒视频APP
- 青春树儿童摄影网网页
- POI Excel插入行,下面的行动态移动
- 微信小程序(登录、分享、支付)
- Chrome浏览器上传图片或图片另存时浏览器无响应
- 华为nova 3e,重新编译内核文件,解除ptrace限制,以使用Frida
- UML设计——网上信用卡管理系统分析与设计(新手)
热门文章
- C#委托之如何理解委托面试常见题:
- 宇文成 Python 第七章 字符串与正则表达式
- 分析手提电子秤芯片方案CSU8RP1186
- ostringstream >>> string >>> char *
- 算法实战应用案例精讲-【图像处理】数字图像处理从原理到应用(python代码实战)
- (附源码)SSM萌宠宠物网店的设计与实现 毕业设计 011042
- java里localtime,java 时间转换之LocalDate,LocalTime ,LocalDateTime
- ComboBox隐藏三角符号
- c语言白盒测试笔试题,软件测试笔试题目第2套共8套
- 谁来阻击腾讯?(转载)