Filament引擎分析--command抽象设备API
1. 前言
Filament中使用了FrameGraph来管理渲染管线,需要准备两点:
- 设备接口抽象:设备API抽象为Command
- 资源抽象:使用虚拟资源,在实际用到时再创建,方便剔除无用资源
下面就围绕Filament中设备API抽象为Command代码部分做一个解读:
2. 代码分析
先贴一段创建顶点缓冲的接口调用堆栈:
[Inlined] filament::backend::CommandBase::CommandBase(void (*)(filament::backend::Driver &, filament::backend::CommandBase *, int *)) CommandStream.h:63
[Inlined] filament::backend::CommandType<void (filament::backend::Driver::*)(filament::backend::Handle<filament::backend::HwVertexBuffer>, unsigned char, unsigned char, unsigned int, std::__ndk1::array<filament::backend::Attribute, 16u>)>::Command<&filament::backend::Driver::createVertexBufferR(filament::backend::Handle<filament::backend::HwVertexBuffer>, unsigned char, unsigned char, unsigned int, std::__ndk1::array<filament::backend::Attribute, 16u>)>::Command<filament::backend::Handle<filament::backend::HwVertexBuffer>, unsigned char, unsigned char, unsigned int, std::__ndk1::array<filament::backend::Attribute, 16u>>(void (*)(filament::backend::Driver&, filament::backend::CommandBase*, int*), filament::backend::Handle<filament::backend::HwVertexBuffer>&&, unsigned char&&, unsigned char&&, unsigned int&&, std::__ndk1::array<filament::backend::Attribute, 16u>&&) CommandStream.h:154
[Inlined] filament::backend::CommandStream::createVertexBuffer(unsigned char, unsigned char, unsigned int, std::__ndk1::array<…>) DriverAPI.inc:169
filament::FVertexBuffer::FVertexBuffer(filament::FEngine &, const filament::VertexBuffer::Builder &) VertexBuffer.cpp:185
[Inlined] utils::Arena::make<…>(filament::FEngine &, const filament::VertexBuffer::Builder &) Allocator.h:647
[Inlined] filament::FEngine::create<…>(filament::ResourceList<…> &, const filament::FVertexBuffer::Builder &) Engine.cpp:680
filament::FEngine::createVertexBuffer(const filament::VertexBuffer::Builder &) Engine.cpp:690
filament::FEngine::init() Engine.cpp:277
filament::FEngine::create(filament::backend::Backend, filament::backend::Platform *, void *, const filament::Engine::Config *) Engine.cpp:110
[Inlined] FilamentTest::setupFilament() FilamentTest.cpp:98
FilamentTest::init() FilamentTest.cpp:68
boxing::xr::composer::StartBase::instance(ANativeWindow *, int, int) StartBase.h:263
[Inlined] native_OnDrawFrame::$_0::operator()() const JniImpl.cpp:100
[Inlined] std::__ndk1::__invoke<…>(native_OnDrawFrame::$_0 &) type_traits:3874
[Inlined] std::__ndk1::__apply_functor<…>(native_OnDrawFrame::$_0 &, std::__ndk1::tuple<…> &, std::__ndk1::__tuple_indices<…>, std::__ndk1::tuple<…> &&) functional:2853
[Inlined] std::__ndk1::__bind::operator()<…>() functional:2886
[Inlined] std::__ndk1::__invoke<…>(std::__ndk1::__bind<…> &) type_traits:3874
std::__ndk1::__packaged_task_func::operator()() future:1817
[Inlined] std::__ndk1::__packaged_task_function::operator()() const future:1994
std::__ndk1::packaged_task::operator()() future:2214
[Inlined] std::__ndk1::__function::__value_func::operator()() const functional:1884
[Inlined] std::__ndk1::function::operator()() const functional:2556
<lambda>::operator()() const ThreadPool.h:71
[Inlined] decltype(std::__ndk1::forward<boxing::core::ThreadPool::ThreadPool(unsigned int)::'lambda'()>(fp)()) std::__ndk1::__invoke<boxing::core::ThreadPool::ThreadPool(unsigned int)::'lambda'()>(boxing::core::ThreadPool::ThreadPool(unsigned int)::'lambda'()&&) type_traits:3874
[Inlined] std::__ndk1::__thread_execute<…>(std::__ndk1::tuple<…> &, std::__ndk1::__tuple_indices<…>) thread:273
std::__ndk1::__thread_proxy<…>(void *) thread:284
__pthread_start(void*) 0x00000000eab36828
__start_thread 0x00000000eaaed5ce
渲染设备API定义:
filament\filament\backend\include\private\backend\DriverAPI.inc
DriverAPI.inc中使用大量的宏替换操作,将设备接口进行封装,或打包,这部分代码可读性极差,不过可从其调用逻辑来进行拆解和理解:
先来分析其中一个接口: createVertexBuffer 创建一个顶点缓冲
DECL_DRIVER_API_R_N(backend::VertexBufferHandle, createVertexBuffer,uint8_t, bufferCount,uint8_t, attributeCount,uint32_t, vertexCount,backend::AttributeArray, attributes)
这里不是真的创建,而要看这个宏接口在哪里使用,我们主要看看这两个地方:
CommandStream.h //命令流Driver.h //设备接口
这两个文件中都对DriverAPI.inc进行了include,但是意义完全不一样,先看DECL_DRIVER_API_R_N:
#define DECL_DRIVER_API_R_N(R, N, ...) \DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
关键在DECL_DRIVER_API_RETURN这个宏,在CommandStream.h和Driver.h头文件中include文件DriverAPI.inc 之前分别定义了自己的DECL_DRIVER_API_RETURN宏,看看CommandStream.h中:
#define DECL_DRIVER_API(methodName, paramsDecl, params) \inline void methodName(paramsDecl) { \DEBUG_COMMAND_BEGIN(methodName, false, params); \using Cmd = COMMAND_TYPE(methodName); \void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \new(p) Cmd(mDispatcher.methodName##_, APPLY(std::move, params)); \DEBUG_COMMAND_END(methodName, false); \}#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params) \inline RetType methodName(paramsDecl) { \DEBUG_COMMAND_BEGIN(methodName, true, params); \AutoExecute callOnExit([=](){ \DEBUG_COMMAND_END(methodName, true); \}); \return apply(&Driver::methodName, mDriver, std::forward_as_tuple(params)); \}#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \inline RetType methodName(paramsDecl) { \DEBUG_COMMAND_BEGIN(methodName, false, params); \RetType result = mDriver.methodName##S(); \using Cmd = COMMAND_TYPE(methodName##R); \void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params)); \DEBUG_COMMAND_END(methodName, false); \return result; \}
上面三个宏的作用基本是一样的,都将要调用的函数和参数封装为了Command,不同之处在于DECL_DRIVER_API是command无返回值的,DECL_DRIVER_API_SYNCHRONOUS是封装为command后同步执行的,DECL_DRIVER_API_RETURN是需要返回值的
主要看看DECL_DRIVER_API_RETURN:
RetType result = mDriver.methodName##S();
将方法名后面拼接了S,调用拿到返回类型
看看拼接S后的实现:
Handle<HwVertexBuffer> OpenGLDriver::createVertexBufferS() noexcept {return initHandle<GLVertexBuffer>();
}
initHandle()这句在filament内存池HandleArena上创建了一个GLVertexBuffer对象,然后根据内存地址创建了对象的唯一handeID
再看下面这句:
using Cmd = COMMAND_TYPE(methodName##R);
方法名后面拼接了R,然后获取了command的类型,没有执行方法,看看拼接R后的实现:
void OpenGLDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,uint8_t bufferCount,uint8_t attributeCount,uint32_t elementCount,AttributeArray attributes) {DEBUG_MARKER()construct<GLVertexBuffer>(vbh, bufferCount, attributeCount, elementCount, attributes);
}
内存池HandleArena上创建了一个GLVertexBuffer对象
再看下面一句
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd)));
new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params));
在CommandStream内部的环形缓冲上申请了一块Command对象的内存p,然后在内存p上new了对象Command
看看CommandBase* execute执行函数的实现:
inline CommandBase* execute(Driver& driver) {// returning the next command by output parameter allows the compiler to perform the// tail-call optimization in the function called by mExecute, however that comes at// a cost here (writing and reading the stack at each iteration), in the end it's// probably better to pay the cost at just one location.intptr_t next;mExecute(driver, this, &next);return reinterpret_cast<CommandBase*>(reinterpret_cast<intptr_t>(this) + next);
}
mExecute就是上面new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params));
后的函数和参数的封装体,然后拿到了下一个圆形缓冲中下一个command的地址偏移量next,返回下一个command地址
CommandStream中执行command,执行完然后获取下一个执行。。。
mDriver.execute([this, buffer]() {Driver& UTILS_RESTRICT driver = mDriver;CommandBase* UTILS_RESTRICT base = static_cast<CommandBase*>(buffer);while (UTILS_LIKELY(base)) {base = base->execute(driver);}
});
相关文章:
Filament引擎分析--command抽象设备API
1. 前言 Filament中使用了FrameGraph来管理渲染管线,需要准备两点: 设备接口抽象:设备API抽象为Command资源抽象:使用虚拟资源,在实际用到时再创建,方便剔除无用资源 下面就围绕Filament中设备API抽象为…...
网络协议与响应码
http:超文本(不止文本)传输协议,底层是tcp/ip get,post,put,delete GET把参数包含在 URL 中, POST 通过 request body 传递参数 请求都是tcp链接,HTTP规定,当…...

