SurfaceView与TextureView的绘制渲染

2024-05-29 13:12

本文主要是介绍SurfaceView与TextureView的绘制渲染,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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进行监听。
0
    在SurfaceView首次绘制前,会调用OnPreDrawListener的onPreDraw方法。在OnPreDrawListener的onPreDraw方法中,会调用updateSurface方法。
1
    updateSurface方法是SurfaceView中的核心方法,当SurfaceView中的属性或者窗口的生命周期发生变化时,都会调用updateSurface方法。

    在SurfaceView的updateSurface方法,主要做了三件事:

1)创建SurfaceControl层级。

2)创建Surface。

3)通知Surface创建完成。
2

1.1 SurfaceControl的创建

    在SurfaceView的createBlastSurfaceControls方法中,会为SurfaceView在ViewRootImpl下创建SurfaceControl,如下图所示:
3
    在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进行关联。
4

1.1.1 BLASTBufferQueue与SurfaceControl的绑定

    在BLASTBufferQueue的update方法中,调用nativeUpdate方法。
5
    BLASTBufferQueue的nativeUpdate方法对应的Native实现为android_graphics_BLASTBufferQueue的nativeUpdate函数。

    在nativeUpdate函数中,主要做了三件事:

1)获取Native层的BLASTBufferQueue。

2)获取Native层的SurfaceControl。

3)绑定Native层的BLASTBufferQueue和SurfaceControl。
6
    在BLASTBufferQueue的update方法中,主要做了三件事:

1)保存SurfaceControl。

2)如果绘制区域发生变化,则通知消费者模型修改绘制缓存的渲染区域大小。

3)如果渲染区域发生变化,同时已渲染的缓存支持缩放,则通知SurfaceFlinger在合成时按照新的渲染区域大小处理已渲染的缓存。
7

1.2 Surface初始化

    在创建SurfaceControl层级后,会调用copySurface方法,初始化Surface。在copySurface方法中,会调用Surface的copyFrom方法,进行初始化。
8
    在Surface的copyFrom方法中,主要做了两件事:

1)创建Native层的Surface,并返回Native层的Surface对应的地址。

2)Java层Surface保存Native层Surface的地址。
9
    Surface的nativeGetFromBlastBufferQueue方法对应的Native实现为android_view_Surface的nativeGetFromBlastBufferQueue函数。

    在nativeGetFromBlastBufferQueue函数中,主要做了两件事:

1)获取Native层的BLASTBufferQueue。

2)通过BLASTBufferQueue创建Surface,并返回对应的地址。
10
    在BLASTBufferQueue的getSurface方法中,直接创建并返回了BBQSurface。
11

2.SurfaceHolder的回调与绘制

    在Surface创建完成后,会调用SurfaceHolder.Callback的surfaceChanged方法,通知Surface创建完成。之后可以通过SurfaceHolder进行绘制。

2.1 画布的获取

    在SurfaceView的surfaceChanged方法中,通过调用SurfaceHolder的lockCanvas方法,可以获取Canvas。最终会通过调用Surface的lockCanvas方法获取Canvas。详情参考:Android软件渲染流程 。
12

2.2 矩形的绘制

    详情参考:Android软件渲染流程 。

2.3 绘制的提交

    在SurfaceView中,通过调用SurfaceHolder的unlockCanvasAndPost方法,提交绘制。最终会通过调用Surface的unlockCanvasAndPost方法提交绘制。详情参考:Android软件渲染流程 。
13

二.TextureView

1.TextureView的初始化

    TextureView的绘制依赖硬件加速渲染,因此在TextureView的draw方法中,首先会判断是否开启硬件加速。在判断开启硬件加速后,主要做了三件事:

1)将Canvas转换为RecordingCanvas。

2)获取TextureLayer。

3)如果TextureLayer不为空,则标记本次的更新,同时绘制TextureLayer。
14
    在首次调用getTextureLayer方法时,会触发TextureLayer与SurfaceTexture的创建。在TextureView的getTextureLayer方法中,主要做了六件事:

1)创建TextureLayer。

2)创建SurfaceTexture。

3)根据SurfaceTexture初始化Surface。

4)将SurfaceTexture绑定到TextureLayer上。

5)设置渲染帧完成时的回调监听。

