Android显示系统(13)- 向SurfaceFlinger提交Buffer
Android显示系统(01)- 架构分析
Android显示系统(02)- OpenGL ES - 概述
Android显示系统(03)- OpenGL ES - GLSurfaceView的使用
Android显示系统(04)- OpenGL ES - Shader绘制三角形
Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件)
Android显示系统(06)- OpenGL ES - VBO和EBO和VAO
Android显示系统(07)- OpenGL ES - 纹理Texture
Android显示系统(08)- OpenGL ES - 图片拉伸
Android显示系统(09)- SurfaceFlinger的使用
Android显示系统(10)- SurfaceFlinger内部结构
Android显示系统(11)- 向SurfaceFlinger申请Surface
Android显示系统(12)- 向SurfaceFlinger申请Buffer
Android显示系统(13)- 向SurfaceFlinger提交Buffer
一、前言:
前面获取了Surface,并且为Surface申请了Buffer,然后通过EGL的往这Buffer里头渲染数据,完成之后,我们就需要去提交这个Buffer。
二、回顾流程图:
- 首先,SF会创建一个Client代表着App;
- App调用
createSurface
得到一个SurfaceControl
,同时,SF会创建一个Layer,代表APP端的SurfaceControl
; - 同时,SF端的Layer会有生产者和消费者,两者都有成员变量
mCore
(代表BufferQueueCore
)和mSlots
数组,而App端会有一个生产者代理,代表SF那边的Layer中的生产者。(中间通过binder通信) - App端的
SurfaceControl
可以通过getSurface
获得Surface,Surface当中也有mSlots和生产者代理。 - App端想要往Surface里面填充数据,首先得通过lock申请buffer,通过dequeueBuffer返回一个buffer,如果SF侧分配的buffer已经用完了,就通过
Gralloc
模块向匿名内存Ashmem
申请一个buffer,并且填入自己的mSlots
当中,同时返回给APP,需要重新分配Buffer,APP侧会重新调用requestBuffer
让SF侧重新关联这个Buffer,然后进行mmap,并且将fd返回给APP; - App收到binder过来的fd之后(其实binder转换成fd’了),进行
mmap(fd')
得到虚拟地址vaddr
,然后填入自己的mSlots
当中; - 最后App填充数据到vaddr当中之后,通过
unlockAndPost
提交给SF。
三、unlockAndPost:
3.1、总体思路:
- Surface->lock被调用获取Buffer之后,生产者的dequeueBuffer调用。
- 获得buffer之后,App侧通过Surface->unlockAndPost提交填充数据的Buffer,也就是调用queueBuffer。
- 那么queueBuffer调用之后,主要做两件事入队列,并且通知消费者取数据,通知顺序是:
- 通知Layer的消费者;
- 通知SurfaceFlinger;
3.2、代码走读:
入口在这儿:
status_t Surface::unlockAndPost()
{if (mLockedBuffer == nullptr) {ALOGE("Surface::unlockAndPost failed, no locked buffer");return INVALID_OPERATION;}int fd = -1;// 解锁当前被锁的缓冲区(异步)status_t err = mLockedBuffer->unlockAsync(&fd);ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);// 提交缓冲区err = queueBuffer(mLockedBuffer.get(), fd);ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",mLockedBuffer->handle, strerror(-err));mPostedBuffer = mLockedBuffer;mLockedBuffer = nullptr;return err;
}
3.3、Layer的消费者:
1)为Layer创建消费者:
看代码之前,我们先看下这个Layer第一次被引用时候:
void BufferQueueLayer::onFirstRef() {BufferLayer::onFirstRef();// Creates a custom BufferQueue for SurfaceFlingerConsumer to usesp<IGraphicBufferProducer> producer;sp<IGraphicBufferConsumer> consumer;// 创建BufferQueue的时候,里面会创建生产者和消费者BufferQueue::createBufferQueue(&producer, &consumer, true);// 将消费者做一次封装mProducer = new MonitoredProducer(producer, mFlinger, this);{// Grab the SF state lock during this since it's the only safe way to access RenderEngine// 同样,将生产者做一次封装Mutex::Autolock lock(mFlinger->mStateLock);mConsumer =new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);}// 。。。
}
看在这里面创建了生产者和消费者。我们看下这个消费者BufferLayerConsumer
:
BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq,renderengine::RenderEngine& engine, uint32_t tex,Layer* layer): ConsumerBase(bq, false), // 调用了父类构造函数//。。。mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {// 。。。
}
发现构造函数中首先调用了父类构造函数:
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :mAbandoned(false),mConsumer(bufferQueue),mPrevFinalReleaseFence(Fence::NO_FENCE) {// Choose a name using the PID and a process-unique ID.mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());// Note that we can't create an sp<...>(this) in a ctor that will not keep a// reference once the ctor ends, as that would cause the refcount of 'this'// dropping to 0 at the end of the ctor. Since all we need is a wp<...>// that's what we create.wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);status_t err = mConsumer->consumerConnect(proxy, controlledByApp);if (err != NO_ERROR) {CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",strerror(-err), err);} else {mConsumer->setConsumerName(mName);}
}
构造函数主要完成以下工作:
- 接受一个指向
IGraphicBufferConsumer
类型的缓冲队列接口和一个控制标志(是否由应用程序控制)。 - 初始化成员变量,例如放弃状态、消费者句柄等。
- 创建并绑定
ConsumerListener
,监听缓冲区的操作事件。 - 通过
BufferQueue
的consumerConnect
方法,将当前消费端与缓冲队列连接。 - 设置消费端名称,以便开发时调试和跟踪。
进去看看consumerConnect:
// 代码路径:native\libs\gui\include\gui\BufferQueueConsumer.hvirtual status_t consumerConnect(const sp<IConsumerListener>& consumer,bool controlledByApp) {return connect(consumer, controlledByApp);}
调用这个connect就将consumer保存到Layer当中了:
status_t BufferQueueConsumer::connect(const sp<IConsumerListener>& consumerListener, bool controlledByApp) {ATRACE_CALL();if (consumerListener == nullptr) {BQ_LOGE("connect: consumerListener may not be NULL");return BAD_VALUE;}BQ_LOGV("connect: controlledByApp=%s",controlledByApp ? "true" : "false");std::lock_guard<std::mutex> lock(mCore->mMutex);if (mCore->mIsAbandoned) {BQ_LOGE("connect: BufferQueue has been abandoned");return NO_INIT;}// 将Consumer赋值给mCoremCore->mConsumerListener = consumerListener;mCore->mConsumerControlledByApp = controlledByApp;return NO_ERROR;
}
其中sp<BufferQueueCore> mCore;
2)给Consumer设置监听者:
void BufferQueueLayer::onFirstRef() {// ...// 给Consumer设置一个ListenermConsumer->setContentsChangedListener(this);mConsumer->setName(mName);// ...
}
稍微进去看看:
void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) {setFrameAvailableListener(listener);Mutex::Autolock lock(mMutex);mContentsChangedListener = listener;
}
这个会走到父类:
void ConsumerBase::setFrameAvailableListener(const wp<FrameAvailableListener>& listener) {CB_LOGV("setFrameAvailableListener");Mutex::Autolock lock(mFrameAvailableMutex);mFrameAvailableListener = listener;
}
发现Listener最终保存到父类的成员变量mFrameAvailableListener
以及BufferLayerConsumer
的mContentsChangedListener
,以后Consumer有变化,就通过这个通知给监听者。
3.3、queueBuffer
入口函数:
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {// ...nsecs_t now = systemTime();// 调用生产者代理的queueBuffer,导致Binder调用status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);mLastQueueDuration = systemTime() - now;if (err != OK) {ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);}// ...
}
调用代理对象的函数:
然后就是调用了QueueBuffer的生产者代理提交buffer。中间一堆binder调用我们省略了,直接看子类BufferQueueProducer
。
status_t BufferQueueProducer::queueBuffer(int slot,const QueueBufferInput &input, QueueBufferOutput *output) { BufferItem item;// 。。。// 取出要提交的那一项,用取出的项构造一个BufferItem对象;item.mAcquireCalled = mSlots[slot].mAcquireCalled;item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;item.mCrop = crop;item.mTransform = transform &~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);item.mTransformToDisplayInverse =(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;item.mScalingMode = static_cast<uint32_t>(scalingMode);item.mTimestamp = requestedPresentTimestamp;item.mIsAutoTimestamp = isAutoTimestamp;item.mDataSpace = dataSpace;item.mHdrMetadata = hdrMetadata;item.mFrameNumber = currentFrameNumber;item.mSlot = slot;item.mFence = acquireFence;item.mFenceTime = acquireFenceTime;item.mIsDroppable = mCore->mAsyncMode ||(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);item.mSurfaceDamage = surfaceDamage;item.mQueuedBuffer = true;item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;item.mApi = mCore->mConnectedApi;// 。。。output->bufferReplaced = false;if (mCore->mQueue.empty()) {// When the queue is empty, we can ignore mDequeueBufferCannotBlock// and simply queue this buffermCore->mQueue.push_back(item);frameAvailableListener = mCore->mConsumerListener;} else {// ...mCore->mQueue.push_back(item);frameAvailableListener = mCore->mConsumerListener;}
}
其实不管队列空不空,最终都会push_back进去;
同时,记录了一下listener,这个listener前面已经分析过了,是一个proxy,也就是BufferQueue::ProxyConsumerListener
对象。
通知观察者:
status_t BufferQueueProducer::queueBuffer(int slot,const QueueBufferInput &input, QueueBufferOutput *output) { // ...{ // scope for the lockstd::unique_lock<std::mutex> lock(mCallbackMutex);while (callbackTicket != mCurrentCallbackTicket) {mCallbackCondition.wait(lock);}// 通知监听者,有数据了if (frameAvailableListener != nullptr) {frameAvailableListener->onFrameAvailable(item);} else if (frameReplacedListener != nullptr) {frameReplacedListener->onFrameReplaced(item);}// ...}// ...
}
就是通知监听者有数据了,这个监听者是谁呢?上面我们说了,是Queue的消费者,以及SurfaceFlinger。所以,我们到了消费者的代理类:
void BufferQueue::ProxyConsumerListener::onFrameAvailable(const BufferItem& item) {sp<ConsumerListener> listener(mConsumerListener.promote());if (listener != nullptr) {listener->onFrameAvailable(item);}
}
这个listener是ConsumerBase
,于是我们看看消费者的onFrameAvailable
函数:
void ConsumerBase::onFrameAvailable(const BufferItem& item) {CB_LOGV("onFrameAvailable");sp<FrameAvailableListener> listener;{ // scope for the lockMutex::Autolock lock(mFrameAvailableMutex);// 通过调用 promote() 方法,将弱引用 mFrameAvailableListener 提升为强引用 listenerlistener = mFrameAvailableListener.promote();}if (listener != nullptr) {CB_LOGV("actually calling onFrameAvailable");listener->onFrameAvailable(item);}
}
当然,mFrameAvailableListener
这个就是Layer:
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {// ...// If this layer is orphaned, then we run a fake vsync pulse so that// dequeueBuffer doesn't block indefinitely.if (isRemovedFromCurrentState()) {fakeVsync();} else {// 通知Layer已经更新mFlinger->signalLayerUpdate();}mConsumer->onBufferAvailable(item);
}
通过SurfaceFlinger来通知Layer已经更新:
// 通知Layer已经更新
void SurfaceFlinger::signalLayerUpdate() {mScheduler->resetIdleTimer();mEventQueue->invalidate();
}
这个invalidate()
会导致另外一个很重要的线程被唤醒,后面文章再分析。
四、总结:
Buffer被填充完渲染数据之后,通过Binder告诉SF端对应的消费者,后续通知流程:生产者->进入了消费者->Layer->SurfaceFlinger。就进入了视频显示的主流程,具体如何显示,且听下回分解。