Android4.4 fence Mechanism Analysis

Source: Internet
Author: User

Android4.4 fence Mechanism Analysis
Android4.4 fence Mechanism Analysis

In any system, it is inevitable to deal with various buffers. The most classic mode is the consumption-producer mode, an independent buffer exchange between them requires a mechanism to control the "lifecycle" of each buffer, that is, ALLOCATION and RELEASE. In addition, synchronization must be considered, when can read buffer and write buffer be executed.

Fence in android is such a mechanism to solve synchronization. First, analyze the basic principles of fence from the semantic perspective:

Fence is a barrier. The role of a barrier is very similar to its name. A group of threads can use barrier to synchronize with each other collectively. In essence, each thread calls the barrier wait () method when it reaches a certain rolling state to block it, wait until all other participating threads call the wait () method to indicate that they have reached this status. once all threads reach the barrier, they will collectively lift the blocking and continue execution together. The state that causes the program to call the wait () method of the barrier to block is called the barrier state.

Next, we will analyze the application of fence in android, which mainly involves the buffer and display related aspects in SurfaceFlinger.

To be exact, fence is responsible for coordinating the synchronization of buffer processing by producer and consumer, so as to ensure the accuracy of the buffer content without being tampered.

First, we know that a buffer has the following statuses:

FREE-> DEQUEUED-> QUEUED-> ACQUIRED-FREE

Can the producer apply for the FREE status? The answer is wrong. He needs to wait for a signal, that is, the NO_FENCE signal, because it is possible that the buffer applied for last time is being processed by the consumer job, so he has to wait for the consumer to send the finish signal, at this time, the buffer in the FREE State is blocked by the barrier. Here we use the wait () or waitForever () method in Fence and wait for a NO_FENCCE signal to open the barrier. Go to the next process.

DEQUEUED indicates that the producer has applied for a buffer to come out of the queue and has not yet entered the queue or canceled the buffer, when the producer wants to modify the UI data, it must wait for a NO_FENCE signal, because other owners may be operating on it. When the signal arrives, poducer can operate it and then send a NO_FENCE signal.

In the QUEUED status, the buffer is put into the queue. However, before this operation, a NO_FENCE signal is required, such as the NO_FENCE sent after the dequeueBuffer is completed in the previous step. after receiving the signal, the system enters the queue or cancels the buffer operation. At this time, its owner becomes BufferQueue.

The ACQUIRED status means that the producer has filled the buffer. Like before, it will have to wait for a NO_FENCE signal before the consumer can operate on it. After the operation is complete, the buffer is released and a NO_FENCE signal is sent.

All fence is implemented at the kernel layer. The androidHAL layer only encapsulates and extends some underlying interfaces.

Surfaceflinger mainly follows the process of drawing the surface:

Surfaceflinger submits the computed layers to HWC. HWC selects the corresponding drawing path based on the actual situation.

Because the openGL implementation code is not open-source, I do not know Z-grams? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> keys + 6687eiz9a7 + keys/tLK7tb3L/Mq1z9a1xLK/t9aw11_am8l3a + keys/keys + cjxwPjxpbWcgc3JjPQ = "http://www.2cto.com/uploadfile/Collfiles/20140913/2014091308422543.png" alt = "\">

Each layer has an acquire and release fence, and each series of layes has a retirefence. Note that layers is used here! Multiple layers.

AcquireFence:

Do not display the content of a buffer until the fence is triggered, which is sent before H/W is set up.

ReleaseFence:

This means that the buffer of this layer is no longer read, and this fence will be triggered when a buffer is not read.

Retire fence:

This scene or a series of layers are no longer displayed on the monitor. This fence is triggered when a frame is displayed.

Here we can know that acquireFence and releaseFence belong to a single layer, while Retire fence belongs to multiple layers, that is, a scene. Then the struct corresponding to layer and layers must have their shadows:

In hardware/libhardware/include/hardware/hwcomposer. h:

