当前位置: 首页 > news >正文

BLASTBufferQueue端的GraphicBuffer怎么和SurfaceFlinger端的BufferStateLayer关联上

BLASTBufferQueue端的GraphicBuffer怎么和SurfaceFlinger端的BufferStateLayer关联上



引言

在跟进hwc_layer是如何产生的,并如何被填充上GraphicBuffer的,怎么也找不到被填充的GraphicBuffer的来源,最终找到了,它的来源是客户端的BLASTBufferQueue传递过来的,我们这里跟进下这个流程。

这里使用的代码是Android 13 aosp



一. BLASTBufferQueue是如何传递GraphicBuffer到SurfaceFlinger端的BufferStateLayer的

当BufferQueueProducer完成绘制调用queueBuffer后,会调用BLASTBufferQueue::onFrameAvailable。

///rameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {...acquireNextBufferLocked(mSyncTransaction)...
}void BLASTBufferQueue::acquireNextBufferLocked(const std::optional<SurfaceComposerClient::Transaction*> transaction) {...status_t status =mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); auto buffer = bufferItem.mGraphicBuffer;t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseBufferCallback);t->setApplyToken(mApplyToken).apply(false, true);...
}

apply最终会通过Binder调用到SurfaceFlinger的>setTransactionState,我们接着往下看:

status_t SurfaceFlinger::setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {...queueTransaction(state);//将相关的transaction状态存起来...}       

后续vsync会触发SurfaceFlinger执行如下逻辑:

MessageQueue::Handler::handleMessagecompositor.commitSurfaceFlinger::commitflushTransactionQueuesSurfaceFlinger::applyTransactionStateSurfaceFlinger::setClientStateLockedlayer->setBufferuint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo,ComposerState& composerState,int64_t desiredPresentTime, bool isAutoTimestamp,int64_t postTime, uint32_t permissions) {layer_state_t& s = composerState.state;sp<Layer> layer = nullptr;layer = fromHandle(s.surface).promote();//关键点,这个layer是怎么获取的if (what & layer_state_t::eBufferChanged) {std::shared_ptr<renderengine::ExternalTexture> buffer =getExternalTextureFromBufferData(*s.bufferData, layer->getDebugName());//这里并不是真的纹理,而是命名像而已if (layer->setBuffer(buffer, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp,dequeueBufferTimestamp, frameTimelineInfo)) {flags |= eTraversalNeeded;}}
}

这里我们看下fromHandle的实现:

//SurfaceFlinger.cpp
wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) const {return Layer::fromHandle(handle);
}//Layer.cpp
wp<Layer> Layer::fromHandle(const sp<IBinder>& handleBinder) {if (handleBinder == nullptr) {return nullptr;}BBinder* b = handleBinder->localBinder();if (b == nullptr || b->getInterfaceDescriptor() != Handle::kDescriptor) {return nullptr;}// We can safely cast this binder since its local and we verified its interface descriptor.sp<Handle> handle = static_cast<Handle*>(handleBinder.get());return handle->owner;
}

那么这个Layer对应的Handle是什么时候被构建的呢,是什么时候呢。

status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,const sp<IBinder>& parentHandle, int32_t* outLayerId,const sp<Layer>& parentLayer, uint32_t* outTransformHint) {...sp<Layer> layer;       createBufferStateLayer(args, outHandle, &layer)...
}    status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle,sp<Layer>* outLayer) {args.textureName = getNewTexture();*outLayer = getFactory().createBufferStateLayer(args);*handle = (*outLayer)->getHandle();return NO_ERROR;
}//frameworks/native/services/surfaceflinger/Layer.cpp
sp<IBinder> Layer::getHandle() {Mutex::Autolock _l(mLock);if (mGetHandleCalled) {ALOGE("Get handle called twice" );return nullptr;}mGetHandleCalled = true;return new Handle(mFlinger, this);
}//frameworks/native/services/surfaceflinger/Layer.h
class Handle : public BBinder, public LayerCleaner {
public:Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer): LayerCleaner(flinger, layer, this), owner(layer) {}const String16& getInterfaceDescriptor() const override { return kDescriptor; }static const String16 kDescriptor;wp<Layer> owner;
};
...
}

这里我们要怎么理解这个Handle呢,它是对Layer的一个封装,不管是BufferStateLayer还是其它的,通过它可以让Layer在Binder中传递

