收藏 分销(赏)

Android的Graphic系统分析之skia.doc

上传人:二*** 文档编号:4714211 上传时间:2024-10-10 格式:DOC 页数:17 大小:44KB 下载积分:5 金币
下载 相关 举报
Android的Graphic系统分析之skia.doc_第1页
第1页 / 共17页
本文档共17页,全文阅读请下载到手机保存,查看更方便
资源描述
skia库 Skia库是一个外部库,代码位于external/skia/下面,生成的库名称是libskia.so。 Skia库负责2维图形的绘制,绘制的结果最终一般以位图的形式存放在存的一块缓冲区中。我们可以从它里面几个比较重要的类来了解它到底完成什么功能。 使用SkCanvas,可以将绘制(drawing)结果保存到一个设备如位图(bitmap)中,这些绘制操作包含一系列几何图形的绘制,如绘制点、线、矩形、多边形、椭圆和圆弧等几何图形。Canvas.cpp调用了skia库的API,有的调用仅仅是对SkCanvas的简单包裹。绘制的状态(State)封装在Paint类中,如绘制的线条粗细、线条颜色、区域如何填充、线条形状等。SkBitmap是光栅位图,它包含高度和宽度两个整数以与格式(配置config规定),也可以通过getAddr()获取存储实际像素(pixel)块的地址。一副图形可以通过它的像素位图来保存,也可以通过保存它的绘制过程通过SkPicture保存起来,然后写到文件里,最后通过绘制过程恢复图形。另外,skia也包括将YUV格式转变为Jpg的编码,见YuvToJpegEncoder.cpp。 Java部分通过JNI调用Skia关系如下,包括但不限于下图中的四个类。 库libsurfaceflinger_client.so 库libsurfaceflinger_client.so到应用程序中,也到server侧(主要因为layer state管理和存控制块等类),因此,其大多数类运行在应用程序所在进程空间中,它通过Binder与与进程sufaceflinger进行交互。它的代码位于frameworks/base/libs/surfaceflinger_client下面, SurfaceComposerClient/SurfaceControl 如JNI层章节所述,在创建SurfaceSession(Java)时,会创建SurfaceComposerClient对象,并将SurfaceComposerClient对象指针保存到SurfaceSession(Java)的mClient中。我们来看下创建SurfaceComposerClient对象时还发生了什么?SurfaceComposerClient继承自RefBase,所以在第一次初始化时,会执行其重载的onFirstRef。在onFirstRef中,会获取Composer Service,也就是SurfaceFlinger在client侧的binder—-ISurfaceComposer,接着使用它建立client connection连接(实际上是分配一个用于两侧通讯的共享存块),获取ISurfaceComposerClient,最后创建layer_state_t,保存窗口状态,用于两侧的窗口状态通讯。 SurfaceComposerClient可以加入到列表中由Composer来维护。 SurfaceControl对象指针保存在Surface(Java)中的mSurfaceControl。 SurfaceControl借助于SurfaceComposerClient,实现对UI控件的一些操作: · show/hide: 显示隐藏操作 · setSize/setPosition: 设置大小和位置 · SetLayer:设置图层 · freeze/unfreeze:冻结与去冻结操作,即是否更新屏幕 · SetAlpha:设置Alpha通道,即设置透明等级 · SetMatrix:设置平移矩阵 · setFlags:设置其它标志 这些SurfaceControl类的功能实现仅仅是对SurfaceComposerClient的简单封装。可以通过SurfaceComposerClient的函数获取Display的个数、高、宽、旋转方向以与其它信息。它是通过ComposerService中的控制块信息来实现的。 ScreenshotClient包含屏幕截屏宽(mWidth)和高(mHeight)以与像素格式(PixelFormat),截图数据保存在IMemoryHeap中(mHeap)。它是调用ISurfaceComposer的captureScreen函数来实现的。 Surface Surface类继承自EGLNativeBase模板类,因此它实际上一个ANativeWindow,只不过该模板给它添加了引用计数功能,并可安全地进行类型转换。 class Surface : public EGLNativeBase<ANativeWindow, Surface, RefBase> 上层应用程序各有自己的surface,因此多个surface会同时存在,这些surface在本侧就是SurfaceComposerClient所代表,它们可以添加到Composer类维护的列表中。 SurfaceControl会使用SurfaceClient和Surface去完成相应功能,SurfaceControl的getSurface函数会创建Surface,从而也会导致SurfaceClient的创建,进而相应的ISurfaceClientComposer等会被创建。 ISurfaceComposer ISurfaceComposer是SurfaceFlinger在client侧的一个binder,提供的接口用于对整个屏幕的全局性的管理,如方向旋转、屏幕快照、屏幕事件、屏幕更新的冻结与去冻结等。它提供的接口对应的枚举类型有: enum { // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, CREATE_CLIENT_CONNECTION, GET_CBLK, OPEN_GLOBAL_TRANSACTION, CLOSE_GLOBAL_TRANSACTION, SET_ORIENTATION, FREEZE_DISPLAY, UNFREEZE_DISPLAY, SIGNAL, CAPTURE_SCREEN, TURN_ELECTRON_BEAM_OFF, TURN_ELECTRON_BEAM_ON }; 它是通过Binder进行IPC通讯的接口,BpSurfaceComposer是client一侧, BnSurfaceComposer是service一侧。它们都继承自各自的模板类BpInterface和BnInterface,这两个模板类完成双重继承的功能,一个继承IPC通讯的API接口,一个继承Binder功能。RefBase用于索引计数,类IInterface和ISurface定义了IPC通讯的接口API,IBinder/BBinder使双方具备Binder通讯功能。 其中CREATE_CONNECTION和REATE_CLIENT_CONNECTION打开关闭一个Transaction,在打开和关闭的过程中,可以设置状态,实现窗口管理。状态变化更改是在一个事务(transaction)中进行的。 其类继承关系如下: 根据Binder继承关系规则,client侧的接口调用通过最终是由Bn侧的子类完成。我们就可以知道它的它动态的调用关系如下,左侧的调用者一般可以通过指向ISurfaceComposer的智能指针将操作将调用到SurfaceFlinger类的成员函数。 ComposerService对IsurfaceComposer进行了包裹,使用它的getComposerService函数可以获取IsurfaceComposer。另外,ComposerService还包含了surface_flinger_cblk_t控制块信息,该存块位于Ashem存上,由SurfaceFlinger申请,并依据display硬件信息填充字段值。client端程序通过读取它,即可得到各display的信息。 struct display_cblk_t {//dispaly的各项信息 uint16_t w; uint16_t h; uint8_t format; uint8_t orientation; uint8_t reserved[2]; float fps; float density; float xdpi; float ydpi; uint32_t pad[2]; }; struct surface_flinger_cblk_t // 4KB max {//控制信息块 uint8_t connected; uint8_t reserved[3]; uint32_t pad[7]; display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX];//最多4个display }; 在SufraceFlinger的readyToRun会申请存,并依据DisplayHardWare中得到display信息: // create the shared control-block mServerHeap = new MemoryHeapBase(4096, MemoryHeapBase::READ_ONLY, “SurfaceFlinger read-only heap”);//分配存,没有指定设备名称或描述符fd,默认使用AShem上的存 LOGE_IF(mServerHeap==0, “can’t create shared memory dealer”); mServerCblk = //得到存基址 static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); LOGE_IF(mServerCblk==0, “can’t get to shared control block’s address”); new(mServerCblk) surface_flinger_cblk_t; // initialize primary screen // (other display should be initialized in the same manner, but // asynchronously, as they could come and go. None of this is supported yet). const GraphicPlane& plane(graphicPlane(dpy)); const DisplayHardware& hw = plane.displayHardware(); const uint32_t w = hw.getWidth(); const uint32_t h = hw.getHeight(); const uint32_t f = hw.getFormat(); hw.makeCurrent(); // initialize the shared control block mServerCblk->connected |= 1<<dpy; display_cblk_t* dcblk = mServerCblk->displays + dpy; memset(dcblk, 0, sizeof(display_cblk_t)); //给结构体赋值,同一块存上,client侧可以立即得到 dcblk->w = plane.getWidth(); dcblk->h = plane.getHeight(); dcblk->format = f; dcblk->orientation = ISurfaceComposer::eOrientationDefault; dcblk->xdpi = hw.getDpiX(); dcblk->ydpi = hw.getDpiY(); dcblk->fps = hw.getRefreshRate(); dcblk->density = hw.getDensity(); IsurfaceComposerClient ISurfaceComposerClient用于通过Binder与SurfaceFlinger交互,创建和销毁ISurface,它也可以获取控制块。在SurfaceFlinger侧会有两种类型的surface:Client(用于创建销毁ISurace)和UserClient(用于获取控制块进行通讯)。它提供的接口对应的枚举类型如下: enum { GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, GET_TOKEN, CREATE_SURFACE, DESTROY_SURFACE, SET_STATE }; 动态调用关系图,调用者通过对IsurfaceComposerClient的引用,最后由SufaceFlinger进程中的Client或UserClient来完成: ISurface Isurface提供了一个与SufaceFlinger侧进行IPC交互的接口,它主要功能是操作缓冲区。我们可以从ISurface这个纯虚类中看出起定义的接口操作: enum { REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION, UNREGISTER_BUFFERS, POST_BUFFER, // one-way transaction CREATE_OVERLAY, REQUEST_BUFFER, SET_BUFFER_COUNT, }; 这些枚举就是所支持的接口操作,相应地对应着纯虚成员函数。我们可以望文生义理解其含义。 如下图,BpSurface是client一侧, BnSurface是service一侧。它们都继承自各自的模板类BpInterface和BnInterface,这两个模板类完成双重继承的功能,一个继承IPC通讯的API接口,一个继承Binder功能。RefBase用于索引计数,类IInterface和ISurface定义了IPC通讯的接口API,IBinder/BBinder使双方具备Binder通讯功能。 类继承关系图 动态调用关系如下图所示: sp<Isurface> Surface flinger制块 在文件SharedBufferStack.h中定义了一个结构体,它是为了通过共享存的方式快速获取系统所有display物理信息,这个控制块由结构体surface_flinger_cblk_t定义: struct display_cblk_t//显示控制块,Android中默认支持最多4个diaplay { uint16_t w; //display的宽 uint16_t h; //display的高 uint8_t format; //格式 uint8_t orientation; //旋转方向 uint8_t reserved[2]; //保留字节 float fps; //刷新率 float density; //密度 float xdpi;//x方向上的解析度,每英寸的点阵数(dots/inch) float ydpi;//y方向上的解析度 uint32_t pad[2];//填充字节 }; struct surface_flinger_cblk_t // 4KB max { uint8_t connected;//是否连接 uint8_t reserved[3];//保留字节 uint32_t pad[7];//填充字节 display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX];//支持最多4个的display }; Java层在创建一个SurfaceSession实例时,建立到server侧的连接,这个连接的动作实际就是分配存、创建surface_flinger_cblk_t对象并初始化获得初始值、以与可以跨进程访问的过程。具体过程是:在client一侧,创建Surface Session时,会创建一个SurfaceComposerClient对象,接着会调用SurfaceComposerClient::onFirstRef: void SurfaceComposerClient::onFirstRef()//第一次创建对象时被调用 { sp<ISurfaceComposer> sm(getComposerService());//导致获取全局控制块 if (sm != 0) { sp<ISurfaceComposerClient> conn = sm->createConnection();//创建一个连接,surface flinger侧会创建一个Client对象 if (conn != 0) { mClient = conn; Composer::addClient(this); mPrebuiltLayerState = new layer_state_t; mStatus = NO_ERROR; } } } 在上面的代码中,先在ComposerService的构造函数中获取surface flinger控制块。 ComposerService(也就是ISurfaceComposer的Wrapper)构造函数获取surface flinger控制块的过程如下: ComposerService::ComposerService() : Singleton<ComposerService>() { const String16 name(“SurfaceFlinger”); while (getService(name, &mComposerService) != NO_ERROR) { usleep(250000); } mServerCblkMemory = mComposerService->getCblk();//获取IMemoryHeap mServerCblk = static_cast<surface_flinger_cblk_t volatile *>( mServerCblkMemory->getBase());//在IMemoryHeap中的基址指针转换为surface_flinger_cblk_t指针 } 另外,SurfaceComposerClient的onFirstRef会创建一个connection,它的目的是创建代理对象,用于Binder IPC通讯,ISurfaceComposerClient接口强指针指向该代理对象。在server侧,它只是调用Client(也就是ISurfaceComposerClient接口在server侧的真正实现者)构造函数创建一个Client对象进行类型转换后返回。而实际的存分配是在server侧创建SurfaceFlinger后准备运行其工作线程时完成的,见SurfaceFlinger::readyToRun函数: status_t SurfaceFlinger::readyToRun() { LOGI( “SurfaceFlinger’s main thread ready to run. ” “Initializing graphics H/W…”); // we only support one display currently int dpy = 0; { // initialize the main display GraphicPlane& plane(graphicPlane(dpy)); DisplayHardware* const hw = new DisplayHardware(this, dpy); plane.setDisplayHardware(hw); } // create the shared control-block //创建共享控制块,因未指定在何处分配存,默认的是ashmem上 mServerHeap = new MemoryHeapBase(4096, MemoryHeapBase::READ_ONLY, “SurfaceFlinger read-only heap”); LOGE_IF(mServerHeap==0, “can’t create shared memory dealer”); mServerCblk = static_cast<surface_flinger_cblk_t*> (mServerHeap->getBase());//获取基址 LOGE_IF(mServerCblk==0, “can’t get to shared control block’s address”); new(mServerCblk) surface_flinger_cblk_t; // initialize primary screen // (other display should be initialized in the same manner, but // asynchronously, as they could come and go. None of this is supported yet). const GraphicPlane& plane(graphicPlane(dpy)); const DisplayHardware& hw = plane.displayHardware(); const uint32_t w = hw.getWidth(); const uint32_t h = hw.getHeight(); const uint32_t f = hw.getFormat(); hw.makeCurrent(); // initialize the shared control block mServerCblk->connected |= 1<<dpy;//下面是为共享控制块赋值 display_cblk_t* dcblk = mServerCblk->displays + dpy; memset(dcblk, 0, sizeof(display_cblk_t)); dcblk->w = plane.getWidth(); dcblk->h = plane.getHeight(); dcblk->format = f; dcblk->orientation = ISurfaceComposer::eOrientationDefault; dcblk->xdpi = hw.getDpiX(); dcblk->ydpi = hw.getDpiY(); dcblk->fps = hw.getRefreshRate(); dcblk->density = hw.getDensity(); ……//省略部分代码 } 它为该控制块在ashmem上分配存并对其初始化赋值。 SharedClient控制块 在SurfaceControl的getSurface() 时,会创建一个Surface,接着调用SurfaceClient的构造函数,由于SurfaceClient是singleton,即系统中只有一个实例,因此,在其第一次创建时调用了构造函数,而在其构造函数中调用了createClientConnection,这个就是建立连接的过程,就是分配存控制块的过程。在client侧,其代码如下: SurfaceClient(): Singleton<SurfaceClient>(), mStatus(NO_INIT) { sp<ISurfaceComposer> //获取Composer service sf(ComposerService::getComposerService()); mComposerService = sf; mClient = sf->createClientConnection();//创建client连接 if (mClient != NULL) {//创建成功的话 mControlMemory = mClient->getControlBlock();//获取存块 if (mControlMemory != NULL) { mControl = static_cast<SharedClient *>( mControlMemory->getBase());//得到基地址,并转换为SharedClient指针,然后赋值给mControl if (mControl) { mStatus = NO_ERROR; } } } } 在server侧,它调用UserClient的构造函数: UserClient::UserClient(const sp<SurfaceFlinger>& flinger) : ctrlblk(0), mBitmap(0), mFlinger(flinger) { const int pgsize = getpagesize();//获取存页大小 const int cblksize = //控制块大小,即进行页对齐后的SharedClient大小 ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); mCblkHeap = new MemoryHeapBase(cblksize, 0,//在ashmem上分配存 “SurfaceFlinger Client control-block”); ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());//指针类型转换 if (ctrlblk) { // construct the shared structure in-place. new(ctrlblk) SharedClient;//调用构造函数初始化存块对象 } } 也就是说,建立一个clientConnection的过程,也就是在server侧:在堆上分配一块页对齐的存块,它被用来存储SharedClient对象;之后,client侧同样也拥有该块存,同样也被解释为SharedClient对象指针。TODO:它们是跨进程的,所以通过IMemoryHeap这个binder接口来操作。 那么SharedClient是何方神圣呢?在头文件SharedBufferStack.h中有代码注释:“ These classes manage a stack of buffers in shared memory. SharedClient: represents a client with several stacks SharedBufferStack: represents a stack of buffers SharedBufferClient: manipulates the SharedBufferStack from the client side SharedBufferServer: manipulates the SharedBufferStack from the server side Buffers can be dequeued until there are none available, they can be locked unless they are in use by the server, which is only the case for the last dequeue-able buffer. When these various conditions are not met, the caller waits until the condition is met. ” 我们先来看一下比较重要的一个类SharedBufferStack class SharedBufferStack { ……//省略部分代码 struct SmallRect {//定义了一个矩形:左上角和右下角的坐标 uint16_t l, t, r, b; }; //定义了一个平面区域,包含了若干(不超过5个)矩形 struct FlatRegion { // 52 bytes = 4 * (1 + 2*N) static const unsigned int NUM_RECT_MAX = 5; uint32_t count; SmallRect rects[NUM_RECT_MAX]; }; struct BufferData {//64Bytes FlatRegion dirtyRegion;//5个矩形区域 SmallRect crop;//1个剪切矩形区 uint8_t transform; uint8_t reserved[3]; }; ……//省略部分代码 //双方同步 // these attributes are part of the conditions/updates volatile int32_t head; // server’s current front buffer volatile int32_t available; // number of dequeue-able buffers volatile int32_t queued; // number of buffers waiting for post volatile int32_t reserved1; volatile status_t status; // surface’s status code // not part of the conditions volatile int32_t reallocMask; volatile int8_t index[NUM_BUFFER_MAX]; int32_t identity; // surface’s identity (const) int32_t token; // surface’s token (for debugging) Statistics stats; int8_t headBuf; // last retired buffer uint8_t reservedBytes[3]; int32_t reserved; BufferData buffers[NUM_BUFFER_MAX]; // 16个数组元素 }; 可见SharedBufferStack里面定义了几个结构体,用于保存矩形区域。如果我们把BufferData所保存的区域称为一块区域的话,那么SharedBufferStack里可以包含多达16块区域。在Android系统里,一个Surface对应一个SharedBufferStack。而SharedClient则包含了31个SharedBufferStack: // 32 KB max class SharedClient { ……//省略部分代码 // FIXME: this should be replaced by a lock-less primitive Mutex lock; Condition cv; SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];//31个数组元素 }; 因此,上图展示了SharedClient中包含的31个Stack元素 每当client侧创建一个surface时,都要通过SharedBufferClient的dequeue从SharedBufferStack取出一个不用的slot。 17 / 17
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服