彻底删除VsCode配置和安装过的插件与缓存
前言 当你准备对 Visual Studio Code(VSCode)进行重新安装时,可能遇到一个常见问题:重新安装后,新的安装似乎仍然保留了旧的配置信息,这可能会导致一些麻烦。这种情况通常是由于卸载不彻底所致,…...
【XILINX】ISE chipscope出现错误 Can‘t load jre bin client jvm.dll
记录一个ISE软件使用过程中遇到的问题及解决方案。 问题 ISE chipscope出现错误 Cant load jre bin client jvm.dll C:\Xilinx\14.7\ISE_DS\ISE\bin\nt C:\Xilinx\14.7\ISE_DS\.xinstall\bin\nt C:\Xilinx\14.7\ISE_DS\.xinstall\bin\nt64 C:\Xilinx\14.7\ISE_DS\ISE\bin\nt6…...

并发编程(已整理,已废弃)
这一块知识,那真是有的啃了。 直接先看速成基础,再直接吃掉高频考点。 每个小知识点,直接看短视频,浅浅了解,在写下来就是自己的资料。 # 基础 一个进程有多个线程,多个线程共享进程的堆和方法区…...

第一篇:MongoDB的安装、启动、关闭、链接shell
目录 简介 安装 安装遇到的问题 查看brew 当前使用的源: 更换brew 源。更换成清华大学镜像源 版本查看 MongoDB 数据目录与日志目录 启动方式一: 启动MongoDB 验证MongoDB 是否正常运行 停止或重新启动 停止MongoDB 服务 重新启动MongoDB服…...

