定义

“Synchronization between consumers and producers who are from different hardware components to use a buffer atomically”

 

应用背景

在复杂的DMA管线如图形管线(多媒体,摄像头,GPU以及显示设备),一个buffer的消费者需要知道生产者什么时候完成生产(即创建一个Buffer,并往里面放置消费者所需要的数据)。同样地,生产者也需要知道消费者什么时候使用它创建的Buffer,以便它可以重新使用这个Buffer。而且,一个Buffer可能被多个不同的消费者使用不同的时间。另外,一个消费者可能需要互斥地消费多个Buffer,等等,有一个问题应运而生,就是如何保证多个消费者之间同步使用Buffer,以及生产者与消费者协调使用Buffer。因为Buffer是一个共享资源,且任何消费者或生产者对Buffer的使用都是排他性的(因为它们属于不同的硬件单元或模块),大体看来,需要解决如下两个问题:

1. 消费者与生产者之间对Buffer的同步访问。

2. 消费者之间对Buffer的同步访问。

方案提出

Android中,引入了Sync框架,它添加了一组API,可以允许生产者和消费者之间以一种通用的方式解决上面提到的同步访问问题,平台需要实现这些Driver定义的同步原语以支持这个Sync框架。

Android Sync框架的目标是:

1. 提供一个通用的API用于表达同步依赖关系。

2. 允许驱动在不同的硬件模块中实现同步。

3. 提供了一套用户空间的API,使得Compositor(等硬件模块)可以管理这些依赖。

4. 提供丰富的测量数据,可以调试图形管线变慢和停止的问题。

 

驱动代码位于drivers/staging/android/sync.c,主要定义了如下三个数据类型:

• sync_timeline

sync_timeline是一种抽象的单调递增的计数器。通常情况下,每个驱动或硬件模块上下文只有一个sync_timeline。一般需要提供硬件模块特有的Sync驱动或使用通用的sw_sync实现,它是基于CPU的一种实现方式。实现上,是通过这些底层的驱动来创建sync_timeline的。一个硬件模块如果要提供Sync支持,则必须实现创建sync_timeline逻辑的驱动。

• sync_pt

sync_pt是一个抽象的值,标记在sync_timeline上。sync_pt只能属于唯一的sync_timeline。它有三种状态:活跃,信号和错误。开始时,处于活跃状态,当sync_timeline的计数值超过了sync_pt的值,就会触发状态转换为信号状态或错误状态。

• sync_fence

sync_fence是驱动间协调同步使用Buffer的主要原语。它包含一系列的sync_pt,这些sync_pt可能来自于不同的sync_timeline。另外,sync_fence上的sync_pt一旦确定,是不可更改的。可以同步或异步等待sync_fence对象状态的改变。两个sync_fence对象也可以合并生成第三个Fence对象,它包含了合并前的两个sync_fence对象的所有sync_pt的拷贝。sync_fence与文件描述符关联,用户空间可以通过它来协调显示管线等硬件单元之间的依赖性关系,即访问Buffer的先后顺序。

 Android Sync Framework

Ownership of a fence fd
If you get a fence fd from the framework, you must close it(Sf dup fence fd and transfer the new one)

If you pass a fence fd to the framework, we will close it(If you want to keep using it, you must dup it, Sf merge fence if need transfer it)


如何使用

   一个实现Sync支持的驱动,应该拥有如下一个工作提交函数:

1. 接受一个sync_fence参数,指定什么时候开始工作。

2. sync_fence处于信号态后,异步地将对应的工作放入队列中去运行。

3. 返回一个sync_fence对象,包含工作何时结束的信息。

4. 当工作结束后,会将关联的sync_fence对象变成信号态。

 

接口声明实例:

Driver API without fence support

/*

* assumes buf is ready to be displayed.

* blocks until the buffer is on screen.

*/

void display_buffer(struct dma_buf *buf);

Driver API with fence support

/*

* will display buf when fence is signaled.

* returns immediately with a fence that will signal

* when buf  is no longer displayed.

*/

struct sync_fence* display_buffer(struct dma_buf *buf, struct sync_fence *fence);

 

Android  Sync框架的软件Stack如下图所示:

Android Sync Framework


