项目github地址: aoce

我是去年年底才知道有GPUImage这个项目,以前也一直没有在移动平台开发过,但是我在win平台有编写一个类似的项目oeip(不要关注了,所有功能都移植或快移植到aoce里了),移动平台是大势所趋,开始是想着把oeip移植到android平台上,后面发现不现实,就直接重开项目,从头开始,从Vulkan到CMake,再到GPUImage,开发主力平台也从Visual Studio 2017换到VSCode了,这也算是前半年的总结了.

Vulkan移植GPUImage(一)高斯模糊与自适应阈值

Vulkan移植GPUImage(二)Harris角点检测与导向滤波

Vulkan移植GPUImage(三)从A到C的滤镜

Vulkan移植GPUImage(四)从D到O的滤镜

Vulkan移植GPUImage(五)从P到Z的滤镜

CMake 常用命令

在Android用vulkan完成蓝绿幕扣像

android下vulkan与opengles纹理互通

Vulkan与DX11交互

PC的Vulkan运算层时间计算记录

Vulkan移植GPUImage的Compute Shader总目录

选择Vulkan的Compute Shader处理管线

当初选择Vulkan,一是越来越多设备与平台支持,且有独立的计算管线.

独立的计算管线在移植GPUImage里时好处如下.

1 避免很多UV生成类,如GPUImage里的GPUImageTwoInputFilter / GPUImageTwoInputCrossTextureSamplingFilter等等这种要么多个输入,要么需要查找周围点来生成不同UV,特别还有多个输入与需要周边UV结合,导致其中GPUImage中有很多类就是用来给FS提供UV.

2 不需要一个对应Vulkan渲染输出窗口,简单来说,你可以无窗口运行计算流程,并把结果直接对接win平台GUI32/DX11的CPU输出/GPU纹理,也可以在android中对接opengl es纹理,也可以方便对接引擎UE4/Unity3D.

3 计算管线可以利用局部共享显存,局部共享显存在那种需要查找周边多个点的情况能大幅提高性能,原则上来说,CS比渲染管线少PS之前的那一系列阶段,最新的硬件应该会比用VS+PS高吧?我用vulkan/cuda/dx11(原oeip实现)比较了下运行复杂计算管线的情况,cuda的GPU占比最低,vulkan其次,dx11会在cuda/vulkan的二倍以上.

不过缺点也有,其中有三个没移植GPUImage的功能,其中二个就是画多条线的,主要就是利用VS/PS渲染管线完成,暂时还没想出好的方法移植,还有一个图像2D-3D多角度转换利用VS/PS渲染管线也很方便,不过这个在独立的计算管线应该也好做.

Vulkan数据处理流程

我定义主要实现要满足二点.

  1. 计算流程可以多个输入/输出,每个节点可以多个输入输出,每个节点可以关闭打开,也可关闭打开此节点分支.

  2. 别的用户能非常容易扩展自己的功能,就是自定义图像处理层的功能.

第一点,我受FrameGraph|设计&基于DX12实现启发,想到利用有向无环图来实现.在开始构建时,节点互相连接好.然后利用深度优先搜索自动排除到关闭自己/分支的节点,拿到最终的有效连接线,有向无环图可以根据有效连接线生成正确的执行顺序,然后检查每层节点与连接的节点的图像类型是否符合,检查成功后就初始化每层节点的资源,如果是Vulkan模块,所有层资源生成后,就会把所有执行命令填充到当前图层的VkCommandBuffer对象中,运行时执行VkCommandBuffer记录的指令.

在运行时,设定节点/分支是否可用,以及有些层参数改变会影响输出大小都会导致图层重启标记开启,用标记是考虑到更新参数层与执行GPU运算不在同一线程的情况,图层下次运行前,检测到重启标记开启,就会重新开始构建.

相关源码在PipeGraph

而第二点,为了方便用户扩展自己的层,我需要尽可能的自动完善各种信息来让用户只专注需求实现.

对于运算层基类(BaseLayer)注意如下几个时序.

  1. onInit/onInitNode 当层被加入PipeGraph前/后分别调用,在之后,会有个弱引用关联PipeGraph的PipeNode,同样,检查这个引用是否有效可以知道是否已经附加到PipeGraph上.

  2. onInitLayer 当PipeGraph生成正确的有效连接线后,根据有效连接线重新连接上下层并生成正确执行顺序后,对各运算层调用.

  3. onInitBuffer 每层输入检查对应连接层的输出的图像类型是否符合.

  4. onFrame 每桢运行时调用.

  5. onUpdateParamet 层的参数更新,时序独立于上面的4个点,设定要求随时可以调用.

相关源码在BaseLayer

