这周抽空研究了一下SurfaceFlinger,发现真正复杂的并不是SurfaceFlinger本身,而是android的display显示系统,网上关于这部分的介绍有不少,本不打算写的,但是发现还是记录一下研究代码的过程比较好,一是能够帮助自己理清思路,另一个原因就是以后当这块内容忘记的时候,能快速的通过这个记录捡起来。

    一.  android显示系统的建立

    我们看SurfaceFlinger的定义就知道,它其实是一个Thread, 因此SurfaceFlinger的初始化工作就理所当然的放在了SurfaceFlinger线程中,详见readyToRun()@SurfaceFlinger.cpp

    SurfaceFlinger对于显示的管理是通过一个或多个GraphicPlane对象(目前android只实现了一个)来管理的,

@SurfaceFlinger.h

[cpp]  view plain copy
  1. GraphicPlane                mGraphicPlanes[1];  
    其实,GraphicPlane类只是一个wrapper层,目的是当android支持多个显示系统时,通过该类来管里各自的图形系统,显示系统真正的初始化工作是通过DisplayHardware类来初始化底层图形系统的管理与显示的。真正的图形显示系统的初始化在init()@DisplayHardware.cpp     目前,android支持一个图形系统,这个图形系统是全局的,surfaceflinger可以访问,其他不通过surfaceflinger进行图形处理的application也可以对其进行操作。


    1. FrameBuffer的建立

    framebuffer,确切的是说是linux下的framebuffer,,它是linux图形显示系统中一个与图形硬件无关的抽象层,user完全不用考虑我们的硬件设备,而仅仅使用framebuffer就可以实现对屏幕的操作。

    android的framebuffer并没有被SurfaceFlinger直接使用,而是在framebuffer外做了一层包装,这个包装就是FramebufferNativeWindow,我们来看一下FramebufferNativeWindow的创建过程。

   我们的framebuffer是由一个设备符fbDev来表示的,它是FramebufferNativeWindow的一个成员,我们来分析一下对fbDev的处理过程。

    1.1. fbDev设备符

    1.1.1 gralloc library

    在这之前,先介绍一下gralloc library,它的形态如grallocBOARDPLATFORM.so, BOARDPLATFORM可以从属性ro.board.platform中获得,这篇文章中我们以Qualcomm msmx7x30为例,也就是gralloc.msm7x30.so中,它的源路径在hardware/msm7k/libgralloc-qsd8k。

    framebuffer的初始化需要通过HAL gralloc.msm7x30.so 来完成与底层硬件驱动的适配,但是gralloc library并不是平台无关的,不同的vendor可能会实现自己的gralloc library,因此为了保证在创建framebuffer时能够平台无关,android只能是动态的判断并使用当前的gralloc library,android通过从gralloc library中再抽象出一个hw_module_t结构来供使用,它为framebuffer的初始化提供了需要的gralloc.msm7x30.so业务。因此通过这个hw_module_t结构我们就不需要知道当前系统使用的到底是哪个gralloc library。按规定,所有gralloc library中的这个结构体被命名为HAL_MODULE_INFO_SYM(HMI)。当前分析的系统中,HAL_MODULE_INFO_SYM在hardware/msm7k/libgralloc-qsd8k/galloc.cpp。

    1.1.2 打开fbDev设备符    

    下面看如何打开 打开fbDev设备符。通过HAL_MODULE_INFO_SYM提供的gralloc.msm7x30.so的接口我们调用到了fb_device_open()@hardware/msm7k/libgralloc-qsd8kframebuffer.cpp。

[cpp]  view plain copy
  1. int fb_device_open(hw_module_t const* module, const char* name,  
  2.         hw_device_t** device)  
  3. {  
  4.     int status = -EINVAL;  
  5.     if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {  
  6.         alloc_device_t* gralloc_device;  
  7.         status = gralloc_open(module, &gralloc_device);  
  8.   
  9.         /* initialize our state here */  
  10.         fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));  
  11.         memset(dev, 0, sizeof(*dev));  
  12.   
  13.         /* initialize the procs */  
  14.         dev->device.common.tag = HARDWARE_DEVICE_TAG;  
  15.   
  16.         private_module_t* m = (private_module_t*)module;  
  17.         status = mapFrameBuffer(m);  
  18.   
  19. }  

在这个函数中,主要为fbDev设备符指定一个fb_context_t实例,并通过函数mapFrameBuffer()对设备节点/dev/graphics/fb0进行操作,操作的目的有:

1.获得屏幕设备的信息,并将屏幕信息保存在HAL_MODULE_INFO_SYM(上面代码中的module)中。

 2. 向/dev/graphics/fb0请求page flip模式,page flip模式需要至少2个屏幕大小的buffer,page flip模式在后面介绍。目前android系统中设置为2个屏幕大小的buffer。当然屏幕设备可能不支持page flip模式。

mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp

[cpp]  view plain copy
  1. /* 
  2.  * Request NUM_BUFFERS screens (at lest 2 for page flipping) 
  3.  */  
  4. info.yres_virtual = info.yres * NUM_BUFFERS;  
  5.   
  6.   
  7. uint32_t flags = PAGE_FLIP;  
  8. if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {  
  9.     info.yres_virtual = info.yres;  
  10.     flags &= ~PAGE_FLIP;  
  11.     LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");  
  12. }  

3. 映射屏幕设备缓存区给fbDev设备符。

mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp

[cpp]  view plain copy
  1. /* 
  2.  * map the framebuffer 
  3.  */  
  4.   
  5. int err;  
  6. size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);  
  7. module->framebuffer = new private_handle_t(dup(fd), fbSize,  
  8.         private_handle_t::PRIV_FLAGS_USES_PMEM);  
  9.   
  10. module->numBuffers = info.yres_virtual / info.yres;  
  11. module->bufferMask = 0;  
  12.   
  13. void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);  
  14. if (vaddr == MAP_FAILED) {  
  15.     LOGE("Error mapping the framebuffer (%s)", strerror(errno));  
  16.     return -errno;  
  17. }  
  18. module->framebuffer->base = intptr_t(vaddr);  
  19. memset(vaddr, 0, fbSize);  

1.2 grDev设备符