6)回调通知SurfaceTexture创建完成。
15

1.1 TextureLayer的创建

    ThreadedRenderer继承自HardwareRenderer。ThreadedRenderer的createTextureLayer方法在父类HardwareRenderer中实现。

    在HardwareRenderer的createTextureLayer方法中,主要做了两件事:

1)创建Native层DeferredLayerUpdater,并返回对应的地址。

2)将Native层DeferredLayerUpdater的地址封装成Java层的TextureLayer。
16
    HardwareRenderer的nCreateTextureLayer方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_createTextureLayer函数。

    在android_view_ThreadedRenderer_createTextureLayer函数中,主要做了两件事:

1)获取Native层的RenderProxy。

2)创建DeferredLayerUpdater。
17
    在RenderProxy的createTextureLayer方法中,会将TextureLayer的创建过程进行封装,然后添加到RenderThread的任务队列WorkQueue中执行。
18
    当RenderThread执行任务时,会调用CanvasContext的createTextureLayer方法。在CanvasContext的createTextureLayer方法中,会调用IRenderPipeline的createTextureLayer。
19
    对于OpenGL平台,IRenderPipeline的实现为SkiaOpenGLPipeline,在SkiaOpenGLPipeline的createTextureLayer方法中,会创建DeferredLayerUpdater。
20

1.2 SurfaceTexture的创建

    在TextureView的getTextureLayer方法中,在创建完TextureLayer后,会创建SurfaceTexture。在SurfaceTexture构造方法中,主要做了两件事:

1)获取当前线程的Looper,用于后续Native层回调Java层时任务的执行。

2)创建Native层的SurfaceTexture。
21
    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中。
22

1.2.1 生产者与消费者模型的初始化

    在BufferQueue的createBufferQueue方法中,主要做了三件事:

1)创建BufferQueueCore。BufferQueueCore负责缓冲区的核心调度。

2)创建生产模型并赋值到参数。

3)创建消费模型并赋值到参数。
23
    详情参考:Android图像缓存与Surface初始化、Android图像生产消费模型。

1.2.2 Native层SurfaceTexture的创建

    SurfaceTexture继承自ConsumerBase,是图像缓存生产消费模型中的消费者。
24
    在创建SurfaceTexture时,会调用父类ConsumerBase的构造方法。

    在ConsumerBase的构造方法中,主要做了三件事:

1)将ConsumerBase转换为ConsumerListener。

2)将ConsumerListener封装为ProxyConsumerListener。

3)向消费模型注册回调。
25
    IGraphicBufferConsumer的cosumerConnect方法是一个跨进程调。最终会调用BufferQueueConsumer的connect方法。
26
    在BufferQueueConsumer的connect方法中,会将IConsumerListener保存到BufferQueueCore中。
27

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进行赋值。
28
    fields是android_graphics_SurfaceTexture中类型为结构体fields_t的全局变量。

struct fields_t {jfieldID  surfaceTexture; jfieldID  producer;jfieldID  frameAvailableListener;jmethodID postEvent;}

    fields会在系统启动时通过android_graphics_SurfaceTexture的SurfaceTexture_classInit函数进行初始化。
29
    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中。
30
    gTextureViewClassInfo是android_view_TextureView的结构体。

static struct {jfieldID nativeWindow;
} gTextureViewClassInfo;

    gTextureViewClassInfo会在系统启动时通过android_view_TextureView的register_android_view_TextureView函数进行初始化。
31

1.4 SurfaceTexture与TextureLayer的绑定

    在TextureView的getTextureLayer方法中,当Surface初始化完成后,会进行TexureLayer与SurfaceTexture的绑定。在TexureLayer的setSurfaceTexture方法中,主要做了两件事:

1)将SurfaceTexture保存到DeferredLayerUpdater中。

2)将DeferredLayerUpdater保存到HardwareRenderer中。
32

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函数进行销毁。
33
    在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中。
34
    SurfaceTexture_getSurfaceTexture函数与SurfaceTexture_getProducer函数通过JNI分别获取Java层SurfaceTexture的mSurfaceTexture字段和mProducer字段对应的值,将这些值作为指针获取Native层对应的对象。

    这些字段的初始化绑定与获取在分析SurfaceTexture_setSurfaceTexture时分析过,这里不再具体分析。

    在DeferredLayerUpdater的setSurfaceTexture方法中,会将AutoTextureRelease保存到全局变量中。