我们接着继续往下看,layer->setBuffer会调用子类的setBuffer,子类是BufferStateLayer

//frameworks/native/services/surfaceflinger/BufferStateLayer.cpp
bool BufferStateLayer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,const BufferData& bufferData, nsecs_t postTime,nsecs_t desiredPresentTime, bool isAutoTimestamp,std::optional<nsecs_t> dequeueTime,const FrameTimelineInfo& info) {...mDrawingState.frameNumber = frameNumber;mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;mDrawingState.buffer = std::move(buffer);mDrawingState.clientCacheId = bufferData.cachedBuffer;setTransactionFlags(eTransactionNeeded);...
}

这里只是把buffer赋值给mDrawingState.buffer了,肯定有地方把mDrawingState.buffer赋值mBufferInfo.mBuffer;

接着找,在updateActiveBuffer找到了mBufferInfo.mBuffer = s.buffer。updateActiveBuffer又是在哪里调用的呢?

status_t BufferStateLayer::updateActiveBuffer() {const State& s(getDrawingState());...mBufferInfo.mBuffer = s.buffer;mBufferInfo.mFence = s.acquireFence;mBufferInfo.mFrameNumber = s.frameNumber;...
}

在BufferStateLayer的父类BufferLayer::latchBuffer里调用:


bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,nsecs_t expectedPresentTime) {
... ...status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);err = updateActiveBuffer();err = updateFrameNumber(latchTime);

接下来看下latchBuffer是在哪里调用的:

MessageQueue::Handler::handleMessagecompositor.commitSurfaceFlinger::commitlatchBuffers()for (const auto& layer : mLayersWithQueuedFrames) {if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {mLayersPendingRefresh.push_back(layer);newDataLatched = true;}layer->useSurfaceDamage();}            


二. BufferStateLayer的GraphicBuffer怎么传递到hwc_layer中去的

这个我们要知道的是BufferStateLayer的GraphicBuffer最终传递到hwc_layer中,是要经过OputputLayer的,通过前面我们知道此时的GraphicBuffer存储在BufferInfo中,如下:

class BufferLayer : public Layer {...struct BufferInfo {nsecs_t mDesiredPresentTime;std::shared_ptr<FenceTime> mFenceTime;sp<Fence> mFence;uint32_t mTransform{0};ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};Rect mCrop;uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};Region mSurfaceDamage;HdrMetadata mHdrMetadata;int mApi;PixelFormat mPixelFormat{PIXEL_FORMAT_NONE};bool mTransformToDisplayInverse{false};std::shared_ptr<renderengine::ExternalTexture> mBuffer;//存放GraphicBufferuint64_t mFrameNumber;int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};bool mFrameLatencyNeeded{false};};    BufferInfo mBufferInfo;...}

我们先看怎么传递到OutputLayer的:

MessageQueue::Handler::handleMessage(...)compositor.composite(...)SurfaceFlinger::composite(...)mCompositionEngine->present(...)//CompositionEngine.cppupdateLayerStateFromFE(args)output->updateLayerStateFromFE(args)//Output.cppfor (auto* layer : getOutputLayersOrderedByZ()) {layer->getLayerFE().prepareCompositionState(args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent: LayerFE::StateSubset::Content);}                    //frameworks/native/services/surfaceflinger/Layer.cppvoid Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {using StateSubset = compositionengine::LayerFE::StateSubset;switch (subset) {case StateSubset::BasicGeometry:prepareBasicGeometryCompositionState();break;case StateSubset::GeometryAndContent:prepareBasicGeometryCompositionState();prepareGeometryCompositionState();preparePerFrameCompositionState();//调用子类BufferLayer的break;case StateSubset::Content:preparePerFrameCompositionState();break;case StateSubset::Cursor:prepareCursorCompositionState();break;}
}  //frameworks/native/services/surfaceflinger/BufferLayer.cpp
void BufferLayer::preparePerFrameCompositionState() {Layer::preparePerFrameCompositionState();...compositionState->buffer = getBuffer();compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)? 0: mBufferInfo.mBufferSlot;compositionState->acquireFence = mBufferInfo.mFence;compositionState->frameNumber = mBufferInfo.mFrameNumber;compositionState->sidebandStreamHasFrame = false;
}