在为framebuffer,也就是FramebufferNativeWindow申请内存之前,我们还要介绍一个概念,就是grDev设备符。它虽然也叫设备符,但是它和具体的设备没有直接关系,我们看它的类型就是知道了alloc_device_t,没错,grDev设备符就是为了FramebufferNativeWindow管理内存使用的。为FramebufferNativeWindow提供了申请/释放内存的接口。

    1.3 FramebufferNativeWindow内存管理

     FramebufferNativeWindow维护了2个buffer,  [cpp]  view plain copy
  1. sp buffers[2];  

    1.3.1 屏幕设备支持page filp模式

    目前的android系统默认要求屏幕设备给系统映射2个屏幕大小的缓存区,以便支持page flip模式,如果屏幕设备支持page flip模式,那么 FramebufferNativeWindow中buffers将分别指向一个屏幕大小的屏幕设备缓存区。 [cpp]  view plain copy
  1. // create a "fake" handles for it  
  2. intptr_t vaddr = intptr_t(m->framebuffer->base);  
  3. private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,  
  4.                                              private_handle_t::PRIV_FLAGS_USES_PMEM |  
  5.                                              private_handle_t::PRIV_FLAGS_FRAMEBUFFER);  
  6.   
  7. // find a free slot  
  8. for (uint32_t i=0 ; i
  9.     if ((bufferMask & (1LU<
  10.         m->bufferMask |= (1LU<
  11.         break;  
  12.     }  
  13.     vaddr += bufferSize;  
  14. }  
  15.   
  16. hnd->base = vaddr;  
  17. hnd->offset = vaddr - intptr_t(m->framebuffer->base);  
  18. *pHandle = hnd;  

    1.3.2 屏幕设备不支持page flip模式

    在 mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中可以得知,如果屏幕设备不支持page flip模式,那么numBuffer值将为1而不是2,那么映射过来的屏幕缓存区将只有一个屏幕大小,不够支持page flip模式,那么此时将不使用这一个屏幕大小的屏幕缓存区,而改为去dev/pmem设备去申请。

gralloc_alloc_framebuffer_locked()@hardware/msm7k/libgralloc-qsd8k/gpu.cpp

[cpp]  view plain copy
  1.     const uint32_t bufferMask = m->bufferMask;  
  2.     const uint32_t numBuffers = m->numBuffers;  
  3.     const size_t bufferSize = m->finfo.line_length * m->info.yres;  
  4.     if (numBuffers == 1) {  
  5.         // If we have only one buffer, we never use page-flipping. Instead,  
  6.         // we return a regular buffer which will be memcpy'ed to the main  
  7.         // screen when post is called.  
  8.         int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;  
  9.         return gralloc_alloc_buffer(bufferSize, newUsage, pHandle);  
  10.     }  

    2. 打开Overlay

    同选择gralloc library相似,根据属性值来选择何时的overlay库,如果vendor厂商没有提供overlay库的话,那么系统将使用默认的overlay库overlay.default.so。同样的我们获得overlay库的HAL_MODULE_INFO_SYM结构体,作为系统调用overlay的接口。 [cpp]  view plain copy
  1. if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {  
  2.     overlay_control_open(module, &mOverlayEngine);  
  3. }  

    3. 选择OpenGL ES library(也即软/硬件加速)

    OpenGL (Open Graphics Library)[3] is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics. The interface consists of over 250 different function calls which can be used to draw complex three-dimensional scenes from simple primitives. OpenGL was developed by Silicon Graphics Inc. (SGI) in 1992[4] and is widely used in CAD, virtual reality, scientific visualization, information visualization, flight simulation, and video games. OpenGL is managed by the non-profit technology consortium Khronos Group.。     android是默认支持OpenGL ES软件加速的,library为libGLES_android,源码路径为frameworks\base\opengl\libagl;如果手机设备支持硬件加速的话,那么复杂的图像处理工作将交由GPU去处理,那么效率将大大提高。但是如果系统真的存在硬件加速,它是如何选择何时用软件加速?何时用硬件加速的呢?     如何查看是否有GPU来实现硬件加速,很容易查看/system/lib/egl/egl.cfg文件内容 [java]  view plain copy
  1. 0 0 android  
  2. 0 1 adreno200  
    因此只要我们的移动设备芯片集成了GPU,并提供了对应的GL图形库,那么我们就可以在我们的工程中device目录下的egl.cfg文件中加入类似上面的配置,那么我们的系统就会支持硬件加速。 如adreno200 GPU提供的GL图形库:
[cpp]  view plain copy
  1. libGLESv1_CM_adreno200.so  
  2. libGLESv2_adreno200.so  
  3. libEGL_adreno200.so  
    那么假如我们的系统中软硬件加速都支持了,那么我们从代码来看能不能让用户自由的选择加速类型,我们带着问题来研究一下代码。

   3.1 OpenGL初始化

    在调用不管是软件加速的还是硬件加速的OpenGL api之前,我们都需要把软硬两种模式的各自的OpenGL api提取出来,抽象出一个interface来供系统使用,这个过程我称之为OpenGL初始化过程。     软硬两种模式的OpenGL api被分别指定到了一个全局数组的对应位置。
frameworks/base/opengl/libs/EGL/egl.cpp
[cpp]  view plain copy
  1. static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];  
[cpp]  view plain copy
  1. enum {  
  2.     IMPL_HARDWARE = 0,  
  3.     IMPL_SOFTWARE,  
  4.     IMPL_NUM_IMPLEMENTATIONS  
  5. };  
gEGLImpl[IMPL_HARDWARE]中保存着硬件图形设备的OpenGL api地址,从 [cpp]  view plain copy
  1. libGLESv1_CM_adreno200.so  
  2. libGLESv2_adreno200.so  
  3. libEGL_adreno200.so  
这3个库中获得;gEGLImpl[IMPL_SOFTWARE]中保存着软件的OpenGL api地址,从libGLES_android.so中获取。 这部分代码在egl_init_drivers_locked()@frameworks/base/opengl/libs/EGL/egl.cpp

3.2 EGL和GLES api

    在OpenGL的初始化过程中,OpenGL提供了两套api,分别称为EGL和GLES。android在OPENGL初始化过程中,会将两种不同的接口分开管理,从下面代码中我们可以看到EGL和GLES api地址被存储到了不同的位置。 @frameworks\base\opengl\libs\EGL\Loader.h
[cpp]  view plain copy
  1. enum {  
  2.     EGL         = 0x01,  
  3.     GLESv1_CM   = 0x02,  
  4.     GLESv2      = 0x04  
  5. };  
load_driver()@frameworks\base\opengl\libs\EGL\Loader.cpp 上面枚举的EGL表示ELG api;GLESvq1_CM表示OpenGL ES 1.0的api;GLESv2表示OpenGL ES 2.0的api。 EGL api地址最终被存储在gEGLImpl[].egl中; GLESvq1_CM api地址最终被存储在gEGLImpl[].hooks[GLESv1_INDEX]->gl中; GLESv2 api地址最终被存储在gEGLImpl[].hooks[GLESv2_INDEX]->gl中;

3.2.1 EGL api     EGL is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system. It handles graphics context management, surface/buffer binding, and rendering synchronization and enables high-performance, accelerated, mixed-mode 2D and 3D rendering using other Khronos APIs.    上面引用了官方的定义,可以看出,EGL是系统和OPENGL ES之间的接口,它的声明在文件frameworks\base\opengl\libs\EGL\egl_entries.in。

3.2.2 GLES     GLES才是真正的OpenGL ES的api,它的声明我们可以在frameworks\base\opengl\libs\entries.in找到。目前的android系统不但将EGL提供给系统使用,同时将GLES也提供给了系统使用,这个我们可以在最开始的显示系统的结构图中可以看到,surfacefliger和framework的opengl模块均可以访问EGL和GLES接口。

3.3 OpenGL config

    每个OpenGL库都根据不同的像素格式(pixel format)提供了一系统的config,android根据framebuffer中设置的像素格式来选择合适的config,android根据中各config中的属性信息来创建main surface和openGL上下文。

3.3.1 系统默认pixel format

    当前的代码分析是基于gingerbread的,在 mapFrameBufferLocked()@hardware/msm7k/libgralloc-qsd8k/framebuffer.cpp中我们可以找到framebuffer的pixel format的类型 [cpp]  view plain copy
  1.    if(info.bits_per_pixel == 32) {  
  2. /* 
  3. * Explicitly request RGBA_8888 
  4. */  
  5.   
  6. /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do 
  7. * not use the MDP for composition (i.e. hw composition == 0), ask for 
  8. * RGBA instead of RGBX. */  
  9. if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)  
  10.     module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;  
  11. else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0))  
  12.     module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;  
  13. else  
  14.     module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;  
  15.    } else {  
  16. /* 
  17. * Explicitly request 5/6/5 
  18. */  
  19. module->fbFormat = HAL_PIXEL_FORMAT_RGB_565;  
  20.    }  
