Android12 显示框架之getSurface

news2024/9/20 22:47:18

目录:Android显示终极宝典

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

SurfaceControl::getSurface()

//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的构造过程:

//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()

//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

//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()

//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。

//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:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1970495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp APP端使用web-view,跳转回APP指定页面

URL Scheme 首先我一开始想到的是UrlSchemes&#xff0c;发现UrlSchemes不好实现就转为下面的方法 URL Scheme 是一种用于在移动应用程序中打开另一个应用程序或执行特定操作的机制。通过使用 URL Scheme&#xff0c;应用程序可以将用户重定向到其他应用程序或执行特定的任务…

大模型在自动驾驶领域是怎么应用的?最新综述一览

写在前面 大语言模型&#xff08;LLMs&#xff09;是在海量文本语料库上训练的人工智能模型&#xff0c;具备卓越的语言理解和生成能力&#xff0c;正在改变自动驾驶&#xff08;AD&#xff09;领域。随着自动驾驶系统从基于规则和优化的方法向基于学习的技术&#xff08;如深…

关于企微群聊天工具功能的开发---PHP+JS+CSS+layui (手把手教学)

文章目录 前言准备工作PHP代码示例前端代码示例 主要是js踩的小坑&笔记最终达成的效果总结 前言 公司要求开发企微群聊天工具。首先一个客户一个群&#xff0c;其余群成员都是公司销售、设计师、工长、售后等人员。要求开发一个群聊天工具&#xff0c;工长点击进来以后就可…

selenium自动化代码报错“NoSuchElementException”——解决方案详解

假设自动化代码报错“NoSuchElementException”&#xff1a; 第一步&#xff1a;在报错的代码前&#xff0c;添加Thread.sleep(秒)&#xff0c;设置的时间长一点。 第二步&#xff1a; 执行自动化&#xff0c;在自动化打开的页面里&#xff0c;打开前端开发者工具&#xff0c…

二百五十三、OceanBase——Linux上安装OceanBase数据库(三):OBD页面上部署OceanBase数据库

一、目的 安装OceanBase后&#xff0c;启动obd web&#xff0c;需要在OBD页面上部署OceanBase数据库 二、参考文档 http://t.csdnimg.cn/Qeedq 三、实施步骤 1 在obadmin用户下&#xff0c;启动obd服务&#xff0c;登录页面访问 [obadminhurys23 oceanbase]$ obd web 2 登…

AIGC重塑设施农业:让农事操作更智能,生产效率更高

设施农业是现代农业的重要组成部分,随着人工智能等前沿技术的快速发展,这个领域迎来了新的变革机遇。尤其是大语言模型(Large Language Model,LLM)技术的崛起,其强大的语言理解和知识汇聚能力,为设施农业智能化发展带来了新的想象空间。本文将深入探讨大模型技术在设施农业生产…

寝室恶性负载识别模块原理和功能

石家庄光大远通电气有限公司寝室恶性负载识别智能模块导轨式安装&#xff0c;采用局域网或者4G集中控制&#xff0c;在宿舍多回路中可以单独设置控制参数达到精细化管理。 原理&#xff1a;‌ 电压电流检测法&#xff1a;‌通过检测电路中的电压和电流&#xff0c;‌计算电路中…

网段划分(为什么+分类划分,CIDR),ip地址组成,路由器介绍,广播地址,DHCP,NAT技术,ipv6,如何申请网络

目录 网段划分 引入 ip地址的组成 同一网段内 不同的网段 路由器 ip地址的分配 DHCP技术 分类划分法 分组 弊端 CIDR&#xff08;无类域间路由&#xff09; 变长子网掩码 数据包转发 子网地址范围计算 两个特殊的ip地址 网络号 广播地址 作用 其他解决方…

学习Java的日子 Day62 Filter过滤器

