安卓图像更新学习总结
总体上是图像生产者,如应用的一个窗口(activity)的绘制、程序调用OpenGL的各种”draw”函数等,把图像数据传给相应的处理接口。2D的一般使用Canvas,3D的可以直接调用OpenGL ES。但是两种方法图像都绘制到一个surface上,关于绘制操作,如OpenGL的图形库有一个graphics pipeline的流程,主要为从把点的坐标转换到normalized device coordinate,即x,y,z是-1.0到正1.0的坐标系中,再裁剪可视区域,进而以Z坐标确定可视图层顺序,rasterization,即像素化,这样一个流程。OpenGL中的framebuffer(帧缓存)已经是像素化之后的位图了,这说明以效果为主要目的的处理图像已经GPU端完成,在Linux内核的framebuffer层之上。但这个“graphics pipeline”的概念不仅仅是OpenGL独有的,操作系统如安卓等在传输和处理图像时也与此相近,只是最终把图像绘制到surface上。
此时的问题是如何把图像传给屏幕端。一般的应用产生的所有图像都会传给surfaceflinger,后者再选择性的把图像传给显示控制器。显示控制器一般是芯片上的一个硬件,它的驱动软件和安卓框架层的接口是HWComposer,由该库与之交互。
安卓通用的模型大致如此,对于我们使用的MTK的芯片,因为很多模块是闭源的或者完全没有说明,我只能作推测。应该是HWCompser接收到surfaceflinger的事件后通过HWC的库调用内核的fb接口,然后显控以DMA的方式读取帧缓存,进行”overlay”的处理,最终在驱动层的overlay处理图像后通过DSI传给屏幕。
现在介绍我理解的一些模块的工作方式:
由于应用传输图像给surfaceflinger的操作不涉及内核,在此不作分析。Surfaceflinger初始化时会创建一个HWComposer实例,等开始上层通过BufferQueue把缓存传给Surfaceflinger,SF会调用hwc的方法prepare来决定哪些图层需要给显示控制器处理,然后把这些图层收集起来通过postFramebuffer方法更新帧缓存,这里的帧缓存并非立即就更新到屏幕上,而是调用mHwc->commit(hwcId)把数据给HWComposer;其余的图层由surfaceflinger调用OpenGL来合成。SF会设置一个“Fence“(围栏)来表示对每一帧操作的开始与完成。AOSP文档(source.android.com)上指出,surfaceflinger曾经直接把帧缓存往比如/dev/graphics/fb0里写,但很久前就不再这么做了。内核里有drivers/gpu/drm/mediatek,里面有mtk_drm_drv,mtk_drm_fb等,但Linux的DRM(direct rendering manager)在安卓里应该用不到,因为计算机上的XWindow或者Wayland用的协议没有Fence的概念,所以这些代码应该没什么作用,但我不很确定是干什么用的,于是从SF到内核层至少有两个通路:
1) surfaceflinger -> HWComposer-> graphics/fb0(mtkfb)->overlay
2) surfaceflinger->GPU->overlay
第一条通路显然是2D绘制。大多数安卓设备都有/dev/graphics/fb0这个framebuffer设备,经分析我们的MTK的系统中fb0最终就是mtkfb.c在驱动,图像设备有major number 29,adb shell执行ls –l /dev/graphics/fb0可知minor number 为0,在对应/sys/dev/char/29:0/device/driver中可以找到该设备的驱动,再通过readlink该驱动发现是bus/platform/drivers/mtkfb的链接。Mtkfb.c中并没有指定具体路径,这说明/dev/graphics/应该是安卓内核图像设备的默认位置。
然而直接写mtkfb(比如cat image > fb0)并没有作用,读(cp fb0 /sdcard/fb)可以得到1个帧(3个图层),通过ffmpeg等解码器转换为常用图片格式后发现所得往往并不是“截图“时屏幕所显示的内容,这已知有几种原因,首先有很多图层不是走的这条通路,第二是图像缓存不是一直更新,比如空闲时primary_display会切换到decouple mode。查看mtkfb.c可知,fb_ops结构并没有read和write的操作,但fb设备和内存设备类似,所以对其进行读操作应该可以复制出它内存中的数据,对其写就不会触发fb驱动的刷屏操作。除了跟primary_display、ddp*等内部互相调用的接口外,mtkfb主要以ioctl来操作,在mtkfb.h中有相应ioctl操作的定义。如果在root shell下以用户层的ioctl来操作mtkfb(dev/graphics/fb0),比如ioctl(fd, MTKFB_META_SHOW_BOOTLOGO),我们会发现屏幕会显示随机的缓存然后恢复,通过日志可知它的调用顺序为mtkfb_ioctl->primary_display_config_input_multiple ,primary_display_trigger,而primary_display_config_input_multiple调用了_config_ovl_input,其中关于”帧“的数据结构为disp_session_input_config,该结构包含了帧大小和地址等信息,进而调用_config_ovl_input,由此可见,2D绘制的调用路径是从mtkfb到ovl。观察fb_info结构,注意到mtkfb.c中对该结构使用的最多的成员是”par”,一个自定义的指针,它指向一个mtkfb_device结构的实例,而后者携带framebuffer的内存地址。
但mtkfb_ioctl有一个疑点,执行MTKFB_CAPTURE_FRAMEBUFFER的操作并没有得到有效数据,目前还不清楚是什么原因。另外关于”decouple mode”,据说该模式类似command屏,有专门的内存用于本地刷新屏幕。在primary_display_idlemgr_*函数中可以找到在空闲时切换到decouplemode的机制。稍微联想一下我们可以发现,这decouple mode、“command”屏和OpenGL提交、更新图像的模式十分相近,都是”客户端“提交数据和指令来指示如何处理,而”服务端“有自己的内存和响应指令的机制,两者间通过某种方式交互,OpenGL commands、mtk cmdq、mipi dsi等等。
GPU这条通路有很多机制尚不清楚,首先安卓的gralloc负责分配GPU使用的显存,但我们用的厂商实现是MTK提供的gralloc库,HWComposer也是如此(在hardware.c里dlopen加载的这些库),MTK的显示控制器如何工作也未知,只知道在内核中驱动是使用中断和DMA,在ddp_irq加上日志可看到,平时图像更新disp_irq_handler函数都会不断响应,紧接着就是RDMA的函数(ddp_ovl_get_cur_addr等),这些是在primary_display_switch_mode里一路往下调用的,由于HWComposer上层是以event(事件)的形式交互,所以primary_display的dpmgr_map_event_to_irq应该是把事件和中断对应起来,DMA是把数据读到”overlay”;
关于显示控制器和overlay:
”overlay”在计算机显示中的作用是图像直接送到显示控制器进行简单的缩放、裁剪、组合等,没有诸如OpenGL的texture mapping、blending等功能。安卓使用“overlay”的意义是有的操作简单,若调用OpenGL用GPU处理占内存多,通常在嵌入式设备和手机中GPU没有独立显存,是共用主内存的,另外GPU一次只能作一个用途,让显控来分担一些GPU的负担,可提升性能。具体哪些帧需要GPU合成哪些需要overlay来处理是由HWComposer对帧来标记决定的,MTK的平台应该是在它的HWC库里实现的算法。MTK的“ovl“有点迷惑,它既有overlay的硬件,也有最后把所有的帧送到屏幕IC的作用。所以所有的图层在两个地方有汇总过,一是surfaceflinger,另一是最后的overlay层,这也就解释了为什么虽然有的图层是用GPU合成的,但如果在MTK的overlay里(定义PHYSICAL_ROTATION_HW的宏)旋转帧缓存,所有的图像都会旋转。现在的截图和录屏无法通过framebuffer接口来实现,都是调用surfaceflinger的接口把图层处理到一个”virtual display”上,通过BufferQueue传输给调用软件。
最后是VSYNC信号和fence,屏幕硬件和surfaceflinger是有关联的,IC会由DSI给primary_display发vsync信号,表示一帧已显示完毕,最后这个信号会给surfaceflinger,后者只在此时进行新的绘制操作,因而vsync、porch值除了和屏幕玻璃有关外,也会影响到surfaceflinger的绘制;fence的作用和mutex的目的接近,但更灵活。其内核接口为sw_sync.h,我们可以看到mtkfb.h中包含了该头文件,底层的fence以文件描述符的形式使用,可以”poll”,检查是否可读写等,以此表示和该fence关联的图像内存是否可用,这些功能在mtkfb_fence.c中实现。
安卓图像更新学习总结相关推荐
- android10新功能,三星A80升级安卓10 更新One UI 2.0内容新功能介绍
三星A80升级安卓10 更新One UI 2.0内容新功能介绍 据网友反馈,三星现已面向Galaxy A80用户推送One UI 2.0更新,升级Android 10. 此外,三星Galaxy A80 ...
- 项目“恶意APK检测系统”——安卓逆向部分学习
项目"恶意APK检测系统"--安卓逆向部分学习 交流逆向工程相关知识 +Q1906661021 以下内容按笔者的浏览和学习顺序为序,并无难易之分 1.proguard progua ...
- 一种水下鱼类图像特征学习与目标识别框架
摘要 活鱼识别是快速获取大量数据的渔业调查应用中最关键的元素之一.与一般场景不同,水下图像识别面临的挑战是图像质量差.目标和环境不可控以及难以获取代表性样本.此外,大多数现有的特征提取技术由于涉及人的 ...
- 消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法
消除安卓SDK更新时的"https://dl-ssl.google.com refused"异常的方法 消除安卓SDK更新时的"https://dl-ssl.google ...
- 基于单幅图像一致性学习的弱光视频增强(CVPR2021)
点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨图灵智库 来源丨 泡泡机器人SLAM 编辑丨3D视觉工坊 标题: Learning Tempor ...
- 解决安卓SDK更新dl-ssl.google.com无法连接的方法
解决安卓SDK更新dl-ssl.google.com无法连接的方法 参考文章: (1)解决安卓SDK更新dl-ssl.google.com无法连接的方法 (2)https://www.cnblogs. ...
- 每周更新学习进度表--第九周
每周更新学习进度表: 学习时间 新增代码行 博客量(篇) 知识总结 第一周 7h 80 2 对于软件工程这门课有个大致的了解,并在学习代码上步入正轨. 第二周 8h 100 4 四 ...
- 无人机图像深度学习的大豆害虫检测与分类
无人机图像深度学习的大豆害虫检测与分类 1.研究内容 实验比较了Inception-v3, Resnet-50, VGG-16, VGG-19 and Xception ,用了微调和迁移学习. 2.创 ...
- android 使用系统下载并更新版本,安卓系统更新升级的种方法
最近有网友问小编"安卓系统怎么升级?",针对该问题,笔者也在网上查找了下相关资料,不过并没有找到什么有价值的相关介绍,多数都是介绍如何自动升级.或者下载升级版包等等方法,对于一些常 ...
最新文章
- python比较好的书籍推荐-推荐几本2019年初学者学习Python最佳书籍!
- ZStack中的编程技巧
- POJ 1269 Intersecting Lines(求直线交点)
- 使用vue控制元素显示隐藏
- 我写的几篇技术文章之一:Windows消息拦截技术的应用
- java httpclient 跨域_13、HttpClient服务器跨域请求
- Linux基本命令解析(1)
- java画一个小车_小轿车简笔画怎么画
- python max_Python max()
- http之url和uri
- 接口自动化测试框架搭建(4、公用方法之url的拼接)--python+HTMLTestRunnerCN+request+unittest+mock+db
- Windows下配置安装Git(一)
- 微信支付“下单账号和支付账号不一致,请核实后再支付”
- c++直角空心三角形_2019秋人教版八年级数学上册三角形教材全解读
- java共享文件夹SMB1服务报错jcifs.smb.SmbException: Failed to connect: 0.0.0.0<00>/122.168.23.26
- vs2017python配置opencv_[opencv +VS2017] opencv、vs2017安装配置,环境搭建
- WhatsApp是啥软件?WhatsApp是什么意思?
- DRE6-1X/210MG24K4M比例减压阀配套US-DAS1放大器
- 2023年最新前端面试题
- 八年级计算机教案下册,信息技术八年级下册教案全册.doc