In iOS development, the problem of lag is an unavoidable problem. Here we analyze the reasons for the lag in the rendering process from the perspective of the iOS Render Loop.

Render loop

VSYNC

Render loopIs acontinuityIn the process. The touch event is transmitted to the APP, which is then converted to the user interface and transmitted to the operating system. It’s presented to the user, and that’s the loop that happens with the refresh rate of the device.

The iphone and the tablet,VSYNCThe frequency of the signal is zero60HZIn theipad proFor the120HZ. Let’s take the iPhone for example, which means that every16.67In milliseconds, you can display oneThe new frame.

The entire rendering cycle consists of five stages: Event, commit, render preparation, render execution, and display.

If it takes more than one frame during the commit or render or presentation phases, it will cause a stutter.

Event phase

At this stage, App processesTouch eventsorTimerAnd other events to determine whether the user interface needs to change.

Commit Phase

In the commit phase, the app submits the render command to the render server.

Render to prepare

In the next VSYNC, the render server processes the commands, during the render prep phase, to prepare for drawing on the GPU.

Render to perform

During the rendering execution phase, the GPU draws the final image of the user interface.

Show stage

The nextVSYNCThis frame will be presented to the user.

Each stage is crucial for a silky user experience. If the time of a phase exceeds the time of VSYNC, it causes stalling:

Caton in the submission phase

Commit the transaction

In the Event stage of the rendering cycle, touch events and other events are processed. After receiving the events, the attributes of View such as backgroundColor and frame need to be changed

The next time a transaction commits, some layout or display will be required for the system to record these subviews

These views, which require some display or layout, are called when a transaction is committeddrawRectlayoutSubviewsTo update accordingly.

Four steps to commit a transaction:

The transaction submission consists of Layout, Display, Prepare, and Commit.

Layout stage

LayoutSubviews are called when the view needs to be laid out, and need to be relaid in the following cases:

  • Positioning views, such as the frame, bounds, and Transform properties, are repositioned.
  • Add or remove views.
  • According to callsetNeedsLayout().

Display(Display stage)

The draw(rect:) method is called whenever a view needs to update its content. The draw(rect:) method is called in the following cases:

  • Added overwritedraw(rect:)Method view.
  • Directly calledsetNeedsDisplay()Method to indicate the need to show.

They are preparing for the New Year.

  • Decode the undecoded picture.
  • If the color format of an image cannot be used directly by the GPU, it will be converted, which consumes a lot of memory.

Commit (Commit phase)

The view hierarchy is recursively packaged and sent to the rendering server.

Avoid submitting Caton’s advice

  • 1, Keep the view light:

    1.1: Use 'CALayer' attributes as much as possible. 1.2: Avoid empty drawRect implementations. 1.3: Reuse views and avoid costly view hierarchy operations, such as add and remove. If you must remove it, consider using the Hidden property.Copy the code
  • 2. If the layout needs to be updated, only setNeedsLayout should be used as far as possible. LayoutIfNeeded will consume the life cycle of the current transaction and cause lag. Most of the time, you can wait until the next iteration to update the layout.

  • 3. Decode the image when loading it.

Stuck in the render phase

The Render stage consists of two stages: Render prepare and Render Execute.

Render preparation stage

Decompose the graph tree into a series of simple operations for the GPU to perform

Render execution phase

The GPU draws the App layer into the final image.

Both phases can cause frame delay.

Rendering process

Illustrate the drawing process by drawing an example with shadows

In the render preparation phase, the render server compiles a series of drawing commands layer by layer, enabling the GPU to draw the user interface from back to front.

The root nodeTo start,The render server goes from level to level, from parent to child, until every layer in the hierarchy is covered, and you have the entire pipeline of rendering.

During the render execution phase, the pipeline is drawn in this order.

1, let’s draw blue 2, let’s draw dark blue

3. Draw shadows

Shadow shape defined by the two layer below it, so the GPU don’t know what kind of shape to draw the shadow, but if the first draw round and strip, the shadow will be in black shade them, seems to be incorrect, at this point, the GPU must switch to a different texture, to determine the shape of the shadow, this kind of situation, what we call the off-screen rendering, in a new texture, Add the following layer and copy it to determine the shape of the shadow. Once the shadow is rendered, copy the off-screen texture into the final texture

4. Draw circles and rectangles and text

In this process, when we draw shadows, we use a special technique to draw: the GPU first renders a layer elsewhere and then copies it over, which we call the Offscreen Pass. In the case of shadows, it has to draw layers to determine the final shape, and off-screen rendering can add up and affect performance.

For shadows, we can use UIBerthPath to specify the shape of the shadow to avoid off-screen rendering.

In order to facilitate detection of off-screen rendering and provide corresponding solutions, a new type of runtime problem called optimization opportunity has been added to Xcode 12. In LLDB state, under the Editor option

Reference video for this article:

Explore UI animation hitches and the render loop

Find and fix hitches in the commit phase

Demystify and eliminate hitches in the render phase