目前的移动设备都是真彩色,所以这里我们认为我们的屏幕设备支持的是HAL_PIXEL_FORMAT_RGBA_8888。

    

3.3.2 config初始化

所有的OpenGL库提供的config,同样需要将软硬两种模式的各自的OpenGL config提取出来供系统使用,如同OpenGL api地址一样。OpenGL config提取出来后保存在另外一个全局变量 [cpp]  view plain copy
  1. static egl_display_t gDisplay[NUM_DISPLAYS];  
[cpp]  view plain copy
  1. //  EGLDisplay are global, not attached to a given thread  
  2. const unsigned int NUM_DISPLAYS = 1;  
中,不同于gEGLImpl分开保存软硬件api,所有的config,不论软硬件的,均保存在gDisplay[0],因为所有的config是以屏幕区分的,同一块屏幕应该保存同一份config信息。
在提取出的openGL的config时,会保存到gDisplay[0].config中,在这儿有一个很tricky的实现,它保证了硬件加速器的优先使用! [cpp]  view plain copy
  1.         // sort our configurations so we can do binary-searches  
  2.         qsort(  dp->configs,  
  3.                 dp->numTotalConfigs,  
  4.                 sizeof(egl_config_t), cmp_configs);  
  5.   
最终,上述代码会将 gDisplay[0].config中的配置按照先硬件的,后软件的规则做一个总体的排序。
代码在eglInitialize()@frameworks/base/opengl/libs/EGL/egl.cpp

3.3.3 config选择

上文说到,android会根据framebuffer的pixel format信息来获取对应的config,这个过程只选择一个合适的config,选到为止。

3.3.3.1 满足属性要求

并不是所有的config都可以被选择,首先这个config的属性需要满足 init()@DisplayHardware.cpp
[cpp]  view plain copy
  1. // initialize EGL  
  2. EGLint attribs[] = {  
  3.         EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,  
  4.         EGL_NONE,           0,  
  5.         EGL_NONE  
  6. };  

3.3.3.2 满足RGBA要求

在pixelflinger中,为系统提供了各个pixel format的基本信息,RGBA值,字节数/pixel,位数/pixel。 system/core/libpixelflinger/format.cpp
[cpp]  view plain copy
  1. static GGLFormat const gPixelFormatInfos[] =  
  2. {   //          Alpha    Red     Green   Blue  
  3.     {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE  
  4.     {  4, 32, {{32,24,   8, 0,  16, 8,  24,16 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_8888  
android会根据 pixelflinger的pixel format信息,去和openGL的config比较,得到想要的config。 selectConfigForPixelFormat()@frameworks/base/libs/ui/EGLUtils.cpp
[cpp]  view plain copy
  1. EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);  
  2. if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {  
  3.     free(configs);  
  4.     return BAD_VALUE;  
  5. }  
  6.   
  7. const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);  
  8. const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);  
  9. const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);  
  10. const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);   
  11.   
  12. int i;  
  13. EGLConfig config = NULL;  
  14. for (i=0 ; i
  15.     EGLint r,g,b,a;  
  16.     EGLConfig curr = configs[i];  
  17.     eglGetConfigAttrib(dpy, curr, EGL_RED_SIZE,   &r);  
  18.     eglGetConfigAttrib(dpy, curr, EGL_GREEN_SIZE, &g);  
  19.     eglGetConfigAttrib(dpy, curr, EGL_BLUE_SIZE,  &b);  
  20.     eglGetConfigAttrib(dpy, curr, EGL_ALPHA_SIZE, &a);  
  21.     if (fbSzA <= a && fbSzR <= r && fbSzG <= g && fbSzB  <= b) {  
  22.         config = curr;  
  23.         break;  
  24.     }  
  25. }  

    4. 创建main surface

    要让OpenGL进行图形处理,那么需要在OpenGL中创建一个openGL surface。代码在eglCreateWindowSurface()@ frameworks/base/opengl/libs/EGL/egl.cpp 调用当前的config所处的openGL库的api来创建surface。通过validate_display_config()方法来获取当前config的openGL api。 创建的surface会和FramebufferNativeWindow关联到一起。

    5. 创建 OpenGL ES 上下文

    An OpenGL context represents many things. A context stores all of the state associated with this instance of OpenGL. It represents the (potentially visible) default framebufferthat rendering commands will draw to when not drawing to a framebuffer object. Think of a context as an object that holds all of OpenGL; when a context is destroyed, OpenGL is destroyed.

   http://www.opengl.org/wiki/OpenGL_context

 具体的创建过程专业术语太多,也没有仔细研究不再介绍。

    6. 绑定context和surface

    有了surface,有了 FramebufferNativeWindow,有了context,基本上与图形系统相关的概念都有了,下一步就是把这几个概念关联起来,在创建surface时已经将surface和FramebufferNativeWindow关联了起来。     eglMakeCurrent()@ frameworks/base/opengl/libs/EGL/egl.cpp

