allocator_host适配
1. 环境 系统:OpenHarmony 5.0.1 Release 单板:rk3568 2. 框架图 基于主流的DRM显示框架,提供一套display hdi的默认参考实现,支持DRM架构通过hdi对接ohos图形服务,对上层图形服务提供HDI驱动操作能力,主要包括显示设备管理、图层合成、显示内存管理等功能。 Display HDI接口能力主体分为三类: display_gralloc:显示内存
1. 环境
系统:OpenHarmony 5.0.1 Release
单板:rk3568
2. 框架图
基于主流的DRM显示框架,提供一套display hdi的默认参考实现,支持DRM架构通过hdi对接ohos图形服务,对上层图形服务提供HDI驱动操作能力,主要包括显示设备管理、图层合成、显示内存管理等功能。
Display HDI接口能力主体分为三类:
- display_gralloc:显示内存相关的hdi操作接口,例如显示内存申请,内存映射等;
- display_device:显示设备操作、图层设置以及合成相关的hdi接口,例如图层的创建、图层的各种设置、图层预处理以及提交合成等接口;涉及显示设备的初始化流程、刷图流程等。
- display_gfx:显示2D加速的相关接口,此接口实现与各芯片厂商的实现和逻辑设计有关,不提供统一参考,可参考RK3568的相关接口。
3. display_buffer的HDI层
3.1 架构图
3.2 interface实现
3.2.1 IDisplayBuffer接口
class IDisplayBuffer {
public:
virtual ~IDisplayBuffer() = default;
virtual bool AddDeathRecipient(const sptr<IRemoteObject::DeathRecipient>& recipient) = 0;
virtual bool RemoveDeathRecipient() = 0;
static IDisplayBuffer *Get();
virtual int32_t AllocMem(const AllocInfo& info, BufferHandle*& handle) const = 0;
virtual void FreeMem(const BufferHandle& handle) const = 0;
virtual void *Mmap(const BufferHandle& handle) const = 0;
virtual int32_t Unmap(const BufferHandle& handle) const = 0;
virtual int32_t FlushCache(const BufferHandle& handle) const = 0;
virtual int32_t InvalidateCache(const BufferHandle& handle) const = 0;
virtual int32_t IsSupportedAlloc(
const std::vector<VerifyAllocInfo>& infos, std::vector<bool>& supporteds) const = 0;
};
Surface接口调用IDisplayBuffer接口。
IDisplayBuffer在框架层通过DisplayBufferHdiImpl类实现。
DisplayBufferHdiImpl实现类通过Proxy/Stub机制或者Passthrough机制调用IDisplayBufferVdi接口。
3.2.2 编译生成
3.2.2.1 目录结构
//drivers/interface/display/buffer
├── v1_0
│ ├── BUILD.gn
│ ├── DisplayBufferType.idl
│ ├── IAllocator.idl
│ ├── IMapper.idl
│ ├── hdi_impl
│ │ ├── display_buffer_hdi_impl.cpp
│ │ └── display_buffer_hdi_impl.h
│ └── include
│ └── idisplay_buffer.h
├── v1_1
│ ├── BUILD.gn
│ ├── IMetadata.idl
│ ├── hdi_impl
│ │ ├── display_buffer_hdi_impl.cpp
│ │ └── display_buffer_hdi_impl.h
│ └── include
│ └── idisplay_buffer.h
└── v1_2
├── BUILD.gn
├── DisplayBufferType.idl
├── IMapper.idl
├── hdi_impl
│ ├── display_buffer_hdi_impl.cpp
│ └── display_buffer_hdi_impl.h
└── include
└── idisplay_buffer.h
bundle.json
//drivers/interface/display/bundle.json
"//drivers/interface/display/buffer/v1_0:display_buffer_idl_target",
"//drivers/interface/display/buffer/v1_0:libdisplay_buffer_hdi_impl",
"//drivers/interface/display/buffer/v1_1:display_buffer_idl_target",
"//drivers/interface/display/buffer/v1_1:libdisplay_buffer_hdi_impl_v1_1",
"//drivers/interface/display/buffer/v1_2:display_buffer_idl_target",
"//drivers/interface/display/buffer/v1_2:libdisplay_buffer_hdi_impl_v1_2",
3.2.2.2 编译idl
display_buffer提供4个idl文件,通过编译工具链自动调用hdi-gen工具生成框架代码。
IAllocator.idl
IMapper.idl
DisplayBufferType.idl
IMetadata.idl
drivers/interface/display/buffer/v1_2/BUILD.gn
hdi("display_buffer") {
module_name = "display_buffer"
imports = [ "ohos.hdi.display.buffer.v1_0:display_buffer" ]
sources = [
"DisplayBufferType.idl",
"IMapper.idl",
]
innerapi_tags = [
"chipsetsdk_indirect",
"platformsdk_indirect",
]
language = "cpp"
subsystem_name = "hdf"
part_name = "drivers_interface_display"
}
编译命令
./build.sh --product-name rk3568 –ccache --gn-flags="--export-compile-commands" -T drivers/interface/display/buffer/v1_2:display_buffer_idl_target
生成模版源代码
//out/rk3568/gen/drivers/interface/display/buffer
├── v1_0
│ ├── allocator_driver.cpp
│ ├── allocator_proxy.cpp
│ ├── allocator_proxy.h
│ ├── allocator_service.cpp
│ ├── allocator_service.h
│ ├── allocator_stub.cpp
│ ├── allocator_stub.h
│ ├── display_buffer_type.cpp
│ ├── display_buffer_type.h
│ ├── iallocator.h
│ ├── imapper.h
│ ├── mapper_driver.cpp
│ ├── mapper_proxy.cpp
│ ├── mapper_proxy.h
│ ├── mapper_service.cpp
│ ├── mapper_service.h
│ ├── mapper_stub.cpp
│ └── mapper_stub.h
└── v1_2
├── display_buffer_type.cpp
├── display_buffer_type.h
├── imapper.h
├── mapper_driver.cpp
├── mapper_proxy.cpp
├── mapper_proxy.h
├── mapper_service.cpp
├── mapper_service.h
├── mapper_stub.cpp
└── mapper_stub.h
生成so文件
//out/rk3568/hdf/drivers_interface_display
├── libdisplay_buffer_proxy_1.0.z.so
├── libdisplay_buffer_proxy_1.2.z.so
├── libdisplay_buffer_stub_1.0.z.so
└── libdisplay_buffer_stub_1.2.z.so
3.2.2.3 编译生成hdi_impl
drivers/interface/display/buffer/v1_2/BUILD.gn
ohos_shared_library("libdisplay_buffer_hdi_impl_v1_2") {
sources = [
"../v1_0/hdi_impl/display_buffer_hdi_impl.cpp",
"../v1_1/hdi_impl/display_buffer_hdi_impl.cpp",
"./hdi_impl/display_buffer_hdi_impl.cpp",
]
public_configs = [ ":libdisplay_buffer_hdi_impl_config" ]
deps = [
":libdisplay_buffer_proxy_1.2",
"../v1_0:libdisplay_buffer_proxy_1.0",
"../v1_1:libdisplay_buffer_proxy_1.1",
]
# ......
}
编译命令
./build.sh --product-name rk3568 –ccache --gn-flags="--export-compile-commands" -T drivers/interface/display/buffer/v1_2:libdisplay_buffer_hdi_impl_v1_2
生成so文件
//out/rk3568/hdf/drivers_interface_display
├── libdisplay_buffer_hdi_impl_v1_2.z.so
├── libdisplay_buffer_proxy_1.0.z.so
├── libdisplay_buffer_proxy_1.1.z.so
├── libdisplay_buffer_proxy_1.2.z.so
├── libdisplay_buffer_stub_1.0.z.so
└── libdisplay_buffer_stub_1.2.z.so
AllocMem内存申请接口使用IPC模式跨进程调用,实现进程隔离,满足安全要求。
FreeMem、Mmap、UnMap等接口使用Passthrough直通模式,提升性能。因map、free等接口涉及访问的内核节点安全权限要求低,甚至不涉及内核节点,而且map接口返回的是虚拟地址,无发跨进程调用。
3.3 service实现
3.3.1 编译生成
框架层已经实现allocator_host的相关流程。
host驱动通过stub机制调用AllocatorService,AllocatorService调用IDisplayBufferVdi接口,响应Surface的调用过程。
源码结构:
//drivers/peripheral/display/buffer/hdi_service
├── BUILD.gn
├── include
│ ├── allocator_service.h
│ ├── idisplay_buffer_vdi.h
│ ├── mapper_service.h
│ ├── mapper_service_1_2.h
│ └── metadata_service.h
└── src
├── allocator_driver.cpp
├── allocator_service.cpp
├── mapper_driver.cpp
├── mapper_service.cpp
├── mapper_service_1_2.cpp
├── metadata_driver.cpp
└── metadata_service.cpp
BUILD.gn
//drivers/peripheral/display/buffer/hdi_service/BUILD.gn
group("hdf_display_buffer_service") {
deps = [
":liballocator_driver_1.0",
":liballocator_service_1.0",
":libmapper_driver_1.0",
":libmapper_service_1.0",
":libmapper_service_1.2",
":libmetadata_driver_1.1",
":libmetadata_service_1.1",
]
}
编译命令
./build.sh --product-name rk3568 –ccache --gn-flags="--export-compile-commands" -T hdf_display_buffer_service
生成so文件
//out/rk3568/hdf/drivers_peripheral_display
liballocator_driver_1.0.z.so
libmapper_driver_1.0.z.so
libmapper_service_1.2.z.so
libmetadata_service_1.1.z.so
liballocator_service_1.0.z.so
libmapper_service_1.0.z.so
libmetadata_driver_1.1.z.so
3.3.2 配置hcs
通过isStub参数判断是否是Proxy/Stub还是Passthrough模式。
IMapper和IMetadata是直通模式,运行时序图参考3.2.2,直接加载libdisplay_buffer_vdi_impl.z.so。
IAllocator是Proxy/Stub模式,通过IPC和allocator_host进程通信。
参考rk3568的hcs配置allocator_host进程
vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs
allocator :: host {
hostName = "allocator_host";
priority = 40;
allocator_device :: device {
device0 :: deviceNode {
policy = 2;
priority = 160;
moduleName = "liballocator_driver_1.0.z.so";
serviceName = "allocator_service";
}
}
}
4. VDI适配层
4.1 drm介绍
OpenHarmony基于主流的DRM显示框架,提供一套VDI接口的默认参考实现。DRM是Linux目前主流的图形显示框架,可以统一管理GPU和Display驱动,使得软件架构更为统一,方便管理和维护。
DRM从模块上划分,可以简单分为3部分:libdrm、KMS、GEM
libdrm
对底层接口进行封装,向上层提供通用的API接口,主要是对各种IOCTL接口进行封装。KMS
Kernel Mode Setting,所谓Mode setting,其实说白了就两件事:更新画面和设置显示参数。
更新画面:显示buffer的切换,多图层的合成方式,以及每个图层的显示位置。
设置显示参数:包括分辨率、刷新率、电源状态(休眠唤醒)等。GEM
Graphic Execution Manager,主要负责显示buffer的分配和释放,也是GPU唯一用到DRM的地方。基本元素
DRM框架涉及到的元素很多,大致如下:
KMS:CRTC,ENCODER,CONNECTOR,PLANE,FB,VBLANK,property
GEM:DUMB、PRIME、fence
详情参考:DRM(Direct Rendering Manager)学习简介-CSDN博客
OpenHarmony VDI接口参考实现的源码结构:
drivers/peripheral/display
├── BUILD.gn
├── include
│ ├── display_adapter_interface.h
│ ├── display_common.h
│ ├── display_gfx.h # 2D加速接口
│ └── display_gralloc_private.h
└── src
├── display_device
│ ├── composer # 图层合成管理
│ ├── core # 显示设备和图层设置
│ ├── display_composer_vdi_impl.cpp
│ ├── display_composer_vdi_impl.h
│ ├── drm # drm设备
│ ├── fbdev # FrameBuffer设备
│ └── vsync # softvsync
├── display_gfx # 2D加速实现
│ └── display_gfx.cpp
├── display_gralloc
│ ├── allocator.cpp
│ ├── allocator.h
│ ├── allocator_manager.cpp
│ ├── allocator_manager.h
│ ├── display_buffer_vdi_impl.cpp
│ ├── display_buffer_vdi_impl.h
│ ├── dmabufferheap_allocator.cpp # dmabufferheap管理
│ ├── dmabufferheap_allocator.h
│ ├── drm_allocator.cpp # drm gem显示内存管理
│ ├── drm_allocator.h
│ ├── framebuffer_allocator.cpp # framebuffer管理
│ └── framebuffer_allocator.h
├── display_layer_video
│ └── display_layer_video.cpp # video图层操作
└── utils
├── display_adapter.cpp # fb设备桥接
├── display_adapter.h
└── display_module_loader.h
4.2 IDisplayBufferVdi的实现
4.2.1 接口
IDisplayBufferVdi接口:
drivers/peripheral/display/buffer/hdi_service/include/idisplay_buffer_vdi.h
#define DISPLAY_BUFFER_VDI_LIBRARY "libdisplay_buffer_vdi_impl.z.so"
class IDisplayBufferVdi {
public:
virtual ~IDisplayBufferVdi() = default;
virtual int32_t AllocMem(const AllocInfo& info, BufferHandle*& handle) const = 0;
virtual void FreeMem(const BufferHandle& handle) const = 0;
virtual void *Mmap(const BufferHandle& handle) const = 0;
virtual int32_t Unmap(const BufferHandle& handle) const = 0;
virtual int32_t FlushCache(const BufferHandle& handle) const = 0;
virtual int32_t InvalidateCache(const BufferHandle& handle) const = 0;
virtual int32_t IsSupportedAlloc(
const std::vector<VerifyAllocInfo>& infos, std::vector<bool>& supporteds) const = 0;
virtual int32_t RegisterBuffer(const BufferHandle& handle)
{
return 0;
}
virtual int32_t SetMetadata(const BufferHandle& handle, uint32_t key, const std::vector<uint8_t>& value)
{
return 0;
}
virtual int32_t GetMetadata(const BufferHandle& handle, uint32_t key, std::vector<uint8_t>& value)
{
return 0;
}
virtual int32_t ListMetadataKeys(const BufferHandle& handle, std::vector<uint32_t>& keys)
{
return 0;
}
virtual int32_t EraseMetadataKey(const BufferHandle& handle, uint32_t key)
{
return 0;
}
virtual int32_t GetImageLayout(const BufferHandle& handle, V1_2::ImageLayout& layout) const
{
return 0;
}
};
using CreateDisplayBufferVdiFunc = IDisplayBufferVdi* (*)();
using DestroyDisplayBufferVdiFunc = void (*)(IDisplayBufferVdi* vdi);
extern "C" IDisplayBufferVdi* CreateDisplayBufferVdi();
extern "C" void DestroyDisplayBufferVdi(IDisplayBufferVdi* vdi);
4.2.2 实现
IDisplayBufferVdi接口的实现:
参考drivers/peripheral/display/hal/default_standard/src/display_gralloc标准实现,编译生成libdisplay_buffer_vdi_impl.z.so
libdisplay_buffer_vdi_impl的gn文件示例,参考rk3568
# device/soc/rockchip/rk3568/hardware/display/BUILD.gn
ohos_shared_library("libdisplay_buffer_vdi_impl") {
sources = [ "src/display_gralloc/display_buffer_vdi_impl.cpp" ]
public_configs = [ ":libdisplay_buffer_vdi_impl_config" ]
include_dirs = [
"./src/display_gralloc",
"${root_path}/drivers/peripheral/base",
"${root_path}/drivers/interface/display/composer/hdifd_parcelable",
"${root_path}/drivers/interface/display/buffer",
"${root_path}/drivers/peripheral/display/utils/include",
"${root_path}/drivers/peripheral/display/buffer/hdi_service/include",
]
output_name = "libdisplay_buffer_vdi_impl"
cflags = [
"-DGRALLOC_GBM_SUPPORT",
"-Wno-macro-redefined",
]
deps = [ ":libdisplay_buffer_vendor" ]
external_deps = [
"c_utils:utils",
"drivers_interface_display:display_buffer_idl_headers",
"drivers_interface_display:display_composer_idl_headers",
"hdf_core:libhdf_utils",
"hilog:libhilog",
"ipc:ipc_single",
]
install_enable = true
install_images = [ chipset_base_dir ]
innerapi_tags = [ "passthrough" ]
subsystem_name = "hdf"
part_name = "rockchip_products"
}
参考实现已经实现IDisplayBufferVdi的相关流程,只需继承Allocator类实现Allocate()函数即可。
当前参考实现提供了FramebufferAllocator、DrmAllocator、DmaBufferHeadAllocator等实现,可以通过继承Allocator类并实现Allocate()函数,适配新的Allocator。
显示内存数据结构BufferHandle:
typedef struct {
int32_t fd; /**< buffer fd, -1 if not supported */
int32_t width; /**< the width of memory */
int32_t stride; /**< the stride of memory */
int32_t height; /**< the height of memory */
int32_t size; /* < size of memory */
int32_t format; /**< the format of memory */
uint64_t usage; /**< the usage of memory */
void *virAddr; /**< Virtual address of memory */
uint64_t phyAddr; /**< Physical address */
uint32_t reserveFds; /**< the number of reserved fd value */
uint32_t reserveInts; /**< the number of reserved integer value */
int32_t reserve[0]; /**< the data */
} BufferHandle;
DrmAllocator的参考实现如下:
int32_t DrmAllocator::Allocate(const BufferInfo &bufferInfo, BufferHandle &handle)
{
// 打开DRM设备文件
drmFd_ = open("/dev/dri/card0", O_RDWR);
// 用于放弃对DRM设备的主控权。在DRM中,主控权是指对设备的完全控制,包括模式设置、输出配置等。通常,只有拥有主控权的进程才能进行这些操作。
drmDropMaster(drmFd_);
// 创建DUMB buffer对象
// DUMB buffer只支持连续物理内存,基于kernel中通用的CMA API实现。
// Prime buffer是DRM中跨设备缓冲区的共享框架,基于dma-buf实现,可以是连续物理内存,也可以是离散的物理内存。
// DUMB buffer可以通过PRIME机制在不同进程中共享。
drmIoctl(drmFd_, DRM_IOCTL_MODE_CREATE_DUMB, &dumb);
// 将DRM PRIME handle 转换为文件描述符fd,可在不同的进程之间使用fd标识共享显示内存。
drmPrimeHandleToFD(drmFd_, dumb.handle, DRM_CLOEXEC | DRM_RDWR, &fd);
// hisi平台获取显示内存的物理地址
ioctl(drmFd_, DRM_IOCTL_HISILICON_GEM_FD_TO_PHYADDR, &args);
// 销毁DUMB buffer对象
drmIoctl(drmFd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destoryDumb)
}
更多推荐
所有评论(0)