This is the fourth day of my participation in the August More text Challenge. For details, see:August is more challenging

preface

Hi Coder, this is CoderStar!

Last week we talked about iOS page rendering, UIView & CALayer. This week we’re going to talk about off-screen rendering, one of the most popular interview questions in iOS page rendering.

In fact, one of the reasons for sharing the relevant knowledge about iOS page rendering is to pave the way for the subsequent UI rendering optimization in the iOS optimization series, so that you can clearly understand the principles behind the optimization method and have a deeper understanding when you read later.

Before I start this article, let me talk about some of the answers I gave to the interview questions when @Zhangferry, the creator of iOS Fish Weekly, interviewed me last week.

  • Zhangferry: Please introduce yourself and your official account.

Myself: CoderStar, coordinate Beijing. Currently, my main work is related to iOS. I have some dabblings in both the front end and the back end.

Public account: CoderStar, share the technical knowledge related to the big front-end, just talk about the technical stuff, the current content is mainly iOS related, and will share some technical knowledge related to the Vue front-end and so on. At present, the contents of the public account articles are their own original, very welcome to contribute some good articles, everyone a progress.

  • Zhangferry: Why do you want to write an official account? Write public number to have what benefit bring?

The first reason to write the public account is actually relatively simple:

  1. Because I have accumulated some notes in the past, which are relatively scattered, I want to tidy them up.
  2. I feel that my work experience has reached a certain stage, and it is time to comb through the knowledge and build my own knowledge system.
  3. I want to share some of my accumulated technical knowledge, so that we can communicate together and create a good technical circle. A good technical circle is really too important.

The benefits of writing the public account:

  1. Writing articles not only enables me to have a more thorough understanding of a knowledge point, but also enhances my writing ability. For technical knowledge, self-understanding is a stage, and writing in a simple way is a higher stage.
  2. Can know a lot of friends, the road will not be lonely, for example, and flying brother is such understanding.
  • Zhangferry: What interesting things are you studying recently? Could you tell us what you plan to do in the next few articles?

Recently I have been working on optimization, and the next few articles may be biased towards optimization series or underlying related.

  • Zhangferry: How can I spare some time to write blog every week? Do you have any good learning methods to share?

I now update frequency is an article on Monday, general weekday evening will go to see some article involves information code and do some practice, and accumulated some notes, notes to polymerization in weekend time, form the article, the process or are tired, after all, sometimes work is busy, but must hold to the things, Give yourself a goal, can not casually break more, after all, there is a second break more.

Learning methods: say, my attitude for technology is more optimal solution practice +, when saw some good articles, will my post will in principle or practice a do-it-yourself, consider what are the disadvantages of this method, and around this technology points to think about to have a better solution, constantly in search of a more optimal solution.

So much about the interview part, I hope some of my experience can give you some reference. All right, let’s get down to business, and the technical stuff starts.

In fact, THIS week I planned to share my experience on some design patterns with you, but later I gave up the idea due to the consistency of the content and the uncertainty of your interest in design patterns. If you are interested in design patterns, you can express it by clicking like.

Off-screen rendering concept

A quick word about the normal flow of iOS page rendering.

To display content on the screen, we need at least one Framebuffer as large as the pixel data on the screen. As the pixel data storage area, the GPU continuously puts the rendered content into the Framebuffer Framebuffer. The display screen is constantly fetching content from the Framebuffer and displaying it in real time.

If sometimes there are constraints that prevent us from writing the render directly to the Framebuffer, we need to create an extra Offscreen Buffer and put the pre-rendered content into it. When the time is right to overlay the contents of the Offscreen Buffer, render them further, and then switch the results to the Framebuffer, this process is called off-screen rendering.

Drawing pages using the Core Graphics API mentioned in last week’s article is sometimes referred to as off-screen rendering (because the pixel data is temporarily stored in the CGContext, not directly into the frame buffer), but according to Apple engineers, This way of rendering occurs in CPU, not off-screen rendering in the real sense. In fact, rendering through CPU is commonly known as’ software rendering ‘, while the real off-screen rendering occurs in GPU. What we are studying here is more off-screen rendering by GPU.