Typedef struct hwc_layer_1 {

.........

Int acquireFenceFd;

Int releaseFenceFd;

.........

} Hwc_layer_0000t;

We can see that in the defined layer, they are two integer variables, all of which end with Fd. We can imagine this will describe a file descriptor.

Similarly:

Typedef struct hwc_display_contents_1 {

............

Int retireFenceFd;

} Hwc_display_contents_cmdt;

After introducing the various fence above (of course there are other types of fence), I will use a picture to describe the fence application mechanism:

From the analysis, fence is analyzed from a macro perspective, and a clear understanding of the fence mechanism framework is probably given. Next, let's see how it is implemented.

Previously, fence is implemented on the kernel layer. In fact, Fence: wait () and waitForever () and mege () are encapsulation of the kernel layer. The fence of the Kernel layer is relatively more complex. After all, it is the implementation principle, but in essence, fence is actually a file descriptor, which also responds to the statement that everything in linux is a file.

There are three fence-related structs in the kernel layer:

Sync_timeline, sync_pt, and sync_fence. The following describes their functions and definitions:

Sync_timeline:

As the name suggests, it is a timeline. Each process has its own timeline, representing an automatically added counter.

Use a graphical image to describe it as follows:

Sync_pt:

It is actually a sync point. The concept of a synchronization point represents a special value on timeline. It has three states: active signalederror.

Sync_fence

It is a collection of sync_pt. It is actually a file descriptor that can be uploaded to the user space. This feature allows the fence of the hal layer to communicate with the kernel.

The above is the basic introduction of these three structures, and the APIS related to fence are not described in detail here, which will be detailed later in the analysis of LCD.

At the beginning, two processes for SF synthetic images to display are provided. Here we will focus on the hwc path:

After the android system is started, Image Rendering is a cyclical State. To facilitate the study, start with the boot animation of the android system:

The first step is that the client requests a buffer (which is not described as an app at the moment). Because it is the beginning, all fence is in the initialization status or has not been created yet, (theoretically, everything is idle at this time, no matter whether it is buffer or something else. So I continue to analyze it based on this assumption mode. How is the truth to be studied) therefore, when dequeue is a Buffer for the first time, you do not need to wait for the display to trigger fence, nor do you worry that SF is performing computation and synthesis on this buffer. This way, you can proceed step by step before SF computing and synthesis, when preparing to assign hwc rendering, initialize acquireFenceFd, releaseFenceFd, and retireFenceFd for the first time, and complete createWorkList in setUpHWComposer:

The key generation Structure Code is as follows:

Hwc_layer_1 framebufferTarget;

Hwc_display_contents_1 list;

For (; dpy

{

For (; numLayers ;)

Disp. framebufferTarget-> acquireFenceFd =-1;

Disp. framebufferTarget-> releaseFenceFd =-1;

}

Disp. list-> retireFenceFd =-1;

}

Such initialization confirms that the acq and rel correspond to each layer, and the retire corresponds to layers.

After Set up, start computing and synthesis. Finally, go to HWComposer: commit () --- "set (…) In postFramebuffer (...) --- "Hwc_set ()

After rendering is completed in hwc_set, ioctl is handed over to fb for display. Here we paste the following in hwc_set:

Running to hwc_sync will block wait in this function:

Voidhwc_sync (hwc_display_contents_own T * list)

{

For (int I = 0; I NumHwLayers; I ++)

{

If (list-> hwLayers [I]. acquireFenceFd> 0)

{

Sync_wait (list-> hwLayers [I]. acquireFenceFd, 500); ALOGV ("fenceFd = % d, name = % s", list-> hwLayers [I]. acquireFenceFd, list-> hwLayers [I]. layerName );

}

}

}

The above red lines show that he is waiting for the signal acquireFence.

If (layer-> acquireFenceFd> 0)

{

G_sync.acq_fence_fd [k] = layer-> acquireFenceFd;

}