35

1.4.2 HardwareRenderer与DeferredLayerUpdater的绑定

    在HardwareRenderer的pushLayerUpdate方法中,调用了nPushLayerUpdate方法。
36
    HardwareRenderer的nPushLayerUpdate方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_pushLayerUpdate函数。

    在android_view_ThreadedRenderer_pushLayerUpdate函数中,主要做了三件事:

1)获取Native层RenderProxy。

2)获取Native层DeferredLayerUpdater。

3)将DeferredLayerUpdater保存到RenderProxy。
37
    在RenderProxy的pushLayerUpdate方法中,会调用DrawFrameTask的pushLayerUpdate方法。
38
    在DrawFrameTask的pushLayerUpdate方法中,会对DeferredLayerUpdater进行保存。
39

1.5 监听器的设置

    在SurfaceTexture的setOnFrameAvailableListener方法中,调用了重载的setOnFrameAvailableListener方法。在重载的setOnFrameAvailableListener方法中,创建了Handler并重写了handleMessage方法。
40

2.SurfaceTexture的回调通知

    在SurfaceTexture创建完毕后,会回调SurfaceTextureListener的onSurfaceTextureAvailable方法通知SurfaceTexture创建完成。

2.1 画布的获取

    通过调用TextureView的lockCanvas方法可以获取Canvas。在TextureView的lockCanvas方法中,调用了重载的lockCanvas方法。在重载的lockCanvas方法中,主要做了两件事:

1)首次调用lockCanvas时,会创建Canvas。

2)对Canvas进行初始化。
41
    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中。
42

2.1.1 ANativeWindow_Buffer的初始化

    在native_window_lock函数中,会调用ANativeWindow的perform方法,发送类型为int的消息NATIVE_WINDOW_LOCK。
43
    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方法。
44
    在Surface的perform方法中,会根据消息的不同类型,调用不同的方法处理。对于NATIVE_WINDOW_LOCK,会调用dispatchLock方法。在Surface的dispatchLock方法中,会调用lock方法。
45
    在Surface的lock方法中,主要做了四件事:

1)从IGraphicBufferProducer中获取一块内存ANativeWindowBuffer。

2)将ANativeWindowBuffer封装成GraphicBuffer。

3)锁定GraphicBuffer,获取存放绘制数据的虚拟地址的指针,用于后续Canvas的绘制。

4)将GraphicBuffer中的变量赋值到ANativeWindow_Buffer中。ANativeWindow_Buffer是ANativeWindowBuffer对外的屏蔽封装,用于指导Canvas在多大的长宽范围内以什么样的格式进行绘制,并提供提交绘制数据的指针。
46

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。
47
    在ACanvas_getNativeHandleFromJava函数中,主要做了两件事:

1)获取Native层Canvas,实际是SkiaCanvas,SkiaCanvas是对SkCanvas的封装。

2)将Canvas转换为ACanvas。
48

2.1.3 Canvas与ANativeWindow_Buffer的绑定

    在graphics::Canvas的setBuffer方法中,会调用android_canvas的ACanvas_setBuffer函数。
49
    在ACanvas_setBuffer函数中,主要做了四件事:

1)声明SkBitmap。SKBitmap是对ANativeWindow_Buffer的封装,SKBitmap会根据ANativeWindow_Buffer的指导,按照指定的大小和格式,向指定的绘制地址写入绘制数据。

2)对SkBitmap进行初始化。

3)通过ACanvas获取Canvas,实际是SkiaCanvas。

4)将SkiaCanvas和SkBitmap绑定。
50

2.1.4 SkBitmap的初始化

    在convert函数中,主要做了三件事:

1)将ANativeWindow_Buffer封装成SkImageInfo。

2)绑定SkImageInfo到SkBitmap中。

3)设置用于存放绘制数据的虚拟地址的指针。
51

2.1.5 SkiaCanvas与SkBitmap的绑定

    在SkiaCanvas的setBitmap方法中,主要做了三件事:

1)将SkBitmap封装成SkCanvas。

2)保存SkCanvas对应的指针。

3)通过SkCanvas指针获取SkCanvas并保存。
52

