安庆网站建设推广,关键词指数,简单的静态网站,腾讯邮箱企业邮箱登录我们在工作的过程中#xff0c;肯定听过分析卡顿或者冻屏问题的时候#xff0c;定位到APP卡在dequeueBuffer方法里面#xff0c;或者也听身边的同事老说3Buffer等信息。所以3Buffer是什么鬼#xff1f;什么是BufferQueue?搞Android#xff0c;你一定知道Graphic Buffer和…我们在工作的过程中肯定听过分析卡顿或者冻屏问题的时候定位到APP卡在dequeueBuffer方法里面或者也听身边的同事老说3Buffer等信息。所以3Buffer是什么鬼什么是BufferQueue?搞Android你一定知道Graphic Buffer和 Buffer Queue, 你的笔记中肯定也有下面这张Graphic Buffer的状态迁移图。系统中有两类Buffer Queue如下图所示Layer背后的Buffer Queue第一类也是最为大家所熟知的就是Layer背后的BufferQueue用来连接App与SurfaceFlinger。App为Producer端而 SurfaceFlinger 为 Consumer 端。App 绘制时先从 Buffer Queue 中 dequeue调用 Producer 的 dequeueBuffer()函数出来一块图形缓冲绘制完成后再把绘制好的图形缓冲 queue调用 Producer 的 queueBuffer()函数到 Buffer Queue 中并通知 SurfaceFlinger来消费。SurfaceFlinger 收到通知后从 Buffer Queue 中 acquire 一块绘制过的 Buffer然后进行合成处理要么进行 GPU合成要么交给 HWC 去合成。合成完成之后这个块 Buffer 就恢复自由身会被返回到 Buffer Queue 中调用 Consumer 的 releaseBuffer()函数以备下一次使用。但是在Android S代码上面谷歌对SurfaceFlinger的代码进行了重构从个人理解是为了减少SF的负责Android S开始强制App端创建BufferQueue也就是强制Client端分配Buffer。在Android S的代码中引入了一个BLASTBufferQueue.java(后面简称BBQ)这个类ViewRootImpl.java在调用relayoutWindow函数的时候会创建BBQ这个对象。Surface getOrCreateBLASTSurface() {if (!mSurfaceControl.isValid()) {return null;}Surface ret null;if (mBlastBufferQueue null) {mBlastBufferQueue new BLASTBufferQueue(mTag, mSurfaceControl,mSurfaceSize.x, mSurfaceSize.y,mWindowAttributes.format);// We only return the Surface the first time, as otherwise// it hasnt changed and there is no need to update.ret mBlastBufferQueue.createSurface();} else {mBlastBufferQueue.update(mSurfaceControl,mSurfaceSize.x, mSurfaceSize.y,mWindowAttributes.format);}return ret;
}
在BBQ对象初初始化的时候会调用nativeCreate方法BBQ对象会在构造方法中传入SurfaceControl对象而这样就会和SurfaceFlinger创建了一个连接通道。SurfaceControl.java封装了很多Client调用的binder接口而服务端是SurfaceFlinger。通过nativeCreate本地方法通过JNIandroid_graphics_BLASTBufferQueue.cpp的nativeCreate方法创建了native层的BBQ。static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,jlong width, jlong height, jint format) {String8 str8;if (jName) {const jchar* str16 env-GetStringCritical(jName, nullptr);if (str16) {str8 String8(reinterpret_castconst char16_t*(str16), env-GetStringLength(jName));env-ReleaseStringCritical(jName, str16);str16 nullptr;}}std::string name str8.string();spBLASTBufferQueue queue new BLASTBufferQueue(name, reinterpret_castSurfaceControl*(surfaceControl), width,height, format);queue-incStrong((void*)nativeCreate);return reinterpret_castjlong(queue.get());
}
BLASTBufferQueue::BLASTBufferQueue(const std::string name, const spSurfaceControl surface,int width, int height, int32_t format): mSurfaceControl(surface),mSize(width, height),mRequestedSize(mSize),mFormat(format),mNextTransaction(nullptr) {createBufferQueue(mProducer, mConsumer);// since the adapter is in the client process, set dequeue timeout// explicitly so that dequeueBuffer will blockmProducer-setDequeueTimeout(std::numeric_limitsint64_t::max());// safe default, most producers are expected to override thismProducer-setMaxDequeuedBufferCount(2);mBufferItemConsumer new BLASTBufferItemConsumer(mConsumer,GraphicBuffer::USAGE_HW_COMPOSER |GraphicBuffer::USAGE_HW_TEXTURE,1, false);static int32_t id 0;mName name # std::to_string(id);auto consumerName mName (BLAST Consumer) std::to_string(id);mQueuedBufferTrace QueuedBuffer - mName BLAST# std::to_string(id);id;mBufferItemConsumer-setName(String8(consumerName.c_str()));mBufferItemConsumer-setFrameAvailableListener(this);mBufferItemConsumer-setBufferFreedListener(this);mBufferItemConsumer-setDefaultBufferSize(mSize.width, mSize.height);mBufferItemConsumer-setDefaultBufferFormat(convertBufferFormat(format));mBufferItemConsumer-setBlastBufferQueue(this);ComposerService::getComposerService()-getMaxAcquiredBufferCount(mMaxAcquiredBuffers);mBufferItemConsumer-setMaxAcquiredBufferCount(mMaxAcquiredBuffers);mTransformHint mSurfaceControl-getTransformHint();mBufferItemConsumer-setTransformHint(mTransformHint);SurfaceComposerClient::Transaction().setFlags(surface, layer_state_t::eEnableBackpressure,layer_state_t::eEnableBackpressure).setApplyToken(mApplyToken).apply();mNumAcquired 0;mNumFrameAvailable 0;BQA_LOGV(BLASTBufferQueue created width%d height%d format%d mTransformHint%d, width,height, format, mTransformHint);
}
从上面的代码中createBufferQueue创建了BufferQueue同时也创建了Graphic Buffer的生产者和消费者。其中有个代码mProducer - setMaxDequeuedBufferCount(2)这个就和3Buffer有关系了我们先整理下Buffer的运转过程如图所示App的RenderThread 调用 Producer.dequeueBuffer()在BufferQueue中拿到一个空闲的Buffer。App的RenderThread调用Producer.queueBuffer将绘制好的 Buffer 入列。注意此时入列的 Buffer 可能还未绘制完成即 GPU 可能还在进行绘制工作。最终调用到 Procuder 的 Bn 端即 SurfaceFliner 进程里的某个 Binder 线程里。在 Bn 端会通过调用SurfaceFlinger的SetTransactionState方法把当前的带有Buffer信息的State保存到一个TransactionQueue队列中。当带有Buffer信息的Layer信息保存到队列中 这个动作称作“上帧”。所以我么可以在 systrace 上看到该Layer待消费的 Buffer 数目1。而 Buffer Queue 的消费者就是 SurfaceFlinger所以在下一个 Vsync信号到来后在 SurfaceFlinger 的 handleMessageInvalidate()函数中调用 acquireBuffer()去取 Buffer取走之后BufferQueue 中待消费的 Buffer 便减少一个。因为有上帧所以要重新进行合成SurfaceFlinger 调用onMessageRefresh()函数去做合成一般是 HWC 合成直接把 Buffer 交给 HWC。合成完成后在 postComposition()里会调用binder接口进行通讯。App端的binder收到消息后调用releaseBuffer()释放 Buffer如 systrace 所示这里释放的是上一帧的 Buffer。上面图中7个步骤就是一个buffer详细的转运过程。DisplayDevice 背后的Buffer Queue第二类Buffer Queue是GPU合成特有的一般在游戏APP渲染过程中会遇到这个Buffer Queue隐藏在DisplayDevice之后是在SurfaceFlinger为每个接入系统的显示屏创建DisplayDevice实例时创建的。执行在SurfaceFlinger::processDisplayAdded函数中。void SurfaceFlinger::processDisplayAdded(const wpIBinder displayToken,const DisplayDeviceState state) {......spcompositionengine::DisplaySurface displaySurface;spIGraphicBufferProducer producer;spIGraphicBufferProducer bqProducer;spIGraphicBufferConsumer bqConsumer;getFactory().createBufferQueue(bqProducer, bqConsumer, /*consumerIsSurfaceFlinger */false);......
}这个函数是为DisplaySurface创建BufferQueue createBufferQueue函数是指向BufferQueue::createBufferQueue传入的第三个参数 consumerIsSurfaceFlinger 为false表示BufferQueue的消费者不是SurfaceFlinger。void SurfaceFlinger::processDisplayAdded(const wpIBinder displayToken,const DisplayDeviceState state) {......if (state.isVirtual()) {const auto displayId VirtualDisplayId::tryCast(compositionDisplay-getId());LOG_FATAL_IF(!displayId);auto surface spVirtualDisplaySurface::make(getHwComposer(), *displayId, state.surface,bqProducer, bqConsumer, state.displayName);displaySurface surface;producer std::move(surface);} else {ALOGE_IF(state.surface ! nullptr,adding a supported display, but rendering surface is provided (%p), ignoring it,state.surface.get());const auto displayId PhysicalDisplayId::tryCast(compositionDisplay-getId());LOG_FATAL_IF(!displayId);displaySurface spFramebufferSurface::make(getHwComposer(), *displayId, bqConsumer,state.physical-activeMode-getSize(),ui::Size(maxGraphicsWidth, maxGraphicsHeight));producer bqProducer;}......
}除了虚拟盘主屏或者外屏采用FrameBufferSurface继承自ConsumerBase把BufferQueueConsumer封装到FrameBufferSurface里面。Buffer共享Buffer分配Buffer同步fence后面三个点的内容还在整理中等整理完毕再同步到这章内容中。