应用程序开发部分
Hobotcv提供的接口为什么不能在w全局对象的构造函数中使用?
hobotcv框架中的接口都需要从CVFramework::Instance()直接或者间接获得。在CVFramework::Instance()第一次被调用时,将进行框架的初始化,调用各个模块的初始化函数。
而各个模块的初始化函数是通过Dummy的全局对象的构造函数注册到初始化框架中。
所以,如果在应用程序的全局对象构造函数中CVFramework::Instance()被调用,则不能保证所有模块的初始化函数已经注册到初始化框架,从而存在风险。
为什么要定义IContext 和 ISession,他们之间是什么关系
IContext 用来表示系统环境,最重要的是包含的设备列表,应用程序还可以在IContext里面设置传给设备的各种参数。
ISession创建之后,在IContext删减设备,不会影响ISession的可用设备列表。
ISession创建之后,修改和增删IContext里的参数是否会生效,取决于具体的 OP实现和设备实现。
为什么屏蔽接口类的析构方法?如果需要实现智能指针封装,自动释放该怎么做?
强化基于接口的编程模式 以及Create/Destroy的资源使用范式,让用户对于资源的生命周期有清晰的掌握。
如果确实需要用智能指针来包裹获取的接口类对象,可以用如下方法:
输入buffer是从相机拿到的vio_buffer_t, 该怎么传给gdc设备? 如果需要同时支持CPU设备呢?
IImage支持设置自定义属性,可以通过设置自定义属性的方式传给设备。属性名和方式需要和设备的实现保持一致。 一个可能的例子:
如果支持该OP的设备同时包含gdc和CPU,应用程序代码可以同时设置好两种数据传递方式。
图像内存从设备分配,如何拿到设备分配内存的私有控制头?
应用程序调用 ISession->AllocDevMem()从设备分配内存以后,可以通过image->GetPlaneVirtAddr()/
image->GetPlanePhysAddr() 拿到设备分配内存的地址。如果想要拿到设备内存的私有控制头,比如vio_buffer_t,需要设备在image中设置相应的属性,应用程序调用 image->GetParamXXX()来获取。
应用程序调用设备分配内存函数来分配输出图像的内存。为什么在分配成功后,可能获取到无效的虚拟地址和物理地址?
有些设备类型,其输出内存事先注入在一个队列中。每执行一次操作,从队列中取出一个buffer并返回给调用者。
这种场景和Hobotcv的使用范式有区别: Hobotcv要求在运行OP前,输出内存必须设置,要么是应用程序已有的内存,或者应用程序调用设备分配内存。
在这类设备上,调用AllocDevMem()去分配输出内存时,设备层会分配无效的虚拟地址和物理地址来告知这种情况,同时,AllocDevMem()返回成功。
后续,设备在Run()函数中,拿到真正的Buffer后,会更新输出图像相应的信息。
如何指定OP运行的设备
有两种方式:
创建IContext时仅添加一个设备。或者
创建ISession后,调用ISession->SetBindDevice()来设置指定的设备
如何在运行OP时,传递临时参数给设备
可以通过ISession 的 Run()和ASyn()的最后一个参数进行传递。
异步执行时,回调函数如何保存应用程序需要保存的私有数据
回调函数实际上是一个仿函数,应用程序可以派生以后,添加自己想要保存的数据。
同步执行时,如何设置回调函数
同步执行,不支持每次OP运行时设置回调,因为作用不大。在 ISession级别可以设置一个正确执行和错误执行的回调函数,该回调函数同样也是仿函数实现。
传给operator()的参数task在函数结束后,不保证可用。
如何获取错误码和错误信息
除了Asyn()接口外,其他函数都可以通过GetLastErrorNo()和GetLastErrorMsg()获取。
GetLastErrorNo()返回的值是添加了Bole和模块编号的,可以调用ParseErrorNo()获取真正的error number。
在Asyn()和回调函数中,可以从task相应的接口,获取该task错误信息。
设备开发部分
如何在运行时给设备传递非初始化参数
有几种方式:
如果是和特定OP相关的,可以在IContext中设置,在设备层读取。
如果是和OP的某次执行相关的,可以在Run()/Async()的最后一个参数传递
如果和特定OP无关的,可以直接通过设备的IParam 接口设置设备参数
设备需要输出文档,详细描述各种方式可以接受的参数名字,含义,类型和用途。
设备初始化时,需要使用的配置参数该如何获取
Hobotcv在框架初始化时,会调用设备的Start()函数来初始化设备。如果设备初始化时,需要动态获取配置参数,则无法通过前面问题中说的方式给设备传递参数,可选的方案有:
通过环境变量来获取
通过搜索预定义好的目录和文件来获取
设备对外暴露私有接口,由应用程序去设置
通过框架提供的全局配置对象获取设备配置参数 (TBD)
其中,第一种和第二种方式,可以实现对应用程序透明(可以不需要添加设置配置代码),对应用程序开发友好。
第三种和第四种,则需要应用程序添加额外的配置代码,并保证在hobotcv框架初始化前完成。
从通用性和灵活性来说第四种最好。
无论采用哪种模式,都需要设备实现提供详细文档,说明配置参数的含义和如何设置。
如何让应用程序调用设备的函数
设备可以重载Get/SetParamXXX的接口来实现调用函数。应用程序可以通过调用Get/SetParamXXX接口来调用,类似于读取/设置设备寄存器。
示意代码如下
如何实现新的设备调度策略
从DeviceScheduler类派生,并实现SelectDevice()方法。
构造函数中传进的两个Vector分别包含了设备列表和设备优先级。
实现后,需要调用DeviceSchedulerRegistry::Instance()->RegisterInterface()来注册。
使用时,可以在IContext中设置“device_scheduler”来使其生效。
如何设置设备状态
框架本身会负责设备状态的设置。一般情况下,设备仅需要在出错时,设置状态为kDevStatusError。
创建设备时,设备构造函数中run_max,pend_max,urgent_reserved时什么含义?
这三个参数分别表示,一个设备同时可以支持的并行任务数(run_max),可以pending的等待任务数(pend_max)。当新任务下发给设备时,当前pend的任务已经达到pend_max, 则会立即失败返回。
urgent_reserved时设备预留给urgent任务的数量。当urgent任务到达时,在执行的urgent任务大于或者等于urgent_reserved, 则该任务会进入pending队列。
一个设备可以同时并行执行的最大任务数为run_max+urgent_reserved
设备的kDevStatusOverload 和kDevStatusFullload 是如何判定和设置
框架会根据设备调度参数和当前负载情况,自动判断这两个状态,逻辑如下代码:
设备在实现IDevSession::ExecAsyncTask()时,为什么在调用task->app_callback(task)之后,不能再访问task
因为task->app_callback()会唤醒应用程序的调用者,应用程序很可能会接着调用释放task的函数。由于操作系统调度问题,不能保证这个task->app_callback()之后使用task的代码,一定会在释放task之前完成,从而存在风险。
