From 56da8763ec87029772120a4e361d5f5c32b54101 Mon Sep 17 00:00:00 2001 From: shegangbin Date: Tue, 28 Mar 2023 20:20:14 +0800 Subject: [PATCH] update readme Signed-off-by: shegangbin --- README_OpenHarmony.md | 145 ++++++++++++++++++ README_zh.md | 126 --------------- .../imgs/vulkan-loader_location_in_OH.png | Bin 0 -> 17363 bytes 3 files changed, 145 insertions(+), 126 deletions(-) create mode 100644 README_OpenHarmony.md delete mode 100644 README_zh.md create mode 100644 openharmony/imgs/vulkan-loader_location_in_OH.png diff --git a/README_OpenHarmony.md b/README_OpenHarmony.md new file mode 100644 index 00000000..8997b2c1 --- /dev/null +++ b/README_OpenHarmony.md @@ -0,0 +1,145 @@ +# Vulkan-Loader + +本仓库包含开源软件Vulkan-Loader,为OpenHarmony提供对Vulkan的支持能力。 + +Vulkan是一个跨平台的2D和3D绘图应用程序接口(API)。它的API分为核心API、窗口系统集成(WSI)扩展API以及其他扩展API。 + +核心API由GPU驱动实现,窗口系统集成(WSI)扩展API由[swapchain_layer](#swapchain_layer)实现,swapchain_layer是OpenHarmony平台是实现的一个Vulkan Layer,安装在`/system/lib[64]/libvulkan_swapchain.so`中。Vulkan Layer属于增强Vulkan开发环境的扩展功能,被实现为动态链接库(.so文件)。 + +Vulkan-Loader会加载这些API的实现并对外提供这些接口给应用开发者使用。Vulkan-Loader安装在`/system/lib[64]/libvulkan.so`中。 + +Vulkan-Loader主要功能概括如下: + +1、加载GPU驱动。 + +2、加载Vulkan Layer。 + +3、提供Vulkan NDK接口。 + +![vulkan-loader_location_in_OH](openharmony/imgs/vulkan-loader_location_in_OH.png) + + +## 加载GPU驱动 + +在OpenHarmony上,Vulkan-Loader会扫描指定路径下的GPU驱动的**json清单文件**并读取该文件加载GPU驱动。 + +### 指定的扫描路径 + +``` +/vendor/etc/vulkan/icd.d/ +/system/etc/vulkan/icd.d/ +/data/vulkan/icd.d/ +``` +建议:GPU驱动的json清单文件应放在`/vendor/etc/vulkan/icd.d/`目录中。 + +Vulkan-Loader会根据GPU驱动的**json清单文件**中配置的`library_path`找到GPU驱动的动态链接库文件(.so文件)并加载。 + +### GPU驱动的json清单文件示例 + +```json +{ + "file_format_version": "1.0.1", + "ICD": { + "library_path": "path to driver library", + "api_version": "1.2.205", + "library_arch" : "64", + "is_portability_driver": false + } +} +``` + +详细介绍请见:[Driver Manifest File Format](docs/LoaderDriverInterface.md#driver-manifest-file-format) + +### GPU驱动的实现 + +GPU驱动需要实现的Vulkan接口请参考文档:[LoaderDriverInterface](docs/LoaderDriverInterface.md),开发者需要按照文档里的要求实现对应的接口才能够被Vulkan-Loader正确加载。 + + +## 加载Vulkan Layer + +Vulkan Layer属于增强Vulkan开发环境的扩展功能,可以由开发人员启用或关闭。启用和关闭Vulkan Layer的方式有很多,可以通过环境变量、配置文件、或者代码来开启和关闭指定的Layer。 + +在OpenHarmony上,Vulkan-Loader通过读取指定路径下的Layer的**json清单文件**加载Vulkan Layer。 + +### 指定的扫描路径 + +``` +/system/etc/vulkan/implicit_layer.d/ +/system/etc/vulkan/explicit_layer.d/ +/data/vulkan/implicit_layer.d/ +/data/vulkan/explicit_layer.d/ +``` + +默认加载的layer的json文件应放在`xxx/implicit_layer.d/`下。 +需要显式加载的layer的json文件应放在`xxx/explicit_layer.d/`下,不会被Vulkan-Loader默认加载。 + +### Vulkan Layer的json清单文件示例 + +下面给出[swapchain_layer](#swapchain_layer)的json清单文件示例: + +```json +{ + "file_format_version" : "1.0.0", + "layer" : { + "name": "VK_LAYER_OpenHarmony_OHOS_surface", + "type": "GLOBAL", + "library_path": "libvulkan_swapchain.so", + "api_version": "1.3.231", + "implementation_version": "1", + "description": "Vulkan Swapchain", + "disable_environment": { + "DISABLE_OPENHARMONY_SWAPCHAIN_LAYER": "1" + }, + "instance_extensions": [ + { "name": "VK_KHR_surface", "spec_version": "25" }, + { "name": "VK_OpenHarmony_OHOS_surface", "spec_version": "1" } + ], + "device_extensions": [ + { "name": "VK_KHR_swapchain", "spec_version": "70" } + ] + } +} +``` + +详细介绍请见:[Layer Manifest File Format](docs/LoaderLayerInterface.md#layer-manifest-file-format) + +### Vulkan Layer的实现 + +Vulkan Layer需要实现的Vulkan接口请参考文档:[LoaderLayerInterface](docs/LoaderLayerInterface.md),开发者需要按照文档里的要求实现对应的接口才能够被Vulkan-Loader正确加载。 + +### swapchain_layer + +swapchain_layer是实现Vulkan-Loader与OpenHarmony平台本地窗口(OHNativeWindow)对接的模块,作为一个隐式加载的Vulkan Layer使用。 + +代码地址:[swapchain_layer](https://gitee.com/openharmony/graphic_graphic_2d/tree/master/frameworks/vulkan_layers/swapchain_layer) + + +## Vulkan NDK + +在OpenHarmony上,Vulkan-Loader会提供Vulkan NDK接口,应用层软件(如:图形引擎、XComponent NAPI等)和系统层图形绘制模块(如:Skia)可以调用这些NDK接口。 + + +## 构建指导 + +适配OpenHarmony平台的编译脚本请见:[openharmony/BUILD.gn](openharmony/BUILD.gn) + +由于graphic_standard模块的编译脚本中包含了Vulkan-Loader(详见:[bundle.json](https://gitee.com/openharmony/graphic_graphic_2d/blob/master/bundle.json)),所以编译graphic_standard模块可以将Vulkan-Loader同时编译出来,以rk3568平台为例,编译命令: + +```shell +./build.sh --product-name rk3568 --ccache --build-target graphic_standard +``` + +也可以单独编译Vulkan-Loader: + +```shell +./build.sh --product-name rk3568 --ccache --build-target vulkan_loader +``` + +编译完成后会在`out/rk3568/graphic/graphic_standard`目录下生成`libvulkan.so` + + +## License + +Apache License 2.0 + +见 [LICENSE](LICENSE.txt). \ No newline at end of file diff --git a/README_zh.md b/README_zh.md deleted file mode 100644 index c04dd22d..00000000 --- a/README_zh.md +++ /dev/null @@ -1,126 +0,0 @@ -# 一、Vulkan介绍 - -Vulkan 是一个适用于高性能 3D 图形设备的低开销、跨平台 API。与 OpenGL ES (GLES) 一样,Vulkan 提供用于在应用中创建高品质实时图形的工具。与OpenGL ES相比使用 Vulkan 的优势明显,Vulkan可以大大降低 CPU 开销,另外Vulkan支持 SPIR-V 二进制Shader语言。 - - -# 二、Vulkan-Loader - -![High Level View of Loader](docs/images/high_level_loader.png) - -Vulkan-Loader处于应用程序和GPU驱动之间,负责加载GPU驱动提供给应用开发者使用,Vulkan-Loader作为Vulkan技术的系统级支持,主要功能如下: - -1、系统上支持一个或多个支持 Vulkan 的驱动程序,而不会相互干扰。 - -2、支持 Vulkan Layers,Vulkan Layer作为可选模块,可以由应用程序、开发人员或标准系统设置启用。 - -## 1、Vulkan-Loader官方文档 - -[LoaderInterfaceArchitecture.md](docs/LoaderInterfaceArchitecture.md) - -[LoaderApplicationInterface.md](docs/LoaderApplicationInterface.md) - -[LoaderDriverInterface.md](docs/LoaderDriverInterface.md) - -[LoaderLayerInterface.md](docs/LoaderLayerInterface.md) - - -## 2、驱动程序和Vulkan Layer的扫描与加载 - -Vulkan-Loader加载驱动程序和Vulkan Layer都是通过配置json清单文件的方式。 - -json清单文件应放在以下三个目录下,否则无法识别 - -`/system/etc/` - -`/vendor/etc/` - -`/data/` - -### 1) 驱动程序 - -驱动的json清单文件需要放在上述三个目录下的`vulkan/icd.d/`目录下,否则无法识别。 - -驱动json清单文件示例 - -```json -{ - "file_format_version": "1.0.1", - "ICD": { - "library_path": "path to driver library", - "api_version": "1.2.205", - "library_arch" : "64", - "is_portability_driver": false - } -} -``` - -详见[Driver Manifest File Format](docs/LoaderDriverInterface.md#driver-manifest-file-format) - -### 2) Vulkan Layer - -Vulkan Layer的json清单文件需要放在上述三个目录下的`vulkan/implicit_layer.d/`和`vulkan/explicit_layer.d/`目录下,否则无法识别。 - -`vulkan/implicit_layer.d/`目录下的Layer会被Vulkan-Loader默认加载,`vulkan/explicit_layer.d/`目录下的Layer不会被默认加载,需要主动开启。 - -下面给出[swapchain_layer](#swapchain_layer)的json清单文件示例 - -```json -{ - "file_format_version" : "1.0.0", - "layer" : { - "name": "VK_LAYER_OpenHarmony_OHOS_surface", - "type": "GLOBAL", - "library_path": "libvulkan_swapchain.so", - "api_version": "1.3.231", - "implementation_version": "1", - "description": "Vulkan Swapchain", - "disable_environment": { - "DISABLE_OPENHARMONY_SWAPCHAIN_LAYER": "1" - }, - "instance_extensions": [ - { "name": "VK_KHR_surface", "spec_version": "25" }, - { "name": "VK_OpenHarmony_OHOS_surface", "spec_version": "1" } - ], - "device_extensions": [ - { "name": "VK_KHR_swapchain", "spec_version": "70" } - ] - } -} -``` - -Vulkan Layer的json清单文件格式的详情请见[Layer Manifest File Format](docs/LoaderLayerInterface.md#layer-manifest-file-format) - -**建议:** 驱动的json清单文件放到`/vendor/etc/vulkan/icd.d/`目录下,Vulkan Layer的json清单文件放到`/system/etc/vulkan/implicit_layer.d/`和`/system/etc/vulkan/explicit_layer.d/`目录下。 - - -# 三、Vulkan API - -Vulkan-Loader当前支持的Vulkan API版本为v1.3.231,实际使用时支持的Vulkan API版本以GPU驱动的实现为准。 - -# 四、Window System Integration(WSI) - -## swapchain_layer - -swapchain_layer是实现Vulkan WSI(Window System Integration, 窗口系统集成) 与OpenHarmony平台本地窗口(OHNativeWindow)对接的模块,作为一个隐式加载的vulkan layer使用。 - -swapchain_layer实现了下面几个扩展: - -**VK_OpenHarmony_OHOS_surface 扩展** - -**VK_KHR_surface 扩展** - -**VK_KHR_swapchain 扩展** - -代码地址:[swapchain_layer](https://gitee.com/openharmony/graphic_graphic_2d/tree/master/frameworks/vulkan_layers/swapchain_layer) - -WSI 实现依赖**VK_OHOS_native_buffer 扩展**;此扩展仅由驱动开发者实现,仅WSI使用,WSI不会提供给应用。 - - -# 五、构建指导 - -参考[BUILD.md](BUILD.md) - - -# 六、License - -见 [LICENSE](LICENSE.txt). \ No newline at end of file diff --git a/openharmony/imgs/vulkan-loader_location_in_OH.png b/openharmony/imgs/vulkan-loader_location_in_OH.png new file mode 100644 index 0000000000000000000000000000000000000000..8cee4f76f7f1f55f440231a1a6fd989dd8b3b844 GIT binary patch literal 17363 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 literal 0 HcmV?d00001 -- Gitee