分析layer是否参与合成

最简单的SurfaceFlinger应用程序

Android14 SurfaceFlinger-BLASTBufferQueue的创建

Android 14 SurfaceFlinger-Layer visibleRegion的计算过程

SurfaceFlinger的commit/handleTransaction分析

这里重点关注各种State!

相关文章:

BLASTBufferQueue端的GraphicBuffer怎么和SurfaceFlinger端的BufferStateLayer关联上

BLASTBufferQueue端的GraphicBuffer怎么和SurfaceFlinger端的BufferStateLayer关联上 引言 在跟进hwc_layer是如何产生的&#xff0c;并如何被填充上GraphicBuffer的&#xff0c;怎么也找不到被填充的GraphicBuffer的来源&#xff0c;最终找到了&#xff0c;它的来源是客户端的…...

48、spfa求最短路

spfa求最短路 题目描述 给定一个n个点m条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c; 边权可能为负数。 请你求出1号点到n号点的最短距离&#xff0c;如果无法从1号点走到n号点&#xff0c;则输出impossible。 数据保证不存在负权回路。 输入格式 第一行包…...

安装PyTorch详细步骤

&#x1f4a5;注意事项&#xff1a; CPU版和GPU版选一个进行安装即可 如果有Nvidia显卡&#xff0c;则安装cuda版本的PyTorch&#xff0c;如没有nvidia显卡&#xff0c;则安装cpu版。 目前常见的深度学习框架有很多&#xff0c;最出名的是&#xff1a;PyTorch&#xff08;faceb…...

linux线程,线程控制与线程相关概念

线程概念 线程这个词或多或少大家都听过&#xff0c;今天我们正式的来谈一下线程&#xff1b; 在我一开始的概念中线程就是进程的一部分&#xff0c;一个进程中有很多个线程&#xff0c;这个想法基本是正确的&#xff0c;但细节部分呢我们需要细细讲解一下&#xff1b; 什么…...

第八大奇迹

目录 题目描述 输入描述 输出描述 输入输出样例 示例 输入 输出 运行限制 原题链接 代码思路 题目描述 在一条 R 河流域&#xff0c;繁衍着一个古老的名族 Z。他们世代沿河而居&#xff0c;也在河边发展出了璀璨的文明。 Z 族在 R 河沿岸修建了很多建筑&#xff0c…...

MySQL:CRUD初阶(有图有实操)

文章目录 &#x1f4d1;1. 数据库的操作&#x1f324;️1.1 显示当前的数据库&#x1f324;️1.2 创建数据库&#x1f324;️1.3 选中数据库&#x1f324;️1.4 删除数据库 &#x1f4d1;2. 表的操作&#x1f324;️2.1 查看表结构&#x1f324;️2.2 创建表&#x1f324;️2.3…...

『大模型笔记』使用 vLLM 和 PagedAttention 快速提供 LLM 服务!

使用 vLLM 和 PagedAttention 快速提供 LLM 服务! 文章目录 一. 使用 vLLM 和 PagedAttention 快速提供 LLM 服务!1.1. PagedAttention二. 参考文献小红书中文字幕视频:https://www.xiaohongshu.com/explore/66502b60000000000500433e官网文档(推荐,里面有动图解释):vLLM:…...

简述vue-loader是什么?使用它的用途有哪些

vue-loader是一个webpack的加载器(loader)&#xff0c;主要用于将Vue组件的单文件(.vue文件)转换为JavaScript模块。使用vue-loader的主要用途包括&#xff1a; 解析.vue文件&#xff1a;vue-loader能够解析.vue文件中的模板、样式和脚本&#xff0c;并将它们分离出来进行处理…...

如何远程访问Redis?

远程访问Redis是一种常见的需求&#xff0c;特别是在分布式系统或跨地域网络中。通过远程访问&#xff0c;我们可以轻松地对远程的Redis数据库进行操作和管理。 天联保障数据安全 对于远程访问Redis的安全性问题&#xff0c;我们可以借助天联来保障数据的安全。天联是一种基于…...

#12松桑前端后花园周刊-SolidStart、Vercel融资、Angular18、Nextjs15RC、p5.js、ChromeDevTools引入AI