Ioctl (context-> fbFd, RK_FBIOSET_CONFIG_DONE, & g_sync );

List-> hwLayers [0]. releaseFenceFd = g_sync.rel_fence_fd [0];

List-> hwLayers [1]. releaseFenceFd = g_sync.rel_fence_fd [1];

// List-> retireFenceFd = g_sync.ret_fence_fd;

Close (g_sync.ret_fence_fd );

List-> retireFenceFd =-1;

There are two arrays named "acq_fence_fd" and "rel_fence_fd". The first step is to save the acqFenfd of each layer initialized to the array, then display starts to display the ioctl mapped to the ioctl of the fd driver in the kernel.

Next, we will analyze the fence-related code in the fb DRIVER:

First, some fence-related variables are defined:

Struct sync_fence * release_fence;

Structsync_fence * retire_fence;

Structsync_pt * release_sync_pt;

Structsync_pt * retire_sync_pt;

Structsync_fence * layer2_fence;

Structsync_pt * layer2_pt;

Fence has three types of releaseretire and layer2.

Find unused fd and save it to rel_fence_fd:

Dev_drv-> win_data.rel_fence_fd [0] = get_unused_fd ();

Dev_drv-> win_data.rel_fence_fd [1] = get_unused_fd ();

Then create fence:

Release_sync_pt = sw_sync_pt_create (dev_drv-> timeline, dev_drv-> timeline_max );

Release_fence = sync_fence_create ("rel_fence", release_sync_pt );

Sync_fence_install (release_fence, dev_drv-> win_data.rel_fence_fd [0]);

Layer2_pt = sw_sync_pt_create (dev_drv-> timeline, dev_drv-> timeline_max );

Layer2_fence = sync_fence_create ("rel2_fence", layer2_pt );

Sync_fence_install (layer2_fence, dev_drv-> win_data.rel_fence_fd [1]);

Retire_sync_pt = sw_sync_pt_create (dev_drv-> timeline, dev_drv-> timeline_max );

Retire_fence = sync_fence_create ("ret_fence", retire_sync_pt );

Sync_fence_install (retire_fence, dev_drv-> win_data.ret_fence_fd );

The creation process is omitted here, and fence is triggered by blocking after being created (waiting for a condition: triggered immediately after the buffer is displayed ), the trigger function is sync_fence_signal_pt (pt) In sync_fence_create; here is the first time that fence is triggered throughout the process.

The trigger is releaseFence and retiredfence, and then go down:

The program will run in the next step:

If (dev_drv-> wait_fs = 1) {// wait for new frame start in kernel

Rk_fb_update_reg (dev_drv, regs );

Kfree (regs );

Mutex_unlock (& dev_drv-> update_regs_list_lock );

}

Next, let's look at the key code in rk_fb_update_reg (dev_drv, regs:

Sw_sync_timeline_inc (dev_drv-> timeline, 1 );

If (dev_drv-> win_data.acq_fence_fd [0]> = 0)

{

For (I = 0; I

If (dev_drv-> win_data.acq_fence_fd [I]> 0 ){

Put_unused_fd (dev_drv-> win_data.acq_fence_fd [I]);

Printk ("acq_fd = % d \ n", dev_drv-> win_data.acq_fence_fd [I]);

}

Rk_fb_free_dma_buf (& regs-> dma_buf_data [I]);

}

}

The core function is probably to invalidate the fd stored in the acq_fence_fd array. It seems that a simple operation is to assign only-1 to acqFenceFd, but define acqFenceFd from the source code:

/* Sync fence object that will be signaled when the buffer's

* Contents are available. May be-1 if the contents are already

* Available .*/

The above is the explanation in the source code. It can be seen that when fd is-1, acqFenceFd will be triggered.

When the program runs here, because it is only one of the threads, the previous client request buffer operation has started and is waiting for the relevant fence. After the releasefence is triggered, the user starts to dequeue a buffer to fill the surface.

Use a picture to represent the process:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.