Android 7.1 GUI系统-BufferQueue 的管理(三)
2017-11-25 19:40
846 查看
BufferQueue
的管理
1),对buffer的管理符合“生产者-消费者”模型,这里有以下几个相关的类:
BufferQueueProducer.cpp是IGraphicBufferProducer对应服务端的实现,负责缓冲区的申请。
BufferQueueConsumer.cpp是IGraphicBufferProducer对应的服务端的实现,是buffer消费者。
BufferQueueCore.cpp,可以看作是Buffer的中枢,一方面BufferqueueProducer对buffer的申请也是通过BufferQueueCore来实现的,具体是BufferQueueCore中的GraphicBufferAlloc。另一方面,当有可以消费的buffer时,是通过BufferQueueCore通知到BufferQueueConsumer,具体是通过ConsumerListener来实现的。
GraphicBufferAlloc.cpp是IGraphicBufferAlloc对应的服务端的实现,负责GraphicBuffer的申请。
既然说BufferQueueCore中的GraphicBufferAlloc负责GraphicBuffer的申请,先来看下谁生成的GraphicBufferAlloc实例。
可以看到这里创建的是一个GraphicBufferAlloc对象。
在BufferQueueCore的初始化列表中虽然给IGraphicBufferAlloc做了赋值:mAllocator(allocator),但实际这个值是null的,因为它是由BufferQueue.cpp的默认参数传过来的,而这默认参数初始值是null的,所以需要在构造函数中重新生成IGraphicBufferAlloc实例。
BufferQueueCore中有一个重要的成员数组BufferQueueDefs::SlotsTypemSlots;
前面在说的surface中也有一个同名的成员数组BufferSlotmSlots[NUM_BUFFER_SLOTS];都是BufferSlot类型,只是定义有差别。
这是Surface中的BufferSlot的定义,是一个结构体。
下面是BufferQueueCore中的Bufferslot中的定义:
一个buffer可以有5中状态。
struct BufferState {
FREE表明缓冲区当前可用,可以被生产者dequeued,这个slots的owner是BufferQueue,当dequeueBuffer后会转变为DEQUEUED。
DEQUEUED表明这个buffer已经被生产者dequeued,但是还没被queued或者canceled,生产者可以修改这个buffer的内容,现在buffer的owner是producer(应用程序),可以通过调用queueBuffer或attachBuffer转成QUEUED,也可以通过调用cancelBuffer或detachBuffer转成FREE。
QUEUED表明这个buffer已经被Producer填充了数据,可以被consumer使用,现在buffer的owner是BufferQueue,可以通过调用acquireBuffer转成ACQUIRED,
ACQUIRED表明这个buffer已经被consumeracquired了,现在的owner是consumer,通过releasebuffer可以转成FREE。
SHARED表明这个buffer被用于sharedbuffer
mode。在同一时间,它可以是除FREE外的其他的状态的集合。
}
通过上面buffer的各个状态的介绍,对buffer的管理主要有BufferQueue,Producer,Consumer,三个对象。BufferQueue的实现者就是BufferQueueCore,它是一个中心,Producer想要获取一个buffer,是通过BufferQueueCore完成的,同样的当有一个buffer可以被consumer消费时,也是通过BufferQueueCore来通知到到consumer的。
Producer通常是指应用程序,应用程序不断刷新UI,把产生的显示数据写到buffer中,当Producer需要一块buffer时,先向bufferQueue发起dequeue申请,然后才能对制定的缓冲区进行填充操作,当填充完成后,通过调用queueBuffer把这个buffer入队到Bufferqueue中,由BufferQueuecore通知consumer有可以别消费的buffer了。
具体怎么通知到consumer的,还要介绍一个类ConsumerListener,介绍了这个类的几个主要接口,就知道是怎么通知到consumer的了。
2),BufferQueue缓冲区的分配。
分析缓冲区的分配,就是分析BufferSlot数组中的指针mGraphicBuffer的空间分配。这个指针一开始是null,下面看什么情况下为mSlots数组中的一个slot分配实际空间。
整个需求的起点是Producer对buffer的dequeueBuffer,所以从分析这个函数开始:
对其中关键步骤做详细分析:
step1,怎么找到一个可用的slot。found指的是这个Bufferslot在mSlots数组中的序号。
Step2,找到可用的slot,还要判断是否要重新分配空间,即needsReallocation,如果buffer的属性跟要求的属性不符(主要指宽,高,格式,usage),就要重新分配,最后的返回值会加上returnFlags|=
BUFFER_NEEDS_REALLOCATION;标记。
Step3,调用IGraphicBufferAlloc的方法createGraphicBuffer方法分配GraphicBuffer。IGraphicBufferAlloc对应的服务端的实现是GraphicBufferAlloc.cpp,所以这个方法的实现就到了GraphicBufferAlloc.cpp中,这里new了一个GraphicBuffer,这个GraphicBuffer会赋值给BufferQueueCore中的变量mSlots中的slot的mGraphicBuffer。
BufferQueueProducer.cpp中的dequeueBuffer的源头是在surface中调用的dequeueBuffer,所以BufferQueueProducer.cpp这边执行完会返回到Surface.cpp中,
调用requestBuffer是获取最新的buffer地址,BufferQueueProducer中分配的buffer是在服务端进程空间的,而surface需要的buffer是要在客户端进程,也就是应用进程空间使用的,这两块buffer应该指向同一块物理内存,怎么实现让两块buffer指向同一块物理内存的,这就是requestbuffer的作用。
//这个方法是BpGraphicBufferProducer中的方法:
相应client请求的代码如下:
上面的实现中,清晰的描述了一个怎样跨进程传递一个对象。
能够通过Binder跨进程传递的对象,在java层的通常要继承Parcelable,如Bundle.java,需要实现的接口是writeToParcel,readFromParcel;
在native层通常要继承Flattenable,如这里的GraphicBuffer.cpp,需要实现的接口是flatten,unflatten。
只要看下GraphicBuffer的flatten,unflatten的函数实现,就可以清楚客户端、服务端的两块buffer是不是指向的同一块物理空间了。
在surface执行dequeuebuffer的过程中,如果需要重新分配空间,就要调用requestbuffer就是来更新client端mSlots中相应的缓冲区信息的。这样就保证了Surface和bufferQueuecore之前在数据缓冲区上的一致。
3)应用程序跟BufferQueue的关系。
应用程序不会直接使用BufferQueue,接下来分析应用程序跟bufferQueue之间怎么配合完成图形绘制的。
分析这个过程需要一个切入点,可以从一个常见的应用程序的启动入手,经过ViewrootImpl.java的setView,到WindowManagerService.java的relayoutWindow,然后转到createSurface的分析。这个过程要从java层进过jni到本地层相对繁琐,不利于直观跟BufferQueue的关系。所以借助系统的一段本地层的测试代码来分析,为什么要用这段代码?我们知道surfaceflinger是借助于opengles来完成绘图的,很多应用程序也是借助于opengles来完成UI显示的,比如图库的图片展示,相机的预览界面等,当然也有应用程序是借助于skia这个图形库。下面这段代码不仅展示了应用程序跟BufferQueue的通信过程,还展示了opengles和egl的使用流程。
SurfaceComposerClient是一个封装,具体功能实现是通过其内部的ISurfaceComposerClient来实现的,而ISurfaceComposerClient对应服务端的实现是Client.cpp,所以上面的createSurface的实现就在Client中。这里涉及ipc,具体细节就不列出代码了。
SurfaceComposerClient.cpp
接着看服务端的实现,createSurface这个方法只能在GL线程中调用,这样它才能范文GL的上下文环境。
Client.cpp
//addClientLayer函数的实现。
//再回头看下*handle=
(*outLayer)→getHandle();其中的handle是什么类型,又起了什么作用呢?
Layer.cpp
//创建了一个handle对象,并传入的surfaceflinger。
//这个handle只是传给client端的一个BBbinder,当客户端释放了这个引用时,会调用其析构函数,那么它的析构函数做了什么事情呢?Handle本身没写析构函数,所以要做的事情就在其父类LayerCleaner的析构函数中。
//LayerCleaner的析构函数,调用了surfaceflinger的onLayerDestroyed,把layer从surfaceflinger的全局变量mCurrentState.layersSortedByZ中移除。
//Layer中很多变量的实例化,都是在onFirstRef中完成的,当Layer实例第一次被引用时会执行onFirstRef函数。
//我们只关注MonitoredProducer的构造函数,看在IGraphicBufferProducer被销毁时,它要做什么。
MonitoredProducer.cpp
在Layer中还有一个重要的变量SurfaceFlingerConsumer。
SurfaceFlingerConsumer是GLConsumer的简单的包装类,把IGraphicBufferConsumer实例传给了GLConsumer。
class GLConsumer :public ConsumerBase {}
class ConsumerBase :public virtual RefBase,protected ConsumerListener {}
GLConsumer有继承自ConsumerBase,间接继承了ConsumerListener。
接下来逐层分析逐个继承关系。
GLConsumer会消费来自BufferQueue的缓冲区或者叫图形数据,并把他们转做texture为opengl使用。一个典型的使用方式是使用所需要的选项设置GLConsumer,然后当有一帧需要时,调用updateTexImage,这个函数会获取最近queued的buffer,然后绑定这个buffer到GLtexture,如果这一帧是可用的,texture会被更新,如果不可用,前一帧的内容会被保留。
ConsumerBase是BufferQueue消费者的基类,它处理一些通用任务,比如到BufferQueue的连接,buffer池的管理,其中的成员变量sp<IGraphicBufferConsumer>mConsumer;就是SurfaceFlingerConsumer传过来的,ConsumerBase是通过IGraphicBufferConsumer对象来对BufferQueue执行操作的。
简单做个总结:
1)应用程序通过BufferQueue执行绘图,surfaceflinger会把系统中所有应用程序最终的绘图结果进行混合,然后送到物理屏幕显示。应用程序跟surfaceflinger之间的通信桥梁是IsurfaceComposrClient。
这个类被封装在SurfaceComposerClient中。
2)应用程序通过SurfaceComposerClient调用CreateSurface的过程中,除了得到IGraphicBufferProducer实例外,还创建了一个layer。把控制这个layer的handle,IGraphicBufferProducer对象,连同SurfaceComposerClient自身都保存在应用端的Surfacecontrol中。
3)Surface,应用程序通过Surfacecontrol的getSurface获取,其内部持有IGraphicBufferProducer对象,即BufferQueueProducer的实现接口。如果egl想通过Surface这个本地窗口完成某个功能,Surface实际上是利用IGraphicBufferProducer取得远程端的服务,完成egl的请求。
4)应用程序跟layer应该是一对多的关系,因为createSurface是可以被调用多次的,并且,一个应用程序申请的多个layer可以通过addClientLayer添加到一个全局变量mLayers中。应用程序申请的layer,一方面要记录都各个Client的内部变量mLayers中,另一方面还要告知SurfaceFlinger,这个操作也是在addClientLayer函数中完成的,即把layer添加到全局变量mCurrentState.layerSortByZ,Surfaceflinger会对这个列表中的所有layer排序,排序的结果直接影响了屏幕显示的画面。
5)每个layer对应一个BufferQueue,所以一个应用程序可能对应多个BufferQueue。layer并没有直接持有BufferQueue对象,而是通过其内部的IGraphicBufferProducer,mSurfaceFlingerConsumer来管理。
的管理
1),对buffer的管理符合“生产者-消费者”模型,这里有以下几个相关的类:
BufferQueueProducer.cpp是IGraphicBufferProducer对应服务端的实现,负责缓冲区的申请。
BufferQueueConsumer.cpp是IGraphicBufferProducer对应的服务端的实现,是buffer消费者。
BufferQueueCore.cpp,可以看作是Buffer的中枢,一方面BufferqueueProducer对buffer的申请也是通过BufferQueueCore来实现的,具体是BufferQueueCore中的GraphicBufferAlloc。另一方面,当有可以消费的buffer时,是通过BufferQueueCore通知到BufferQueueConsumer,具体是通过ConsumerListener来实现的。
GraphicBufferAlloc.cpp是IGraphicBufferAlloc对应的服务端的实现,负责GraphicBuffer的申请。
既然说BufferQueueCore中的GraphicBufferAlloc负责GraphicBuffer的申请,先来看下谁生成的GraphicBufferAlloc实例。
BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mAllocator(allocator)@BufferQueueCore.cpp{ if (allocator == NULL) { //这里返回的 ISurfaceComposer类型的对象 composer,实际就是SurfaceFinger,最终 IGraphicBufferAlloc的实例生成还是由SurfaceFinger来完成的。 ComposerService类是SurfaceComposerClient.cpp的内部类。 sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mAllocator = composer->createGraphicBufferAlloc(); } }
可以看到这里创建的是一个GraphicBufferAlloc对象。
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()@SurfaceFlinger.cpp { sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); return gba; }
在BufferQueueCore的初始化列表中虽然给IGraphicBufferAlloc做了赋值:mAllocator(allocator),但实际这个值是null的,因为它是由BufferQueue.cpp的默认参数传过来的,而这默认参数初始值是null的,所以需要在构造函数中重新生成IGraphicBufferAlloc实例。
BufferQueueCore中有一个重要的成员数组BufferQueueDefs::SlotsTypemSlots;
前面在说的surface中也有一个同名的成员数组BufferSlotmSlots[NUM_BUFFER_SLOTS];都是BufferSlot类型,只是定义有差别。
这是Surface中的BufferSlot的定义,是一个结构体。
Surface.h struct BufferSlot { sp<GraphicBuffer> buffer; Region dirtyRegion; }; BufferSlot mSlots[NUM_BUFFER_SLOTS];
下面是BufferQueueCore中的Bufferslot中的定义:
BufferSlot.h struct BufferSlot { // mGraphicBuffer指向一个slot所分配的buffer,如果buffer还没分配,值为null。 sp<GraphicBuffer> mGraphicBuffer; //标示一个buffer slot的当前状态。 BufferState mBufferState; }
一个buffer可以有5中状态。
struct BufferState {
mShared | mDequeueCount | mQueueCount | mAcquireCount | |
FREE | false | 0 | 0 | 0 |
DEQUEUED | False | 1 | 0 | 0 |
QUEUED | False | 0 | 1 | 0 |
ACQUIRED | False | 0 | 0 | 1 |
SHARED | True | Any | Any | any |
DEQUEUED表明这个buffer已经被生产者dequeued,但是还没被queued或者canceled,生产者可以修改这个buffer的内容,现在buffer的owner是producer(应用程序),可以通过调用queueBuffer或attachBuffer转成QUEUED,也可以通过调用cancelBuffer或detachBuffer转成FREE。
QUEUED表明这个buffer已经被Producer填充了数据,可以被consumer使用,现在buffer的owner是BufferQueue,可以通过调用acquireBuffer转成ACQUIRED,
ACQUIRED表明这个buffer已经被consumeracquired了,现在的owner是consumer,通过releasebuffer可以转成FREE。
SHARED表明这个buffer被用于sharedbuffer
mode。在同一时间,它可以是除FREE外的其他的状态的集合。
}
通过上面buffer的各个状态的介绍,对buffer的管理主要有BufferQueue,Producer,Consumer,三个对象。BufferQueue的实现者就是BufferQueueCore,它是一个中心,Producer想要获取一个buffer,是通过BufferQueueCore完成的,同样的当有一个buffer可以被consumer消费时,也是通过BufferQueueCore来通知到到consumer的。
Producer通常是指应用程序,应用程序不断刷新UI,把产生的显示数据写到buffer中,当Producer需要一块buffer时,先向bufferQueue发起dequeue申请,然后才能对制定的缓冲区进行填充操作,当填充完成后,通过调用queueBuffer把这个buffer入队到Bufferqueue中,由BufferQueuecore通知consumer有可以别消费的buffer了。
具体怎么通知到consumer的,还要介绍一个类ConsumerListener,介绍了这个类的几个主要接口,就知道是怎么通知到consumer的了。
class ConsumerListener : public virtual RefBase { //当一帧对消费者来说可用时就会调用这个函数, virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */ //这个函数会去通知consumer,BufferQueue已经释放了一个或多个GraphicBuffers的引用,consumer应该调用getReleasedBuffers去检索这个buffer列表。 virtual void onBuffersReleased() = 0; }
2),BufferQueue缓冲区的分配。
分析缓冲区的分配,就是分析BufferSlot数组中的指针mGraphicBuffer的空间分配。这个指针一开始是null,下面看什么情况下为mSlots数组中的一个slot分配实际空间。
整个需求的起点是Producer对buffer的dequeueBuffer,所以从分析这个函数开始:
BufferQueueProducer.cpp status_t BufferQueueProducer::dequeueBuffer(int *outSlot,sp<android::Fence> *outFence, uint32_t width,uint32_t height, QueueBufferOutput *output) @BufferQueueProducer.cpp{ //step1,这个while循环,查找一个可用的slot,具体是通过 waitForFreeSlotThenRelock函数实现,也就是found的有效值。 int found = BufferItem::INVALID_BUFFER_SLOT; while (found == BufferItem::INVALID_BUFFER_SLOT) { status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,&found); //如果不允许分配新的buffers, waitForFreeSlotThenRelock还必须返回一个包含buffer的slot,如果这个buffer需要充分配才能满足要求,就要先把它free了,然后尝试再获取一个。 const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if (!mCore->mAllowAllocation) { if (buffer->needsReallocation(width, height, format, usage)) { mCore->mFreeSlots.insert(found); mCore->clearBufferSlotLocked(found); found = BufferItem::INVALID_BUFFER_SLOT; continue; } } } //step2,成功找到slot序号,接下来对这个bufferslot对象做初始化。还要判断要不要为这个slot重新分配空间。 *outSlot = found; mSlots[found].mBufferState.dequeue(); if ((buffer == NULL) || buffer->needsReallocation(width, height, format, usage)){ mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; mSlots[found].mFence = Fence::NO_FENCE; mCore->mIsAllocating = true; returnFlags |= BUFFER_NEEDS_REALLOCATION; } //step3,上一步的判断结果需要重新分配空间,调用 createGraphicBuffer分配空间。 if (returnFlags & BUFFER_NEEDS_REALLOCATION) { sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer( width, height, format, usage,{mConsumerName.string(), mConsumerName.size()} , &error)); //分配的空间,赋值给了slot,这里的mSlots实质是BufferQueueCore中的变量。 mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } }
对其中关键步骤做详细分析:
step1,怎么找到一个可用的slot。found指的是这个Bufferslot在mSlots数组中的序号。
status_t BufferQueueProducer::waitForFreeSlotThenRelock( FreeSlotCaller caller,int* found) const { bool tryAgain = true; while (tryAgain) { // mActiveBuffers这个集合中包含所有非free的buffer。然后分别统计dequeued的个数,acquired的个数。 for (int s : mCore->mActiveBuffers) { if (mSlots[s].mBufferState.isDequeued()) { ++dequeuedCount; } if (mSlots[s].mBufferState.isAcquired()) { ++acquiredCount; } } //不允许Producersdequeue的数量的超过 mMaxDequeuedBufferCount,这个判断只在buffer已经被queued的情况下。 mMaxDequeuedBufferCount是Producer一次可以dequeue的buffers的数量,默认是1,可以通过setMaxDequeuedBufferCount来修改。 if (mCore->mBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) { return INVALID_OPERATION; } //如果在shared buffer mode,并且有一个shared buffer存在,就返回这个slot。 if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = mCore->mSharedBufferSlot; }else { //slot的获取,主要来自两个集合,mFreeSlots和mFreeBuffers, //mFreeSlots包含的是所有状态是free,并且没有attached的slots, //mFreeBuffers包含所有状态是free,但是已经attached的slots。 if (caller == FreeSlotCaller::Dequeue) { //如果调用来自与dequeue,优先选择mFreeBuffers中的。 int slot = getFreeBufferLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; }else{ *found = getFreeSlotLocked(); } }else{ //如果调用来自于attache,优先选择mFreeSlots中的。 int slot = getFreeSlotLocked(); if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) { *found = slot; }else{ *found = getFreeBufferLocked(); } } } //如果没有找到符合要求的buffer,或者queue的buffers还有太多没有完成,就要等待这个buffer被acquired或者released,或者修改最大的buffer数量。这里使用条件变量mDequeueCondition进入wait,当有buffer被释放时,这个条件就会满足,然后继续查找。 if (tryAgain) { mCore->mDequeueCondition.wait(mCore->mMutex); } }//while(tryAgain) return NO_ERROR; }
Step2,找到可用的slot,还要判断是否要重新分配空间,即needsReallocation,如果buffer的属性跟要求的属性不符(主要指宽,高,格式,usage),就要重新分配,最后的返回值会加上returnFlags|=
BUFFER_NEEDS_REALLOCATION;标记。
Step3,调用IGraphicBufferAlloc的方法createGraphicBuffer方法分配GraphicBuffer。IGraphicBufferAlloc对应的服务端的实现是GraphicBufferAlloc.cpp,所以这个方法的实现就到了GraphicBufferAlloc.cpp中,这里new了一个GraphicBuffer,这个GraphicBuffer会赋值给BufferQueueCore中的变量mSlots中的slot的mGraphicBuffer。
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, std::string requestorName, status_t* error) @GraphicBufferAlloc.cpp{ sp<GraphicBuffer> graphicBuffer(new GraphicBuffer( width, height, format, usage, std::move(requestorName))); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) { if (err == NO_MEMORY) { GraphicBuffer::dumpAllocationsToSystemLog(); } return 0; } return graphicBuffer; }
BufferQueueProducer.cpp中的dequeueBuffer的源头是在surface中调用的dequeueBuffer,所以BufferQueueProducer.cpp这边执行完会返回到Surface.cpp中,
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) @Surface.cpp{ //BufferQueueProducer.cpp的dequeueBuffer是从这里开始的。 status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, reqFormat, reqUsage); //如果返回值带有BUFFER_NEEDS_REALLOCATION,还要调用 requestBuffer。 if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); } }
调用requestBuffer是获取最新的buffer地址,BufferQueueProducer中分配的buffer是在服务端进程空间的,而surface需要的buffer是要在客户端进程,也就是应用进程空间使用的,这两块buffer应该指向同一块物理内存,怎么实现让两块buffer指向同一块物理内存的,这就是requestbuffer的作用。
//这个方法是BpGraphicBufferProducer中的方法:
virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) @IGraphicBufferProducer.cpp{ Parcel data, reply; //只传了在mSlots中的序号 bufferIdx,第二个参数* buf实际是一个出参。 data.writeInt32(bufferIdx); //开始跨进程操作。 status_t result =remote()->transact(REQUEST_BUFFER, data, &reply); //读取服务端返回的信息,在执行跨进程操作时,client端会被挂起,等服务端处理完成返回结果时,在唤醒client继续执行。 bool nonNull = reply.readInt32(); if (nonNull) { //这里生成一个GraphicBuffer实例,实际是一个空壳,要通过服务端的返回值来填充。 *buf = new GraphicBuffer(); //使用服务端的返回的结果填充**buf ,这个**buf具体指的什么?从surface.cpp传入的参数说起: //sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);这个gbuf 是一个指向 mSlots[buf].buffer的引用,//传入requestBuffer中的实参是&gbuf,也就是说*buf指针指向的是 gbuf 的地址,所以**buf指向的就是 gbuf代表的内容,也就是 mSlots[buf].buffer。 result = reply.read(**buf); } result = reply.readInt32(); }
相应client请求的代码如下:
status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch(code) { //匹配请求的业务码 REQUEST_BUFFER。 case REQUEST_BUFFER: { //读取要处理的slot序号。 int bufferIdx = data.readInt32(); sp<GraphicBuffer> buffer; int result = requestBuffer(bufferIdx, &buffer); //写入本地端是否成功获取到了对应的GraphicBuffer,这个GraphicBuffer就是dequeuebuffer中申请//的,也即是BufferQueueCore中的mSlots[slot].mGraphicBuffer。 reply->writeInt32(buffer != 0); if (buffer != 0) { //把 mGraphicBuffer写入reply,等待客户端读取。 reply->write(*buffer); } reply->writeInt32(result); return NO_ERROR; } } }
上面的实现中,清晰的描述了一个怎样跨进程传递一个对象。
能够通过Binder跨进程传递的对象,在java层的通常要继承Parcelable,如Bundle.java,需要实现的接口是writeToParcel,readFromParcel;
在native层通常要继承Flattenable,如这里的GraphicBuffer.cpp,需要实现的接口是flatten,unflatten。
只要看下GraphicBuffer的flatten,unflatten的函数实现,就可以清楚客户端、服务端的两块buffer是不是指向的同一块物理空间了。
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const @GraphicBuffer.cpp{ int32_t* buf = static_cast<int32_t*>(buffer); //handle的类型是buffer_handle_t* handle,它是在生成GraphicBuffer实例时,//由GraphicBufferAllocator在申请真实的物理内存时赋值的,代表了代表了一块共享缓冲区的句柄。 if (handle) { //写入缓冲区相关的数据,client端也会按相同的格式读取。 buf[9] = handle->numFds; buf[10] = handle->numInts; memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int)); memcpy(&buf[11], handle->data + handle->numFds, static_cast<size_t>(handle->numInts) * sizeof(int)); } }
status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count) @GraphicBuffer.cpp{ const size_t numFds = static_cast<size_t>(buf[9]); const size_t numInts = static_cast<size_t>(buf[10]); if (numFds || numInts) { //通过生成一个本地层 native_handle实例,把相关的数据复制过来。这块物理空间跟BufferQueueCore中指向的物理空间是一致的。这就实现了client和服务端之间缓冲区的共享。 native_handle* h = native_handle_create( static_cast<int>(numFds), static_cast<int>(numInts)); memcpy(h->data, fds, numFds * sizeof(int)); memcpy(h->data + numFds, &buf[11], numInts * sizeof(int)); } }
在surface执行dequeuebuffer的过程中,如果需要重新分配空间,就要调用requestbuffer就是来更新client端mSlots中相应的缓冲区信息的。这样就保证了Surface和bufferQueuecore之前在数据缓冲区上的一致。
3)应用程序跟BufferQueue的关系。
应用程序不会直接使用BufferQueue,接下来分析应用程序跟bufferQueue之间怎么配合完成图形绘制的。
分析这个过程需要一个切入点,可以从一个常见的应用程序的启动入手,经过ViewrootImpl.java的setView,到WindowManagerService.java的relayoutWindow,然后转到createSurface的分析。这个过程要从java层进过jni到本地层相对繁琐,不利于直观跟BufferQueue的关系。所以借助系统的一段本地层的测试代码来分析,为什么要用这段代码?我们知道surfaceflinger是借助于opengles来完成绘图的,很多应用程序也是借助于opengles来完成UI显示的,比如图库的图片展示,相机的预览界面等,当然也有应用程序是借助于skia这个图形库。下面这段代码不仅展示了应用程序跟BufferQueue的通信过程,还展示了opengles和egl的使用流程。
frameworks/native/libs/gui/tests/GLTest.cpp void GLTest::SetUp() { //获取默认的物理屏幕。 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); //初始化。 eglInitialize(mEglDisplay, &majorVersion, &minorVersion); //选取最佳的config。 eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig, 1, &numConfigs); //生成一个SurfaceComposerClient实例,它是应用程序与surfaceflinger之间的通信桥梁,不过SurfaceComposerClient只是一个封装,实质是通过内部的ISurfaceComposerClient来执行的,ISurfaceComposerClient对应的服务端实现是Client。 mComposerClient = new SurfaceComposerClient; mComposerClient→initCheck(); //生成一个surface,surface是由surfaceControl来管理的,所以这里返回的是SurfaceControl。 mSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(),PIXEL_FORMAT_RGB_888, 0); //设置layer的层级,层级越大越靠近用户。 mSurfaceControl->setLayer(0x7FFFFFFF); mSurfaceControl→show(); //从surfacecontrol中取出surface,得到了egl需要的本地窗口。 sp<ANativeWindow> window = mSurfaceControl→getSurface(); //通过本地窗口window创建surface。 mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); //创建、设置当前context环境。 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT, getContextAttribs()); eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,mEglContext)); }
SurfaceComposerClient是一个封装,具体功能实现是通过其内部的ISurfaceComposerClient来实现的,而ISurfaceComposerClient对应服务端的实现是Client.cpp,所以上面的createSurface的实现就在Client中。这里涉及ipc,具体细节就不列出代码了。
SurfaceComposerClient.cpp
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name,uint32_t w, uint32_t h,PixelFormat format,uint32_t flags)@SurfaceComposerClient.cpp{ sp<IBinder> handle; sp<IGraphicBufferProducer> gbp; //调用服务端的实现,实质是创建了一个layer,通过这个layer获取 IGraphicBufferProducer。 status_t err = mClient->createSurface(name, w, h, format, flags,&handle, &gbp); //生成一个 SurfaceControl,由他管理surface。 sur = new SurfaceControl(this, handle, gbp); return sur; }
接着看服务端的实现,createSurface这个方法只能在GL线程中调用,这样它才能范文GL的上下文环境。
Client.cpp
status_t Client::createSurface(const String8& name,uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp){ class MessageCreateLayer : public MessageBase { SurfaceFlinger* flinger; //这个client表明,这个消息来自于那个client, Client* client; //与这个layer对应的handle和gbp。 sp<IBinder>* handle; sp<IGraphicBufferProducer>* gbp; status_t result; const String8& name; uint32_t w, h; PixelFormat format; uint32_t flags; virtual bool handler() { //这里是由surfaceFlinger来执行操作。 result = flinger->createLayer(name, client, w, h, format, flags,handle, gbp); return true; } } //把请求通过一个同步函数把msg放入队列,等到有结果再返回。 sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(), name, this, w, h, format, flags, handle, gbp); mFlinger->postMessageSync(msg); return static_cast<MessageCreateLayer*>( msg.get() )->getResult(); }
SurfaceFlinger.cpp status_t SurfaceFlinger::createLayer(const String8& name,const sp<Client>& client, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)@SurfaceFlinger.cpp{ sp<Layer> layer; switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { //根据flag,创建不同的layer,这里是创建普通的layer,代表了一个画面。 case IsurfaceComposerClient::eFXSurfaceNormal: result = createNormalLayer(client,name, w, h, flags, format, handle, gbp, &layer); break; } //将layer,gbp添加到全局的管理中。 result = addClientLayer(client, *handle, *gbp, layer); }
SurfaceFlinger.cpp status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)@SurfaceFlinger.cpp{ //创建一个layer,同时给他设置缓冲区。 *outLayer = new Layer(this, client, name, w, h, flags); status_t err = (*outLayer)->setBuffers(w, h, format, flags); //通过layer获取IGraphicBufferProducer。 *handle = (*outLayer)→getHandle(); *gbp = (*outLayer)->getProducer(); }
//addClientLayer函数的实现。
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc,const sp<Layer>& lbc)@SurfaceFlinger.cpp{ //把layer添加到当前state的列表中。把gbc添加到全局变量中。 mCurrentState.layersSortedByZ.add(lbc); mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); //让layer与client产生关联,也就是添加到client的mLayers成员变量中。 client->attachLayer(handle, lbc); }
//再回头看下*handle=
(*outLayer)→getHandle();其中的handle是什么类型,又起了什么作用呢?
Layer.cpp
//创建了一个handle对象,并传入的surfaceflinger。
sp<IBinder> Layer::getHandle() @Layer.cpp{ return new Handle(mFlinger, this); }
//这个handle只是传给client端的一个BBbinder,当客户端释放了这个引用时,会调用其析构函数,那么它的析构函数做了什么事情呢?Handle本身没写析构函数,所以要做的事情就在其父类LayerCleaner的析构函数中。
class Layer::Handle : public BBinder, public LayerCleaner { Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) : LayerCleaner(flinger, layer), owner(layer) {} };
//LayerCleaner的析构函数,调用了surfaceflinger的onLayerDestroyed,把layer从surfaceflinger的全局变量mCurrentState.layersSortedByZ中移除。
Layer::LayerCleaner::~LayerCleaner() { mFlinger->onLayerDestroyed(mLayer); }
//Layer中很多变量的实例化,都是在onFirstRef中完成的,当Layer实例第一次被引用时会执行onFirstRef函数。
Layer.cpp void Layer::onFirstRef() { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; //通过BufferQueue创建BufferQueueProducer,BufferQueueConsumer,这样标识了 IGraphicBufferProducer对应的服务端是BufferQueueProducer, IGraphicBufferConsumer对应的服务端是 BufferQueueConsumer,同时BufferQueueProducer、 BufferQueueConsumer的构造函数中都有一个BufferQueueCore实例,生成者,消费者的对缓冲区的操作都会经过BufferQueueCore。 BufferQueue::createBufferQueue(&producer, &consumer); //这里返回给client端的并不是 IGraphicBufferProducer,而是对它的封装类 MonitoredProducer, //MonitoredProducer并没有增加新的功能,只是在 IGraphicBufferProducer被销毁时,通知 // Surfaceflinger做些操作。 mProducer = new MonitoredProducer(producer, mFlinger); mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,this); }
//我们只关注MonitoredProducer的构造函数,看在IGraphicBufferProducer被销毁时,它要做什么。
MonitoredProducer.cpp
MonitoredProducer::~MonitoredProducer() @MonitoredProducer.cpp{ //这里使用了跟Client.cpp中调用surfaceflinger创建layer类似的方式,不同的是这里是异步的消息机制。 class MessageCleanUpList : public MessageBase { virtual bool handler() { //把IGraphicBufferProducer从surfaceflinger的列表中删除,这个操作是异步执行的,因为不知道会从哪里调用这个析构函数。还记得 mProducer是什么时候添加到这个列表中的吗?是在surfaceflinger的createLayer中,当创建一个layer之后,调用addClientLayer来添加的。 mFlinger->mGraphicBufferProducerList.remove(mProducer); } } mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder(this))); }
在Layer中还有一个重要的变量SurfaceFlingerConsumer。
SurfaceFlingerConsumer是GLConsumer的简单的包装类,把IGraphicBufferConsumer实例传给了GLConsumer。
SurfaceFlingerConsumer.cpp class SurfaceFlingerConsumer : public GLConsumer { SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t tex, const Layer* layer) : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false), mPrevReleaseFence(Fence::NO_FENCE), mLayer(layer){} }
class GLConsumer :public ConsumerBase {}
class ConsumerBase :public virtual RefBase,protected ConsumerListener {}
GLConsumer有继承自ConsumerBase,间接继承了ConsumerListener。
接下来逐层分析逐个继承关系。
GLConsumer会消费来自BufferQueue的缓冲区或者叫图形数据,并把他们转做texture为opengl使用。一个典型的使用方式是使用所需要的选项设置GLConsumer,然后当有一帧需要时,调用updateTexImage,这个函数会获取最近queued的buffer,然后绑定这个buffer到GLtexture,如果这一帧是可用的,texture会被更新,如果不可用,前一帧的内容会被保留。
ConsumerBase是BufferQueue消费者的基类,它处理一些通用任务,比如到BufferQueue的连接,buffer池的管理,其中的成员变量sp<IGraphicBufferConsumer>mConsumer;就是SurfaceFlingerConsumer传过来的,ConsumerBase是通过IGraphicBufferConsumer对象来对BufferQueue执行操作的。
简单做个总结:
1)应用程序通过BufferQueue执行绘图,surfaceflinger会把系统中所有应用程序最终的绘图结果进行混合,然后送到物理屏幕显示。应用程序跟surfaceflinger之间的通信桥梁是IsurfaceComposrClient。
这个类被封装在SurfaceComposerClient中。
2)应用程序通过SurfaceComposerClient调用CreateSurface的过程中,除了得到IGraphicBufferProducer实例外,还创建了一个layer。把控制这个layer的handle,IGraphicBufferProducer对象,连同SurfaceComposerClient自身都保存在应用端的Surfacecontrol中。
3)Surface,应用程序通过Surfacecontrol的getSurface获取,其内部持有IGraphicBufferProducer对象,即BufferQueueProducer的实现接口。如果egl想通过Surface这个本地窗口完成某个功能,Surface实际上是利用IGraphicBufferProducer取得远程端的服务,完成egl的请求。
4)应用程序跟layer应该是一对多的关系,因为createSurface是可以被调用多次的,并且,一个应用程序申请的多个layer可以通过addClientLayer添加到一个全局变量mLayers中。应用程序申请的layer,一方面要记录都各个Client的内部变量mLayers中,另一方面还要告知SurfaceFlinger,这个操作也是在addClientLayer函数中完成的,即把layer添加到全局变量mCurrentState.layerSortByZ,Surfaceflinger会对这个列表中的所有layer排序,排序的结果直接影响了屏幕显示的画面。
5)每个layer对应一个BufferQueue,所以一个应用程序可能对应多个BufferQueue。layer并没有直接持有BufferQueue对象,而是通过其内部的IGraphicBufferProducer,mSurfaceFlingerConsumer来管理。
相关文章推荐
- Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)
- Android 7.1 GUI系统-窗口管理WindowManagerService(一)
- Android 7.1 GUI系统-窗口管理WMS-窗口添加(三)
- Android 7.1 GUI系统-窗口管理WMS-窗口大小计算(五)
- Android 7.1 GUI系统-窗口管理WMS-窗口动画、应用动画的加载(六)
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
- GUI系统之SurfaceFlinger(5)BufferQueue内部原理
- GUI系统之SurfaceFlinger(5)BufferQueue内部原理
- GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
- Android 7.1 GUI系统-vsync信号的产生和接收(五)
- GUI系统之SurfaceFlinger(5)BufferQueue内部原理
- GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
- Android7.1 GUI系统-概述(一)
- Android7.1 GUI系统中的本地窗口(二)
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
- GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)