⚡️行业动态 SolidStart 1.0 元框架发布 Solidjs 核心团队发布其元框架 SolidStart 1.0 正式版&#xff0c;其特点如下&#xff1a;基于文件系统的路由&#xff1b;支持SSR、流式SSR、CSR、SSG渲染模式&#xff1b;通过代码分割、树摇和无用代码删除构建优化&#xff1b;基于…...

vue3 vite title 页面标题设置

效果图&#xff1a; 1. 安装 vite-plugin-html 插件 npm install vite-plugin-html -D2. 修改 vite.config.js import {defineConfig, loadEnv} from vite import { createHtmlPlugin } from "vite-plugin-html" import {resolve} from path import vue from vitej…...

spring boot添加License(软件许可)

文章目录 前言1. 生成钥匙库2. 生成证书3. 生成公匙库4.业务代码1. 引入依赖2. 关键代码3. 配置文件 5、改成线上地址&#xff0c;这样不用每次打包&#xff0c;发送license.lic文件给客户&#xff0c;重启项目就行5.1、工具类5.2 修改部分&#xff1a; 总结 前言 工作需要给软…...

LangChain打造一个AI客服

最近在学习LangChain&#xff0c;langchain的第一个入门应用就是和ChatGPT结合形成的一个AI客服&#xff0c;本期文章就带大家一起认识下 LangChain LangChain是现在用得最多的AI框架&#xff0c;langchain在帮助如基于文档数据的回答、聊天机器人和代理这类的应用程序 langch…...

【前端三剑客之JS】详解JS

1. JS的引入方式 (1). 内部脚本方式引入 在页面上&#xff0c;通过一对script标签引入js代码.script代码放置位置有一定随意性&#xff0c;一般放在head标签中. (2).外部脚本方式引入. 内部脚本只能在当前页面中使用&#xff0c;代码复用度不高.可以将脚本放在单独的js文件…...

重庆耶非凡科技有限公司有选品师项目培训吗?

在当今科技飞速发展的时代&#xff0c;各种科技公司如雨后春笋般涌现&#xff0c;它们在不同领域发挥着重要作用。其中&#xff0c;重庆耶非凡科技有限公司以其独特的业务模式和专业服务&#xff0c;在业界赢得了良好的口碑。那么&#xff0c;重庆耶非凡科技有限公司究竟是做什…...

格式转化——Labelme标注好的json文件批量转为png(标签)文件(物体为红色,背景为黑色)和jpg原图

作用如题目&#xff0c;批量将标注好的json文件转成png标签&#xff0c;jpg原图&#xff0c;其中标签时红黑图。 代码如下&#xff1a; import argparse import base64 import json import os import os.path as osp import imgviz import PIL.Image import yaml from labelm…...

力扣刷题--2535. 数组元素和与数字和的绝对差【简单】

题目描述 给你一个正整数数组 nums 。 元素和 是 nums 中的所有元素相加求和。 数字和 是 nums 中每一个元素的每一数位&#xff08;重复数位需多次求和&#xff09;相加求和。 返回 元素和 与 数字和 的绝对差。 注意&#xff1a;两个整数 x 和 y 的绝对差定义为 |x - y| 。…...

2024年【危险化学品经营单位安全管理人员】考试报名及危险化学品经营单位安全管理人员找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位安全管理人员考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新危险化学品经营单位安全管理人员找解析题目及答案&#xff01;多做几遍&#xff0c;其实通过危险化学品经营单位安全管…...

IntelliJ IDEA集成Baidu Comate,商城系统支付交易功能开发实战

文章目录 Baidu Comate介绍安装配置体验安装插件配置体验注释生成代码技术问答 实战设计表生成代码导入数据 总结 Baidu Comate介绍 在科技互联网飞速发展的今天&#xff0c;百度凭借其深厚的技术积累和创新能力&#xff0c;推出了一款名为Baidu Comate智能代码助手的产品。该…...

20212313 2023-2024-2 《移动平台开发与实践》第5次作业

20212313 2023-2024-2 《移动平台开发与实践》第5次作业 1.实验内容 设计并开发一个地图应用系统。 该实验需提前申请百度API Key&#xff0c;调用接口实现百度地图的定位功能、地图添加覆盖物和显示文本信息。 2.实验过程 2.1 获取SHA1 &#xff08;1&#xff09;打开控制台…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...