Android12 显示框架之getSurface

目录:Android显示终极宝典

在上篇文章中,我们讲到了应用通过createSurface()在surfaceflinger内生成了一个Layer,并且获取到了该Layer的Handle且将其和其他信息保存到了SurfaceControl。应用拿到了这个SurfaceControl,那么接下来就要创建应用端的surface了。完成这个任务的接口就是getSurface()。

SurfaceControl::getSurface()

cpp 复制代码
//frameworks/native/libs/gui/SurfaceControl.cpp
sp<Surface> SurfaceControl::getSurface()
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == nullptr) {
        return generateSurfaceLocked();
    }
    return mSurfaceData;
}

sp<Surface> SurfaceControl::generateSurfaceLocked()
{
    uint32_t ignore;
    auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
                                 ISurfaceComposerClient::eOpaque);
    mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
                                       flags, mHandle, {}, &ignore);
    mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);

    // This surface is always consumed by SurfaceFlinger, so the
    // producerControlledByApp value doesn't matter; using false.
    mSurfaceData = mBbq->getSurface(true);

    return mSurfaceData;
}

我们在这个函数里发现两个点,这是Android12与之前版本的不同之处,一个是这里再次调用并创建一个SurfaceControl,另一个是创建一个BLASTBufferQueue。个人感觉这个设计应该还是一个过渡性的内容,因为里面的内容多多少少感觉有些冗余性。

下面逐一看看generateSurfaceLocked()内部要做的事情:

createSurface()

这里不再赘述了,上一篇文章已经讲解过了。这里生成的SurfaceControl保存在了当前SurfaceControl的mBbqChild变量中。值得注意的是,这里创建Layer时传入的宽和高都为0。

创建BLASTBufferQueue

这是Android12新加入的内容,其实就是对BufferQueue的一个封装。之前应用的BufferQueue都是在surfaceflinger内部,现在Google把它移到了应用进程内自己管理。这个可能是想参考Wayland的设计吧。

言归正传,来看看BLASTBufferQueue的构造过程:

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& 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 block
    mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());

    // safe default, most producers are expected to override this
    mProducer->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()

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                         sp<IGraphicBufferConsumer>* outConsumer) {
    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");

    sp<BufferQueueCore> core(new BufferQueueCore());
    LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");

    sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
    LOG_ALWAYS_FATAL_IF(producer == nullptr,
                        "BLASTBufferQueue: failed to create BBQBufferQueueProducer");

    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
    consumer->setAllowExtraAcquire(true);
    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
                        "BLASTBufferQueue: failed to create BufferQueueConsumer");

    *outProducer = producer;
    *outConsumer = consumer;
}

很简单,

  • 创建了一个BufferQueue,即BufferQueueCore。
  • 基于BufferQueue创建了一个生产者,即BBQBufferQueueProducer。
  • 基于BufferQueue创建了一个消费者,即BufferQueueConsumer。

BLASTBufferItemConsumer

cpp 复制代码
//frameworks/native/include/gui/BLASTBufferQueue.h
BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
						int bufferCount, bool controlledByApp)
	  : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
		mCurrentlyConnected(false),
		mPreviouslyConnected(false),
		mBLASTBufferQueue(nullptr) {}

//frameworks/native/libs/gui/BufferItemConsumer.cpp
BufferItemConsumer::BufferItemConsumer(
        const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
        int bufferCount, bool controlledByApp) :
    ConsumerBase(consumer, controlledByApp)
{
    status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
    LOG_ALWAYS_FATAL_IF(err != OK,
            "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
    if (bufferCount != DEFAULT_MAX_BUFFERS) {
        err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
        LOG_ALWAYS_FATAL_IF(err != OK,
                "Failed to set max acquired buffer count to %d", bufferCount);
    }
}

//frameworks/native/libs/gui/ConsumerBase.cpp
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);
    }
}

可以看到三者之间的继承关系:BLASTBufferItemConsumer->BufferItemConsumer->ConsumerBase。在ConsumerBase构造函数内会创建一个ProxyConsumerListener,并且通过BufferQueueConsumer将其保存到BufferQueueCore内。

setFrameAvailableListener()

将BLASTBufferQueue本身设置到ConsumerBase的mFrameAvailableListener对象,当有新的帧到来时,它会被通知到。

setBufferFreedListener()

将BLASTBufferQueue本身设置到BufferItemConsumer的mBufferFreedListener对象,当有旧的buffer在被释放时,它会被通知到。

Transaction

SurfaceComposerClient::Transaction()设置Layer对应的属性到surfaceflinger,这里设置了layer_state_t和applyToken两种属性。下一篇文章将详细讲解Transaction的原理。

到此,BLASTBufferQueue创建完毕,接下来就是真正创建应用端surface的时候了。

BLASTBufferQueue::getSurface()

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::unique_lock _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}

这里首先看mSurfaceControl->getHandle(),它的mSurfaceControl是指向当前SurfaceControl的子SurfaceControl的,所以用来获取子SurfaceControl的Handle。

cpp 复制代码
//frameworks/native/libs/gui/SurfaceControl.cpp
sp<IBinder> SurfaceControl::getHandle() const {
    if (mBbqChild != nullptr) {
        return mBbqChild->getHandle();
    }
    return getLayerStateHandle();
}

sp<IBinder> SurfaceControl::getLayerStateHandle() const
{
    return mHandle;
}

看getHandle()的实现很明显的看出,这个函数永远获取子SurfaceControl所指向的mHandle。

最后是new一个BBQSurface,它继承自Surface:

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
		   const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
	  : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

这里用BLASTBufferQueue本身、它的BBQBufferQueueProducer、Layer的Handle构建出了一个BBQSurface。

简单的画个BLASTBufferQueue的生产者消费者模型则如下:

总结

通过本节内容,应用程序搭建完成了生产者消费者模型,获取到了Surface接口端,下面就可以生产buffer送显了。但是在这之前还要设置surface的各项属性,通过Transaction来达成目的,这个在下节讲解,这里提一嘴。

老规矩,还是通过框架图的形式总结下本节的内容,注意这里没有再去画出来surfaceflinger内部生成的内容了,因为上篇文章已经展示过了。

相关推荐
长亭外的少年1 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿4 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神5 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛5 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法6 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter7 小时前
Android吸顶效果,并有着ViewPager左右切换
android
猫猫的小茶馆8 小时前
【C语言】指针常量和常量指针
linux·c语言·开发语言·嵌入式软件
_祝你今天愉快8 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl8 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
麦田里的守望者江9 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin