图片渲染到屏幕流程

图像从加载到显示,主要过程下所示(主要是cpu、总线、gpu、显示器之间的交互)

![image.png](p6-juejin.byteimg.com/tos-cn-i-k3…. image?)

GPU:解码图片,计算 fra工作流程模板me 等信息,需要绘制纹理图片通过 总线 传递给 GPU

GPU:纹理混合,顶点变换计算,像素点的填充计算,渲染到帧缓冲区

时钟信号:垂直同步信号V-Sync 、水平同步信号ios下载H-Sync(由于电子枪逐行扫描,所以提到的最多的就是垂直同步新信号)

iOS设备缓冲机制:显示系统通常会引入两个帧缓冲区,双缓冲ios是苹果还是安卓机制(后面 GPU 性能更高,甚至引出缓存视频合并app三缓冲)缓存是什么意思

单缓冲机制:比较早的缓存清理缓冲手段,即GPU渲染完成之后,直接更新显示器buiOSffer,这样的问题就是,一旦卡顿,电子枪显示上一帧一部分图像之后,缓冲区发生了变化,紧接着显示下一帧的下半部分图像,因此会出现屏幕画面撕裂现象(上一帧渲染部分画面和下一帧的部分画面混合到一起工作流程表格模板显示了;

双缓冲:多引出一个备用缓冲区,即GPU渲线程数是什么染完成之后保存到缓冲区,等待显示器的垂直同步信号(电子枪处理显示完毕当前屏幕帧后),接收到同步信号之后,立即交换缓冲区,这样就避线程撕裂者免了屏幕工作流程撕裂现象,但也会有一个问题,当垂直信号发送之后,gpu这边还没渲染完毕,那么画面就不会变,在下一个垂直同步信号过来时,gpu可能会连上一帧带当前帧都渲染完毕,当前的图像帧会吧上一个图像给覆盖,因此可能会出现丢帧现象

ps:上面提到的总线其线程池实就是我们的主板,显示器也是通过线和gpu连接的,如果连接的是cpu,那么基本也是集显(gpu集成在cpu上),同步信号相关就是屏幕刷新阶段信号,自然是和显示器相关,交互为 cpu ~ gpu,gpu ~ 显示器

ios图片加载工作流

1、假设我们使用 imageWithContentsOfFilios15e: 方法来加载本地缓存图片,且加载的图片默认不是解压缩后的图片

2、将获取的 image 赋值给 UIImageView

3、CoreAnimation中隐式的 CATrios14.4.1更新了什么ansaction捕获到了 UIImageView图形树的变化

4、主线程下一个runios是什么意思loop到来是,CoreAnimation提交了隐线程池的七个参数式的 CATransaction,这个过程可能会对图片进行 copy 解压操作,而受图片是否字节对齐等因素的影响,这个copy操作可能会涉及以下部分或全部步骤:

  • 将压缩的图片数据解码成未压缩的位图形式,这是一个非常耗时的像素生存者2 CPU 操作
  • 最后 Core AnimationCALayer使用未压缩的位图数据渲染 UIImageView 的图层
  • CPU 计算好ios15图片的Frame,对图片解压之后,就会交给 GPU 来做图片渲染
  1. 开始渲染,渲染流程如下
  • GPU获取获取图片的坐标
  • 将坐标交给顶点着色器(顶点计算)
  • 将图片光栅化(获取图片对应屏幕上的像素点)
  • 片元着色器计算(计算每个像素点的最ios是苹果还是安卓终显示的颜色值)
  • 从帧缓线程数是什么存区中渲染到屏幕上

从这个步骤来看,图片解压缩的过程ios是苹果还是安卓cpu 上,因此当很多没有解压的图片在一个列表上加载,cpu 很可能出现瓶颈,尤其是快速滑工作流程模板动,很可能iOS造成卡顿(庆幸的是解压缩的过程,基本上三方都处理好了,就剩大图加载优化了)

对于已经解压过的图片,系统不会在进行二次解压,而是直接使用,当然对于工作流程表格模板没有解压的图片,系统会在主线程解压然后保存使用

解压ios16

图片的解压缩在 cpu上,且需要大量的计算,很耗时,那么不解压缩可以不,那肯定是不可以的,了解它之前,先理解什么是位图

  • 位图为一个像素数组,每个像素代表图片中的一个点,平时应用中使用的 jpeg、png就是位图,

  • 实际上不管是 png 还是 jpeg,都是压缩后的位图,只不过png是无损压缩,jpeg可以指定百分比进行压缩

因此,图片在渲染到屏幕之前,需要现将压缩后的位图转化为图片原始数据,才能执行后面的渲染操作

解压缩方案

既然解压无法避免,那么就得有一个方案,解压过程在 cpu 中执行,且没有指定在主线程执行,那么目前行业方案就是本地或者网络获取图片之后线程,在子线程解压缩图片,然后将解压缩后的图片返回像素画生成器外部使用

ios中解压逻辑

而强制解压缩的原理就是对图片进行重新绘制,得到一张新的解压缩后的位图。其中,用到的最核心的函数是 CGBitmapContextCreate :

CG_EXTERN CGContextRef __nullable CGBitmapContextCreate(void * __nullable data,
    size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
    CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)
    CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

data :如果不为 NULL ,那么它应该指向一块大小至少为 bytesPerRow * height 字节的内存;如果 为 NULL ,那么系统就线程数越多越好吗会为我们自动分配和释放所需的内存,所以一般指定 NULL 即可;

width 和height:位图的宽度和高度,工作流程表格模板分别赋值为图片的像素宽度和像素高度即可;

bitsPerComponent :像素的每个颜色分量使用的 bit 数,在 RGB 颜色空间下指定 8 即可;

bytesPerRow工作流程怎么写位图的每一行使用的字节数,大小至少为 width * bytes per pixel 字节。当我们指定 0/NULL 时,系统不仅会为我们自动计算,而且还会进行 cache line alignment 的优化

space :就是我们前面提到的颜色空间,一般使用 RGB 即可;

bitmapInfo :位图的布局信息.kCGImag工作流eAlphaPremul工作流程图模板样式tipliedFirst

下面是 YYImage 的解压部分代码,通过重绘的方式,获取解压后的新图片 CGImage

CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, YYCGColorSpaceGetDeviceRGB(), bitmapInfo);
if (!context) return NULL;
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); // decode
CGImageRef newImage = CGBitmapContextCreateImage(context);
CFRelease(context);

可以说,解压重绘过程一共分为如下三步

  • 使用 CGBitmapCo线程数越多越好吗ntextCreate 函数创建一工作流个位图上下文;缓存的视频在哪
  • 使用 CGC线程数是什么ontextDrawImage 函数将原始位图绘制到上下文中;
  • 使用 CGBitmapContextCreate线程池Image 函数创建一张新的解压缩后的位图

总结

1、图片文件只有在确定要显示时,CPU才会对齐进行解压缩,因为解压是非常消耗性能的事情,解压过的图片就不像素游戏会重复解压,会缓存起来

2、图片渲染到屏幕的过程: 读取文件->计算Frame->图片解码-工作流引擎>解码后纹理图片位图数据通过数据总线交给GPU->GPU获取图片Frame->顶点变换计算->光栅化->根据纹理坐标工作流引擎获取每个像素点的颜色值(如果出现透明值需要将每个像素点的颜色*透明度值)工作流程图->渲染到帧缓存区->渲染到屏幕