2.1.6 SkCanvas的创建

    在SkCanvas的构造方法中,主要做了两件事:

1)将SkBitmap封装为SkBitmapDevice。

2)保存SkBitmapDevice。
53

2.2 矩形的绘制

    当在TextureView的onSurfaceTextureAvailable方法中调用Canvas的drawRect方法时,在Canvas的drawRect方法中,会调用nDrawRect方法。
54
    Canvas的nDrawRect方法对应的Native实现为android_graphics_Canvas的drawRect函数。在drawRect函数中,主要做了两件事:

1)获取Native层Canvas。

2)通过Canvas绘制矩形。
55
    在SkiaCanvas的drawRect方法中,会调用SkCanvas的drawRect方法。最终会绘制到SKBitmap上。SKBitmap封装了图像绘制缓冲,实际会绘制到图像缓冲上。
56

2.3 绘制的提交

    通过调用TextureView的unlockCanvasAndPost方法可以提交本次的绘制。在TextureView的unlockCanvasAndPost方法中,如果参数中Canvas与TextureView中的全局变量mCanvas相同,会调用了nUnlockCanvasAndPost方法。
57
    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)提交绘制。
58
    在native_window_unlockAndPost函数中,会调用ANativeWindow的perform方法,发送类型为int的消息NATIVE_WINDOW_UNLOCK_AND_POST。
59
    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方法。
60
    在Surface的perform方法中,会根据消息的不同类型,调用不同的方法处理。如果消息为NATIVE_WINDOW_UNLOCK_AND_POST,会调用dispatchUnlockAndPost方法。在Surface的dispatchUnlockAndPost方法中,会调用unlockAndPost方法。
61
    在Surface的unlockAndPost方法中,主要做了三件事:

1)解除GraphicBuffer锁定。

2)将渲染完的图像缓冲添加到IGraphicBufferProducer中。

3)清除对GraphicBuffer的引用。
62
    在Surface的queueBuffer方法中,主要做了两件事:

1)获取缓存位置。

2)提交缓存。
63
    通过Surface的初始化流程,可以知道这里Surface的实际类型为BBQSurface,因此IGraphicBufferProducer对应的类型为BBQBufferQueueProducer。

    在BBQBufferQueueProducer的queueBuffer方法中,主要做了四件事:

1)创建FenceTime。

2)创建渲染帧BufferItem。

3)对BufferItem进行初始化设置。

4)通知消费者消费渲染帧。
64

2.4 渲染帧的回调

    通过Surface的初始化流程,可以知道这里的mCore的类型为BufferQueueCore。BufferQueueCore的IConsumerListener的类型为BufferQueue::ProxyConsumerListener。

    调用BufferQueue::ProxyConsumerListener的onFrameAvailable方法,最终会调用JNISurfaceTextureContext的onFrameAvailable方法。
65
    在JNISurfaceTextureContext的onFrameAvailable方法中,主要做了两件事:

1)获取JNI。

2)通过JNI调用Java层SurfaceTexture的静态方法postEventFromNative。
66
    在SurfaceTexture的postEventFromNative方法中,主要做了两件事:

1)从SurfaceTexture的弱引用中获取SurfaceTexture,从SurfaceTexture中获取Handler。

2)使用Handler发送消息。
67
    在Handler的sendEmptyMessage方法中,会调用handleMessage方法。在handleMessage方法中,会回调OnFrameAvailableListener的onFrameAvailable方法。
68
    这里的OnFrameAvailableListener就是TextureView中的全局变量mUpdateListener。在OnFrameAvailableListener的onFrameAvailable方法中,会请求界面刷新。
69

3.TextureView的绘制

    当下一次VSync信号到来时,会触发TextureView的draw方法。在TextureView的draw方法中,首先会判断是否开启硬件加速。在判断开启硬件加速后,主要做了三件事:

1)将Canvas转换为RecordingCanvas。

2)获取TextureLayer。

3)如果TextureLayer不为空,则标记本次的更新,同时绘制TextureLayer。
70

3.1 渲染标识位的更新

    在TextureView的applyUpdate方法中,主要做了两件事:

1)更新SurfaceTexture。

2)回调通知本次的更新。
71
    在TextureLayer的updateSurfaceTexture方法中,主要做了两件事:

1)更新Native层SurfaceTexture。

