SurfaceView与TextureView的绘制渲染
- 一.SurfaceView
- 1.SurfaceView的初始化
- 1.1 SurfaceControl的创建
- 1.1.1 BLASTBufferQueue与SurfaceControl的绑定
- 1.2 Surface初始化
- 2.SurfaceHolder的回调与绘制
- 2.1 画布的获取
- 2.2 矩形的绘制
- 2.3 绘制的提交
- 二.TextureView
- 1.TextureView的初始化
- 1.1 TextureLayer的创建
- 1.2 SurfaceTexture的创建
- 1.2.1 生产者与消费者模型的初始化
- 1.2.2 Native层SurfaceTexture的创建
- 1.2.3 Native层SurfaceTexture对Java层SurfaceTexture的初始化
- 1.3 Surface的初始化
- 1.4 SurfaceTexture与TextureLayer的绑定
- 1.4.1 SurfaceTexture与DeferredLayerUpdater的绑定
- 1.4.2 HardwareRenderer与DeferredLayerUpdater的绑定
- 1.5 监听器的设置
- 2.SurfaceTexture的回调通知
- 2.1 画布的获取
- 2.1.1 ANativeWindow_Buffer的初始化
- 2.1.2 Native层Canvas的创建
- 2.1.3 Canvas与ANativeWindow_Buffer的绑定
- 2.1.4 SkBitmap的初始化
- 2.1.5 SkiaCanvas与SkBitmap的绑定
- 2.1.6 SkCanvas的创建
- 2.2 矩形的绘制
- 2.3 绘制的提交
- 2.4 渲染帧的回调
- 3.TextureView的绘制
- 3.1 渲染标识位的更新
- 3.2 TextureLayer的绘制
- 4.硬件加速层的处理
- 4.1 图像缓存的获取
- 4.2 图像缓存的渲染
- 4.3 Layer的更新
- 5.绘制的渲染
- 三.总结
- 1.SurfaceView的初始化
- 1.1 SurfaceControl的创建
- 1.2 Surface的初始化
- 2.SurfaceView的双缓冲机制
- 3.TextureView的初始化
- 3.1 硬件加速层的创建
- 3.2 图像生产消费模型的创建
- 3.3 硬件加速层与图像生产消费模型的绑定
- 3.4 Surface的初始化
- 4.BLASTBufferQueue与SurfaceTexture的对比
- 5.TextureView的绘制
- 5.1 硬件加速层的更新
- 5.2 TextureLayer的绘制
- 6.硬件加速层的处理
- 7.TextureView的渲染
- 8.TextureView绘制渲染的三线程切换。
- 8.1 TextureView渲染延迟的原因
- 9.SurfaceView与TextureView的对比
一.SurfaceView
1.SurfaceView的初始化
当SurfaceView绑定到窗口时,会调用SurfaceView的onAttachedToWindow方法。在SurfaceView的onAttachedToWindow方法中,会对ViewTree进行监听。
在SurfaceView首次绘制前,会调用OnPreDrawListener的onPreDraw方法。在OnPreDrawListener的onPreDraw方法中,会调用updateSurface方法。
updateSurface方法是SurfaceView中的核心方法,当SurfaceView中的属性或者窗口的生命周期发生变化时,都会调用updateSurface方法。
在SurfaceView的updateSurface方法,主要做了三件事:
1)创建SurfaceControl层级。
2)创建Surface。
3)通知Surface创建完成。
1.1 SurfaceControl的创建
在SurfaceView的createBlastSurfaceControls方法中,会为SurfaceView在ViewRootImpl下创建SurfaceControl,如下图所示:
在SurfaceView的createBlastSurfaceControls方法中,主要做了五件事:
1)在ViewRootImpl中创建一个用于控制子SurfaceControl的绘制边界的容器SurfaceControl,挂在ViewRootImpl中用于控制绘制的SurfaceControl下。
2)在SurfaceView中创建一个用于管理当前SurfaceView的容器SurfaceControl,挂在ViewRootImpl中用于控制绘制边界的SurfaceControl下。
3)在SurfaceView中创建一个用于绘制BLASTBufferQueue中数据的SurfaceControl,挂在SurfaceView中用于管理当前SurfaceView的容器SurfaceControl下。
4)在SurfaceView中创建一个用于绘制背景的SurfaceControl,挂在SurfaceView中用于管理当前SurfaceView的容器SurfaceControl下。
5)创建BLASTBufferQueue,将BLASTBufferQueue与用于绘制BLASTBufferQueue中数据的SurfaceControl进行关联。
1.1.1 BLASTBufferQueue与SurfaceControl的绑定
在BLASTBufferQueue的update方法中,调用nativeUpdate方法。
BLASTBufferQueue的nativeUpdate方法对应的Native实现为android_graphics_BLASTBufferQueue的nativeUpdate函数。
在nativeUpdate函数中,主要做了三件事:
1)获取Native层的BLASTBufferQueue。
2)获取Native层的SurfaceControl。
3)绑定Native层的BLASTBufferQueue和SurfaceControl。
在BLASTBufferQueue的update方法中,主要做了三件事:
1)保存SurfaceControl。
2)如果绘制区域发生变化,则通知消费者模型修改绘制缓存的渲染区域大小。
3)如果渲染区域发生变化,同时已渲染的缓存支持缩放,则通知SurfaceFlinger在合成时按照新的渲染区域大小处理已渲染的缓存。
1.2 Surface初始化
在创建SurfaceControl层级后,会调用copySurface方法,初始化Surface。在copySurface方法中,会调用Surface的copyFrom方法,进行初始化。
在Surface的copyFrom方法中,主要做了两件事:
1)创建Native层的Surface,并返回Native层的Surface对应的地址。
2)Java层Surface保存Native层Surface的地址。
Surface的nativeGetFromBlastBufferQueue方法对应的Native实现为android_view_Surface的nativeGetFromBlastBufferQueue函数。
在nativeGetFromBlastBufferQueue函数中,主要做了两件事:
1)获取Native层的BLASTBufferQueue。
2)通过BLASTBufferQueue创建Surface,并返回对应的地址。
在BLASTBufferQueue的getSurface方法中,直接创建并返回了BBQSurface。
2.SurfaceHolder的回调与绘制
在Surface创建完成后,会调用SurfaceHolder.Callback的surfaceChanged方法,通知Surface创建完成。之后可以通过SurfaceHolder进行绘制。
2.1 画布的获取
在SurfaceView的surfaceChanged方法中,通过调用SurfaceHolder的lockCanvas方法,可以获取Canvas。最终会通过调用Surface的lockCanvas方法获取Canvas。详情参考:Android软件渲染流程 。
2.2 矩形的绘制
详情参考:Android软件渲染流程 。
2.3 绘制的提交
在SurfaceView中,通过调用SurfaceHolder的unlockCanvasAndPost方法,提交绘制。最终会通过调用Surface的unlockCanvasAndPost方法提交绘制。详情参考:Android软件渲染流程 。
二.TextureView
1.TextureView的初始化
TextureView的绘制依赖硬件加速渲染,因此在TextureView的draw方法中,首先会判断是否开启硬件加速。在判断开启硬件加速后,主要做了三件事:
1)将Canvas转换为RecordingCanvas。
2)获取TextureLayer。
3)如果TextureLayer不为空,则标记本次的更新,同时绘制TextureLayer。
在首次调用getTextureLayer方法时,会触发TextureLayer与SurfaceTexture的创建。在TextureView的getTextureLayer方法中,主要做了六件事:
1)创建TextureLayer。
2)创建SurfaceTexture。
3)根据SurfaceTexture初始化Surface。
4)将SurfaceTexture绑定到TextureLayer上。
5)设置渲染帧完成时的回调监听。
6)回调通知SurfaceTexture创建完成。
1.1 TextureLayer的创建
ThreadedRenderer继承自HardwareRenderer。ThreadedRenderer的createTextureLayer方法在父类HardwareRenderer中实现。
在HardwareRenderer的createTextureLayer方法中,主要做了两件事:
1)创建Native层DeferredLayerUpdater,并返回对应的地址。
2)将Native层DeferredLayerUpdater的地址封装成Java层的TextureLayer。
HardwareRenderer的nCreateTextureLayer方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_createTextureLayer函数。
在android_view_ThreadedRenderer_createTextureLayer函数中,主要做了两件事:
1)获取Native层的RenderProxy。
2)创建DeferredLayerUpdater。
在RenderProxy的createTextureLayer方法中,会将TextureLayer的创建过程进行封装,然后添加到RenderThread的任务队列WorkQueue中执行。
当RenderThread执行任务时,会调用CanvasContext的createTextureLayer方法。在CanvasContext的createTextureLayer方法中,会调用IRenderPipeline的createTextureLayer。
对于OpenGL平台,IRenderPipeline的实现为SkiaOpenGLPipeline,在SkiaOpenGLPipeline的createTextureLayer方法中,会创建DeferredLayerUpdater。
1.2 SurfaceTexture的创建
在TextureView的getTextureLayer方法中,在创建完TextureLayer后,会创建SurfaceTexture。在SurfaceTexture构造方法中,主要做了两件事:
1)获取当前线程的Looper,用于后续Native层回调Java层时任务的执行。
2)创建Native层的SurfaceTexture。
SurfaceTexture的nativeinit方法对应的Native实现为android_graphics_SurfaceTexture的SurfaceTexture_init函数。
在SurfaceTexture_init函数中,主要做了四件事:
1)创建并初始化生产者消费者模型。
2)创建Native层SurfaceTexture。
3)将Native层SurfaceTexture和生产者模型对应的地址保存到Java层SurfaceTexture中。
4)创建Native层绘制帧完成的监听器,监听Native层SurfaceTexture帧绘制完成通知,将Native层绘制帧完成的监听器对应的地址保存到Java层SurfaceTexture中。
1.2.1 生产者与消费者模型的初始化
在BufferQueue的createBufferQueue方法中,主要做了三件事:
1)创建BufferQueueCore。BufferQueueCore负责缓冲区的核心调度。
2)创建生产模型并赋值到参数。
3)创建消费模型并赋值到参数。
详情参考:Android图像缓存与Surface初始化、Android图像生产消费模型。
1.2.2 Native层SurfaceTexture的创建
SurfaceTexture继承自ConsumerBase,是图像缓存生产消费模型中的消费者。
在创建SurfaceTexture时,会调用父类ConsumerBase的构造方法。
在ConsumerBase的构造方法中,主要做了三件事:
1)将ConsumerBase转换为ConsumerListener。
2)将ConsumerListener封装为ProxyConsumerListener。
3)向消费模型注册回调。
IGraphicBufferConsumer的cosumerConnect方法是一个跨进程调。最终会调用BufferQueueConsumer的connect方法。
在BufferQueueConsumer的connect方法中,会将IConsumerListener保存到BufferQueueCore中。
1.2.3 Native层SurfaceTexture对Java层SurfaceTexture的初始化
在SurfaceTexture_init函数中,调用了SurfaceTexture_setSurfaceTexture函数。在SurfaceTexture_setSurfaceTexture函数中,会将Native层SurfaceTexture对应的地址保存到Java层的SurfaceTexture中。
在SurfaceTexture_setSurfaceTexture中,主要做了两件事:
1)获取Java层SurfaceTexture中成员变量的字段名。
2)根据字段名对Java层SurfaceTexture进行赋值。
fields是android_graphics_SurfaceTexture中类型为结构体fields_t的全局变量。
struct fields_t {
jfieldID surfaceTexture;
jfieldID producer;
jfieldID frameAvailableListener;
jmethodID postEvent;
}
fields会在系统启动时通过android_graphics_SurfaceTexture的SurfaceTexture_classInit函数进行初始化。
SurfaceTexture_setProducer函数与SurfaceTexture_setFrameAvailableListener函数的实现与SurfaceTexture_setSurfaceTexture函数类似。
1.3 Surface的初始化
在TextureView的getTextureLayer方法中,在创建完SurfaceTexture后,会调用nCreateNativeWindow方法初始化Surface。TextureView的nCreateNativeWindow方法对应的Native实现为android_view_TextureView的android_view_TextureView_createNativeWindow函数。
在android_view_TextureView_createNativeWindow函数中,主要做了三件事:
1)获取生产者模型。
2)创建Native层的Surface。
3)将Native层的Surface对应的地址保存到Java层的TextureView中。
gTextureViewClassInfo是android_view_TextureView的结构体。
static struct {
jfieldID nativeWindow;
} gTextureViewClassInfo;
gTextureViewClassInfo会在系统启动时通过android_view_TextureView的register_android_view_TextureView函数进行初始化。
1.4 SurfaceTexture与TextureLayer的绑定
在TextureView的getTextureLayer方法中,当Surface初始化完成后,会进行TexureLayer与SurfaceTexture的绑定。在TexureLayer的setSurfaceTexture方法中,主要做了两件事:
1)将SurfaceTexture保存到DeferredLayerUpdater中。
2)将DeferredLayerUpdater保存到HardwareRenderer中。
1.4.1 SurfaceTexture与DeferredLayerUpdater的绑定
TextureView的nSetSurfaceTexture方法对应的Native实现为android_graphics_TextureLayer的TextureLayer_setSurfaceTexture函数。
在TextureLayer_setSurfaceTexture函数中,主要做了三件事:
1)获取Native层DeferredLayerUpdater。
2)获取Native层SurfaceTexture,并将SurfaceTexture封装成ASurfaceTexture。
3)将ASurfaceTexture进行封装AutoTextureRelease,设置到DeferredLayerUpdater中。AutoTextureRelease是对删除器为ASurfaceTexture_release函数的ASurfaceTexture智能指针的重命名。当ASurfaceTexture指针不再被使用时,会通过ASurfaceTexture_release函数进行销毁。
在ASurfaceTexture_fromSurfaceTexture函数中,调用了surface_texture的ASurfaceTexture_routeFromSurfaceTexture函数。在ASurfaceTexture_routeFromSurfaceTexture函数中,调用了ASurfaceTexture_fromSurfaceTexture函数。
在ASurfaceTexture_fromSurfaceTexture函数中,主要做了三件事:
1)创建ASurfaceTexture。
2)根据Java层SurfaceTexture保存的指针,获取Native层SurfaceTexture,作为消费者模型保存到ASurfaceTexture中。
3)根据Java层SurfaceTexture保存的指针,获取Native层IGraphicBufferProducer,作为生产者模型保存到ASurfaceTexture中。
SurfaceTexture_getSurfaceTexture函数与SurfaceTexture_getProducer函数通过JNI分别获取Java层SurfaceTexture的mSurfaceTexture字段和mProducer字段对应的值,将这些值作为指针获取Native层对应的对象。
这些字段的初始化绑定与获取在分析SurfaceTexture_setSurfaceTexture时分析过,这里不再具体分析。
在DeferredLayerUpdater的setSurfaceTexture方法中,会将AutoTextureRelease保存到全局变量中。
1.4.2 HardwareRenderer与DeferredLayerUpdater的绑定
在HardwareRenderer的pushLayerUpdate方法中,调用了nPushLayerUpdate方法。
HardwareRenderer的nPushLayerUpdate方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_pushLayerUpdate函数。
在android_view_ThreadedRenderer_pushLayerUpdate函数中,主要做了三件事:
1)获取Native层RenderProxy。
2)获取Native层DeferredLayerUpdater。
3)将DeferredLayerUpdater保存到RenderProxy。
在RenderProxy的pushLayerUpdate方法中,会调用DrawFrameTask的pushLayerUpdate方法。
在DrawFrameTask的pushLayerUpdate方法中,会对DeferredLayerUpdater进行保存。
1.5 监听器的设置
在SurfaceTexture的setOnFrameAvailableListener方法中,调用了重载的setOnFrameAvailableListener方法。在重载的setOnFrameAvailableListener方法中,创建了Handler并重写了handleMessage方法。
2.SurfaceTexture的回调通知
在SurfaceTexture创建完毕后,会回调SurfaceTextureListener的onSurfaceTextureAvailable方法通知SurfaceTexture创建完成。
2.1 画布的获取
通过调用TextureView的lockCanvas方法可以获取Canvas。在TextureView的lockCanvas方法中,调用了重载的lockCanvas方法。在重载的lockCanvas方法中,主要做了两件事:
1)首次调用lockCanvas时,会创建Canvas。
2)对Canvas进行初始化。
TextureView的nLockCanvas方法对应的Native实现为android_view_TextureView的android_view_TextureView_lockCanvas函数。
在android_view_TextureView_lockCanvas函数中,主要做了五件事:
1)创建ANativeWindow_Buffer。ANativeWindow_Buffer是对渲染缓存属性的封装。
2)将Native层Surface对应的地址强制转换为ANativeWindow指针。
3)使用ANativeWindow对ANativeWindow_Buffer进行初始化。
4)根据Java层Canvas,创建Native层Canvas。
5)将ANativeWindow_Buffer设置到Native层Canvas中。
2.1.1 ANativeWindow_Buffer的初始化
在native_window_lock函数中,会调用ANativeWindow的perform方法,发送类型为int的消息NATIVE_WINDOW_LOCK。
perform方法是ANativeWindow中定义的函数指针,在Native层Surface创建时会绑定到Surface的hook_perform方法。
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
在Surface的hook_perform方法中,主要做了两件事:
1)将ANativeWindow转换为Surface。
2)调用Surface的perform方法。
在Surface的perform方法中,会根据消息的不同类型,调用不同的方法处理。对于NATIVE_WINDOW_LOCK,会调用dispatchLock方法。在Surface的dispatchLock方法中,会调用lock方法。
在Surface的lock方法中,主要做了四件事:
1)从IGraphicBufferProducer中获取一块内存ANativeWindowBuffer。
2)将ANativeWindowBuffer封装成GraphicBuffer。
3)锁定GraphicBuffer,获取存放绘制数据的虚拟地址的指针,用于后续Canvas的绘制。
4)将GraphicBuffer中的变量赋值到ANativeWindow_Buffer中。ANativeWindow_Buffer是ANativeWindowBuffer对外的屏蔽封装,用于指导Canvas在多大的长宽范围内以什么样的格式进行绘制,并提供提交绘制数据的指针。
2.1.2 Native层Canvas的创建
在graphics::Canvas的构造方法中,会调用android_canvas的ACanvas_getNativeHandleFromJava函数,将Native层对应的Canvas转换为ACanvas,并保存到graphics::Canvas的mCanvas字段中。
ACanvas是对Native层Canvas的代理,ACanvas是一个没有任何方法的结构体,当需要调用Native层Canvas时,会再将ACanvas强转为Canvas。
在ACanvas_getNativeHandleFromJava函数中,主要做了两件事:
1)获取Native层Canvas,实际是SkiaCanvas,SkiaCanvas是对SkCanvas的封装。
2)将Canvas转换为ACanvas。
2.1.3 Canvas与ANativeWindow_Buffer的绑定
在graphics::Canvas的setBuffer方法中,会调用android_canvas的ACanvas_setBuffer函数。
在ACanvas_setBuffer函数中,主要做了四件事:
1)声明SkBitmap。SKBitmap是对ANativeWindow_Buffer的封装,SKBitmap会根据ANativeWindow_Buffer的指导,按照指定的大小和格式,向指定的绘制地址写入绘制数据。
2)对SkBitmap进行初始化。
3)通过ACanvas获取Canvas,实际是SkiaCanvas。
4)将SkiaCanvas和SkBitmap绑定。
2.1.4 SkBitmap的初始化
在convert函数中,主要做了三件事:
1)将ANativeWindow_Buffer封装成SkImageInfo。
2)绑定SkImageInfo到SkBitmap中。
3)设置用于存放绘制数据的虚拟地址的指针。
2.1.5 SkiaCanvas与SkBitmap的绑定
在SkiaCanvas的setBitmap方法中,主要做了三件事:
1)将SkBitmap封装成SkCanvas。
2)保存SkCanvas对应的指针。
3)通过SkCanvas指针获取SkCanvas并保存。
2.1.6 SkCanvas的创建
在SkCanvas的构造方法中,主要做了两件事:
1)将SkBitmap封装为SkBitmapDevice。
2)保存SkBitmapDevice。
2.2 矩形的绘制
当在TextureView的onSurfaceTextureAvailable方法中调用Canvas的drawRect方法时,在Canvas的drawRect方法中,会调用nDrawRect方法。
Canvas的nDrawRect方法对应的Native实现为android_graphics_Canvas的drawRect函数。在drawRect函数中,主要做了两件事:
1)获取Native层Canvas。
2)通过Canvas绘制矩形。
在SkiaCanvas的drawRect方法中,会调用SkCanvas的drawRect方法。最终会绘制到SKBitmap上。SKBitmap封装了图像绘制缓冲,实际会绘制到图像缓冲上。
2.3 绘制的提交
通过调用TextureView的unlockCanvasAndPost方法可以提交本次的绘制。在TextureView的unlockCanvasAndPost方法中,如果参数中Canvas与TextureView中的全局变量mCanvas相同,会调用了nUnlockCanvasAndPost方法。
TextureView的nUnlockCanvasAndPost方法对应的Native实现为android_view_TextureView的android_view_TextureView_unlockCanvasAndPost函数。
在android_view_TextureView_unlockCanvasAndPost函数中,主要做了三件事:
1)获取Native层Canvas,将之前绑定的ANativeWindow_Buffer与Canvas解绑。
2)将Native层Surface对应的指针强制转换为ANativeWindow对应的指针。
3)提交绘制。
在native_window_unlockAndPost函数中,会调用ANativeWindow的perform方法,发送类型为int的消息NATIVE_WINDOW_UNLOCK_AND_POST。
perform方法是ANativeWindow中定义的函数指针,在Native层Surface创建时会绑定到Surface的hook_perform方法。
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
在Surface的hook_perform方法中,主要做了两件事:
1)将ANativeWindow转换为Surface。
2)调用Surface的perform方法。
在Surface的perform方法中,会根据消息的不同类型,调用不同的方法处理。如果消息为NATIVE_WINDOW_UNLOCK_AND_POST,会调用dispatchUnlockAndPost方法。在Surface的dispatchUnlockAndPost方法中,会调用unlockAndPost方法。
在Surface的unlockAndPost方法中,主要做了三件事:
1)解除GraphicBuffer锁定。
2)将渲染完的图像缓冲添加到IGraphicBufferProducer中。
3)清除对GraphicBuffer的引用。
在Surface的queueBuffer方法中,主要做了两件事:
1)获取缓存位置。
2)提交缓存。
通过Surface的初始化流程,可以知道这里Surface的实际类型为BBQSurface,因此IGraphicBufferProducer对应的类型为BBQBufferQueueProducer。
在BBQBufferQueueProducer的queueBuffer方法中,主要做了四件事:
1)创建FenceTime。
2)创建渲染帧BufferItem。
3)对BufferItem进行初始化设置。
4)通知消费者消费渲染帧。
2.4 渲染帧的回调
通过Surface的初始化流程,可以知道这里的mCore的类型为BufferQueueCore。BufferQueueCore的IConsumerListener的类型为BufferQueue::ProxyConsumerListener。
调用BufferQueue::ProxyConsumerListener的onFrameAvailable方法,最终会调用JNISurfaceTextureContext的onFrameAvailable方法。
在JNISurfaceTextureContext的onFrameAvailable方法中,主要做了两件事:
1)获取JNI。
2)通过JNI调用Java层SurfaceTexture的静态方法postEventFromNative。
在SurfaceTexture的postEventFromNative方法中,主要做了两件事:
1)从SurfaceTexture的弱引用中获取SurfaceTexture,从SurfaceTexture中获取Handler。
2)使用Handler发送消息。
在Handler的sendEmptyMessage方法中,会调用handleMessage方法。在handleMessage方法中,会回调OnFrameAvailableListener的onFrameAvailable方法。
这里的OnFrameAvailableListener就是TextureView中的全局变量mUpdateListener。在OnFrameAvailableListener的onFrameAvailable方法中,会请求界面刷新。
3.TextureView的绘制
当下一次VSync信号到来时,会触发TextureView的draw方法。在TextureView的draw方法中,首先会判断是否开启硬件加速。在判断开启硬件加速后,主要做了三件事:
1)将Canvas转换为RecordingCanvas。
2)获取TextureLayer。
3)如果TextureLayer不为空,则标记本次的更新,同时绘制TextureLayer。
3.1 渲染标识位的更新
在TextureView的applyUpdate方法中,主要做了两件事:
1)更新SurfaceTexture。
2)回调通知本次的更新。
在TextureLayer的updateSurfaceTexture方法中,主要做了两件事:
1)更新Native层SurfaceTexture。
2)保存本次更新的DeferredLayerUpdater。
TextureLayer的nUpdateSurfaceTexture方法对应的Native实现为android_graphics_TextureLayer的TextureLayer_updateSurfaceTexture函数。
在TextureLayer_updateSurfaceTexture函数中,主要做了两件事:
1)获取Native层DeferredLayerUpdater。
2)更新对应标识位。
在DeferredLayerUpdater的updateTexImage方法中,会将标识位设置为true。
3.2 TextureLayer的绘制
在RecordingCanvas的drawTextureLayer方法中,调用了nDrawTextureLayer方法。
RecordingCanvas的nDrawTextureLayer方法对应的Native实现为android_graphics_DisplayListCanvas的android_view_DisplayListCanvas_drawTextureLayer函数。在android_view_DisplayListCanvas_drawTextureLayer函数中,主要做了三件事:
1)获取Native层Canvas。
2)获取Native层DeferredLayerUpdater。
3)绘制DeferredLayerUpdater。
Java层RecordingCanvas对应的Native层Canvas为SkiaRecordingCanvas,详情参考:Android硬件渲染流程。
在SkiaRecordingCanvas的drawLayer方法中,主要做了两件事:
1)将DeferredLayerUpdater封装陈LayerDrawable,将LayerDrawable转换为父类SkDrawable对应的指针。
2)获取SkDrawable并进行绘制。
SkiaRecordingCanvas继承自SkiaCanvas。这里的drawDrawable方法在SkiaRecordingCanvas的父类SkiaCanvas中实现。
在SkiaCanvas的drawDrawable方法中,会调用SkCanvas的drawDrawable方法。
在SkCanvas的drawDrawable方法中,会调用子类RecordingCanvas的onDrawDrawable方法。
在RecordingCanvas的onDrawDrawable方法中,会调用之前保存的DisplayListData的drawDrawable方法。在DisplayListData的drawDrawable方法中,会创建一个DrawDrawable指令并保存。
4.硬件加速层的处理
在Android硬件渲染中,分成了绘制和渲染两个阶段。在渲染阶段,会调用DrawFrameTask的syncFrameState方法。参考:Android硬件渲染流程。
在DrawFrameTask的syncFrameState方法中,主要做了两件事:
1)处理硬件加速层,如TextureView的绘制。
2)构建TreeInfo。
在DeferredLayerUpdater的apply方法中,主要做了六件事:
1)如果Layer为空,则创建Layer。
2)判断更新标识位是否允许更新,如果允许则重制标识位。
3)从SurfaceTexture中获取一块已经绘制好的缓存。
4)使用硬件渲染,将绘制好的缓存渲染成SkImage,并返回SkImage指针。
5)释放缓存。
6)使用SkImage指针对Layer进行更新。
4.1 图像缓存的获取
在ASurfaceTexture_dequeueBuffer函数中,主要做了三件事:
1)通过SurfaceTexture获取绘制缓存,并通过参数返回缓存的位置信息。
2)将绘制缓存强制转换为AHardwareBuffer。
3)为AHardwareBuffer增加一个引用。
在SurfaceTexture的dequeueBuffer方法中,会调用ImageConsumer的dequeueBuffer方法。
ImageConsumer是对SurfaceTexture的获取渲染完成缓存方法的封装,内部持有ImageSlot数组。ImageSlot是对EGLSyncKHR的封装,EGLSyncKHR是类似Fence的用于EGL绘制之间的同步信号。
ImageSlot数组中的每个元素与SurfaceTexture中GraphicBuffer数组的每个元素的位置一一对应。当通过ImageConsumer从SurfaceTxture中获取GraphicBuffer时,ImageConsumer会在ImageSlot数组中相同的位置创建一个EGLSyncKHR。
在ImageConsumer的dequeueBuffer方法中,主要做了五件事:
1)创建BufferItem。
2)通过SurfaceTexture对BufferItem进行初始化。
3)从BufferItem中获取缓存位置信息。
4)使用位置信息对参数进行初始化。
5)根据位置信息从SurfaceTexture中获取缓存。
Slot中保存着缓存的指针与对应Fence的指针。
4.2 图像缓存的渲染
在ImageSlot的createIfNeeded方法中,主要做了两件事:
1)首次调用时,会为ImageSlot创建对应的AutoBackendTextureRelease。AutoBackendTextureRelease用于管理SkImage的生命周期,通过引用计数的方式使GPU持续渲染。
2)通过AutoBackendTextureRelease创建和获取SkImage。
4.3 Layer的更新
在DefferredLayerUpdater的updateLayer方法中,会对SkImage指针进行保存。
5.绘制的渲染
在实际渲染时,会调用DrawDrawable的draw方法。在DrawDrawable的draw方法中,会调用SkDrawable的draw方法。在SkDrawable的draw方法中,有回调用onDraw方法。SkDrawable的onDraw方法在子类LayerDrawable中重写。参考:Android硬件渲染流程。
在LayerDrawable的onDraw方法中,主要做了两件事:
1)从DeferredLayerUpdater中获取绘制完成的Layer。
2)将Layer中的内容绘制到SkCanvas上。
在LayerDrawable的DrawLayer方法中,主要做了两件事:
1)从Layer中获取SkImage指针。
2)通过SkImage指针获取SkImage,并绘制到SkCanvas上。
三.总结
1.SurfaceView的初始化
SurfaceView的初始化流程发生在首次绘制前。
1.1 SurfaceControl的创建
SurfaceView在初始化过程中会创建三个SurfaceControl节点:容器节点、绘制节点、背景节点。首先会在ViewRootImpl的SurfaceControl节点下创建SurfaceView的容器节点,然后在SurfaceView的容器节点下创建SurfaceView的绘制节点和SurfaceView的背景节点。
1.2 Surface的初始化
SurfaceView的绘制节点会与SurfaceView自身维护的BLASTBufferQueue进行绑定,并通过BLASTBufferQueue初始化Surface。
2.SurfaceView的双缓冲机制
SurfaceView依靠自身维护BLASTBufferQueue获取Surface,在SurfaceFlinger有独立的Layer,独享图像生产消费模型的双缓冲机制。
3.TextureView的初始化
TextureView的初始化流程发生在首次绘制过程中。
3.1 硬件加速层的创建
在TextureView的初始化过程中,会创建TextureLayer,Java层TextureLayer对应的Native对象类型是DeferredLayerUpdater。DeferredLayerUpdater就是硬件加速层。
3.2 图像生产消费模型的创建
在TextureView的初始化过程中,会创建SurfaceTexture。Java层SurfaceTexture对应的Native对象类型也是SurfaceTexture。SurfaceTexture的创建会触发图像生产消费模型的创建。
3.3 硬件加速层与图像生产消费模型的绑定
硬件加速层与图像生产消费模型的绑定本质上是将SurfaceTexture保存到DeferredLayerUpdater中,然后再将DeferredLayerUpdater保存到RenderProxy中。
3.4 Surface的初始化
在TextureView中Surface会通过SurfaceTexture中的图像生产者模型初始化。
4.BLASTBufferQueue与SurfaceTexture的对比
在Native层中,BLASTBufferQueue与SurfaceTexture都是负责Surface初始化的类。BLASTBufferQueue和SurfaceTexture的创建都会触发图像生产消费模型的创建。
BLASTBufferQueue负责整个图像生产消费模型,SurfaceTexture只负责图像的生产者模型。
BLASTBufferQueue在处理图像消费的过程中会直接将绘制好的图像缓存提交到SurfaceFlinger中进行合成。但是SurfaceTexture在处理图像消费的过程中会回调通知Java层的SurfaceTexture。Java层的SurfaceTexture在收到回调后会调用TextureView的invalidate方法刷新界面,等待下一次VSync信号的到来。
5.TextureView的绘制
当VSync信号到来时,会调用TextureView的draw方法触发绘制。
5.1 硬件加速层的更新
在TextureView的draw方法中会对硬件加速层进行更新。硬件加速层的更新本质上是将DeferredLayerUpdater中的更新标识位设置为true,为后续硬件加速层的处理做准备。
5.2 TextureLayer的绘制
在更新完硬件加速层后,会将TextureLayer绘制到TextureView的Canvas上。TextureLayer的绘制本质上是将DeferredLayerUpdater封装成LayerDrawable保存到TextureView的RenderNode中。
6.硬件加速层的处理
在UI线程构建完DisplayList后,Render线程会从UI线程获取DisplayList。在构建TreeInfo之前,会优先处理硬件加速层。
硬件加速层的处理本质上是DeferredLayerUpdater从绑定的SurfaceTexture中获取绘制好的图像缓存,使用硬件进行渲染,实现绘制内容的更新。硬件加速层的处理依赖硬件加速层更新时设置更新标识位为true。
7.TextureView的渲染
在处理完硬件加速层后,DeferredLayerUpdater对应的RenderNode会被构建到TreeInfo中,与TreeInfo中保存的所有的RenderNode绘制到同一个SkCanvas上,最终提交到SurfaceFlinger。
8.TextureView绘制渲染的三线程切换。
TextureView的绘制渲染流程需要经过绘制线程、UI线程、Render线程的切换。
用户在绘制线程(子线程)中进行绘制。当结束绘制时,会通过SurfaceTexture触发invalidate方法,切换到UI线程等待VSync信号。之后会在UI线程进行DisplayList的构建,在DisplayList构建完成后,会切换到Render线程进行渲染。
8.1 TextureView渲染延迟的原因
TextureView比SurfaceView渲染延迟至少一帧。假设TextureView和SurfaceView同时完成初始化。
在第一次VSync信号到来时,TextureView和SurfaceView同时开始绘制并同时结束绘制。
在第二次VSync信号到来时,SurfaceView绘制的内容在SurfaceFlinger中被合成并展示。TextureView开始在UI线程构建DisplayList,构建完成后由Render线程进行渲染。
在第三次VSync信号到来时,TextureView绘制的内容在SurfaceFlinger中被合成并展示。
9.SurfaceView与TextureView的对比
SurfaceView | TextureView | |
---|---|---|
初始化时机 | 首次绘制前 | 首次绘制过程中 |
图像生产消费模型 | BLASTBufferQueue | SurfaceTexture |
绘制渲染过程的线程切换 | 绘制线程 -> UI线程 | 绘制线程 -> UI线程 -> Render线程 |
是否有独立的Surface | 是 | 是 |
是否有独立的图像生产消费模型 | 是 | 是 |
是否有独立的Layer | 是 | 否 |