GUI系统之SurfaceFlinger(4)opengl es本地窗口SurfaceTextureClient

文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/





1.1.1 SurfaceTextureClient

针对应用程序端的本地窗口是SurfaceTextureClient,和FramebufferNativeWindow一样,它必须继承ANativeWindow:

class SurfaceTextureClient

    : publicANativeObjectBase<ANativeWindow, SurfaceTextureClient,RefBase>

 

这个本地窗口当然也需要实现ANativeWindow所制定的“协议”,我们的重点是关注它与前面的FramebufferNativeWindow有什么不同。SurfaceTextureClient的构造函数只是简单地调用了init函数,后者则对ANativeWindow::dequeueBuffer等函数指针及内部变量赋了初值。由于整个函数的功能很简单,我们只摘录其中的一部分:

/*frameworks/native/libs/gui/SurfaceTextureClient.cpp*/

void SurfaceTextureClient::init() {

    /*给ANativeWindow中的函数指针赋值*/

   ANativeWindow::setSwapInterval  =hook_setSwapInterval;

    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;

    …

    /*为各内部变量赋值,因为此时用户还没有真正发起申请,所以基本是0*/

    mReqWidth = 0;

    mReqHeight = 0;

    …

    mDefaultWidth = 0;

    mDefaultHeight = 0;

    mUserWidth = 0;

    mUserHeight = 0;…

}

SurfaceTextureClient是面向Android系统中所有UI应用程序的,也就是说它承担着单个应用进程中的UI显示需求。基于这点考虑,可以推测出它的内部实现至少会有以下几点:

Ø  提供给上层(主要是java层)绘制图像的“画板”

前面说过,这个本地窗口分配的内存应该不是来自于帧缓冲区,那么具体是由谁分配的,又是如何管理的呢?

Ø  它与SurfaceFlinger间是如何分工的

显然SurfaceFlinger需要收集系统中所有应用程序绘制的图像数据,然后集中显示到物理屏幕上。在这个过程中,SurfaceTextureClient扮演了什么样的角色呢?

 

我们先来解释下这个类中的一些重要的成员变量,如下表所示:

表格 11‑4 SurfaceTextureClient部分成员变量一览

成员变量

说明

sp<ISurfaceTexture> mSurfaceTexture

这个变量是SurfaceTextureClient的核心,很多“协议”就是通过它实现的,后面会有详细讲解

BufferSlot mSlots[NUM_BUFFER_SLOTS]

从名称上可以看出,这是Client内部用于存储buffer的地方,容量NUM_BUFFER_SLOTS最多达32个。BufferSlot类内部又由一个GraphicBuffer和一个dirtyRegion组成,当有用户dequeueBuffer时就会分配真正的空间

uint32_t  mReqWidth

SurfaceTextureClient中有多组相似的宽高变量,它们之间是有区别的。这里的宽和高是指下一次dequeue时将会申请的尺寸,初始值都是1

uint32_t  mReqHeight

uint32_t mReqFormat

和上面的两变量类似,这是指下次dequeue时将会申请的buffer的像素格式,初始值是PIXEL_FORMAT_RGBA_8888

uint32_t mReqUsage

指下次dequeue时将会指定的usage类型

Rect mCrop

Crop表示“修剪”,这个变量将在下次queue时用于修剪缓冲区,可以调用setCrop来设置具体的值

int mScalingMode

同样,这个变量将用于下次queue时对缓冲区进行scale,可以调用setScalingMode来设置具体的值

uint32_t mTransform

用于下次queue时的图形翻转等操作(Transform)

uint32_t mDefaultWidth

默认情况下的缓冲区宽高值

uint32_t mDefaultHeight

uint32_t mUserWidth

如果不为零的话,就是应用层指定的值,将会覆盖前面的mDefaultWidth/ mDefaultHeight

uint32_t mUserHeight

sp<GraphicBuffer>           mLockedBuffer

这三个值需要锁的保护,接下来还会有分析

sp<GraphicBuffer>           mPostedBuffer

Region mDirtyRegion

从这些内部变量的描述中,我们可以大概了解到两点:SurfaceTextureClient中将通过mSurfaceTexture来获得buffer,而且这些缓冲区会被记录在mSlots数组中。接下来就来分析其中的实现细节。

前面SurfaceTextureClient构造函数里我们看到ANativeWindow中的函数指针赋予的是各种以hook开头的函数,这些函数内部又直接调用了SurfaceTextureClient中真正的实现,比如hook_dequeueBuffer对应的是dequeueBuffer。这就好像是“钩子”一样,所以称之为hook。

int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t**buffer) {…

    Mutex::Autolocklock(mMutex);

int buf = -1;

/*Step1. 宽高计算*/

    int reqW = mReqWidth ?mReqWidth : mUserWidth;

int reqH = mReqHeight ? mReqHeight :mUserHeight;

/*Step2. dequeueBuffer得到一个缓冲区*/

    status_t result =mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,mReqFormat, mReqUsage);

    …

   sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);//注意buf只是一个int值,代表的是mSlots数组序号

