opening


This article gives a brief introduction to off-screen rendering in iOS.

1. What is off-screen rendering:


To understand off-screen rendering, let’s first take a brief look at the logic of non-off-screen rendering

Non-off-screen rendering

Non-off-screen rendering is the normal rendering process. The brief process is shown in the figure below:

Off-screen rendering

The brief flow of off-screen rendering is shown as follows:

2. What is the impact of off-screen rendering on performance?


  • There is an extra render merge compared to the non-off-screen render mode, which is the process of merging multiple textures. With this extra step, the performance requirements are higher. More likely to drop frames.
  • Added additional storage offscreen Buffer, which is 2.5 times the size of the screen

3. The simulator opens off-screen render color annotation


Support -> Support -> Support -> Support -> support -> support -> support

MasksToBounds =YES, you can’t see it if you don’t set it. The reasons will be explained below.

4. Why use off-screen rendering?


There are two ways to use off-screen rendering:

  1. Special effects can be displayed, and you need to use the Offscreen Buffer to save the intermediate state.
  2. If the texture will be displayed multiple times on the screen, you can use the Offscreen Buffer to render it in advance and save it for reuse. There is a shouldRasterize property in the layer

Case 1:

It is usually triggered by the system, such as the layer related processing: rounded corners, shadows, masks, etc. The Gaussian blur that appears after flattening in iOS also takes advantage of off-screen rendering.

The rounded handle

Why does setting rounded corners trigger off-screen rendering? It starts with the layer structure. The layer structure consists of three parts:

  1. backgroundColor
  2. contents
  3. Information about Boarder (borderWidth and Color)

Set up the rounded corner code, which you should know:

view.layer.cornerRadius = 2
Copy the code

Let’s look at the cornerRadius documentation:

masksToBounds=YES;
Copy the code

This is why I want to turn on masksToBounds as shown in the simulator with off-screen render mode on above. MasksToBounds needs to crop everything on the layer, saving the intermediate values in the process. So I render it off-screen.

Note: If the layer layer is simple, it does not trigger off-screen rendering. For example, setting the cornerRadius and masksToBounds on UIImageView will not trigger an off-screen render, but setting the background color on UIImageView will.

    self.view.backgroundColor = [UIColor grayColor];
    
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
    imageView.frame = CGRectMake(100, 100, 100, 100);
    imageView.layer.cornerRadius = 30;
    imageView.layer.masksToBounds = YES;
    [self.view addSubview:imageView];
    
    UIImageView *imageView2 = [[UIImageView alloc]  initWithImage:[UIImage imageNamed:@"1"]];
    imageView2.backgroundColor = UIColor.redColor;
    imageView2.frame = CGRectMake(100, 250, 100, 100);
    imageView2.layer.cornerRadius = 30;
    imageView2.layer.masksToBounds = YES;
    [self.view addSubview:imageView2];
    
    UIButton *btn = [UIButton   buttonWithType:UIButtonTypeCustom];
    [btn setBackgroundImage:[UIImage imageNamed:@"1"]   forState:UIControlStateNormal];
    btn.layer.cornerRadius = 30;
    btn.layer.masksToBounds = YES;
    btn.frame = CGRectMake(100, 400, 100, 100);
    [self.view addSubview:btn];
Copy the code

There are three controls in the code, the first two are UIImageView and the last is UIButton.

  • The first UIImageView sets the image and doesn’t set the background color, doesn’t trigger off screen rendering.
  • The second UIImageView sets the image and background color, triggering off-screen rendering.
  • The last UIButton, setting the image without setting the background color, triggers off-screen rendering. The reason is that we see that UIButton is a mixture of its layer and UIImageView’s layer (UIButton has imageView), so setting the rounded corners triggers off-screen rendering.

Situation 2:

Is an active action to improve reuse efficiency. This is usually done by setting the layer shouldRasterize property.

ShouldRasterize rasterizer

ShouldRasterize official document

ShouldRasterize use advice:

  • Layer does not reuse, so there is no need to use shouldRasterize
  • The layer is not static, which means it needs to be changed frequently. There is no need to use shouldRasterize
  • Time: The off-screen rendering cache has a time limit of 100ms, and the content beyond this time will be discarded, so that the purpose of reuse cannot be achieved
  • Spatial: The off-screen render space is 2.5 times the screen pixels, and if you exceed it, it’s not reusable.

5. Off-screen rendering logic


The layer overlay follows the “artist’s algorithm”, which is to draw the layer from far to near on the screen. Drawing the close layer has the logic of overlaying the far layer.

In normal rendering mode, after drawing one layer, discard it directly. Then draw a closer layer. And so on:

6. Avoid off-screen rendering with rounded corners


To avoid off-screen rendering when setting the rounded corners, use the following solution instead of setting the rounded corners directly

  • Replace the support directly and have the UI provide images with rounded corners.
  • Using the layer.mask attribute, add a mask with the same color as the background to cover 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.
  • Use bezier curves to draw a rectangle with closed rounded corners, set only the inside to be visible in the context, then 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 overwrites drawRect: and uses coreGraphics-related methods to manually draw when rounded corners need to be applied. However, CoreGraphics efficiency is also very limited, if the need for multiple calls will also be efficient problems.

7. Summary of the reasons for triggering off-screen rendering


  1. Set the layer. MashsToBounds/view. ClipsToBounds
  2. Set the layer mask
  3. Set layer.shadow and other related properties
  4. Set layer.shouldRasterize to rasterize
  5. Set up a group to YES, transparency and transparency of 1 layer (layer. AllowsGroupOpacity/layer. Opacity)
  6. Draw a layer of Text (UILabel, CATextLayer, Core Text, etc.)

8. Refer to articles


IOS rendering principle analysis