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

相关推荐
dancing9991 小时前
Android Studio中Gradle 7.0上下项目配置及镜像修改
android·ide·android studio
EQ-雪梨蛋花汤2 小时前
【Part 2安卓原生360°VR播放器开发实战】第四节|安卓VR播放器性能优化与设备适配
android·性能优化·vr
每次的天空2 小时前
Android学习总结之kotlin篇(二)
android·学习·kotlin
刘洋浪子2 小时前
Android Studio中Gradle中Task列表显示不全解决方案
android·ide·android studio
橙子199110162 小时前
Kotlin 中 infix 关键字的原理和使用场景
android·开发语言·kotlin
后端码匠9 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
梓仁沐白10 小时前
Android清单文件
android
董可伦13 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空13 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭13 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin