从bootamition出发分析OpenHarmony下Gralloc buffer管理机制
从bootamition出发分析OpenHarmony下Gralloc buffer管理机制
引言
这个文档主要记录从bootamition角度出发,分析OpenHarmony下对gralloc buffer的管理!由于OpenHarmony图形子系统过于复杂,且个人由于能力有限,这里我仅从gralloc buffer出发,从整体上对Gralloc buffer进行梳理!虽然过程会很艰辛,但是我一定要坚持下来。加油!加油!加油!
一.bootamitin核心流程分析
bootamitin的核心功能是播放开机动画,其中会涉及到音频播放这块我们可以忽视。既然其中涉及开机动画的播放,那么就和graphics有关。我们正好可以拿这块来作为gralloc buffer管理来分析。这里我只放出核心的步骤,具体的在后面分析:
//boot_animation.cpp BootAnimation::Init auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance() receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", mainHandler_)//注册Vsync监听 receiver_->Init()//初始化 InitBootWindow()//创建窗口 scene_ = new OHOS::Rosen::WindowScene(); window_ = scene_->GetMainWindow() scene_->Init(displayId, nullptr, listener, option) window_ = scene_->GetMainWindow() rsSurface_ = OHOS::Rosen::RSSurfaceExtractor::ExtractRSSurface(window_->GetSurfaceNode()); //此处是重点,surface的创建 OHOS::Rosen::VSyncReceiver::FrameCallback fcb = { .userData_ = this, .callback_ = std::bind(&BootAnimation::OnVsync, this),//其中OnVsync响应Vsync事件 }; int32_t changefreq = static_cast((1000.0 / freq_) / 16); ret = receiver_->SetVSyncRate(fcb, changefreq);//发送VSync监听到周期变化 BootAnimation::OnVsync(...) PostTask(std::bind(&BootAnimation::Draw, this)) BootAnimation::Draw() //申请一个buffer auto frame = rsSurface_->RequestFrame(windowWidth_, windowHeight_) canvas = framePtr_->GetCanvas(); rsSurface_->FlushFrame(framePtr_)
上述的流程是bootamition的核心流程,其中几个核心在于:
- rsSurface_的创建过程
- RequestFrame的执行流程(主要涉及渲染buffer的申请)
- FlushFrame的流程(渲染buffer,flush到消费端)
二.rsSurface的创建
2.1 RSSurface rsSurface_的创建
- 具体调用流程如下:
rsSurface_ = OHOS::Rosen::RSSurfaceExtractor::ExtractRSSurface(window_->GetSurfaceNode());//这里的rsSurfa指向RSSurfaceOhosGlwindow_->GetSurfaceNode() = CreateSurfaceNode(property_->GetWindowName(), option->GetWindowType()) // window_impl.cppRSSurfaceNode::Create(rsSurfaceNodeConfig, rsSurfaceNodeType)RSSurfaceNode::CreateNodeAndSurfaceRSRenderServiceClient->CreateNodeAndSurface(...) auto renderService = RSRenderServiceConnectHub::GetRenderService();//这里获取的是RSRenderServiceConnectionProxy代理端RSRenderServiceConnectHub::GetRenderServiceConnectionsptr conn = renderService->CreateConnection(token_); sptr surface = renderService->CreateNodeAndSurface(config); //调用到服务端,这里使用的是IPC调用 CreateRSSurface(surface)producer = std::make_shared(surface);//客户端调用流程sptr surface = renderService->CreateNodeAndSurface(config);//注意这里的renderService是代理端Remote()->SendRequest(RSIRenderServiceConnection::CREATE_NODE_AND_SURFACE, data, reply, option); //通过ipc传输,跨进程调用sptr surface = CreateNodeAndSurface(config);//rs_render_connection_stub.cppnode = RSSurfaceRenderNode(...)surface = Surface::CreateSurfaceAsConsumer(config.name);//作为消费端node->SetConsumer(surface); std::weak_ptr surfaceRenderNode(node); //创建RSSurfaceRenderNode sptr listener = new RSRenderServiceListener(surfaceRenderNode); SurfaceError ret = surface->RegisterConsumerListener(listener);//注册回调监听 sptr surfaceObject = reply.ReadRemoteObject(); sptr bp = iface_cast(surfaceObject);//这个地方IBufferProducer具体的指向,这个是BufferClientProducer sptr surface = Surface::CreateSurfaceAsProducer(bp);//render_service服务端调用流程 sptr surface = CreateNodeAndSurface(config);RSRenderServiceConnection::CreateNodeAndSurface(...)//rs_render_service_connection.cppRSSurfaceRenderNode node = std::make_shared(...)surface = Surface::CreateSurfaceAsConsumer(...) auto producer = surface->GetProducer(); reply.WriteRemoteObject(producer->AsObject()); //这里跨进程传递的是代理端
- 其中IBufferProducer的IPC客户端和服务端的实现如下(其中类似的实现还有RSIRenderServiceConnection,可以类比Android中的SurfaceFlinger中nnection的实现)):
- 其中RSIRenderServiceConnection的类图关系如下:
- 其中Surface之间的类图关系如下:
三.RequestFrame流程
3.1 RequestFrame的流程
-
具体的调用流程如下:
rsSurface_->RequestFrame(windowWidth_, windowHeight_);RSSurfaceOhosGl::RequestFrame //rs_surface_ohos_gl.cppRenderContext* context = GetRenderContext()mWindow = CreateNativeWindowFromSurface(&producer_)nativeWindow->surface = *reinterpret_cast<OHOS::sptr *>(pSurface);//这个地方的pSurface有啥作用呢,传入到Mesa中去了mEglSurface = context->CreateEGLSurfaceframe = RSSurfaceFrameOhosGlcontext->MakeCurrent(mEglSurface)frame->SetRenderContext(context)
-
需要注意的点:
在bootamition主要是通过egl配合gl进行渲染操作,那么前面创建的rsSurface_还有啥作用呢:
1.主要是将该rsSurface传入到Mesa
2.在后续的使用中,在Mesa实现的EGL上面创建EGLSurface并将其传递给EGL,然后EGL也将该surface传递
3.然后后续一些调用中就会通过psurface接口调用相关的request和acquiire和release操作
四.FlushFrame流程
4.1 FlushFrame的流程
- 具体的调用流程如下:
rsSurface_->FlushFrameRSSurfaceOhosGl::FlushFrame//rs_surface_ohos_gl.cppcontext->SwapBuffers(mEglSurface)eglSwapBuffers(...)//render_context.cppdisp->Driver->SwapBuffers(...) //eglapi.cSwapBuffers = dri2_swap_buffersdri2_dpy->vtbl->swap_buffers(disp, surf)ohos_swap_buffers()ohos_window_enqueue_bufferANativeWindow_queueBufferNativeWindowFlushBufferwindow->surface->FlushBuffer(buffer->sfbuffer, acquireFence, config) //produce_surface.cppproducer_->FlushBUffer(...)//buffer_client_producer.cppIPC send BUFFER_PRODUCER_FLUSH_BUFFER //跨进程调用到render_service服务端响应:BufferQueueProducer::FlushBufferRemote(...)//buffer_queue_producer.cppBufferQueueProducer::Flush(...)bufferQueue_->FlushBuffer(...)//这里的bufferQueue指向BufferQueueDoFlushBuffer(...)listener_->OnBufferAvailable()//通知有渲染完成了,后续会触发vsync,这个地方跟下sptr listener = new RSRenderServiceListener(surfaceRenderNode); SurfaceError ret = surface->RegisterConsumerListener(listener);//此处的listener是在rs_render_service_connection.cpp被注册回调RSRenderServiceListener::OnBufferAvailable(...)RSMainThread::Instance()->RequestNextVSync(...)//触发下次vsync,且此处的是一个全局的
五.RequestBuffer流程
5.1 RequestBuffer流程分析
- 具体调用流程如下:
NativeWindowRequestBuffer(...) //native_window.cpp //客户端发出请求window->surface->RequestBuffer(...) producer_->RequestBuffer(...)//buffer_client_producer.cppSEND_REQUEST(BUFFER_PRODUCER_REQUEST_BUFFER, arguments, reply, option);ReadSurfaceBufferImpl(reply, retval.sequence, retval.buffer)BufferQueueProducer::RequestBufferRemote//render_service服务端响应RequestBuffer(.)bufferQueue_->RequestBuffer(...)//buffer_queue.cpp,这一部分有时间的话需要更加精细化的去分析,主要是分析buffer的管理部分AllocBuffer(...)//这里我们默认没有足够的buffer,需要重新创建SurfaceBuffer bufferImpl = new SurfaceBufferImpl()bufferImpl->Alloc(..)displayGralloc_->AllocMem(info, handle);//DisplayGrallocClient,通过gralloc服务进行分配,这里的displayGralloc_是gralloc服务的客户端 allocatorProxy_->AllocMem(...) //allocator_proxy.cppRemote()->SendRequest(CMD_REMOTE_ALLOCATOR_ALLOCMEM, data, reply, option)//调用到服务端retHandle = ReadBufferHandle(reply)bufferImpl->Map(...)//映射到用户空间,这里木有通过gralloc服务WriteSurfaceBufferImpl(reply, retval.sequence, retval.buffer)//将申请到的buffer写回服务端,这其中需要注意的是会会有一次dup操作###disp_gralloc_bo服务端接收请求AllocatorServiceStub::OnRemoteRequest(...)//接收CMD_ALLOCATOR_ALLOCMEM命令,allocator_service_stub.cppAllocaltorStubAllocMem(...)AllocMeme(...) //allocator_service_impl.cppgrallocFuncs_->AllocMem(...)\\disp_gralloc.cGbmGrallocMem(...)//display_gralloc_gbm.chdi_gbm_bo_create(...)drmIoctl(gbm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb)hdi_gbm_bo_get_fd(...)drmPrimeHandleToFD(bo->gbm->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR, &fd)InitBufferHandle(bo, fd, info, priBuffer)hdi_gbm_bo_destroy(...)drmIoctl(bo->gbm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dumb)WriteBufferHandle(...)FreeMem(...)//注意这个地方并不是把buffer释放了,只是把dup前的fd释放了
- gralloc跨进程调用简图:
这里我们可以看到RequestBuffer的调用过程中,牵涉到多次的IPC跨进程调用,其中核心的就是传递dumb的fd。
5.2 RequestBuffer过程中的几次dup
- 核心点这里通过前面的总结可以看出,在RequestBuffer中一共有经历过两次dup操作!
//前面说的存在两次dup操作,都存在于服务端返回fd的时候,会分别调用WriteSurfaceBufferImpl(...)和WriteBufferHandle(...),我们下面对上述两个函数分贝展开来看看:void WriteSurfaceBufferImpl(MessageParcel &parcel, uint32_t sequence, const sptr &buffer){ ... buffer->WriteToMessageParcel(parcel);}GSError SurfaceBufferImpl::WriteToMessageParcel(MessageParcel &parcel){ ... bool ret = WriteBufferHandle(parcel, *handle);//后面调用的也是这个接口 ...}bool WriteBufferHandle(MessageParcel &parcel, const BufferHandle &handle){... if (validFd && !parcel.WriteFileDescriptor(handle.fd)) { UTILS_LOGE("%{public}s parcel.WriteFileDescriptor fd failed", __func__); return false; }...}bool MessageParcel::WriteFileDescriptor(int fd){ ... int dupFd = dup(fd); ...}
参考:
Android Binder传递文件描述符原理分析
六.小结
至此,以bootamition为例说明的,OH下gralloc buffer管理就基本结束了。由于时间和个人能力的原因,总结的不是非常的彻底和到位,其中还有很多的地方只是简单的概括或者待过了。如果开发者或者读者有过Android graphcis相关经验的话,理解起来就比较容易了。这里我们可以使用如下的图示来概括下gralloc buffer的管理模式:
上述图示有如下几点需要注意:
- 上述不但可以表述渲染buffer的管理模型,也可使是在使用GPU合成时framebuffer的模型图
- 上述生产者和消费者可以位于不同的进程,也可以是同一个进程,绝大部分的时候位于不同的进程
从上面的总结可以看出:
- gralloc buffer的模型就是一种典型的生产,消费者模型。应用申请gralloc buffer渲染完成之后,归还给bufferqueue
- 消费者在收到vsync之后,从bufferqueue取出已经生产好的buffer,做进一步处理
- 当进行GPU合成时,会拿到前面已经生产好的buffer,再在framebuffer中进行合成
- 还有就是我们一定要有一个概念,就是应用端和render_server并不是直接进行通信的,而是通过IPC机制进行的。正是由于IPC机制设计的巧妙,是使用者以为是直接在和服务端交互。其实不然!
七.关于OH下graphics图形栈调试小技巧
对于OH我们不要要求太多,肯定不能像Android那样提供完善的工具,但是也提供了一些基本的调试命令,其中对于graphics图形栈的调试,可以通过如下命令查看:
# hidumper -s RenderService-------------------------------[ability]-----------------------------------------------------------------RenderService---------------------------------------Graphic2D--RenderSerice ------Usage: h |help text for the toolscreen |dump all screen infomation in the systemsurface |dump all surface informationcomposer fps |dump the fps info of composer[surface name] fps |dump the fps info of surfacecomposer fpsClear |clear the fps info of composer[surface name] fpsClear |clear the fps info of surfacenodeNotOnTree |dump nodeNotOnTree infoallSurfacesMem |dump surface mem infoRSTree |dump RSTree infoEventParamList |dump EventParamList infoallInfo |dump all info# hidumper -s RenderService -a allInfo -------------------------------[ability]-----------------------------------------------------------------RenderService----------------------------------- ScreenInfoscreen[0]: id=2, powerstatus=POWER_STATUS_ON, backlight=-1, screenType=EXTERNAL_TYPE supportedMode[0]: 720x400, refreshrate=70 supportedMode[1]: 640x480, refreshrate=60 supportedMode[2]: 640x480, refreshrate=75 supportedMode[3]: 800x600, refreshrate=60 supportedMode[4]: 800x600, refreshrate=75 supportedMode[5]: 1024x768, refreshrate=60 supportedMode[6]: 1152x864, refreshrate=75 supportedMode[7]: 1280x1024, refreshrate=60 supportedMode[8]: 1280x1024, refreshrate=75 supportedMode[9]: 1920x1080, refreshrate=60 activeMode: 1920x1080, refreshrate=60 capability: name=Unknown, phywidth=530, phyheight=300,supportlayers=0, virtualDispCount=0, propCount=0, type=INVILID_DISP_INTF, supportWriteBack=false-- LayerInfo surface [ScreenLockWindow] NodeId[2954937499653] LayerId[2]://锁屏界面 zOrder = 0, visibleNum = 1, transformType = 0 , compositionType = 0 , blendType = 3 , layerAlpha = [enGlobalAlpha(1), enPixelAlpha(0), alpha0(0), alpha1(0), gAlpha(255)]. layerRect = [0, 0, 1920, 1080], visibleRegion = [0, 0, 1920, 1080], dirtyRegion = [0, 0, 1920, 1080], cropRect = [0, 0, 1920, 1080]. BufferQueue: default-size = [1920x1080], FIFO = 3, name = ScreenLockWindow, uniqueId = 2954937499653, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB). bufferQueueCache: sequence = 8, state = 0 , timestamp = 780011576923, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 9, state = 0 , timestamp = 840016378613, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 13, state = 3 , timestamp = 900011540119, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).FrameBufferSurface BufferQueue: default-size = [0x0], FIFO = 3, name = FrameBuffer, uniqueId = 2954937499648, usedBufferListLen = 2, freeBufferListLen = 1, dirtyBufferListLen = 0, totalBuffersMemSize = 16200.00(KiB). bufferQueueCache: sequence = 2, state = 3 , timestamp = 900046439, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 73, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 4, state = 0 , timestamp = 840051447, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 73, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB).-- Node Not On Tree node Id[6597069766667]: BufferQueue: default-size = [0x0], FIFO = 3, name = SystemUi_BannerNotice, uniqueId = 2954937499659, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: node Id[6597069766666]: BufferQueue: default-size = [0x0], FIFO = 3, name = SystemUi_DropdownPanel, uniqueId = 2954937499658, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: node Id[6597069766658]: BufferQueue: default-size = [0x0], FIFO = 3, name = SystemUi_VolumePanel, uniqueId = 2954937499654, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: node Id[7146825580544]: BufferQueue: default-size = [0x0], FIFO = 3, name = imeWindow, uniqueId = 2954937499652, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: node Id[6962141986820]: BufferQueue: default-size = [0x0], FIFO = 3, name = RecentView, uniqueId = 2954937499651, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache:-- All Surfaces Memory Sizethe memory size of all surfaces buffer is : 94680.00 KiB. BufferQueue: default-size = [0x0], FIFO = 3, name = SystemUi_DropdownPanel, uniqueId = 2954937499658, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: BufferQueue: default-size = [1920x32], FIFO = 3, name = SystemUi_PrivacyIndicator, uniqueId = 2954937499657, usedBufferListLen = 3, freeBufferListLen = 1, dirtyBufferListLen = 0, totalBuffersMemSize = 720.00(KiB). bufferQueueCache: sequence = 12, state = 1 , timestamp = 40645170158, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB). sequence = 14, state = 3 , timestamp = 40912469187, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB). sequence = 17, state = 0 , timestamp = 40827680126, damageRect = [0, 0, 1920, 32], config = [1920x32, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 32, bufferMemSize = 240.00(KiB). BufferQueue: default-size = [1920x1080], FIFO = 3, name = EntryView, uniqueId = 2954937499650, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB). bufferQueueCache: sequence = 5, state = 0 , timestamp = 31794906265, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 6, state = 0 , timestamp = 32561536655, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 7, state = 3 , timestamp = 32644867137, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). BufferQueue: default-size = [1920x108], FIFO = 3, name = SystemUi_NavigationBar, uniqueId = 2954937499656, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 2430.00(KiB). bufferQueueCache: sequence = 11, state = 0 , timestamp = 40827680126, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB). sequence = 16, state = 0 , timestamp = 40912469187, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB). sequence = 19, state = 3 , timestamp = 60012066524, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB). BufferQueue: default-size = [0x0], FIFO = 3, name = SystemUi_VolumePanel, uniqueId = 2954937499654, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: BufferQueue: default-size = [1920x1080], FIFO = 3, name = ScreenLockWindow, uniqueId = 2954937499653, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 24300.00(KiB). bufferQueueCache: sequence = 8, state = 0 , timestamp = 780011576923, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 9, state = 0 , timestamp = 840016378613, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). sequence = 13, state = 3 , timestamp = 900011540119, damageRect = [0, 0, 1920, 1080], config = [1920x1080, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 1080, bufferMemSize = 8100.00(KiB). BufferQueue: default-size = [0x0], FIFO = 3, name = imeWindow, uniqueId = 2954937499652, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: BufferQueue: default-size = [0x0], FIFO = 3, name = RecentView, uniqueId = 2954937499651, usedBufferListLen = 0, freeBufferListLen = 0, dirtyBufferListLen = 0, totalBuffersMemSize = 0.00(KiB). bufferQueueCache: BufferQueue: default-size = [1920x108], FIFO = 3, name = SystemUi_StatusBar, uniqueId = 2954937499655, usedBufferListLen = 3, freeBufferListLen = 2, dirtyBufferListLen = 0, totalBuffersMemSize = 2430.00(KiB). bufferQueueCache: sequence = 10, state = 0 , timestamp = 40827680126, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB). sequence = 15, state = 3 , timestamp = 60012066524, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB). sequence = 18, state = 0 , timestamp = 40912469187, damageRect = [0, 0, 1920, 108], config = [1920x108, 8, 12, 9, 3000], bufferWith = 1920, bufferHeight = 108, bufferMemSize = 810.00(KiB).-- RenderServiceTreeDump: Animating Node: [];| BASE_NODE[0], isOnTheTree: 1, children[2963527434241 ] | DISPLAY_NODE[2963527434241], isOnTheTree: 1, children[6597069766656 6597069766661 6597069766664 6597069766665 6962141986816 ] | SURFACE_NODE[6597069766656], isOnTheTree: 1, hasConsumer: 1, Name [ScreenLockWindow], parent [2963527434241], { Region Size 1: [0, 0, 1920, 1080] }, SurfaceBgAlpha[ 255 ], children[] | SURFACE_NODE[6597069766661], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_StatusBar], parent [2963527434241], { Region Size 0: }, SurfaceBgAlpha[ 0 ], children[] | SURFACE_NODE[6597069766664], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_NavigationBar], parent [2963527434241], { Region Size 0: }, SurfaceBgAlpha[ 0 ], children[] | SURFACE_NODE[6597069766665], isOnTheTree: 1, hasConsumer: 1, Name [SystemUi_PrivacyIndicator], parent [2963527434241], { Region Size 0: }, SurfaceBgAlpha[ 0 ], children[] | SURFACE_NODE[6962141986816], isOnTheTree: 1, hasConsumer: 1, Name [EntryView], parent [2963527434241], { Region Size 0: }, SurfaceBgAlpha[ 0 ], children[]-- EventParamListDump: rosen.RsDFXEvent.RS_COMPOSITION_TIMEOUT.timeOutThresholdMs: 100rosen.RsDFXEvent.RS_COMPOSITION_TIMEOUT.eventIntervalMs: 60000-- QosDump: QOS is disabled
虽然不是很完备,但是凑合能用吗!希望OH以后能把相关的调试手段补全吗!聊胜于无!
写在最后
- OH的buffer管理参照的是Android中的,并且是通过renderserver对buffer进行管理的,有点类似android 12以前的实现
- ,但是并不是通过egl gbm进行buffer的申请和释放的,而是通过调用开源的Mesa实现将OH的surface传递到了Mesa中,然后在Mesa中通过surface的dequeue和queue将绘制好的buffer传递回去
- 而OH的buffer的最终申请调用到了/device/soc/phytium/d2000/hardware/display/display_gralloc模块中
- buffer的申请不一定需要通过render_server进行中转,可以是native应用可以创建ConsumerSurface,然后获取produceSurace,绕过和render_server交互,直接和gralloc服务进行交互
- buffer的mmap不是通过gralloc服务进行的,而是通过render_service进行的
这里我们也可以参考,OH官网的一个例子简单来说明,gralloc buffer的基本流程:
- 以WMS组件和UI组件交互为例,UI为生产者,WMS为消费者。
- 生产者:从Free队列中获取Buffer,将UI内容绘制到Buffer中,然后将Buffer放到Dirty队列;
- 消费者:从Dirty队列中获取Buffer并进行合成,然后将Buffer重新放到Free队列中。