Performance issues with off-screen rendering

Generally speaking, off-screen rendering is very performance consuming in two ways:

  • Creating a new buffer: To render off-screen, you must first create a new buffer, which requires additional space. A large amount of off-screen rendering can cause excessive memory stressOffscreen BufferThe total size of the screen is also limited and cannot exceed 2.5 times the total screen pixels;
  • Context switch: The entire process of off-screen rendering requires two context switches, first to the off-screen environment and then to the current screen after the off-screen rendering is complete. Context switch is very expensive, especially in scroll view.

It’s easy to lose frames if you have too much to render off screen. So for the most part, we should try to avoid off-screen rendering.

Why off-screen rendering exists

Why use off-screen rendering when it hurts performance? There are two main reasons:

  1. Some special effects require extra useOffscreen BufferTo save the render intermediate state, so you had to use off-screen rendering;
  2. For efficiency purposes, pre-rendered content can be saved inOffscreen BufferTo achieve the purpose of reuse.

For the first case, where you have to use off-screen rendering, it’s usually automatically triggered by the system, such as masks, UIBlurEffectView, etc. The following sections describe some common scenarios where off-screen rendering occurs.

In the second case, we can use the CALayer shouldRasterize property to trigger off-screen rendering. After the function is enabled, the Render Server will force the CALayer’s bitmap result to be saved, so that the next time it needs to Render, it can be reused directly, thus improving efficiency.

The saved Bitmap contains layer subLayer, rounded corners, shadows, group opacity, etc. Therefore, if the layer structure contains the above elements, the structure is complex and needs to be reused repeatedly, you can consider turning rasterization on. The idea is to reduce the performance penalty, but always trigger at least one off-screen render.

Rounded corners, shadows, group transparency, etc., are automatically triggered by the system to render off screen, so turning on rasterization can save second and subsequent render time. The multi-layer subLayer does not automatically trigger off-screen rendering, so it takes more time for the first off-screen rendering, but saves the cost of repeated rendering later.

However, there are a few things to keep in mind when using rasterization:

  • iflayerIt’s not complicated, there are no rounded shadows, etc., so there’s no need to turn rasterization on;
  • iflayerIf it cannot be reused, it is not necessary to turn on rasterization;
  • layerThe content (including the sublayer) of must be static, because any changes (such as resize, animation) will inactivate the hard-earned cache. So iflayerNot static, need to be frequently modified, such as in animation, so off screen rendering will affect the efficiency;
  • Off-screen rendering of cached content has a time limit, cached content100msIf it is not used, it is discarded and cannot be reused.
  • Off-screen render cache space is limited, over2.5If you multiply the size of the screen pixels, it will also fail and cannot be reused.

ShouldRasterize shouldRasterize can also be used in another scene, in addition to addressing the overhead of multiple off-screen renderings: If the substructure of the layer is very complex and takes a long time to render once, you can also turn this on, draw the layer into a cache and reuse the result later, so you don’t need to redraw the entire layer tree each time.

Off-screen rendering generates logic

The layer overlay is roughly based on the artist’s algorithm, in which layers are drawn, first drawing the distant scene and then covering the distant part with a drawing of the closer scene.

In ordinary layer drawing, the upper sublayer overwrites the lower sublayer. After the lower sublayer is drawn, it can be abandoned to save space and improve efficiency. After all sublayer are drawn in turn, the whole drawing process is completed and the subsequent rendering can be carried out.

Some scenarios are not that simple. While the GPU can output layer by layer to the canvas, it cannot go back and erase/change parts of a rendered layer after it has been rendered — the previous layers have been permanently overwritten in the render. This means that for each layer, you either have to find an algorithm that can render it in a single pass, or you have to open up a separate block of memory and use this temporary transit area to do more complex, multiple changes/clipping.