6.1 多线程支持

OpenGL 提供了多线程的支持,有以下2点的支持: 1. 一个Context只能被一个线程使用,不能存在多个线程使用同一个context。因此在多线层操作中使用到了TLS技术,即Thread-local storage,来保证context被唯一使用。 makeCurrent()@frameworks/base/opengl/libs/libagl/egl.cpp
[cpp]  view plain copy
  1.     ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();  
  2.     if (gl) {  
  3.         egl_context_t* c = egl_context_t::context(gl);  
  4.         if (c->flags & egl_context_t::IS_CURRENT) {  
  5.             if (current != gl) {  
  6.                 // it is an error to set a context current, if it's already  
  7.                 // current to another thread  
  8.                 return -1;  
  9.             }  
  10.         } else {  
  11.             if (current) {  
  12.                 // mark the current context as not current, and flush  
  13.                 glFlush();  
  14.                 egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;  
  15.             }  
  16.         }  
  17.         if (!(c->flags & egl_context_t::IS_CURRENT)) {  
  18.             // The context is not current, make it current!  
  19.             setGlThreadSpecific(gl);  
  20.             c->flags |= egl_context_t::IS_CURRENT;  
  21.         }  
2. 在同一进程中,对于不同的线程对OpenGL库的访问,可能使用的GLES api version不同,同样可以使用TLS技术来保证多线程过程中,不同线程调用各自的GLES api。 前面我们介绍过GLES api地址被存放在gEGLImpl[].hooks[VERSION]->gl中,因此为保证多线程支持,android将gEGLImpl[].hooks[VERSION]保存到了TLS中,这样就实现了不同线程各自调用各自版本的GLES api。 eglMakeCurrent()@frameworks/base/opengl/libs/EGL/egl.cpp
[cpp]  view plain copy
  1. // cur_c has to be valid here (but could be terminated)  
  2. if (ctx != EGL_NO_CONTEXT) {  
  3.     setGlThreadSpecific(c->cnx->hooks[c->version]);  
  4.     setContext(ctx);  
  5.     _c.acquire();  
  6. else {  
  7.     setGlThreadSpecific(&gHooksNoContext);  
  8.     setContext(EGL_NO_CONTEXT);  
  9. }  
尽管openGL 实现了多线程的支持,目前我从代码中别没有找到多线程的使用。

6.2 设置surface和context之间的关系

由于vendor厂商提供的GPU的GLES库是不可见的,因此以libGLES_android.so软件加速为例来说明这个过程。 contex中保存着两个surface,read和draw,多少情况下这两个surface为同一个surface。 设置FramebufferNativeWindow中Buffers[2]之一为surface的数据区, 通过connect()和bindDrawSurface()。最终的形态如下图所示:


在init()@DisplayHardware.cpp中,在绑定surface和context之后,马上在当前线程中unbind了context,通过 [cpp]  view plain copy
  1. // Unbind the context from this thread  
  2. eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  
这么做的目的应该是支持多display系统中的特殊处理,目的是当系统有多个display系统的话,那么surfaceflinger就会去定义多个 DisplayHardware对象,那么为了保证下一个DisplayHardware对象的创建不受影响,在当前的DisplayHardware创建完成后,将context从当前的进程中unbind掉。 不过没关系,在所有的DisplayHardware创建完成之后,surfaceflinger会重新bind 主Display系统的context和surface。 readyToRun()@SurfaceFlinger.cpp
[cpp]  view plain copy
  1. // initialize primary screen  
  2. // (other display should be initialized in the same manner, but  
  3. // asynchronously, as they could come and go. None of this is supported  
  4. // yet).  
  5. const GraphicPlane& plane(graphicPlane(dpy));  
  6. const DisplayHardware& hw = plane.displayHardware();  
  7. const uint32_t w = hw.getWidth();  
  8. const uint32_t h = hw.getHeight();  
  9. const uint32_t f = hw.getFormat();  
  10. hw.makeCurrent();  

下图为这个图形系统的类图结构。

接下来研究一下framework是如何与surfaceflinger进行业务交互的。

       1)如何创建surface

       2)如何显示窗口等等

       所有的这一切都是通过系统服务WindowManagerService与surfaceflinger来进行的。

        Android中的Surface机制这一块代码写的比较难理解,光叫Surface的类就有3个,因此本篇文章从两部分来分析。

       首先,想要理解Surface机制,还是需要首先理清各个类之间的关系。

       其次,在理解了整个Surface机制的类关系之后,到时我们再结合前一篇文章中对显示系统的介绍,研究一下一个Surface是如何和显示系统建立起联系来的,这个联系主要是指Surface的显示buffer的存储管理。

        在下篇文章中,再分析SurfaceFlinger是如何将已经存储了窗口图形数据的Surface Buffer显示到显示系统中。

1. Surface机制的静态关系

    将这一部分叫做Surface机制,是有别于SurfaceFlinger而言的,android的图形系统中,作为C/S模型两端的WMS和SurfaceFlinger是图形系统业务的核心,但是不把WMS和SurfaceFlinger中间的这层联系搞清楚的话,是很难理解整个图形系统的,在本文中我将两者之间的这个联系关系称之为Surface机制,它的主要任务就是创建一个Surface,ViewRoot在这个Surface上描绘当前的窗口,SurfaceFlinger将这个Surface flinger(扔)给显示系统将其呈现在硬件设备上。其实这里这个Surface在不同的模块中是以不同的形态存在的,唯一不变的就是其对应的显示Buffer。

