天天看點

07.顯示系統:第004課_SurfaceFlinger内部機制:第005節_APP申請(lock)Buffer的過程_配置設定buffer

該小節我們從源代碼上分析,應用程式申請Buffer的調用過程,下面是一個從應用程式開始的流程圖:

07.顯示系統:第004課_SurfaceFlinger内部機制:第005節_APP申請(lock)Buffer的過程_配置設定buffer

應用程式在調用surface->lock(&outBuffer,NULL);函數的時候,會發起Surface::dequeueBuffer()的操作,進入調用:

/*代理端的生産者*/
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,reqWidth, reqHeight, reqFormat, reqUsage);
           

發起一個遠端調用,該函數會查詢SurfaceFlinger邊的mSlots,輸出結果放入buf中,他得到的是數組mSlots的一個下标,表示已經配置設定了一個mSlots的下标。那麼這個遠端調用會導緻那個函數被調用呢?

進入IGraphicBufferProducer.cpp檔案,查找到class BpGraphicBufferProducer (代理類),在找到其中的dequeueBuffer:

virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width,uint32_t height, PixelFormat format, uint32_t usage) {
	/*建構資料*/
	data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
    data.writeUint32(width);
    data.writeUint32(height);
    data.writeInt32(static_cast<int32_t>(format));
    data.writeUint32(usage);
    /*發起遠端調用,到最後調用本檔案中的status_t BnGraphicBufferProducer::onTransact方法*/
    status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply);
           

其中上的所說的onTransact函數如下:

status_t BnGraphicBufferProducer::onTransact(
	case DEQUEUE_BUFFER: {
		/*此處的dequeueBuffer由他的派生類BufferQueueProducer實作*/
		int result = dequeueBuffer(&buf, &fence, width, height, format,usage);
           

在BufferQueueProducer.cpp檔案中:

status_t BufferQueueProducer::dequeueBuffer(int *outSlot,sp<android::Fence> *outFence, uint32_t width, uint32_t height,PixelFormat format, uint32_t usage) {
	/*等待空閑的Slot,得到以後把他鎖定*/
	status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,&found);
	const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
	/*如果GraphicBuffer 中擷取的buffer是空的,或者參數和申請的參數不一樣*/
	if ((buffer == NULL) ||buffer->needsReallocation(width, height, format, usage))
		/*标記為需要重新配置設定*/
		returnFlags |= BUFFER_NEEDS_REALLOCATION;
	/*如果需要重新配置設定*/
	if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
		/*重新配置設定*/
		sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage,{mConsumerName.string(), mConsumerName.size()}, &error));
           

現在我們詳細的分析一下graphicBuffer,看看其是怎麼配置設定buffer的。之前的小節我們提到過,生産者和消費者指向同一個mCore(BufferQueueCore類),mAllocator(GraphicBufferAlloc類)。

進入GraphicBufferAlloc.cpp,檢視其createGraphicBuffer函數:

sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,uint32_t height, PixelFormat format, uint32_t usage,std::string requestorName, status_t* error) {
	sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(width, height, format, usage, std::move(requestorName)));	
           

進入GraphicBuffer.cpp檔案,檢視其構造函數:

GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,PixelFormat inFormat, uint32_t inUsage, std::string requestorName): BASE(),mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),mInitCheck(NO_ERROR),mId(getUniqueId()), mGenerationNumber(0){
    mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,std::move(requestorName));
    	GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    	status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
           

我們猜測一下initSize會調用gralloc HAL配置設定buffer,那麼肯定是在GraphicBufferAllocator的構造函數中打開HAL了。進入GraphicBufferAllocator的構造函數:

可以知道,其繼承于Loader與mDevice,其中Loader的構造函數如下:

Loader::Loader()
  : mDevice(nullptr)
{
    hw_module_t const* module;
    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    uint8_t majorVersion = (module->module_api_version >> 8) & 0xFF;
    uint8_t minorVersion = module->module_api_version & 0xFF;
    gralloc1_device_t* device = nullptr;
    if (majorVersion == 1) {
        gralloc1_open(module, &device);
    } else {
        if (!mAdapter) {
            mAdapter = std::make_unique<Gralloc1On0Adapter>(module);
        }
        device = mAdapter->getDevice();
    }
    mDevice = std::make_unique<Gralloc1::Device>(device);
}
           

可以看到,與我們猜測的一緻。下面我們在來分析:

GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    	status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
           

中的allocator.allocate:

/*通過Ashmem配置設定buf,得到fd,使用fd構造handle,并且memap,這邊memp得到的虛拟位址隻是給SurfaceFlinger程序使用*/
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,PixelFormat format, uint32_t usage, buffer_handle_t* handle,uint32_t* stride, uint64_t graphicBufferId, std::string requestorName)
	auto descriptor = mDevice->createDescriptor();
	auto error = descriptor->setDimensions(width, height);
	error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
	error = descriptor->setProducerUsage()
	error = descriptor->setConsumerUsage(
           

在SurfaceFlinger生産者roducer.cpp中包含了mCore與mslots[],配置設定記憶體就是標明空餘的mslots,然後對其進行構造。

打開生産者,BufferQueueProducer.h,可以找到

/*typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];*/
BufferQueueDefs::SlotsType& mSlots;

           

可以知道mSlots是一個SlotsType的引用,BufferSlot定義如下(主要成員):

struct BufferSlot {
	sp<GraphicBuffer> mGraphicBuffer;
           

GraphicBuffer中存在函數initSize():

mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage,std::move(requestorName));
    	GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    	status_t err = allocator.allocate(inWidth, inHeight, inFormat,inUsage,&handle, &outStride, mId, std::move(requestorName));
           

可以知道GraphicBuffer包括了handle,handle中至少包括了檔案句柄,以及base。與之對應在我們應用程式的Surface也尊在mslots[],其中的BufferSlot中的GraohicBuffer也包含了handle,并且handle中也存在fd與base。

現在我們分析了SurfaceFlinger如何建立buffer,下小節我們繼續分析,分析其如何傳遞回去給我們編寫的應用程式。

繼續閱讀