Surface

一、Surface

在Andorid的窗口实现里,每一个Window其实都会对应一个Surface,而每个Activity都会持有一个Window,所以,我们通常在Activity里设置的view(通过setContentView),从java抽象上看其最终的绘制目标就是在Surface上。

通常我们并不手动去创建Surface,帮我们创建Surface的是WindowManagerService,它在帮我们创建Surface时,会生成一个SurfaceSession,然后将这个SurfaceSession作为参数来构造Surface

Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都是画在Surface上的,传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行

屏幕绘制

应用层的绘制,从ViewRootImpl的performDraw开始,

通过Suface.lockCanvas()得到canvas,

Surface的架构

  • Surface本质上仅仅代表了一个平面,绘制不同图案显然是一种操作,而不是一段数据,一般一个Act对应一个Surface
  • Android使用了Skia绘图驱动库来进行平面上的绘制,在程序中使用canvas来表示这个功能.

 二、Canvas 与Surface

     

屏幕绘制

应用层的绘制,从ViewRootImpl的performDraw开始,

通过Suface.lockCanvas()得到canvas,

Surface的架构

  • Surface本质上仅仅代表了一个平面,绘制不同图案显然是一种操作,而不是一段数据,一个Activity对应一个Surface,其中多个View都是在这个Surface中(SurfaceView除外,每个SurfaceView有单独的Surface)
  • Android使用了Skia绘图驱动库来进行平面上的绘制,在程序中使用canvas来表示这个功能.

Canvas总结:

  • Android中的Canvas不是View的成员,是比View更底层的东西
  • 通过Suface.lockCanvas()得到canvas
  • Canvas对应的是Surface
    • Surface,一个平面
    • 通过Canvas来实现对这个平面进行绘制

这里既然讲到了Canvas,就不得不说Canvas Paint View的关系 

  • Canvas是一个黑匣子里的白纸,它的特性是可以添加图层和平移,旋转、缩放、斜切等,最重要的就是它的n种drawXXX...
  • Paint是绘制用的画笔,它的特性是提供绘制工具与制定画笔的特殊效果(如笔头Cap,线接方式Join,六种Effect)
  • View则是让黑匣子变成透明的视口,也是我们最熟悉。那Coder就是在操纵画笔的在白纸上绘制的人,是最核心的

所以,Canvas不是属于View,不是View里面的内部成员,至少Canvas是可以离开View存在的(Compose就是底层基于Canvas,但是View那一套都替换了)

三、SurfaceFlinger

WMS会请求SurfaceFlinger来绘制surface.

SurfaceFlinger创建layer;

一个生产者的Binder对象通过WMS传递给app, 因此app可以直接向SurfaceFlinger发送帧信息.

对应用册:通过 Surface 与不同的应用进程建立联系,接收它们写入 Surface 中的绘制缓冲数据,对它们进行统一合成。

对底层:通过屏幕的后缓存区与屏幕建立联系,发送合成好的数据到屏幕显示设备。

Surface:数据的生产者

BufferQueue:传输数据的管道

SurfaceFlinger:消费者端

图像数据链条:

Android内容-->Surface-->BufferQueue-->SurfaceFlinger

四、拥有独立Surface的控件

  • SurfaceView: 基于view视图进行拓展的视图类,更适合2D游戏的开发,是view的子类,使用了双缓冲机制,即:允许在子线程中更新画面,所以刷新界面速度比view快。
  • GLSurfaceView: 基于SurfaceView视图再次进行拓展的视图类,在SurfaceView基础上封装了EGL环境管理以及render线程,专用于3D游戏开发的视图。是SurfaceView的子类,openGL专用。
  • TextrueView: 前面的SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口,脱离了Android的普通窗口,因此无法对其应用变换操作(平移、缩放、旋转等),而TextureView则解决了此问题,Android4.0引入。

而SurfaceView 系的API由于是在新的线程中更新画面所以不会阻塞你的UI线程。但这也带来了另外一个问题,就是事件同步,涉及到线程同步

常规:通过Canvas在Surface上面画

直接操作Surface:SurfaceView / GLSurfaceView

SurfaceView保证内容能及时渲染到界面上的做法:

为每一帧设置一个帧时间戳 T(这一帧应该要渲染到界面上的时间点),然后提交到BufferQueue中:

  • 当在T-1的时间点,队首为这一帧时,SurfaceFlinger会继续hold住当前帧,也就是说这个时候显示的还是前一帧的数据
  • 当达到了T时间点,当前队首为这一帧的时候,SurfaceFlinger便直接提交这一帧到Display
  • 当达到了T+1时间点,当队首为这一帧,因为已经超过了这一帧设置的时间戳T,因此SurfaceFlinger便直接丢弃这一帧,继续处理队列剩余的帧数据(丢帧)

这样SurfaceFlinger就可以针对上屏的每一帧数据延迟做精确的控制了

这样只能保证界面不延迟,但是会出现丢帧,保证不丢帧根本的解决方案,还是得尽量在16ms内,渲染完一帧数据

区别与选择

  • SurfaceView: 基于view视图进行拓展的视图类,更适合2D游戏的开发,是view的子类,
    • 使用了双缓冲机制
      • 两张Canvas
    • 允许在子线程中更新画面,所以刷新界面速度比view快。
    • 单独的Surface,所以不能像View一样平移缩放
  • GLSurfaceView: 基于SurfaceView视图再次进行拓展的视图类,在SurfaceView基础上封装了EGL环境管理以及render线程,专用于3D游戏开发的视图。是SurfaceView的子类,openGL专用。
  • TextrueView:
    • Android4.0引入。
    • 将内容流直接投影到View中。
    • 必须在硬件加速的窗口
    • 在android 7.0上系统surfaceview的性能比TextureView更有优势,支持对象的内容位置和包含的应用内容同步更新,平移、缩放不会产生黑边。 在7.0以下系统如果使用场景有动画效果,可以选择性使用TextureView
    • TextureView并没有创建一个单独的Surface用来绘制,这使得它可以像一般的View一样执行一些变换操作,设置透明度等

选择:

对于一些类似于坦克大战等需要不断告诉更新画布的游戏来说,SurfaceView绝对是极好的选择。但是比如视频播放器或相机应用的开发,TextureView则更加适合

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值