/*Step3. requestBuffer*/

    if ((result &ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {

        result =mSurfaceTexture->requestBuffer(buf, &gbuf);

        …

    }

    *buffer = gbuf.get();

    return OK;

}

Step1@ SurfaceTextureClient::dequeueBuffer。用于UI绘制的图形缓冲区一定有宽高属性,具体的值由mReqWidth/mReqHeight或者mUserWidth/mUserHeight决定,其中前者的优先级比后者高

Step2@ SurfaceTextureClient::dequeueBuffer。可以看到,真正执行dequeueBuffer操作的确实是mSurfaceTexture(ISurfaceTexture)。这个变量的赋值有两个来源:作为SurfaceTextureClient的构造函数参数传入,然后间接调用setISurfaceTexture来设置的;或者SurfaceTextureClient的子类通过直接调用setISurfaceTexture来生成。

在应用进程环境中,属于后面一种情况。

具体流程就是:当Java层的Surface进行init时,实际上执行的函数是Surface_init@android_view_Surface.cpp。这个JNI函数将进一步调用SurfaceComposerClient::createSurface生成一个SurfaceControl,后者是用于管理Surface的类。它将在SurfaceControl::getSurface时生成一个Surface实例,在构造时通过SurfaceControl:: getSurfaceTexture来获得一个ISurfaceTexture。而Surface类实际上又继承自SurfaceTextureClient,所以它可以调用setISurfaceTexture。

由于Android源码有多处称为Surface的地方,取名极其混乱,我们下面通过一张完整的流程图来帮助大家把这些关系理顺:


图 11‑10 ISurfaceTexture创建流程

 

从这个图中可以看到,ISurfaceTexture是由ISurface::getSurfaceTexture生成的,而ISurface则是由SurfaceFlinger生成的。在这一过程中,总共使用到了三个匿名binderserver,它们所提供的接口整理如下表:

表格 11‑5 与Surface相关的三个匿名binder

匿名Binder

提供的接口

ISurfaceComposerClient

sp<ISurface> createSurface(…);

status_t  destroySurface(SurfaceID sid);

ISurface

sp<ISurfaceTexture> getSurfaceTexture(…);

ISurfaceTexture

status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);

status_t setBufferCount(int bufferCount);

status_t dequeueBuffer(…);

status_t queueBuffer(…);

void cancelBuffer(int slot);

int query(int what, int* value);

status_t setSynchronousMode(bool enabled);

status_t connect(int api, QueueBufferOutput* output);

status_t disconnect(int api);

由此可见,这三个匿名binder是一环扣一环的,也就是说我们访问的顺序只能是ISurfaceComposerClientàISurfaceàISurfaceTexture。当然,第一个匿名binder就一定是需要由一个实名binder来提供,它就是SurfaceFlinger,而SurfaceFlinger则是在ServiceManager中“注册在案”的。具体是在SurfaceComposerClient::onFirstRef()这个函数中,通过向ServiceManager查询名称为“SurfaceFlinger”的binder server来获得的。不过和其它常见binder server不同的是,SurfaceFlinger虽然在ServiceManager中注册的名称为“SurfaceFlinger”,但它在server端实现的binder接口却是ISurfaceComposer,因而SurfaceComposerClient得到的其实是ISurfaceComposer,这点大家要特别注意,否则可能会搞乱。

//我们可以从SurfaceFlinger的继承关系中看出这一区别,如下代码片断

class SurfaceFlinger :

        publicBinderService<SurfaceFlinger>, //在ServiceManager中注册为“SurfaceFlinger”

        public BnSurfaceComposer, //实现的接口却叫ISurfaceComposer,不知道为什么要这么设计。。。

绕了一大圈后,我们接着分析前面dequeueBuffer函数的实现。很显然SurfaceTextureClient只是一个中介,它间接调用mSurfaceTexture也就是ISurfaceTexture的服务。那么ISurfaceTexture在Server端又是由谁来完成的呢?


图 11‑11 ISurfaceTexture的本地端实现

 

因为这里面牵扯到很多新的类,我们先不做过多解释,到后面BufferQueue小节再详细分析其中的依赖关系。

当mSurfaceTexture->dequeueBuffer返回后,buf变量就是mSlots[]数组中可用的成员序号。接下来就要通过这个序号来获取真正的buffer地址,即mSlots[buf].buffer。

 

Step3@ SurfaceTextureClient::dequeueBuffer。假如返回值result中的标志包含了BUFFER_NEEDS_REALLOCATION,说明BufferQueue为这个Slot重新分配了空间,具体细节请参见下一个小节。此时我们还需要另外调用requestBuffer来确定gbuf的值,这其中又牵涉到很多东西,我们放在下面小节统一解释原因。

通过这两个小节,我们学习了显示系统中两个重要的本地窗口,即FramebufferNativewindow和SurfaceTextureClient。第一个窗口是专门为SurfaceFlinger服务的,它由Gralloc提供支持,相对逻辑上很好理解。而SurfaceTextureClient则是为应用程序服务的,同时它从本质上还是由SurfaceFlinger服务统一管理的,因而涉及到很多跨进程的通信细节。这个小节我们只是简单地勾勒出其中的框架,接下去就要分几个方面来做完整的分析了。

Ø  BufferQueue

为应用程序服务的本地窗口SurfaceTextureClient在server端的实现是BufferQueue。我们将详细解析BufferQueue的内部实现,并结合应用程序端的使用流程来理解清楚它们之间的关系。

 

Ø  Buffer、Consumer、Producer是“生产者-消费者”模型中的三个参与对象,如何协调好它们的工作是应用程序能否正常显示UI的关键。在接下来内容的安排上,我们先讲解Buffer(BufferQueue)与Producer(应用程序)间的交互,然后再专门切入Consumer(SurfaceFlinger)做详细分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值