Skip to content

Latest commit

 

History

History
63 lines (31 loc) · 3.63 KB

li-ping-xuan-ran.md

File metadata and controls

63 lines (31 loc) · 3.63 KB

GPU渲染机制:

CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。

GPU屏幕渲染有以下两种方式:

On-Screen Rendering意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。

Off-Screen Rendering意为离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

**特殊的离屏渲染:**如果将不在GPU的当前屏幕缓冲区中进行的渲染都称为离屏渲染,那么就还有另一种特殊的“离屏渲染”方式: CPU渲染。如果我们重写了drawRect方法,并且使用任何Core Graphics的技术进行了绘制操作,就涉及到了CPU渲染。整个渲染过程由CPU在App内 同步地完成,渲染得到的bitmap最后再交由GPU用于显示。

备注:CoreGraphic通常是线程安全的,所以可以进行异步绘制,显示的时候再放回主线程,一个简单的异步绘制过程大致如下

- (void)display {
    dispatch_async(backgroundQueue, ^{
        CGContextRef ctx = CGBitmapContextCreate(...);
        // draw in context...
        CGImageRef img = CGBitmapContextCreateImage(ctx);
        CFRelease(ctx);
        dispatch_async(mainQueue, ^{
            layer.contents = img;
        });
    });
}

为什么会使用离屏渲染

当使用圆角,阴影,遮罩的时候,图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制,所以就需要屏幕外渲染被唤起。

屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。

所以当使用离屏渲染的时候会很容易造成性能消耗,因为在OPENGL里离屏渲染会单独在内存中创建一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的。

离屏渲染的代价是什么

离屏渲染需要在屏幕外开辟内存空间,提前使用 CPU 渲染复杂的视图,保证视频控制器能够及时地从缓存区读到新的渲染结果。它在 GPU 面临性能瓶颈时,将压力转移一部分给比较空闲的 CPU,然而 CPU 的渲染能力远没有 GPU 高效,有点杀鸡出牛刀的意思。

同时这也是一种以空间换取时间的策略。

视频控制器要读取离屏渲染的结果,需要把渲染上下文从当前屏幕缓存区切到屏幕外缓存区,当要显示非离屏渲染视图的时候又要切换回来,然而不可能在一屏上所有的元素都是离屏渲染的,所以视频控制器上下文需要不停地来回切换。而这种上下文切换的代价非常昂贵。

所以离屏渲染会带来各方面的开销,要尽可能的避免。

离屏渲染有没有好处

离屏渲染并不是一无是处的,虽然会造成很多额外的开销,但也是为了充分利用设备的资源来保证界面的流畅。发生离屏渲染时,是为了引起开发者对性能的关注,减少不必要的透明视图层级。如果不可避免的要触发离屏渲染,并且发生离屏渲染视图内容不会频繁的变化,可以利用 CALayer.shouldRasterize 开启光栅化,将离屏渲染的内容以位图的形式缓存,减少复杂视图频繁渲染的开销。然而,这个缓存的时效是 100ms,也就是刷新 6 帧的时间,如果视图内容更新频繁,缓存就会不停的刷新,导致无法命中,开启光栅化并没有什么作用。