准确到Vulkan模块,Vulkan下的运算层基类(VkLayer)会针对BaseLayer提供更精确的Vulkan资源时序.

  1. 初始化,一般指定使用的shader路径,UBO大小,更新UBO内数据.默认认为一个输入,一个输出,如果是多输入与多输出,可以在这指定.注意输入/输出个数一定要在附加在PipeGraph之前确定,相应数组会根据这二个值生成空间.

  2. onInitGraph,当vklayer被添加到VkPipeGraph时上被调用.一般用来加载shader,根据输入与输出个数生成pipelineLayout,如果有自己逻辑,请override.默认指定输入输出的的图像格式为rgba8,如果不是,请在这指定对应图像格式.如果层内包含别的处理层逻辑,请在这添上别的处理层.

  3. onInitNode,当onInitGraph后被添加到PipeGraph后调用.本身layer在onInitGraph后,onInitNode前添加到PipeGraph了,当层内包含别的层时,用来指定层内之间的数据如何链接.

  4. onInitLayer,当PipeGraph根据连接线重新构建正确的执行顺序后.根据各层是否启用等,PipeGraph构建正确的各层执行顺序,在这里,每层都知道对应层数据的输入输出层,也知道输入输出层的大小.当前层的输入大小默认等于第0个输入层的输出大小,并指定线程组的分配大小,如果逻辑需要变化,请在这里修改.

  5. onInitVkBuffer,当所有有效层执行完后onInitLayer后,各层开始调用onInitBuffer,其在自动查找到输入层的输出Texture,并生成本层的输出Texture给当前层的输出使用后调用.如果自己有Vulkan Buffer需要处理,请在onInitVkBuffer里处理.

  6. onInitPipe,当本层执行完onInitVkBuffer后调用,在这里,根据输入与输出的Texture自动更新VkWriteDescriptorSet,并且生成ComputePipeline.如果有自己的逻辑,请override实现.

  7. onCommand 当所有层执行完onInitBuffer后,填充vkCommandBuffer,vkCmdBindPipeline/vkCmdBindDescriptorSets/vkCmdDispatch 三件套.

  8. onFrame 每桢处理时调用,一般来说,只有输入层或输出层override处理,用于把vulkan texture交给CPU/opengl es/dx11等等.

相关源码在VkLayer

虽然列出有这么多,但是从我移植GPUImage里来看,很多层特别是混合模式那些处理,完全一个都不用重载,就只在初始化指定下glslPath就行了,还有许多层按上面设定只需要重载一到二个方法就不用管了.

其中Vulkan图层中,每个图层中包含一个VulkanContext对象,其有独立的VkCommandBuffer对象,这样可以保证每个图层在多个线程互不干扰,各个线程可以独立运行一个或是多个图层,对于cuda图层来说,每个图层也有个cudaStream_t对象,做到各个线程独立运行.

其中aoce_vulkan我定义了VkPipeGraph/VkLayer的实现,以及各个Vulkan对象的封装,还有输入/输出,包含RGBA<->YUV的转化这些基本的计算层,余下的GPUImage的所有层全在aoce_vulkan_extra完成,也算是对方便用户扩展自己的层的一个测试,说实话,在移植GPUImage到aoce_vulkan_extra模块过程中,我感觉以前存储的一些Vulkan知识已经快被我忘光了.

最后到这,用户实现自己的vulkan处理层,就不需要懂太多vulkan知识就能完成,只需要写好glsl源码,继承VkLayer,然后根据需求重载上面的一二个函数就行了,欢迎大家在这基础之上实现自己的运算层.

框架数据流程

数据提供现主要包含如下三种.

  1. 摄像头,在win端,有aoce_win_mf模块提供,在android端,有aoce_android提供.

  2. 对于多媒体文件(本地多媒体,RTMP等),由aoce_ffmpeg(win/android都支持)提供解码.

  3. 直接非压缩的图像二进制数据.

数据处理模块现有aoce_cuda/aoce_vulkan模块处理,win端现支持这二个模块,而android端只支持aoce_vulkan模块.

如果数据提供的是桢数据,对应摄像头/多媒体模块都会解析到VideoFrame并给出回调,而在数据处理模块会有InputLayer层,专门用来接收上面三种数据.

而处理后数据会根据对应OutputLayer需要,导出CPU数据以及GPU数据对接对应系统常用渲染引擎对应纹理上,如在win端,aoce_cuda/aoce_vulkan模块的OutputLayer都支持直接导致到对应DX11纹理,而在android上,aoce_vulkan能直接导致到对应opengl es纹理上,这样就能直接与对应引擎(UE4/Unity3D)底层进行对接.

导出给用户调用

在重新整理了框架与结构,完善了一些内容,API应该不会有大的变动了,现开始考虑外部用户使用.

在框架各模块内部,引用导出的类不要求什么不能用STL,毕竟肯定你编译这些模块肯定是相同编译环境,但是如果导出给别的用户使用,需要限制导出的数据与格式,以保证别的用户与你不同的编译环境也不会有问题.

配合CMake,使用install只导出特殊编写的.h头文件给外部程序使用,这些头文件主要包含如下三种类型.

  1. C风格的结构,C风格导出帮助函数,与C风格导出用来创建对应工厂/管理对象.

  2. 纯净的抽像类,不包含任何STL对象结构,主要用来调用API,用户不要继承这些类.

  3. 后缀为Observer的抽像类,用户继承针对接口处理回调.