2)保存本次更新的DeferredLayerUpdater。
72
    TextureLayer的nUpdateSurfaceTexture方法对应的Native实现为android_graphics_TextureLayer的TextureLayer_updateSurfaceTexture函数。

    在TextureLayer_updateSurfaceTexture函数中,主要做了两件事:

1)获取Native层DeferredLayerUpdater。

2)更新对应标识位。
73
    在DeferredLayerUpdater的updateTexImage方法中,会将标识位设置为true。
74

3.2 TextureLayer的绘制

    在RecordingCanvas的drawTextureLayer方法中,调用了nDrawTextureLayer方法。
75
    RecordingCanvas的nDrawTextureLayer方法对应的Native实现为android_graphics_DisplayListCanvas的android_view_DisplayListCanvas_drawTextureLayer函数。在android_view_DisplayListCanvas_drawTextureLayer函数中,主要做了三件事:

1)获取Native层Canvas。

2)获取Native层DeferredLayerUpdater。

3)绘制DeferredLayerUpdater。
76
    Java层RecordingCanvas对应的Native层Canvas为SkiaRecordingCanvas,详情参考:Android硬件渲染流程。

    在SkiaRecordingCanvas的drawLayer方法中,主要做了两件事:

1)将DeferredLayerUpdater封装陈LayerDrawable,将LayerDrawable转换为父类SkDrawable对应的指针。

2)获取SkDrawable并进行绘制。
77
    SkiaRecordingCanvas继承自SkiaCanvas。这里的drawDrawable方法在SkiaRecordingCanvas的父类SkiaCanvas中实现。

    在SkiaCanvas的drawDrawable方法中,会调用SkCanvas的drawDrawable方法。
78
    在SkCanvas的drawDrawable方法中,会调用子类RecordingCanvas的onDrawDrawable方法。
79
    在RecordingCanvas的onDrawDrawable方法中,会调用之前保存的DisplayListData的drawDrawable方法。在DisplayListData的drawDrawable方法中,会创建一个DrawDrawable指令并保存。
80

4.硬件加速层的处理

    在Android硬件渲染中,分成了绘制和渲染两个阶段。在渲染阶段,会调用DrawFrameTask的syncFrameState方法。参考:Android硬件渲染流程。

    在DrawFrameTask的syncFrameState方法中,主要做了两件事:

1)处理硬件加速层,如TextureView的绘制。

2)构建TreeInfo。
81
    在DeferredLayerUpdater的apply方法中,主要做了六件事:

1)如果Layer为空,则创建Layer。

2)判断更新标识位是否允许更新,如果允许则重制标识位。

3)从SurfaceTexture中获取一块已经绘制好的缓存。

4)使用硬件渲染,将绘制好的缓存渲染成SkImage,并返回SkImage指针。

5)释放缓存。

6)使用SkImage指针对Layer进行更新。
82

4.1 图像缓存的获取

    在ASurfaceTexture_dequeueBuffer函数中,主要做了三件事:

1)通过SurfaceTexture获取绘制缓存,并通过参数返回缓存的位置信息。

2)将绘制缓存强制转换为AHardwareBuffer。

3)为AHardwareBuffer增加一个引用。
83
    在SurfaceTexture的dequeueBuffer方法中,会调用ImageConsumer的dequeueBuffer方法。

    ImageConsumer是对SurfaceTexture的获取渲染完成缓存方法的封装,内部持有ImageSlot数组。ImageSlot是对EGLSyncKHR的封装,EGLSyncKHR是类似Fence的用于EGL绘制之间的同步信号。

    ImageSlot数组中的每个元素与SurfaceTexture中GraphicBuffer数组的每个元素的位置一一对应。当通过ImageConsumer从SurfaceTxture中获取GraphicBuffer时,ImageConsumer会在ImageSlot数组中相同的位置创建一个EGLSyncKHR。
84
    在ImageConsumer的dequeueBuffer方法中,主要做了五件事:

1)创建BufferItem。

2)通过SurfaceTexture对BufferItem进行初始化。

3)从BufferItem中获取缓存位置信息。

4)使用位置信息对参数进行初始化。

5)根据位置信息从SurfaceTexture中获取缓存。
85
    Slot中保存着缓存的指针与对应Fence的指针。

