【Android GUI】FramebufferNativeWindow与Surface

显示整体体系

native window为OpenGL与本地窗口系统之间搭建了桥梁。
在这里插入图片描述
这个窗口系统中,有两类本地窗口,nativewindow1是能直接显示在屏幕的,使用的是帧缓冲区;nativewindow2是从内存缓冲区分配的空间,通常需要通过其他方式(例如将其内容绘制到帧缓冲区)才能在屏幕上显示。

当系统中存在多个需要显示UI的应用程序时,一方面这种改进设计保证了它们都能获得一个“本地窗口”;另一方面这些“本地窗口”也都可以被有序地显示到终端屏幕上,因为SurfaceFlinger会收集所有程序的显示需求,对它们进行统一的图像混合操作,然后输出到自己的NativeWindow-1上。

应用程序也可以使用Skia等第三方图形库,只要它们和SurfaceFlinger之间的“协议”不变即可。
在这里插入图片描述

FramebufferNativeWindow

EGL需要本地窗口为OpenGL创造环境:

EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
NativeWindowTypewindow, const EGLint *attrib_list);

无论哪种本地窗口都需要和NativeWindowType保持一致,数据类型的定义:

/*frameworks/native/opengl/include/egl/Eglplatform.h*/
typedef EGLNativeWindowType  NativeWindowType;//注意这两种数据类型其实是一样的#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
 /* Win32 和 WinCE系统下的定义 */typedef HWND    EGLNativeWindowType;
#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian系统 */typedef void *EGLNativeWindowType;
#elif defined(__ANDROID__) || defined(ANDROID)/* Android系统 */
struct ANativeWindow;typedef struct ANativeWindow* EGLNativeWindowType;#elif defined(__unix__)/* UNIX系统 */typedef Window   EGLNativeWindowType;
#else
#error "Platform not recognized"
#endif

ANativeWindow定义:

/*system/core/include/system/Window.h*/
struct ANativeWindow
{const uint32_t flags; //与Surface或updater有关的属性
    const int   minSwapInterval;//所支持的最小交换间隔时间
    const int   maxSwapInterval;//所支持的最大交换间隔时间
    const float xdpi; //水平方向的密度,以dpi为单位
    const float ydpi;//垂直方向的密度,以dpi为单位
    intptr_t    oem[4];//为OEM定制驱动所保留的空间
    int (*setSwapInterval)(struct ANativeWindow* window, int interval);
    int (*dequeueBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer** buffer, int* fenceFd);
    int (*queueBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer* buffer, int fenceFd);
    int (*cancelBuffer)(struct ANativeWindow* window,
                struct ANativeWindowBuffer* buffer, int fenceFd);
    int (*query)(const struct ANativeWindow* window,int what, int* value);
    int (*perform)(struct ANativeWindow* window,int operation, ... );
    void* reserved_proc[2];
};

FramebufferNativeWindow构造函数

/*frameworks/native/libs/ui/FramebufferNativeWindow.cpp*/
FramebufferNativeWindow::FramebufferNativeWindow() 
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
    hw_module_t const* module;
    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {//加载模块
        int stride;
        int err;
        int i;
        err = framebuffer_open(module, &fbDev);
        err = gralloc_open(module, &grDev);//分别打开fb和grallocif(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
           fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){//根据fb设备属性获得buffer数
            mNumBuffers = fbDev->numFramebuffers;
        } else {
            mNumBuffers = MIN_NUM_FRAME_BUFFERS;//否则就采用最少的buffer数值,即2
        }
        mNumFreeBuffers = mNumBuffers;//可用的buffer个数,初始时是所有buffer可用
        mBufferHead = mNumBuffers-1;for (i = 0; i < mNumBuffers; i++) //给每个buffer初始化
        {
            buffers[i] = new NativeBuffer(fbDev->width, fbDev->height, fbDev->format,
                                  GRALLOC_USAGE _HW_FB);
        }//NativeBuffer是什么?

        for (i = 0; i < mNumBuffers; i++) //给每个buffer分配空间
        {
            err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format,
                       GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);}
             /*为本地窗口赋属性值*/
        const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 
        const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
        const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
        const_cast<int&>(ANativeWindow::minSwapInterval) =fbDev->minSwapInterval;
        const_cast<int&>(ANativeWindow::maxSwapInterval) = fbDev->maxSwapInterval;
    } else {
        ALOGE("Couldn't get gralloc module");
    }
    /*以下代码段开始履行窗口“协议”*/
    ANativeWindow::setSwapInterval = setSwapInterval;
    ANativeWindow::dequeueBuffer = dequeueBuffer;
    ANativeWindow::queueBuffer = queueBuffer;
    ANativeWindow::query = query;
    ANativeWindow::perform = perform;
    /*下面这几个接口已经被废弃了,不过为了保持兼容性,暂时还是保留的*/
    ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED; 
}

重点关注的是FramebufferNativeWindow是如何分配buffer的。

成员变量mNumBuffers代表了FramebufferNativeWindow所管理的buffer总数。它取决于两个方面:首先从fb设备中取值,即numFramebuffers;否则就默认定义为MIN_NUM_FRAME_BUFFERS:

#define MIN_NUM_FRAME_BUFFERS  2
#define MAX_NUM_FRAME_BUFFERS  3