GPUImage移植总结的更多相关文章

  1. Vulkan移植GpuImage(一)高斯模糊与自适应阈值

    自适应阈值效果图 demo 这几天抽空看了下GpuImage的filter,移植了高斯模糊与自适应阈值的vulkan compute shader实现,一个是基本的图像处理,一个是组合基础图像处理聚合 ...

  2. Vulkan移植GpuImage(二)Harris角点检测与导向滤波

    Harris角点检测 UI还是用的上次扣像的,只有前后置可以用,别的没有效果,只看实现就好. 相应源码 在实现之前,我先重新整理编译glsl的生成工具,如Harris角点检测中间计算过程需要针对rgb ...

  3. Vulkan移植GpuImage(三)从A到C的滤镜

    前面移植了几个比较复杂的效果后,算是确认了复杂滤镜不会对框架造成比较大的改动,开始从头移植,现已把A到C的所有滤镜用vulkan的ComputeShader实现了,讲一些其中实现的过程. Averag ...

  4. Vulkan移植GpuImage(四)从D到O的滤镜

    现把D到O的大部分滤镜用vulkan的ComputeShader实现了,列举其中一些有点特殊的说明. GaussianBlurPosition 指定区域高斯模糊 没有按照GPUImage里的方式实现, ...

  5. Vulkan移植GPUImage(五)从P到Z的滤镜

    现aoce_vulkan_extra把GPUImage里从P到Z的大部分滤镜用vulkan的ComputeShader实现了,也就是最后一部分的移植,整个过程相对前面来说比较简单,大部分我都是直接复制 ...

  6. Vulkan移植GPUImage的安卓Demo展示

    演示Android apk下载 需要Android 8以上. 先看效果图,大约一百多种滤镜,有超过一半的滤镜有参数设置,其参数调整界面使用反射自动生成与绑定. 如下每种选择一些进行展示. 视觉效果 图 ...

  7. GPUImage相关(转)

    3.滤镜 除了上面提到的美颜和水印之外,视频中还有很多其它的处理效果也在这个环节完成.七牛直播云提供的 SDK 在开放性设计基础之上,通过数据源回调接口,可以支持各种自定义滤镜的接入. 为了实现丰富的 ...

  8. MVVM框架从WPF移植到UWP遇到的问题和解决方法

    MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...

  9. IIC驱动移植在linux3.14.78上的实现和在linux2.6.29上实现对比(deep dive)

    首先说明下为什么写这篇文章,网上有许多博客也是介绍I2C驱动在linux上移植的实现,但是笔者认为他们相当一部分没有分清所写的驱动时的驱动模型,是基于device tree, 还是基于传统的Platf ...

随机推荐

  1. frida hook_RegisterNatives--使用frida打印so中动态注册的函数

    原文地址:https://github.com/lasting-yang/frida_hook_libartfrida -U --no-pause -f package_name -l hook_Re ...

  2. MySQL的安装及使用

    安装MySQL 这里建议大家使用压缩版,安装快,方便.不复杂. 1.MySQL软件下载 mysql5.7 64位下载地址: https://dev.mysql.com/get/Downloads/My ...

  3. 实验四 Python综合实践

    课程:<Python程序设计> 班级:1843 姓名:章森洋 学号:20184307 实验教师:王志强 实验日期:2020年5月16日 必修/选修: 公选课 1.实验内容 此处填写实验的具 ...

  4. Linux和Docker的Capabilities介绍及Setcap命令

    Linux和Docker的capabilities介绍 转载:https://www.cnblogs.com/charlieroro/p/10108577.html 验证环境:centos7 x86/ ...

  5. leetcode 刷题(数组篇)1题 两数之和(哈希表)

    题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数组中同一个元 ...

  6. java面试一日一题:mysql中的自增主键

    问题:请讲下mysql中的自增主键 分析:该问题主要考察对mysql中自增主键的掌握,使用场景及如何设置 回答要点: 主要从以下几点去考虑 1.什么自增主键 2.使用场景是什么: 3.innodb_a ...

  7. Dubbo学习笔记(二) Dubbo的基本配置

    Check启动检查 根据之前的学习,我们简单理解的Dubbo远程调用的基本流程,服务提供者注册到注册中心,然后服务消费者通过监听注册中心达到远程调用的目的,那么如果注册中心中没有消费者对应的接口会怎么 ...

  8. 1035 Password

    To prepare for PAT, the judge sometimes has to generate random passwords for the users. The problem ...

  9. Salesforce 集成篇零基础学习(一)Connected App

    本篇参考: https://zhuanlan.zhihu.com/p/89020647 https://trailhead.salesforce.com/content/learn/modules/c ...

  10. 05- web网站链接测试与XENU工具使用

    什么是链接 链接也叫超链接,是指从某一个网页元素指向另一个目标的连接关系,这个目标可以是另一个网站的网页,可以是本网站的一个网页,可以使同一个网页的不同位置,还可以是一个图片,一个视频,一个文件甚至是 ...