4.2 图像缓存的渲染

    在ImageSlot的createIfNeeded方法中,主要做了两件事:

1)首次调用时,会为ImageSlot创建对应的AutoBackendTextureRelease。AutoBackendTextureRelease用于管理SkImage的生命周期,通过引用计数的方式使GPU持续渲染。

2)通过AutoBackendTextureRelease创建和获取SkImage。
86

4.3 Layer的更新

    在DefferredLayerUpdater的updateLayer方法中,会对SkImage指针进行保存。
87

5.绘制的渲染

    在实际渲染时,会调用DrawDrawable的draw方法。在DrawDrawable的draw方法中,会调用SkDrawable的draw方法。在SkDrawable的draw方法中,有回调用onDraw方法。SkDrawable的onDraw方法在子类LayerDrawable中重写。参考:Android硬件渲染流程。
88
    在LayerDrawable的onDraw方法中,主要做了两件事:

1)从DeferredLayerUpdater中获取绘制完成的Layer。

2)将Layer中的内容绘制到SkCanvas上。
89
    在LayerDrawable的DrawLayer方法中,主要做了两件事:

1)从Layer中获取SkImage指针。

2)通过SkImage指针获取SkImage,并绘制到SkCanvas上。
90

三.总结

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的对比

    SurfaceViewTextureView
初始化时机首次绘制前首次绘制过程中
图像生产消费模型BLASTBufferQueueSurfaceTexture
绘制渲染过程的线程切换绘制线程 -> UI线程绘制线程 -> UI线程 -> Render线程
是否有独立的Surface
是否有独立的图像生产消费模型
是否有独立的Layer

这篇关于SurfaceView与TextureView的绘制渲染的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1013725

相关文章

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

OpenGL ES 2.0渲染管线

http://codingnow.cn/opengles/1504.html Opengl es 2.0实现了可编程的图形管线,比起1.x的固定管线要复杂和灵活很多,由两部分规范组成:Opengl es 2.0 API规范和Opengl es着色语言规范。下图是Opengl es 2.0渲染管线,阴影部分是opengl es 2.0的可编程阶段。   1. 顶点着色器(Vert

使用matplotlib绘制散点图、柱状图和饼状图-学习篇

一、散点图 Python代码如下: num_points = 100x = np.random.rand(num_points) #x点位随机y = np.random.rand(num_points) #y点位随机colors = np.random.rand(num_points) #颜色随机sizes = 1000 * np.random.rand(num_points) # 大

黑神话:悟空》增加草地绘制距离MOD使游戏场景看起来更加广阔与自然,增强了游戏的沉浸式体验

《黑神话:悟空》增加草地绘制距离MOD为玩家提供了一种全新的视觉体验,通过扩展游戏中草地的绘制距离,增加了场景的深度和真实感。该MOD通过增加草地的绘制距离,使游戏场景看起来更加广阔与自然,增强了游戏的沉浸式体验。 增加草地绘制距离MOD安装 1、在%userprofile%AppDataLocalb1SavedConfigWindows目录下找到Engine.ini文件。 2、使用记事本编辑

Excel绘制CDF图

对如下20个原始数据绘制cdf图 1. 对数据进行排序,从小到大 2. 计算累积分布: 计算公式为: 然后对C3下拉,得到累积分布数据。 3. 选中B、C两列绘制散点图:

【鸿蒙HarmonyOS NEXT】调用后台接口及List组件渲染

【鸿蒙HarmonyOS NEXT】调用后台接口及List组件渲染 一、环境说明二、调用后台接口及List组件渲染三、总结 一、环境说明 DevEco Studio 版本: API版本:以12为主 二、调用后台接口及List组件渲染 后台接口及返回数据分析 JSON数据格式如下: {"code": 0,"data": {"total": 6,"pageSize"

【python 图像绘制】图像绘制知识总结

颜色图谱 具体颜色描述autumn 红橙黄cool 青-洋红copper 黑-铜flag 红-白-蓝-黑gray 黑-白hot 黑-红-黄-白hsv hsv颜色空间, 红-黄-绿-青-蓝-洋红-红inferno 黑-红-黄jet 蓝-青-黄-红magma 黑-红-白pink 黑-粉-白plasma 绿-红-黄prism 红-黄-