1.1 ViewRoot和WMS共享Surface

      我们知道每个Activity都会有一个ViewRootImpl作为Activity Window与WMS交互的接口,ViewRootImpl会绘制整个Activity的窗口View到Surface上,因此我们在ViewRootImpl中就有了创建Surface的需求。看一下代码中的Surface的定义:

ViewRootImpl.java

[cpp]  view plain copy
  1. // These can be accessed by any thread, must be protected with a lock.  
  2. // Surface can never be reassigned or cleared (use Surface.clear()).  
  3. private final Surface mSurface = new Surface();  

Surface(SurfaceTexture surfaceTexture)@Surface.java

[cpp]  view plain copy
  1. /** 
  2.  * Create Surface from a {@link SurfaceTexture}. 
  3.  * 
  4.  * Images drawn to the Surface will be made available to the {@link 
  5.  * SurfaceTexture}, which can attach them an OpenGL ES texture via {@link 
  6.  * SurfaceTexture#updateTexImage}. 
  7.  * 
  8.  * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 
  9.  * Surface. 
  10.  */  
  11. public Surface(SurfaceTexture surfaceTexture) {  
  12.     if (DEBUG_RELEASE) {  
  13.         mCreationStack = new Exception();  
  14.     }  
  15.     mCanvas = new CompatibleCanvas();  
  16.     initFromSurfaceTexture(surfaceTexture);  
  17. }  

       由上面可以看出在ViewRootImpl中定义的Surface只是一个空壳,那么真正的Surface是在哪里被初始化的呢?大管家WMS中!当ViewRootImpl请求WMS relayout时,会将ViewSurface中的Surface交给WMS初始化。在WMS中,对应每个WindowState对象,在relayout窗口时,同样会创建一个Surface,wms中的这个Surface会真正的初始化,然后再将这个WMS Surface复制给ViewRootImpl中的Surface。这么实现的目的就是保证ViewRootImpl和WMS共享同一个Surface。ViewRootImpl对Surface进行绘制,WMS对这个Surface进行初始化及管理。很和谐!

[email protected]

[cpp]  view plain copy
  1. private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,  
  2.         boolean insetsPending) throws RemoteException {  
  3.     ...   
  4.     int relayoutResult = sWindowSession.relayout(  
  5.             mWindow, mSeq, params,  
  6.             (int) (mView.getMeasuredWidth() * appScale + 0.5f),  
  7.             (int) (mView.getMeasuredHeight() * appScale + 0.5f),  
  8.             viewVisibility, insetsPending, mWinFrame,  
  9.             mPendingContentInsets, mPendingVisibleInsets,  
  10.             mPendingConfiguration, mSurface);  
  11.     //Log.d(TAG, "<<<<<< BACK FROM relayout");  
  12.     if (restore) {  
  13.         params.restore();  
  14.     }  
  15.       
  16.     if (mTranslator != null) {  
  17.         mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);  
  18.         mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);  
  19.         mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);  
  20.     }  
  21.     return relayoutResult;  
  22. }  

relayoutWindow()@WindowManagerService.java

