{
For(;numLayers;)
disp.framebufferTarget->acquireFenceFd =-1;
disp.framebufferTarget->releaseFenceFd= -1;
}
disp.list->retireFenceFd = -1;
}
这样的初始化印证了之前所说的acq,rel分别对应每个layer,而retire对应的是layers。
Set up之后,开始进行计算合成。最后走到postFramebuffer中的HWComposer::commit()---》set(…)---》hwc_set()
在hwc_set中完成了渲染工作,然后通过ioctl交给了fb去显示,这里贴出hwc_set中:
一直运行到hwc_sync 会堵塞在这个函数中的wait里:
voidhwc_sync(hwc_display_contents_1_t *list)
{
for (int i=0; inumHwLayers; 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);
}
}
}
由上面的红色代码行可知他在等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;
首先这里有两个数组 acq_fence_fd和rel_fence_fd,看名字就能猜出这是存放对应两个fence的fd,第一步是把之前初始化的每个layer的acqFenfd保存到数组中,接着display就开始显示了,ioctl映射到内核中fd驱动程序的ioctl。
接下来分析fb驱动中跟fence相关的代码:
首先定义了跟fence相关的一些变量:
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有三类 releaseretire 和layer2 。
接着寻找没有被用过的fd保存到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();
然后开始创建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);
创建过程这里省略掉,fence在这里被创建完之后就阻塞触发了(等待一个条件:当buffer被显示后马上触发),触发的函数在sync_fence_create中的sync_fence_signal_pt(pt);在这里是一整个过程fence第一次被触发。
触发的是releaseFence 和retiredfence,接着往下走:
程序下一步会运行:
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);
}
接着看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(®s->dma_buf_data[i]);
}
}
核心功能大概就是让之前保存在acq_fence_fd数组中的fd无效,看似简单的一个操作,好像对acqFenceFd只是单纯的赋值为-1,但是从源代码中定义acqFenceFd的说明:
/*Sync fence object that will be signaled when the buffer's
* contents are available. May be -1 if the contents are already
* available.*/
上面是源代码中的解释,由此可以看出当fd为-1时acqFenceFd会被触发。
当程序运行到这里的时候,由于只是当中的一个线程,所以前面客户端请求buffer的操作早已经开始了,而且已经在等待相关的fence了。触发了releasefence之后用户那边收到之后就开始dequeue一个buffer进行填充surface了。
用一张图来表示下这个过程: