SurfaceView与TextureView的绘制渲染

news2024/11/16 15:43:29

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1712767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文搞懂Java8 Lambda表达式、方法引用

Lambda表达式介绍 Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。通过Lambda表达式,可以替代我们以前经常写的匿名内部类来实现接口。Lambda表达式本质是一个匿名函数; 体验Lambda表达式 我们通过一个小例子来体验下L…

物联网都有什么优缺点?——青创智通

工业物联网平台解决方案 物联网,这个曾经似乎遥不可及的科技概念,如今已逐渐渗透到我们生活的方方面面。从智能家居到智能工业,从智能医疗到智能城市,物联网技术正在改变着我们的世界。 然而,正如任何一项技术一样&a…

代码随想录算法训练营第五十四天||392.判断子序列、115.不同的子序列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、392.判断子序列 思路 二、115.不同的子序列 思路 一、392.判断子序列 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是…

FPGA中的乒乓操作

为什么不直接选用一个缓存更大的FIFO而选用乒乓操作为什么乒乓操作可以实现低速处理高速数据乒乓操作适用哪些场景 一、乒乓操作结构 首先先介绍一下乒乓操作的原理,其结构如下: 输入选择单元负责将数据送到数据缓冲模块,然后输出选择单元负…

51 html网页

上节内容的网页是hello world的字符串,但实际上网页应该是html格式的这种超文本标记语言,这一节完善一下网页的各种格式和内容 分文件 实际服务器中,网页的界面应该单独放一个文件,服务器从文件里读取网页的内容 先创建一个wroo…

有效运营企业内部社区的板块有哪些?

随着企业内部沟通和协作的重要性日益凸显,建立一个高效运营的企业内部社区成为越来越多企业的首要任务。针对不同的需求和目标,将企业内部社区分为多个板块,可以更好地促进员工之间的沟通、协作和共享知识。下面介绍如何从分多个板块创建的角…

Docker搭建Redis主从 + Redis哨兵模式(一主一从俩哨兵)

我这里是搭建一主一从,俩哨兵,准备两台服务器,分别安装docker 我这里有两台centos服务器 主服务器IP:192.168.252.134 从服务器IP:192.168.252.135 1.两台服务器分别拉取redis镜像 docker pull redis 2.查看镜像 d…

2024长三角快递物流展即将亮相,致鸿物流器材有限公司值得关注

广东致鸿物流器材有限公司,前身为广州致鸿物流器材有限公司,成立于2002年初,是一家中国专业仓储笼研发制造公司,公司员工约400名,日产仓储笼制造规模近8000个,在全国范围内有五大配送服务中心:江…

AI绘画Stable Diffusion XL 可商用模型!写实艺术时尚摄影级真实感大模型推荐(附模型下载)

大家好,我是设计师阿威 大家在使用AI绘画的时候,是不是遇到这种问题:收藏的模型确实很多,可商用的没几个,而今天阿威将给大家带来的这款写实艺术时尚摄影级真实感大模型-墨幽人造人XL, 对于个人来讲完全是…

应用弹窗优先级

背景 由于活动业务越来越多,积累的弹窗越来越多和杂乱,出现如下弹窗交互问题: 弹窗无限重叠,影响操作 弹出顺序无优先级,重要弹窗被隐藏 原因相信大家都一样,产品是一次次迭代的,也可能是不同人开发的,两个毫不相关的业务,弹窗时机也没有任何关联,重不重叠我怎么控制…

第8周 分布式事务与数据一致性主流解决方案落地

第8周 分布式事务与数据一致性主流解决方案落地 1. OpenFeign 服务间的远程调用_实战2. 客户端与服务端负载均衡机制_概念3. 微服务负载均衡NacosLoadbalancer_实战网关基于nacos实现负载均衡:默认轮询方式权重方式实现4. OSI七层网络模型_概念5. 微服务分布式环境下的事务问题…

Ubuntu22.04设置程序崩溃产生Core文件

Ubuntu22.04设置程序崩溃产生Core文件 文章目录 Ubuntu22.04设置程序崩溃产生Core文件摘要Ubuntu 生成Core文件配置1. 检查 core 文件大小限制2. 设置 core 文件大小限制3. 配置 core 文件命名和存储路径4. 重启系统或重新加载配置5. 测试配置 关键字: Ubuntu、 C…

VSCode连接远程服务器使用jupyter报错问题解决

目录 一. 问题描述二. jupyter环境确认三. 插件安装 一. 问题描述 经常会遇到一种问题就是, VSCode连接远程服务器, 上次jupyter notebook 还用的好好的, 下次打开就显示找不到内核了. 今天提供了全套解决方案, 帮大家迅速解决环境问题. 二. jupyter环境确认 首先进入自己需…

React 中的 Fiber 架构

React Fiber 介绍 React Fiber 是 React 的一种重写和改进的核心算法,用于实现更细粒度的更新和高效的调度。它是 React 16 版本中的一个重要更新,使得 React 能够更好地处理复杂和高频的用户交互。以下是对 React Fiber 的详细介绍: 为什么…

java中的工具类

以下是我们到现在学的三个类 在书写工具类的时候我们要遵循以下的规则 类名见面知意是为了知道这个工具类的作用 私有化构造方法的作用是为了不让外界不能创造这个类的对象吗,因为工具类不是描述一个事物的,它是一个工具。 方法定义位静态是为了方便调用…

8086 汇编笔记(一):寄存器

前言 8086 CPU 有 14 个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW 一、通用寄存器 8086 CPU 的所有寄存器都是 16 位的,可以存放两个字节。AX、BX、CX、DX 这 4个寄存器通常用…

剧本杀小程序开发,探索市场发展新的商业机遇

剧本杀游戏作为一个新兴行业,经历了爆发式的增长,剧本杀游戏在市场中的热度不断升高。 不过,在市场的火热下,竞争也在逐渐加大。因此,在市场竞争下,成本低、主题多样、有趣的线上剧本杀小程序成为了创业者…

永恒之蓝(MS17-010)详解

这个漏洞还蛮重要的,尤其在内网渗透和权限提升。 目录 SMB简介 SMB工作原理 永恒之蓝简原理 影响版本 漏洞复现 复现准备 复现过程 修复建议 SMB简介 SMB是一个协议服务器信息块,它是一种客户机/服务器、请求/响应协议,通过SMB协议…

两年半前端面字节,广度和深度让我不想做前端了

两年半经历,面的是前端工程师,字节面试官的问题挺有广度与深度的,这里整理一下面试过程中的题目(有些忘记了),分享给大家: 面试过程中的问题 1、简单的自我介绍与项目经验。 2、一道算法题。 3、一道 …

揭秘!编写高质量代码的关键:码农必知的黄金法则!

文章目录 一、保持代码的简洁与清晰二、遵循良好的命名规范三、注重代码的可读性四、利用抽象与封装五、遵循SOLID原则六、关注代码性能七、确保代码安全性《码农修行:编写优雅代码的32条法则》编辑推荐内容简介目录前言/序言 在编程的世界里,每一位码农…