The scene where off-screen rendering occurs

Let’s start by turning on the off-screen rendering color marker in the simulator Debug, as shown in the left image. When off-screen rendering occurs, the corresponding controls will appear yellow as shown in the right image.

Based on the above reasons for off-screen rendering, in fact, we can easily conclude the scene that appears in off-screen rendering.

Off-screen rendering is triggered whenever the clipped content requires the participation of content before the artist’s algorithm is complete.

To summarize, the following situations trigger off-screen rendering:

  • Layer (layer.mask) with mask;
  • Added a layer for the shadow (layer.shadow*, indicating the associated shadow beginning attribute)
  • Set up a group to YES, transparency and transparency of 1 layer (layer. AllowsGroupOpacity/layer. Opacity)
  • Use rasterized layer (layer.shouldrasterize)
  • Draw a layer of Text (UILabel, CATextLayer, Core Text, etc.)
  • Layer to crop (layer.maskstobounds/view.clipstobounds)

One of the most common scenarios that triggers off-screen rendering is rounded corners, which need to be emphasized.

We often see rounded corners trigger off-screen rendering. But that’s not accurate, because rounded corners trigger off-screen renderings conditionally!

Let’s take a look at the official apple documentation for a cornerRadius:

Discussion Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to true causes the content to be clipped to the rounded corners. The default value of this property is 0.0.

When the cornerRadius value is greater than 0, only the backgroundColor and border of the layer are rounded. You don’t fillet the layer contents unless you also set layer.masksToBounds to true (corresponding to the UIView’s clipsToBounds property).

But when layer.masksToBounds or clipsToBounds are set to true, it doesn’t necessarily trigger off-screen rendering.

When we have rounded corners + clipping, we also need to set contents to trigger the off-screen render, and the way we set contents is not necessarily by directly assigning the contents property to the layer, but by adding subviews with image information and so on.

For rounded corners, Apple has made some improvements in iOS 9 and later. We just set the contents of the layer or the IMAGE of the UIImageView, and add rounded corners and crop, and it’s not going to render off screen. But if you add a background color, border, or other layer with image content, you still get an off-screen rendering.

To summarize, the conditions for off-screen rendering caused by rounded corners after iOS 9 include:

  • Rounded corners
  • tailoring
  • The contents of the layer is not nil
  • Set the background color/border/other layer with image content

Some conclusions must be tried by myself. For example, my above conclusions may not be correct, because there may be other cases THAT I have not noticed.

Since rounded corners + clipping will in some cases produce off-screen renderings, what can we do to help us draw rounded corners without producing off-screen renderings? As follows:

  • Use the image with rounded corners directly, or replace the background color with a solid color background with rounded corners to avoid using rounded corners. But it depends on the situation, it’s not universal;
  • [UIBezierPath] Draw a closed rectangle with rounded corners using bezier curves, set only the inside to be visible in the context, render the layer without rounded corners as an image and add it to the Bezier rectangle. This method is more efficient, but once the layout of the layer changes, the Bezier curve needs to be manually redrawn, so you need to manually monitor and redraw the frame, color, etc.
  • 【CoreGraphics】 Override drawRect:, and use coreGraphics-related methods to manually draw when rounded corners need to be applied. However, CoreGraphics efficiency is also limited, if the need for multiple calls will also be efficient problems;
  • Mask: Add a mask with the same color as the background. Mask is placed on the top layer, covering the four corners to create the rounded shape. However, this method is difficult to solve the background color of the picture or gradient.

The last

New week to work harder!

Let’s be CoderStar!

Refer to the link

  • Full Rendering of iOS Rendering
  • An in-depth look at iOS off-screen rendering
  • IOS Interface rendering and optimization (IV) – Summary of off-screen rendering and optimization
  • Have you really figured out the off-screen rendering of iOS rounded corners

There is a technology circle and a group of fellow public is very important, to my technology public number, here only talk about technology dry goods.

Wechat official account: CoderStar