Day62 Filter过滤器 简介 Filter&#xff1a;过滤器&#xff0c;通过Filter可以拦截访问web资源的请求与响应操作。 Servlet API中提供了一个Filter接口&#xff0c;开发web应用时&#xff0c;如果编写的Java类实现了这个接口&#xff0c;则把这个java类称之为过滤器。他可以拦…

数据结构——二叉树_堆

目录 一、堆的概念 二、堆的结构 三、性质 &#xff08;1&#xff09;堆的性质 &#xff08;2&#xff09;二叉树的性质 四、堆的实现 &#xff08;1&#xff09;头文件——Heap.h (2)源文件——Heap.c 1.堆的初始化 2.堆的销毁 3.向上调整算法 4.堆的插入 4.判断堆…

​人工智能薪酬排行榜:2024年哪些岗位最吃香?

近日&#xff0c;智联招聘发布了2024年二季度《中国企业招聘薪酬报告》。报告显示&#xff0c;人工智能行业平均薪酬为13594元/月&#xff0c;位居行业榜首。 同时&#xff0c;在“2024年二季度企业招聘薪酬TOP20职业”中&#xff0c;人工智能工程师以平均月薪22003元排名第一。…

口碑最好的麦克风品牌有哪些,无线领夹麦克风十大品牌推荐

​在内容丰富的自媒体世界里&#xff0c;每一个细节都可能是吸引观众的关键&#xff0c;尤其是音质。面对这么多的无线领夹麦克风&#xff0c;到底哪款更值得入手呢&#xff1f;我试用并挑选了几款性价比高的无线领夹麦克风&#xff0c;它们能够为各类视频制作提供令人印象深刻…

7.5寸电子日历

7.5英寸无线智能纸质显示屏幕办公名牌电子墨水数字显示ESL标签仓库使用

ONVIF 摄像头视频流获取 - 步骤与Python例程

1.基本流程 加入组播udp接口&#xff0c;查询子网内在线的ONVIF摄像头的设备地址&#xff1a; 设备地址形如&#xff1a;http://192.168.0.6/onvif/device_service 这一步&#xff0c;参看上一篇发文&#xff1a;[ONVIF系列 - 01] 简介 - 设备发现 - 相关工具-CSDN博客查询med…

叉车车队管理系统怎么选,满足监管要求!

在现代物流与仓储管理中&#xff0c;选择一个高效且可靠的叉车车队管理系统至关重要。一个高性能的管理系统不仅提升作业效率&#xff0c;还能保障作业安全。企业管理者在采购叉车车队管理系统前需要考虑几个关键因素&#xff1a; 1、提升管理效率&#xff1a;‌确保系统能够实…

机器学习赋能的智能光子学器件系统研究与应用

在人工智能与光子学设计融合的背景下&#xff0c;科研的边界持续扩展&#xff0c;创新成果不断涌现。从理论模型的整合到光学现象的复杂模拟&#xff0c;从数据驱动的探索到光场的智能分析&#xff0c;机器学习正以前所未有的动力推动光子学领域的革新。据调查&#xff0c;目前…

【计算机毕业设计】707高校宿舍管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

电脑数据有没有办法恢复?适用于 Windows电脑的的 14 款Windows 恢复工具

如果您在笔记本电脑上安装了 Windows 10&#xff0c;却发现文件均未复制到新系统&#xff0c;该怎么办&#xff1f;您可以在线搜索 Windows 10 恢复工具下载&#xff0c;结果会有很多。 确实&#xff0c;优秀的 Windows 恢复工具能够有效地恢复已删除的文件。问题是市场上有太…

为什么有时候银行贷款审核会查大数据信用?

在申请银行贷款时&#xff0c;不少人会疑惑为何银行会深入审查申请人的大数据信用信息。这背后&#xff0c;其实是银行风险控制与精准决策的体现。 首先&#xff0c;大数据信用信用能全面反映申请人的信用状况 它不仅仅局限于传统的征信报告&#xff0c;还涵盖了消费行为、社交…