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内部生成的内容了,因为上篇文章已经展示过了。

相关推荐
QING6182 分钟前
Kotlin inline 实战详解 —— 新手须知
android·kotlin·android jetpack
ElevenS_it1889 分钟前
MySQL慢查询监控与告警实战:从slow_log采集到分钟级定位慢SQL的完整链路配置
android·sql·mysql
沐言人生20 分钟前
ReactNative 源码分析12——Native View创建流程onBatchComplete
android·react native
caicai_xiaobai20 分钟前
QT搭建安卓开发环境
android
YF021121 分钟前
Android 异形屏与横屏全屏沉浸式适配技术方案
android·app
2501_9419820542 分钟前
通过 API 实时监听企业微信外部群变更事件并同步本地数据库
android·自动化·企业微信·rpa
白雪落青衣2 小时前
buuoj course 1详细解析
android
恋猫de小郭2 小时前
Android 发布全新性能分析器,实用性和性能大升级
android·前端·flutter
Kapaseker2 小时前
为什么 Java 的数组需要 new 出来
android·java·kotlin
黄林晴2 小时前
颠覆开发!Google AI Studio 一句话生成原生 Android App
android·google io