[cpp]  view plain copy
  1. public int relayoutWindow(Session session, IWindow client, int seq,  
  2.         WindowManager.LayoutParams attrs, int requestedWidth,  
  3.         int requestedHeight, int viewVisibility, boolean insetsPending,  
  4.         Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,  
  5.         Configuration outConfig, Surface outSurface) {  
  6.     boolean displayed = false;  
  7.     boolean inTouchMode;  
  8.     boolean configChanged;  
  9.   
  10.     // if they don't have this permission, mask out the status bar bits  
  11.     synchronized(mWindowMap) {  
  12.         WindowState win = windowForClientLocked(session, client, false);  
  13.   
  14.         if (viewVisibility == View.VISIBLE &&  
  15.                 (win.mAppToken == null || !win.mAppToken.clientHidden)) {  
  16.             displayed = !win.isVisibleLw();  
  17.             ...  
  18.             try {  
  19.                 Surface surface = win.createSurfaceLocked();  
  20.                 if (surface != null) {  
  21.                     outSurface.copyFrom(surface);  
  22.                     win.mReportDestroySurface = false;  
  23.                     win.mSurfacePendingDestroy = false;  
  24.                     if (SHOW_TRANSACTIONS) Slog.i(TAG,  
  25.                             "  OUT SURFACE " + outSurface + ": copied");  
  26.                 } else {  
  27.                     // For some reason there isn't a surface.  Clear the  
  28.                     // caller's object so they see the same state.  
  29.                     outSurface.release();  
  30.                 }  
  31.             } catch (Exception e) {  
  32.                 mInputMonitor.updateInputWindowsLw(true /*force*/);  
  33.                   
  34.                 Slog.w(TAG, "Exception thrown when creating surface for client "  
  35.                          + client + " (" + win.mAttrs.getTitle() + ")",  
  36.                          e);  
  37.                 Binder.restoreCallingIdentity(origId);  
  38.                 return 0;  
  39.             }  
  40.             ...  
  41.        }  
  42. }  

1.2 SurfaceSession

     SurfaceSession可以认为是创建Surface过程中,WMS和SurfaceFlinger之间的会话层,通过这个SurfaceSession实现了Surface的创建。 

     一个SurfaceSession表示一个到SurfaceFlinger的连接,通过它可以创建一个或多个Surface实例。

       SurfaceSession是JAVA层的概念,@SurfaceSession.java。它对应的native实体是一个SurfaceComposerClient对象。

       SurfaceComposerClient通过ComposerService类来获得SurfaceFlinger的IBinder接口ISurfaceComposer,但是光获得SurfaceFlinger的IBinder接口是不够的,要想请求SurfaceFlinger创建一个Surface,还需要向SurfaceFlinger获得一个IBinder接口ISurfaceComposerClient,通过这个ISurfaceComposerClient来请求SurfaceFlinger创建一个Surface,为什么这么绕呢,为什么不直接让SurfaceFlinger创建Surface呢?

     站在SurfaceFlinger的角度来考虑,对于SurfaceFlinger来说,可能有多个Client来请求SurfaceFlinger的业务,每个Client可能会请求SurfaceFlinger创建多个Surface,那么SurfaceFlinger本地需要提供一套机制来保存每个client请求创建的Surface,SurfaceFlinger通过为每个client创建一个Client对象实现这个机制,并将这个Client的IBinder接口ISurfaceComposerClient返给SurfaceComposerClient对象。SurfaceComposerClient对象在通过ISurfaceComposerClient去请求创建Surface(ISurfaceComposerClient的功能只有创建和销毁Surface)。

@SurfaceFlinger.h

[cpp]  view plain copy
  1. class Client : public BnSurfaceComposerClient  
  2.   
  3. class SurfaceFlinger :  
  4.         public BinderService,  
  5.         public BnSurfaceComposer,  
  6.         public IBinder::DeathRecipient,  
  7.         protected Thread  

@SurfaceComposerClient.cpp

[cpp]  view plain copy
  1. void SurfaceComposerClient::onFirstRef() {  
  2.     sp sm(getComposerService());  
  3.     if (sm != 0) {  
  4.         sp conn = sm->createConnection();  
  5.         if (conn != 0) {  
  6.             mClient = conn;  
  7.             mStatus = NO_ERROR;  
  8.         }  
  9.     }  
  10. }  

在SurfaceFlinger中对应的执行代码为:

[cpp]  view plain copy
  1. sp SurfaceFlinger::createConnection()  
  2. {  
  3.     sp bclient;  
  4.     sp client(new Client(this));  
  5.     status_t err = client->initCheck();  
  6.     if (err == NO_ERROR) {  
  7.         bclient = client;  
  8.     }  
  9.     return bclient;  
  10. }  

     下图描述了整个SurfaceSession的内部结构与工作流程。

      蓝色箭头是SurfaceComposerClient通过ComposerService获得SurfaceFlinger的IBinder接口ISurfaceComposer过程;

      红色箭头表示SurfaceComposerClient通过IPC请求SurfaceFlinger创建Client的过程,并获得Client的IBinder接口ISurfaceComposerClient;

      绿色箭头表示SurfaceComposerClient通过IPC请求Client创建Surface。


 

1.3 Surface的形态

       上一节我们分析了SurfaceSession的静态结构,得知Surface的创建过程是通过SurfaceSession这个中间会话层去请求SurfaceFlinger去创建的,并且这篇文章中,我们说了半天Surface了,那么究竟我们要创建的Surface究竟是什么样的一个东西呢,它的具体形态是什么呢?这一小节我们就来分析以下Surface的形态。

1.3.1 client端Surface的形态

    首先,我们看一下Surface在WMS中定义的代码

createSurfaceLocked()@WindowState.java

[cpp]  view plain copy
  1. Surface createSurfaceLocked() {  
  2.       if (mSurface == null) {  
  3.           ...  
  4.           try {  
  5.               final boolean isHwAccelerated = (mAttrs.flags &  
  6.                       WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;  
  7.               final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : mAttrs.format;  
  8.               if (!PixelFormat.formatHasAlpha(mAttrs.format)) {  
  9.                   flags |= Surface.OPAQUE;  
  10.               }  
  11.               mSurface = new Surface(  
  12.                       mSession.mSurfaceSession, mSession.mPid,  
  13.                       mAttrs.getTitle().toString(),  
  14.                       0, w, h, format, flags);  
  15.               if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,  
  16.                       "  CREATE SURFACE "  
  17.                       + mSurface + " IN SESSION "  
  18.                       + mSession.mSurfaceSession  
  19.                       + ": pid=" + mSession.mPid + " format="  
  20.                       + mAttrs.format + " flags=0x"  
  21.                       + Integer.toHexString(flags)  
  22.                       + " / " + this);  
  23.           }   
  24.           ...  
  25.       }  
  26.       return mSurface;  
  27.   }  

       我们可以看到,它将SurfaceSession对象当作参数传递给了Surface的构造函数。往下看Surface的构造函数。

@Surface.java

[cpp]  view plain copy
  1. /** create a surface with a name @hide */  
  2. public Surface(SurfaceSession s,  
  3.         int pid, String name, int display, int w, int h, int format, int flags)  
  4.     throws OutOfResourcesException {  
  5.     if (DEBUG_RELEASE) {  
  6.         mCreationStack = new Exception();  
  7.     }  
  8.     mCanvas = new CompatibleCanvas();  
  9.     init(s,pid,name,display,w,h,format,flags);  
  10.     mName = name;  
  11. }  

       这个构造函数,不同于我们在ViewRootImpl中看到的Surface的构造函数,这个构造函数并不是一个空壳,它做了本地实体的初始化工作,因此这个Surface才是一个真正的Suface。

       Native函数init([email protected]_view_Surface.cpp)会调到SurfaceComposerClient::createSurface,再向下的过程在上一节的图中描述很清楚了,在此不作介绍了。同时,先不管SurfaceFlinger为SurfaceComposerClient创建的Surface到底是一个什么东西,我们先看看SurfaceComposerClient为WMS创建的是一个什么东西?

@SurfaceComposerClient.cpp

[cpp]  view plain copy
  1. sp SurfaceComposerClient::createSurface(  
  2.         const String8& name,  
  3.         DisplayID display,  
  4.         uint32_t w,  
  5.         uint32_t h,  
  6.         PixelFormat format,  
  7.         uint32_t flags)  
  8. {  
  9.     sp result;  
  10.     if (mStatus == NO_ERROR) {  
  11.         ISurfaceComposerClient::surface_data_t data;  
  12.         sp surface = mClient->createSurface(&data, name, //mClient为BpSurfaceComposerClient  
  13.                 display, w, h, format, flags);  
  14.         if (surface != 0) {  
  15.             result = new SurfaceControl(this, surface, data);  
  16.         }  
  17.     }  
  18.     return result;  
  19. }  

       从上面的代码我们可以看出,SurfaceComposerClient为WMS返回的是一个SurfaceControl对象,这个SurfaceControl对象包含了surfaceFlinger为SurfaceComposerClient创建的surface,这个surfaceFlinge创建的Surface在Client端的形态为ISurface。这个过程下面分析SurfaceFlinger端的Surface形态时会看到。

    SurfaceControl类中还有一个非常重要的成员mSurfaceData,它的类型也叫做Surface,定义在frameworks/base/include/surfaceflinger/surface.h。这个Surface提供了显示Buffer的管理。在文章的后面再介绍。

@frameworks/base/libs/gui/Surface.cpp

[cpp]  view plain copy
  1. sp SurfaceControl::getSurface() const  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     if (mSurfaceData == 0) {  
  5.         sp surface_control(const_cast(this));  
  6.         mSurfaceData = new Surface(surface_control);  
  7.     }  
  8.     return mSurfaceData;  
  9. }  


1.3.2 SurfaceFlinger端Surface形态