这代表双缓冲或者三缓冲机制。
FramebufferNativeWindow构造函数中的第一个for循环里先给各buffer创建相应的实例(new NativeBuffer),其中的属性值都来源于fbDev,如宽、高、格式等。紧随其后的就是调用Gralloc设备的alloc()方法:

err = grDev->alloc(grDev, fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);

所有申请到的缓冲区都需要由FramebufferNativeWindow中的全局变量buffers[MAX_NUM_FRAME_BUFFERS]来记录,每个数据元素是一个NativeBuffer:

class NativeBuffer : public ANativeObjectBase<ANativeWindowBuffer, 
       NativeBuffer,LightRefBase<NativeBuffer>>
{

NativeBuffer 继承自ANativeWindowBuffer:

typedef struct ANativeWindowBuffer
{int width; //宽
    int height;//高
    …
    buffer_handle_t handle;/*代表内存块的句柄,比如ashmem机制。*/} ANativeWindowBuffer_t;

一个本地窗口包含了很多属性值,如各种标志(flags)、横纵坐标的密度值等。这些数值都可以从fb设备中查询到,我们需要将它们赋予刚生成的FramebufferNativeWindow实例的属性。

FramebufferNativeWindow会将其对应的成员函数逐个填充到ANativeWindow的函数指针中:

ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;

这样的话OpenGL ES就通过ANativeWindow与本地窗口建立了联系。

dequeueBuffer

OpenGL ES就是通过这个方法来分配用于渲染的缓冲区的:

int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd)
{
    FramebufferNativeWindow* self = getSelf(window); /*Step1*/
    Mutex::Autolock _l(self->mutex);/*Step2*//*Step3. 计算mBufferHead */
    int index = self->mBufferHead++;
    if (self->mBufferHead >= self->mNumBuffers)
        self->mBufferHead = 0;//循环

    /*Step4. 如果当前没有可用缓冲区*/
    while (!self->mNumFreeBuffers) {
        self->mCondition.wait(self->mutex);
    }
    /*Step5. 如果有人释放了缓冲区*/
    self->mNumFreeBuffers--;
    self->mCurrentBufferIndex = index;
    *buffer = self->buffers[index].get();
    *fenceFd = -1;
    return 0;
}

Surface

应用程序端的本地窗口是Surface,和FramebufferNativeWindow一样,它必须继承AnativeWindow

class Surface
    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
/*frameworks/native/libs/gui/Surface.cpp*/
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer): mGraphicBufferPro duc  er(bufferProducer)
{/*给ANativeWindow中的函数指针赋值*/
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;/*为各内部变量赋值,因为此时用户还没有发起申请,所以大部分变量的初始值是0*/
    mReqWidth = 0;
    mReqHeight = 0;
    …
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;}

surface承担应用进程UI显示的责任。

Surface将通过mGraphicBufferProducer来获取buffer,而且这些缓冲区会被记录在mSlots数组中。

int Surface::dequeueBuffer(android_native_buffer_t** buffer,int *fenceFd) {…
    Mutex::Autolock lock(mMutex);
    int buf = -1;
    /*Step1. 宽高计算*/
    int reqW = mReqWidth ? mReqWidth : mUserWidth;
    int reqH = mReqHeight ? mReqHeight : mUserHeight;
    /*Step2. dequeueBuffer得到一个缓冲区*/
    sp<Fence> fence;
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
                           reqW, reqH, mReqFormat, mReqUsage);/*生产者发挥作用了*/ 
    …
sp<GraphicBuffer>&gbuf(mSlots[buf].buffer);/*注意buf是一个int值,
                                            代表的是mSlots数组序号*/if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);//申请空间}*buffer = gbuf.get();
}

摘自原书:

大致流程是:ViewRootImpl持有一个Java层的Surface对象(即mSurface),初始时是空的。后续ViewRootImpl将向WindowManagerService发起relayout请求,此时mSurface才被赋予真正有效的值。WindowManagerService会先让WindowStateAnimator生成一个SurfaceControl,然后通过Surface.copyFrom()函数将其复制到mSurface中。这个复制函数会通过native接口nativeCreateFrom SurfaceControl来生成本地Surface(C++)对象,具体是在android_view_Surface.cpp文件中。JNI函数nativeCreateFromSurfaceControl将从SurfaceControl中提取出Surface(C++),最终记录到Surface(Java)的成员变量中。这样,后期我们就可以从此变量中还原出底层的Surface对象了。

Surface由SurfaceControl管理,而后者又由SurfaceComposerClient创建。

/*frameworks/native/libs/gui/SurfaceComposerClient.cpp*/
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name,uint32_t w,
                                       uint32_t h,PixelFormat format,uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags, &handle, &gbp);  
        //生成一个Surfaceif (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);//SurfaceControl是“本地”的对象
        }
    }
    return sur;
}

mClient是一个ISurfaceComposerClient的sp指针,通过它创建一个surface。

SurfaceControl对象并不是由ISurfaceComposerClient的createSurface直接生成的,这个函数的参数中包括了gbp,即前面所说的“buffer生产者”。

真正与SurfaceFlinger间有联系的应该就是gbp。

来看下ISurfaceComposerClient的服务端:

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

这里面与三个匿名Binder相关联,它们是由surfaceflinger提供的。surface flinger是注册在server manager上面的。

总结

FramebufferNativeWindow是为surfaceflinger服务的,由Gralloc提供。
surface虽然为应用程序服务的,但是本质上还是由surface flinger服务统一管理的。

参考

《深入理解Android内核设计思想》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林树杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值