Python爬虫之重放攻击详解
更多资料获取 📚 个人网站:ipengtao.com 重放攻击是一种网络攻击方式,攻击者通过截获合法用户的请求,并将其重新发送,以模拟合法用户的行为。在Python爬虫领域,了解重放攻击的原理和防范方法至关重要。本文…...

构建一个语音转文字的WebApi服务
构建一个语音转文字的WebApi服务 简介 由于业务需要,我们需要提供一个语音输入功能,以便更方便用户的使用,所以我们需要提供语音转文本的功能,下面我们将讲解使用Whisper将语音转换文本,并且封装成WebApi提供web服务…...
在开发软件KEIL MDK和IAR开发工程里面打印行号、文件名、函数名、时间
最近应用固件没有时间记录,分别请那个是最新的(在没有版本区别的情况下),有个办法记录编译时间即可,记录笔记以便查看 在软件工程里面直接用宏 __FILE __ 当前程序文件名的字符串 __FUNCTION __ 当前函数的名字字符串 …...
springboot(ssm健身器材用品网 健身用品商城Java(codeLW)
springboot(ssm必录德健身器材用品网 健身用品商城Java(code&LW) 开发语言:Java 框架:ssm/springboot vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7(或8.0&am…...
idea git合并推送分支
远端代码合并到当前分支 1.本地切换到当前分支 2.远端目标分支右键合并到当前分支(使用合并拉入) 本地当前分支推送合并到远端分支 1.切换到远端本地分支 2.合并本地其他分支(想要推送的分支)到当前分支 3.推送分支 注意:这里的合并是:将XXX合并到XXX中 …...

AntDesignBlazor示例——创建列表页
本示例是AntDesign Blazor的入门示例,在学习的同时分享出来,以供新手参考。 示例代码仓库:https://gitee.com/known/AntDesignDemo 1. 学习目标 使用Table组件创建列表页面使用DisplayName特性显示中文表头使用模板和Tag组件显示高温数据使…...

微信小程序模板选择指南:如何找到靠谱的平台?
随着移动互联网的快速发展,越来越多的企业和商家都在微信小程序上开展业务。而他们也希望可以通过微信小程序模板快速搭建小程序,那么如何才能找到一个靠谱的微信小程序模板平台呢?下面给大家简单讲解一下。 首先要知道的是,微信小…...
es常用查询编辑
查询指定id信息 GET /index_name/_doc/1074266245查询指定信息并降序 GET /index_name/_search {"query": {"term": {"deviceId": {"value": "1074266245"}}}, "sort": [{"timestamp": {"order&qu…...

记录 | linux静态库和动态库的理解
hello.cpp: #include <cstdio>void hello() {printf("Hello, world!\n"); }main.cpp: #include <cstdio>void hello();int main() {hello();return 0; }静态库编译配置: cmake_minimum_required(VERSION 3.12) proj…...

ParBFT: Faster Asynchronous BFT Consensus with a Parallel Optimistic Path
目录 笔记后续的研究方向摘要引言 ParBFT: Faster Asynchronous BFT Consensus with a Parallel Optimistic Path CCS 2023 笔记 后续的研究方向 摘要 为了减少异步拜占庭容错(BFT)共识的延迟和通信开销,通常会添加一条乐观的路径…...

java小工具util系列3:JSON转实体类对象工具
文章目录 准备工作1.JSONObject获取所有的key2.集合中实体对象转换 list中Enrey转Dto3.字符串转List<BusyTimeIndicatorAlarmThreshold>4.json字符串转JSONObject5.list根据ids数组过滤list6.json字符串转JavaBean对象7.json对象转javabean8.jsonObject转map9.List\<U…...

MySQL:找回root密码
一、情景描述 我们在日常学习中,经常会忘记自己的虚拟机中MySQL的root密码。 这个时候,我们要想办法重置root密码,从而,解决root登陆问题。 二、解决办法 1、修改my.cnf配置文件并重启MySQL 通过修改配置文件,来跳…...

计算机网络扫盲(1)——因特网
一、概述 因特网是一个世界范围的计算机网络,即它是一个互联了遍及全世界数十亿计算设备的网络。大家对此应该并不陌生,我们身边有着不计其数的计算机设备被接入了因特网,如今计算机网络这个术语似乎已经有点过时了,用因特网的术语…...
C语言 if语句有无(;)分号问题
在C语言中,if语句后面不带分号(;)的情况有两种主要形式: 1. 带有大括号的代码块:如果if语句后面跟随一个由大括号({})包围的代码块,那么这个代码块中的语句只有在if条件为真时才会执…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...