SurfaceFlinger::[email protected]   [cpp]  view plain copy
  1. sp SurfaceFlinger::createSurface(  
  2.         ISurfaceComposerClient::surface_data_t* params,  
  3.         const String8& name,  
  4.         const sp& client,  
  5.         DisplayID d, uint32_t w, uint32_t h, PixelFormat format,  
  6.         uint32_t flags)  
  7. {  
  8.     sp layer;  
  9.     sp surfaceHandle;  
  10.   
  11.     if (int32_t(w|h) < 0) {  
  12.         LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",  
  13.                 int(w), int(h));  
  14.         return surfaceHandle;  
  15.     }  
  16.   
  17.     //LOGD("createSurface for pid %d (%d x %d)", pid, w, h);  
  18.     sp normalLayer;  
  19.     switch (flags & eFXSurfaceMask) {  
  20.         case eFXSurfaceNormal:  
  21.             normalLayer = createNormalSurface(client, d, w, h, flags, format);  
  22.             layer = normalLayer;  
  23.             break;  
  24.         case eFXSurfaceBlur:  
  25.             // for now we treat Blur as Dim, until we can implement it  
  26.             // efficiently.  
  27.         case eFXSurfaceDim:  
  28.             layer = createDimSurface(client, d, w, h, flags);  
  29.             break;  
  30.         case eFXSurfaceScreenshot:  
  31.             layer = createScreenshotSurface(client, d, w, h, flags);  
  32.             break;  
  33.     }  
  34.   
  35.     if (layer != 0) {  
  36.         layer->initStates(w, h, flags);  
  37.         layer->setName(name);  
  38.         ssize_t token = addClientLayer(client, layer);  
  39.   
  40.         surfaceHandle = layer->getSurface();  
  41.         if (surfaceHandle != 0) {  
  42.             params->token = token;  
  43.             params->identity = layer->getIdentity();  
  44.             if (normalLayer != 0) {  
  45.                 Mutex::Autolock _l(mStateLock);  
  46.                 mLayerMap.add(layer->getSurfaceBinder(), normalLayer);  
  47.             }  
  48.         }  
  49.   
  50.         setTransactionFlags(eTransactionNeeded);  
  51.     }  
  52.   
  53.     return surfaceHandle;  
  54. }  

       当client请求SurfaceFlinger创建Surface时,SurfaceFlinger首先根据WMS提供的窗口的属性来一个命名为Layer概念的对象,然后再根据Layer创建它的子类对象LayerBaseClient::BSurface。此时第三个名为Surface(BSurface)类出现了,下一节我们来介绍一下这个Layer的概念。

 

 1.4 Layer 

 

1.4.1 Layer的分类

    目前,android4.0中有3中Layer类型,如上图所示。  

    1. Layer, 普通的Layer,它为每个Client端请求的Surface创建显示Buffer。

    2. LayerDim,这种Layer不会创建显示Buffer,它只是将通过这个Layer将原来FrameBuffer上的数据进行暗淡处理;

    3. LayerScreenshot,这种Layer不会创建显示Buffer,它只是将通过这个Layer将原来FrameBuffer上的数据进行抓取;

     从这些Layer看出,我们分析的重点就是第一种Layer,下面我们着重分析一下普通的Layer。Layer的具体业务我们在下一篇文章中分析

1.4.2 Layer的管理

    上文我们在分析SurfaceSession的时候,也分析过,一个Client可能会创建多个Surface,也就是要创建多个Layer,那么SurfaceFlinger端如何管理多个Layer呢?SurfaceFlinger维护了3个Vector来管理LayerDefaultKeyedVector< size_t, wp > mLayers;SurfaceFlinger:LayerVector     layersSortedByZ;>。

       第一种方式,我们知道SurfaceFlinger会为每个SurfaceSession创建一个Client对象,这第一种方式就是将所有为某一个SurfacSession创建的Layer保存在它对应的Client对象中。

     SurfaceFlinger::createSurface()@SurfaceFlinger.cpp,调用路径如下:

     SurfaceFlinger::addClientLayer->

         client->attachLayer(lbc)->

              mLayers.add(name, layer);

       第二种方式,在SurfaceFlinger中以排序的方式保存下来。其调用路径如下:

       SurfaceFlinger::addClientLayer->

          SurfaceFlinger::addLayer_l->

             mCurrentState.layersSortedByZ.add(layer)

       第三种方式,将所有的创建的普通的Layer保存起来,以便Client Surface在请求实现Buffer时能够辨识Client Surface对应的Layer。

SurfaceFlinger::createSurface()@SurfaceFlinger.cpp

[cpp]  view plain copy
  1. surfaceHandle = layer->getSurface();  
  2. if (surfaceHandle != 0) {  
  3.     params->token = token;  
  4.     params->identity = layer->getIdentity();  
  5.     if (normalLayer != 0) {  
  6.         Mutex::Autolock _l(mStateLock);  
  7.         mLayerMap.add(layer->getSurfaceBinder(), normalLayer);  
  8.     }  
  9. }  

2. Surface 显示Buffer的存储管理

       在前文介绍Client端的Surface形态的内容时,我们提到SurfaceControl中还会维护一个名为Surface对象,它定义在 frameworks/base/libs/surfaceflinger/Surface.h中,它负责向LayerBaseClient::BSurface请求显示Buffer,同时将显示Buffer交给JAVA Surface的Canvas去绘制窗口,我们称这个Surface为Client Surface

2.1 窗口绘制

    我们先从ViewRootImpl中分析一下,它是如何显示窗口View的,如何用到Client Surface请求的显示Buffer的。

draw()@ViewRoot.java

