Skip to content

Commit 569b20e

Browse files
committed
hal/vulkan: add OpenHarmony surface support
The Vulkan backend has no OpenHarmony window-system integration, so surface creation fails there and GLES is the only usable backend. That rules out anything needing `VERTEX_STORAGE` or compute, even though OpenHarmony devices ship a working Vulkan driver. `ash` generates no OpenHarmony bindings, so `vkCreateSurfaceOHOS` is resolved via `get_instance_proc_addr` and `VkSurfaceCreateInfoOHOS` is declared locally, matching the OpenHarmony SDK's `vulkan_ohos.h`. OpenHarmony is also excluded from the X11/Wayland extension list: it is unix and reports `target_os = "linux"`, but has neither. Surfaces are created from the `OHNativeWindow` an XComponent hands out, which `raw-window-handle` already exposes as `RawWindowHandle::OhosNdk` and the GLES backend already consumes. Tested on a HUAWEI MatePad Air (Maleoon 920, HarmonyOS 6.1): the Vulkan adapter is selected and storage-buffer/compute pipelines build, which the GLES backend could not do.
1 parent ef79a92 commit 569b20e

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Bottom level categories:
8585

8686
#### Vulkan
8787

88+
- Add OpenHarmony surface support via `VK_OHOS_surface`. Previously the Vulkan backend could not create a surface on OpenHarmony, leaving GLES as the only usable backend. By @ozongzi in [#9908](https://github.com/gfx-rs/wgpu/pull/9908).
8889
- Stop passing an un-waited fence to `vkAcquireNextImageKHR` on non-Windows platforms, which triggered `VUID-vkAcquireNextImageKHR-fence-10066` validation errors every frame since v30.0.0. By @ErichDonGubler in [#9855](https://github.com/gfx-rs/wgpu/issues/9855).
8990

9091
#### GLES

wgpu-hal/src/vulkan/instance.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ use arrayvec::ArrayVec;
1111
use ash::{ext, khr, vk};
1212
use parking_lot::RwLock;
1313

14+
/// Name of the `VK_OHOS_surface` extension.
15+
///
16+
/// `ash` does not generate OpenHarmony bindings, so this mirrors
17+
/// `VK_OHOS_SURFACE_EXTENSION_NAME` from the OpenHarmony SDK's `vulkan_ohos.h`.
18+
#[cfg(target_env = "ohos")]
19+
const OHOS_SURFACE_EXTENSION_NAME: &CStr = c"VK_OHOS_surface";
20+
1421
unsafe extern "system" fn debug_utils_messenger_callback(
1522
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
1623
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
@@ -309,10 +316,15 @@ impl super::Instance {
309316
extensions.push(khr::surface::NAME);
310317

311318
// Platform-specific WSI extensions
319+
//
320+
// Note: OpenHarmony (`target_env = "ohos"`) reports `target_os = "linux"` and is
321+
// unix, but has neither X11 nor Wayland. It must be excluded here and uses
322+
// `VK_OHOS_surface` instead (see below).
312323
if cfg!(all(
313324
unix,
314325
not(target_os = "android"),
315-
not(target_os = "macos")
326+
not(target_os = "macos"),
327+
not(target_env = "ohos")
316328
)) {
317329
// VK_KHR_xlib_surface
318330
extensions.push(khr::xlib_surface::NAME);
@@ -325,6 +337,11 @@ impl super::Instance {
325337
// VK_KHR_android_surface
326338
extensions.push(khr::android_surface::NAME);
327339
}
340+
#[cfg(target_env = "ohos")]
341+
{
342+
// VK_OHOS_surface: surfaces are created from an XComponent's `OHNativeWindow`.
343+
extensions.push(OHOS_SURFACE_EXTENSION_NAME);
344+
}
328345
if cfg!(target_os = "windows") {
329346
// VK_KHR_win32_surface
330347
extensions.push(khr::win32_surface::NAME);
@@ -570,6 +587,74 @@ impl super::Instance {
570587
Ok(self.create_surface_from_vk_surface_khr(surface, None))
571588
}
572589

590+
/// OpenHarmony window-system integration.
591+
///
592+
/// `ash` has no `VK_OHOS_surface` bindings, so the `vkCreateSurfaceOHOS` entry point is
593+
/// resolved manually and `VkSurfaceCreateInfoOHOS` is declared here, matching the
594+
/// OpenHarmony SDK's `vulkan_ohos.h` (`VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS`
595+
/// is 1000685000).
596+
///
597+
/// `window` is the `OHNativeWindow*` handed out by an XComponent.
598+
#[cfg(target_env = "ohos")]
599+
fn create_surface_ohos(
600+
&self,
601+
window: *mut c_void,
602+
) -> Result<super::Surface, crate::InstanceError> {
603+
if !self
604+
.shared
605+
.extensions
606+
.contains(&OHOS_SURFACE_EXTENSION_NAME)
607+
{
608+
return Err(crate::InstanceError::new(String::from(
609+
"Vulkan driver does not support VK_OHOS_surface",
610+
)));
611+
}
612+
613+
#[repr(C)]
614+
struct VkSurfaceCreateInfoOHOS {
615+
s_type: vk::StructureType,
616+
p_next: *const c_void,
617+
flags: vk::Flags,
618+
window: *mut c_void,
619+
}
620+
const S_TYPE_SURFACE_CREATE_INFO_OHOS: vk::StructureType =
621+
vk::StructureType::from_raw(1000685000);
622+
type PfnCreateSurfaceOHOS = unsafe extern "system" fn(
623+
vk::Instance,
624+
*const VkSurfaceCreateInfoOHOS,
625+
*const vk::AllocationCallbacks,
626+
*mut vk::SurfaceKHR,
627+
) -> vk::Result;
628+
629+
let raw_instance = self.shared.raw.handle();
630+
let Some(pfn) = (unsafe {
631+
self.shared
632+
.entry
633+
.get_instance_proc_addr(raw_instance, c"vkCreateSurfaceOHOS".as_ptr())
634+
}) else {
635+
return Err(crate::InstanceError::new(String::from(
636+
"vkCreateSurfaceOHOS not exposed by Vulkan driver",
637+
)));
638+
};
639+
let create: PfnCreateSurfaceOHOS = unsafe { core::mem::transmute(pfn) };
640+
641+
let info = VkSurfaceCreateInfoOHOS {
642+
s_type: S_TYPE_SURFACE_CREATE_INFO_OHOS,
643+
p_next: core::ptr::null(),
644+
flags: 0,
645+
window,
646+
};
647+
let mut surface = vk::SurfaceKHR::null();
648+
let result = unsafe { create(raw_instance, &info, core::ptr::null(), &mut surface) };
649+
if result != vk::Result::SUCCESS {
650+
return Err(crate::InstanceError::new(format!(
651+
"vkCreateSurfaceOHOS failed: {result:?}"
652+
)));
653+
}
654+
655+
Ok(self.create_surface_from_vk_surface_khr(surface, None))
656+
}
657+
573658
fn create_surface_from_hwnd(
574659
&self,
575660
hinstance: vk::HINSTANCE,
@@ -995,6 +1080,8 @@ impl crate::Instance for super::Instance {
9951080
(Rwh::AndroidNdk(handle), _) => {
9961081
self.create_surface_android(handle.a_native_window.as_ptr())
9971082
}
1083+
#[cfg(target_env = "ohos")]
1084+
(Rwh::OhosNdk(handle), _) => self.create_surface_ohos(handle.native_window.as_ptr()),
9981085
(Rwh::Win32(handle), _) => {
9991086
let hinstance = handle.hinstance.ok_or_else(|| {
10001087
crate::InstanceError::new(String::from(

0 commit comments

Comments
 (0)