1, http://blog.csdn.net/windskier/article/details/7030732

文章如下:


android surfaceflinger研究----显示系统

5965人阅读 评论(11) 收藏 举报

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

一. android显示系统的建立

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

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

@SurfaceFlinger.h

[cpp] view plain copy
  1. GraphicPlanemGraphicPlanes[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.1gralloc library

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

framebuffer的初始化需要通过HALgralloc.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. intfb_device_open(hw_module_tconst*module,constchar*name,
  2. hw_device_t**device)
  3. {
  4. intstatus=-EINVAL;
  5. if(!strcmp(name,GRALLOC_HARDWARE_FB0)){
  6. alloc_device_t*gralloc_device;
  7. status=gralloc_open(module,&gralloc_device);
  8. /*initializeourstatehere*/
  9. fb_context_t*dev=(fb_context_t*)malloc(sizeof(*dev));
  10. memset(dev,0,sizeof(*dev));
  11. /*initializetheprocs*/
  12. dev->device.common.tag=HARDWARE_DEVICE_TAG;
  13. private_module_t*m=(private_module_t*)module;
  14. status=mapFrameBuffer(m);
  15. }

在这个函数中,主要为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. *RequestNUM_BUFFERSscreens(atlest2forpageflipping)
  3. */
  4. info.yres_virtual=info.yres*NUM_BUFFERS;
  5. uint32_tflags=PAGE_FLIP;
  6. if(ioctl(fd,FBIOPUT_VSCREENINFO,&info)==-1){
  7. info.yres_virtual=info.yres;
  8. flags&=~PAGE_FLIP;
  9. LOGW("FBIOPUT_VSCREENINFOfailed,pageflippingnotsupported");
  10. }


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

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

[cpp] view plain copy
  1. /*
  2. *maptheframebuffer
  3. */
  4. interr;
  5. size_tfbSize=roundUpToPageSize(finfo.line_length*info.yres_virtual);
  6. module->framebuffer=newprivate_handle_t(dup(fd),fbSize,
  7. private_handle_t::PRIV_FLAGS_USES_PMEM);
  8. module->numBuffers=info.yres_virtual/info.yres;
  9. module->bufferMask=0;
  10. void*vaddr=mmap(0,fbSize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
  11. if(vaddr==MAP_FAILED){
  12. LOGE("Errormappingtheframebuffer(%s)",strerror(errno));
  13. return-errno;
  14. }
  15. module->framebuffer->base=intptr_t(vaddr);
  16. 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<NativeBuffer>buffers[2];

1.3.1 屏幕设备支持page filp模式

目前的android系统默认要求屏幕设备给系统映射2个屏幕大小的缓存区,以便支持page flip模式,如果屏幕设备支持page flip模式,那么 FramebufferNativeWindow中buffers将分别指向一个屏幕大小的屏幕设备缓存区。 [cpp] view plain copy
  1. //createa"fake"handlesforit
  2. intptr_tvaddr=intptr_t(m->framebuffer->base);
  3. private_handle_t*hnd=newprivate_handle_t(dup(m->framebuffer->fd),size,
  4. private_handle_t::PRIV_FLAGS_USES_PMEM|
  5. private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
  6. //findafreeslot
  7. for(uint32_ti=0;i<numBuffers;i++){
  8. if((bufferMask&(1LU<<i))==0){
  9. m->bufferMask|=(1LU<<i);
  10. break;
  11. }
  12. vaddr+=bufferSize;
  13. }
  14. hnd->base=vaddr;
  15. hnd->offset=vaddr-intptr_t(m->framebuffer->base);
  16. *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. constuint32_tbufferMask=m->bufferMask;
  2. constuint32_tnumBuffers=m->numBuffers;
  3. constsize_tbufferSize=m->finfo.line_length*m->info.yres;
  4. if(numBuffers==1){
  5. //Ifwehaveonlyonebuffer,weneverusepage-flipping.Instead,
  6. //wereturnaregularbufferwhichwillbememcpy'edtothemain
  7. //screenwhenpostiscalled.
  8. intnewUsage=(usage&~GRALLOC_USAGE_HW_FB)|GRALLOC_USAGE_HW_2D;
  9. returngralloc_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. 00android
  2. 01adreno200
因此只要我们的移动设备芯片集成了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.1OpenGL初始化

在调用不管是软件加速的还是硬件加速的OpenGL api之前,我们都需要把软硬两种模式的各自的OpenGL api提取出来,抽象出一个interface来供系统使用,这个过程我称之为OpenGL初始化过程。 软硬两种模式的OpenGL api被分别指定到了一个全局数组的对应位置。
frameworks/base/opengl/libs/EGL/egl.cpp
[cpp] view plain copy
  1. staticegl_connection_tgEGLImpl[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. *ExplicitlyrequestRGBA_8888
  4. */
  5. /*Note:theGLdriverdoesnothavear=8g=8b=8a=0config,soifwedo
  6. *notusetheMDPforcomposition(i.e.hwcomposition==0),askfor
  7. *RGBAinsteadofRGBX.*/
  8. if(property_get("debug.sf.hw",property,NULL)>0&&atoi(property)==0)
  9. module->fbFormat=HAL_PIXEL_FORMAT_RGBX_8888;
  10. elseif(property_get("debug.composition.type",property,NULL)>0&&(strncmp(property,"mdp",3)==0))
  11. module->fbFormat=HAL_PIXEL_FORMAT_RGBX_8888;
  12. else
  13. module->fbFormat=HAL_PIXEL_FORMAT_RGBA_8888;
  14. }else{
  15. /*
  16. *Explicitlyrequest5/6/5
  17. */
  18. module->fbFormat=HAL_PIXEL_FORMAT_RGB_565;
  19. }

目前的移动设备都是真彩色,所以这里我们认为我们的屏幕设备支持的是HAL_PIXEL_FORMAT_RGBA_8888。

3.3.2 config初始化

所有的OpenGL库提供的config,同样需要将软硬两种模式的各自的OpenGL config提取出来供系统使用,如同OpenGL api地址一样。OpenGL config提取出来后保存在另外一个全局变量 [cpp] view plain copy
  1. staticegl_display_tgDisplay[NUM_DISPLAYS];
[cpp] view plain copy
  1. //EGLDisplayareglobal,notattachedtoagiventhread
  2. constunsignedintNUM_DISPLAYS=1;
中,不同于gEGLImpl分开保存软硬件api,所有的config,不论软硬件的,均保存在gDisplay[0],因为所有的config是以屏幕区分的,同一块屏幕应该保存同一份config信息。
在提取出的openGL的config时,会保存到gDisplay[0].config中,在这儿有一个很tricky的实现,它保证了硬件加速器的优先使用!
[cpp] view plain copy
  1. <strong></strong>//sortourconfigurationssowecandobinary-searches
  2. qsort(dp->configs,
  3. dp->numTotalConfigs,
  4. sizeof(egl_config_t),cmp_configs);<strong>
  5. </strong>
最终,上述代码会将 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. //initializeEGL
  2. EGLintattribs[]={
  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. staticGGLFormatconstgPixelFormatInfos[]=
  2. {//AlphaRedGreenBlue
  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*constconfigs=(EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
  2. if(eglChooseConfig(dpy,attrs,configs,numConfigs,&n)==EGL_FALSE){
  3. free(configs);
  4. returnBAD_VALUE;
  5. }
  6. constintfbSzA=fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
  7. constintfbSzR=fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
  8. constintfbSzG=fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
  9. constintfbSzB=fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE);
  10. inti;
  11. EGLConfigconfig=NULL;
  12. for(i=0;i<n;i++){
  13. EGLintr,g,b,a;
  14. EGLConfigcurr=configs[i];
  15. eglGetConfigAttrib(dpy,curr,EGL_RED_SIZE,&r);
  16. eglGetConfigAttrib(dpy,curr,EGL_GREEN_SIZE,&g);
  17. eglGetConfigAttrib(dpy,curr,EGL_BLUE_SIZE,&b);
  18. eglGetConfigAttrib(dpy,curr,EGL_ALPHA_SIZE,&a);
  19. if(fbSzA<=a&&fbSzR<=r&&fbSzG<=g&&fbSzB<=b){
  20. config=curr;
  21. break;
  22. }
  23. }

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 上下文

AnOpenGL contextrepresents 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 aframebuffer 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. //itisanerrortosetacontextcurrent,ifit'salready
  7. //currenttoanotherthread
  8. return-1;
  9. }
  10. }else{
  11. if(current){
  12. //markthecurrentcontextasnotcurrent,andflush
  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. //Thecontextisnotcurrent,makeitcurrent!
  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_chastobevalidhere(butcouldbeterminated)
  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. //Unbindthecontextfromthisthread
  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. //initializeprimaryscreen
  2. //(otherdisplayshouldbeinitializedinthesamemanner,but
  3. //asynchronously,astheycouldcomeandgo.Noneofthisissupported
  4. //yet).
  5. constGraphicPlane&plane(graphicPlane(dpy));
  6. constDisplayHardware&hw=plane.displayHardware();
  7. constuint32_tw=hw.getWidth();
  8. constuint32_th=hw.getHeight();
  9. constuint32_tf=hw.getFormat();
  10. hw.makeCurrent();



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


分享到:
17
0
查看评论
8楼 kobewylb2012-04-16 14:08发表[回复]
hi,我之前在Android2.3上能直接open("/dev/graphics/fb0", O_RDONLY) 对Framebuffer进行操作,但是Android3.0之后open("/dev/graphics/fb0", O_RDONLY)就会失败请问是什么原因
7楼 dajijidanaizi2012-03-21 15:26发表[回复]
hi windskier,请问能在其他进程里面map到nativebuffer或framebuffer吗?
6楼 dajijidanaizi2012-03-19 15:09发表[回复]
请问博主:当native buffer的地址分配完后,上层是怎样获取到这个地址的?
5楼 tankai198806192012-02-16 16:54发表[回复]
网上分析Android显示系统的确实很多,其中也不乏大牛级别。但只有博主能让我看懂,博主分析的很清晰、没有把易混淆的地方绕过去、更没有分析错。经典!
4楼 windskier2011-12-19 15:33发表[回复]
回复dajijidanaizi:FramebufferNativeWindow中会定义2个NativeBuffer,这2个NativeBuffer是提供给OpenGL Surface的。这2个NativeBuffer 可以从/dev/fb0中申请,也可以从/dev/pmem中申请。framebuffer不是具体的buffer,你可以把它看作是一种图形缓存机制,其实这2个NativeBuffer就可以看作是framebuffer。我的下一篇文章中对framebuffer的具体情况做了介绍。
3楼 ppppzflpppp2011-12-17 15:41发表[回复]
在viewRoot里面 我在draw函数里面打印了canvas的大小,是480*320没什么问题。你得意思是本来是480*320 结果java层传了个320*480过来? 我通过android_view_Surface.java里面得setSize函数打印得话,屏幕切换得时候 这个函数打印出来得也都是480*320啊 ,现在感觉这个地方思路好乱,没有整体的把握。
Re: windskier2011-12-17 16:15发表[回复]
回复ppppzflpppp:surface尺寸没有问题的话,你跟踪一下在切换屏幕时,WMS有没有通过setOrientation通知SF去更新Orientation?
2楼 ppppzflpppp2011-12-17 14:32发表[回复]
恩 我看了你的另一篇文章收获不小,我现在遇到一个问题就是屏幕一半是黑的,一半显示正常的画面,具体操作过程就是设置一个闹钟,然后进入图库,等闹钟响起,然后切换屏幕方向,这个时候,图库切换成横屏得时候大小成了320*480(本来应该是480*320),这样的话这个区域(0,160,320,480)就显示黑色了,通过log看,sf进入了错误的状态,它走到了drawWormhole()函数里面,但是在handlePageFlip函数里面的注释看,系统是不能调用这个函数的,一旦调用,说明WindowManager出问题了,但是我找了好久也没找到哪里出问题了,希望能得到你得帮助,楼主方便留邮箱或者qq之类得吗?希望能得到你第一时间得帮助。o(∩∩)o...哈哈
Re: windskier2011-12-17 15:19发表[回复]
回复ppppzflpppp:从sf代码来看,mWormholeRegion不为空才会出现这个情况,
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mWormholeRegion区域为屏幕整个的区域减去所有要显示的layer组合在一起的不透明区域,mWormholeRegion不为0说明当前有一部分的区域是没有被layer覆盖到的。这个应该是JAVA层在横竖屏切换时,frame大小错乱导致的,你可以去跟踪一下你在做横屏操作时,创建的Surface的尺寸是否正确?有结果的话分享一下。
1楼 ppppzflpppp2011-12-12 22:02发表[回复]
这文章真是写得太好了,我想请教一下SF里面有个叫Client和UserClient得类,这两个类得关系是什么,各自在什么场合需要用到啊?
Re: windskier2011-12-12 22:30发表[回复]
回复ppppzflpppp:你可以参考一下我的下一篇文章,里边的图里有介绍,从目前的代码来看,Client是供客户端请求SF创建Surface用的,而UserClient主要是配合frameworks/base/libs/surfaceflinger_client/Surface.cpp中的那个Surface,我称之为Client Surface,对其显示Buffer进行一些属性设置以及PageFlip管理用的。
发表评论

更多相关文章

  1. android系统学习笔记六
  2. 为Android应用程序读取/dev下设备而提权
  3. Android(安卓)编译系统(一):Android.mk的学习
  4. Android(安卓)Things | 用Android玩转物联网
  5. Android(安卓)图形架构简介
  6. 关于Android中Dialog点击屏幕外失去焦点消失的问题
  7. android手机修改系统分变率/修改机型/系统属性等信息
  8. Android重写HorizontalScrollView仿ViewPager效果
  9. Android(安卓)开发 res里面的drawable(ldpi、mdpi、hdpi、xhdpi

随机推荐

  1. mysql安装配置方法图文教程(CentOS7)
  2. MySQL按常规排序、自定义排序和按中文拼
  3. 详解如何通过Mysql的二进制日志恢复数据
  4. Linux下mysql5.6.33安装配置教程
  5. Mysql非安装版使用步骤及忘记密码解决方
  6. MySQl数据库必知必会sql语句(加强版)
  7. mysql 5.1版本修改密码及远程登录mysql数
  8. 在centos7下安装和部署java8和mysql
  9. 如何修改Xampp服务器上的mysql密码(图解)
  10. 阿里云安装mysql数据库出现2002错误解决