[cpp]  view plain copy
  1. Canvas canvas;  
  2. try {  
  3.     int left = dirty.left;  
  4.     int top = dirty.top;  
  5.     int right = dirty.right;  
  6.     int bottom = dirty.bottom;  
  7.   
  8.     final long lockCanvasStartTime;  
  9.     if (ViewDebug.DEBUG_LATENCY) {  
  10.         lockCanvasStartTime = System.nanoTime();  
  11.     }  
  12.   
  13.     canvas = surface.lockCanvas(dirty);  
  14.   
  15.     if (ViewDebug.DEBUG_LATENCY) {  
  16.         long now = System.nanoTime();  
  17.         Log.d(TAG, "Latency: Spent "  
  18.                 + ((now - lockCanvasStartTime) * 0.000001f)  
  19.                 + "ms waiting for surface.lockCanvas()");  
  20.     }  
  21.   
  22.     if (left != dirty.left || top != dirty.top || right != dirty.right ||  
  23.             bottom != dirty.bottom) {  
  24.         mAttachInfo.mIgnoreDirtyState = true;  
  25.     }  
  26.   
  27.     // TODO: Do this in native  
  28.     canvas.setDensity(mDensity);  

       上面的代码显示,JAVA Surface 会lock canvas。而Client Surface的创建就在这个过程中,即下面代码中的第一行getSurface().我们先不管Client Surface的创建,先看看Canvas是如何与Client Surface的显示Buffer关联的。

       [email protected]_view_Surface.cpp

[cpp]  view plain copy
  1. static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)  
  2. {  
  3.     const sp& surface(getSurface(env, clazz));  
  4.     if (!Surface::isValid(surface)) {  
  5.         doThrowIAE(env);  
  6.         return 0;  
  7.     }  
  8.   
  9.     // get dirty region  
  10.     Region dirtyRegion;  
  11.     if (dirtyRect) {  
  12.         Rect dirty;  
  13.         dirty.left  = env->GetIntField(dirtyRect, ro.l);  
  14.         dirty.top   = env->GetIntField(dirtyRect, ro.t);  
  15.         dirty.right = env->GetIntField(dirtyRect, ro.r);  
  16.         dirty.bottom= env->GetIntField(dirtyRect, ro.b);  
  17.         if (!dirty.isEmpty()) {  
  18.             dirtyRegion.set(dirty);  
  19.         }  
  20.     } else {  
  21.         dirtyRegion.set(Rect(0x3FFF,0x3FFF));  
  22.     }  
  23.   
  24.     Surface::SurfaceInfo info;  
  25.     status_t err = surface->lock(&info, &dirtyRegion);  
  26.     if (err < 0) {  
  27.         const charconst exception = (err == NO_MEMORY) ?  
  28.             OutOfResourcesException :  
  29.             "java/lang/IllegalArgumentException";  
  30.         jniThrowException(env, exception, NULL);  
  31.         return 0;  
  32.     }  
  33.   
  34.     // Associate a SkCanvas object to this surface  
  35.     jobject canvas = env->GetObjectField(clazz, so.canvas);  
  36.     env->SetIntField(canvas, co.surfaceFormat, info.format);  
  37.   
  38.     SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);  
  39.     SkBitmap bitmap;  
  40.     ssize_t bpr = info.s * bytesPerPixel(info.format);  
  41.     bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);  
  42.     if (info.format == PIXEL_FORMAT_RGBX_8888) {  
  43.         bitmap.setIsOpaque(true);  
  44.     }  
  45.     if (info.w > 0 && info.h > 0) {  
  46.         bitmap.setPixels(info.bits);  
  47.     } else {  
  48.         // be safe with an empty bitmap.  
  49.         bitmap.setPixels(NULL);  
  50.     }  
  51.     nativeCanvas->setBitmapDevice(bitmap);  
  52.   
  53.     SkRegion clipReg;  
  54.     if (dirtyRegion.isRect()) { // very common case  
  55.         const Rect b(dirtyRegion.getBounds());  
  56.         clipReg.setRect(b.left, b.top, b.right, b.bottom);  
  57.     } else {  
  58.         size_t count;  
  59.         Rect const* r = dirtyRegion.getArray(&count);  
  60.         while (count) {  
  61.             clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);  
  62.             r++, count--;  
  63.         }  
  64.     }  
  65.   
  66.     nativeCanvas->clipRegion(clipReg);  
  67.   
  68.     int saveCount = nativeCanvas->save();  
  69.     env->SetIntField(clazz, so.saveCount, saveCount);  
  70.   
  71.     if (dirtyRect) {  
  72.         const Rect& bounds(dirtyRegion.getBounds());  
  73.         env->SetIntField(dirtyRect, ro.l, bounds.left);  
  74.         env->SetIntField(dirtyRect, ro.t, bounds.top);  
  75.         env->SetIntField(dirtyRect, ro.r, bounds.right);  
  76.         env->SetIntField(dirtyRect, ro.b, bounds.bottom);  
  77.     }  
  78.   
  79.     return canvas;  
  80. }  

      上面的代码,我们可以看出,Canvas的Bitmap设备设置了Client Surface的显示Buffer为其Bitmap pixel存储空间。 

[cpp]  view plain copy
  1. bitmap.setPixels(info.bits);  

    这样Canvas的绘制空间就有了。下一步就该绘制窗口了。

   draw()@ViewRootImpl.java

[cpp]  view plain copy
  1. try {  
  2.       canvas.translate(0, -yoff);  
  3.       if (mTranslator != null) {  
  4.           mTranslator.translateCanvas(canvas);  
  5.       }  
  6.       canvas.setScreenDensity(scalingRequired  
  7.               ? DisplayMetrics.DENSITY_DEVICE : 0);  
  8.       mAttachInfo.mSetIgnoreDirtyState = false;  
  9.       mView.draw(canvas);  
  10.   }  


    其中ViewRootImpl中的mView为整个窗口的View。它将Render自己和所有它的子View。

2.2 Client Surface的初始化(SurfaceControl中的Surface)

        Client Surface的创建是从ViewRootImpl首次Lock canvas时进行的,这么做的目的可能也是为了节约空间,减少不必要的开支。

        Client Surface的初始化和显示Buffer的管理过程比较复杂,下图给出了这一部分的一个静态结构图,有些东西从图上表现不出来,下面我简单的介绍一下。

 


更多相关文章

  1. Android系统调试(01)日志分析基础流程
  2. Android初始化语言(Android(安卓)Init Language)
  3. JDK8的安装及win10配置JDK8的环境变量
  4. IOS 5编程 -2 -准备工作。
  5. Android系统文件夹结构详细解析
  6. android电话流程(打电话,接电话,挂断电话)(一)
  7. Android系统启动流程(一)解析init进程启动过程
  8. Android(安卓)P 系统新特性概述
  9. android、apple PUSH 异同比较

随机推荐

  1. Android 7.1.2(Android N) Activity启动
  2. android 学习笔记(四)
  3. 关于Android如何禁止屏幕旋转刷新界面
  4. Android 动画小知识点
  5. android之启动桌面activity
  6. Android文件操作
  7. Android ------ 拍照相册选择图片 剪裁图
  8. Android 依赖报错Version 28 (intended f
  9. android hack相关
  10. Linkify匹配电话号码,Email等