Android使用类Fence封装了sync用户接口,所以Android框架层中一般通用Fence类来使用Android Sync框架

 

Sync驱动

Sync驱动包含两部分:

  •  fence的通用操作,已经实现
  • 各个sync 驱动相关的代码,由各个硬件Vendor实现,其中,基于CPUsync驱动已经提供

主要数据结构

struct sync_timeline_ops

sync对象需要实现的一些操作

struct sync_timeline

代表一个sync对象的描述

它包含许多struct sync_pt

struct sync_pt

同步点

有三种状态

signaled(status > 0)

active(status = 0)

error(status < 0)

它位于一个sync_timeline以及sync_fence

struct sync_fence

struct sync_fence_waiter

在一个fence上异步等待的waiter的相关信息

主要API

API focomponentsr sync_time implementers

sync_timeline_create()

  创建一个sync对象

sync_timeline_destory()

销毁一个sync对象

sync_timeline_signal()

signal a status change on a sync_timeline

sync_pt_create()

创建一个同步点

sync_pt_free()

释放一个同步点

此函数仅能在该同步点未加入到一个fence前调用

sync_fence_create()

创建一个sync fence

API for sync_fence consumers

sync_fence_merge()

合并两个fence

当两个sync_pt位于同一个timeline时,需要将他们合并成一个sync_pt, 
并以触发时间最晚些的那个sync_pt那个为准

Android Sync Framework

sync_fence_fdget()

根据一个fd获取对应的fence对象

sync_fence_put()

减少一次对sync fence的引用

sync_fence_install()

安装fence到一个文件描述符中

sync_fence_waiter_init()

sync_fence_wait_async()

注册和异步等待某个fence对象

sync_fence_cancel_async()

取消一个异步等待

sync_fence_wait()

等待一个fence状态变为signaled error

主要有三种IOCTL命令

SYNC_IOC_WAIT

SYNC_IOC_MERGE

SYNC_IOC_FENCE_INFO

fill_driver_data


实现一个Sync-aware的驱动

1.定义自己的timeline, pt数据结构

Mali 驱动定义的:

[cpp] view plain copy
  1. struct mali_sync_timeline  
  2. {  
  3.     struct sync_timeline timeline;  
  4.     atomic_t counter;  
  5.     atomic_t signalled;  
  6. };  
  7. struct mali_sync_pt  
  8. {  
  9.     struct sync_pt pt;  
  10.     u32 order;  
  11.     s32 error;  
  12. };  

sw sync定义的:

[cpp] view plain copy
  1. struct sw_sync_timeline {  
  2.     struct    sync_timeline    obj;  
  3.     u32            value;  
  4. };  
  5. struct sw_sync_pt {  
  6.     struct sync_pt        pt;  
  7.     u32            value;  
  8. };  

2.提供创建struct sync_timeline, struct sync_pt的接口

3.实现struct sync_timeline_ops定义的一些回调函数

sw_sync驱动实现了如下函数,它是创建sync_timeline所必需的:

[cpp] view plain copy
  1. static struct sync_timeline_ops sw_sync_timeline_ops = {  
  2.     .driver_name = "sw_sync",  
  3.     .dup = sw_sync_pt_dup,  
  4.     .has_signaled = sw_sync_pt_has_signaled,  
  5.     .compare = sw_sync_pt_compare,  
  6.     .fill_driver_data = sw_sync_fill_driver_data,  
  7.     .timeline_value_str = sw_sync_timeline_value_str,  
  8.     .pt_value_str = sw_sync_pt_value_str,  
  9. };  

4.提供创建fence的接口

根据自身的设计,可能会提供如下两个IOCTL命令,注意区分上面提供的几个通用的IOCTL命令,以提供用户空间创建Fence的接口:

创建Fence的命令:

sw_sync中定义义了如下命令:

SW_SYNC_IOC_CREATE_FENCE

另外,sw_sync还有一个改变sync_timeline当前值的命令(每个驱动也都会提供类似的操作,根据自身的逻辑,实现方法不尽相同)

SW_SYNC_IOC_INC, 每当这个值变化时,会检查当前的值与位于sync_timeline中的syn_pt的值是否相等,以此来判断状态是否变为信号态。


相关文章: