Vulkan Surface Development

When to Use

In OpenHarmony, the VK_OHOS_surface extension enables the creation of a VkSurfaceKHR, which connects to the OHNativeWindow module to implement the rotation of OHNativeBuffers for display purposes.

A VkSurfaceKHR instance is obtained through an OHNativeWindow, which is obtained from the XComponent. Therefore, the OHNativeWindow module must be used together with the XComponent and NativeWindow modules. For specific usage of the XComponent, see Custom Rendering (XComponent).

Available APIs

API Description
vkCreateSurfaceOHOS (VkInstance instance, const VkSurfaceCreateInfoOHOS* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) Creates a VkSurfaceKHR instance.

For details about the APIs, see Vulkan.

How to Develop

The following steps illustrate how to create a VkSurfaceKHR instance.

OpenHarmony Platform Macro

To use the extension, you must define the macro VK_USE_PLATFORM_OHOS in the CMakeLists.txt file.

ADD_DEFINITIONS(-DVK_USE_PLATFORM_OHOS=1)

Adding Dynamic Link Libraries

Add the Vulkan library and associated module libraries in the CMakeLists.txt file.

libvulkan.so
libace_ndk.z.so
libnative_window.so
libnative_image.so
libnative_buffer.so

NOTE

When the dlopen function is used to link the libvulkan.so dynamic library in a program, you do not need to add dependencies in CMake. Otherwise, symbol conflicts occur.

Including Header Files

#include <ace/xcomponent/native_interface_xcomponent.h>
#include <native_window/external_window.h>
#include <vulkan/vulkan.h>
  1. Create a Vulkan instance.

    VkInstance instance = VK_NULL_HANDLE;
    
    VkApplicationInfo appInfo = {};
    appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.pApplicationName = "vulkanExample";
    appInfo.pEngineName = "vulkanExample";
    appInfo.apiVersion = VK_API_VERSION_1_3;
    
    VkInstanceCreateInfo instanceCreateInfo = {};
    instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    instanceCreateInfo.pNext = NULL;
    instanceCreateInfo.pApplicationInfo = &appInfo;
    
    std::vector<const char *> instanceExtensions = {
        VK_KHR_SURFACE_EXTENSION_NAME,
        VK_OHOS_SURFACE_EXTENSION_NAME // Surface extension.
    };
    instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
    instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
    
    vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
    
  2. Obtain an OHNativeWindow instance.

    The OHNativeWindow instance is obtained from the XComponent. For details about how to use the XComponent, see Custom Rendering (XComponent).

    1. Add an XComponent to ets/pages/Index.ets.

      XComponent({
          id: 'xcomponentId',
          type: 'surface',
          libraryname: 'entry'
      })
      .margin({ bottom: 20 })
      .width(360)
      .height(360)
      
    2. Obtain an OHNativeWindow instance from the XComponent.

      // Callback function of the XComponent triggered when a surface is created.
      void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) {
          // You can obtain an OHNativeWindow instance from the callback function.
          OHNativeWindow *nativeWindow = static_cast<OHNativeWindow *>(window);
      }
      
      static napi_value Init(napi_env env, napi_value exports) {
          napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};
          napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
      
          napi_value exportInstance = nullptr;
          OH_NativeXComponent *nativeXComponent = nullptr;
          // Obtain a native XComponent.
          napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
          napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent));
          // Obtain the XComponent ID.
          char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
          uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
          OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
      
          // Declare an XComponent callback.
          OH_NativeXComponent_Callback callback;
          // Register the OnSurfaceCreated callback function.
          callback.OnSurfaceCreated = OnSurfaceCreatedCB;
          // Register the callback function for the native XComponent.
          OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback);
      
          return exports;
      }
      
  3. Create a VkSurfaceKHR instance.

    VkSurfaceKHR surface = VK_NULL_HANDLE;
    VkSurfaceCreateInfoOHOS surfaceCreateInfo = {};
    surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS;
    surfaceCreateInfo.window = nativeWindow; // nativeWindow is obtained from the OnSurfaceCreatedCB callback function in the previous step.
    int err = vkCreateSurfaceOHOS(instance, &surfaceCreateInfo, NULL, &surface);
    if (err != VK_SUCCESS) {
        // Creating the surface failed.
    }
    

Samples

The following sample is provided to help you better understand how to use Vulkan: