Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Bottom level categories:

#### Vulkan

- 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).
- 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).

#### GLES
Expand Down
106 changes: 105 additions & 1 deletion wgpu-hal/src/vulkan/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use arrayvec::ArrayVec;
use ash::{ext, khr, vk};
use parking_lot::RwLock;

/// Name of the `VK_OHOS_surface` extension. Used with [`create_surface_ohos`].
#[cfg(target_env = "ohos")]
const OHOS_SURFACE_EXTENSION_NAME: &CStr = c"VK_OHOS_surface";

unsafe extern "system" fn debug_utils_messenger_callback(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
Expand Down Expand Up @@ -312,7 +316,10 @@ impl super::Instance {
if cfg!(all(
unix,
not(target_os = "android"),
not(target_os = "macos")
not(target_os = "macos"),
// NOTE: OpenHarmony (`target_env = "ohos"`) reports `target_os = "linux"` and is
// unix, but has neither X11 nor Wayland.
not(target_env = "ohos")
)) {
// VK_KHR_xlib_surface
extensions.push(khr::xlib_surface::NAME);
Expand All @@ -325,6 +332,11 @@ impl super::Instance {
// VK_KHR_android_surface
extensions.push(khr::android_surface::NAME);
}
#[cfg(target_env = "ohos")]
{
// VK_OHOS_surface: surfaces are created from an XComponent's `OHNativeWindow`.
extensions.push(OHOS_SURFACE_EXTENSION_NAME);
}
if cfg!(target_os = "windows") {
// VK_KHR_win32_surface
extensions.push(khr::win32_surface::NAME);
Expand Down Expand Up @@ -570,6 +582,96 @@ impl super::Instance {
Ok(self.create_surface_from_vk_surface_khr(surface, None))
}

/// OpenHarmony window-system integration, using the `VK_OHOS_surface` extension.
///
/// `ash` has no bindings for this, so we create bindings ad-hoc as needed. See also:
///
/// - <https://docs.vulkan.org/refpages/latest/refpages/source/VK_OHOS_surface.html>
/// - [`vulkan_ohos.h`](https://github.com/KhronosGroup/Vulkan-Headers/blob/e3b1eec08173d6b825cd3ac88c885a63b621504a/include/vulkan/vulkan_ohos.h)
///
/// `window` is the `OHNativeWindow*` handed out by an XComponent.
#[cfg(target_env = "ohos")]
fn create_surface_ohos(
&self,
window: *mut c_void,
) -> Result<super::Surface, crate::InstanceError> {
// - Upstream docs:
// <https://docs.vulkan.org/refpages/latest/refpages/source/VkSurfaceCreateInfoOHOS.html>
#[repr(C)]
struct VkSurfaceCreateInfoOHOS {
s_type: vk::StructureType,
p_next: *const c_void,
flags: vk::Flags,
window: *mut c_void,
}

// - Upstream docs: Search for term `VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS` in
// <https://docs.vulkan.org/refpages/latest/refpages/source/VkStructureType.html>.
const S_TYPE_SURFACE_CREATE_INFO_OHOS: vk::StructureType =
vk::StructureType::from_raw(1000685000);

// - Upstream docs:
// <https://docs.vulkan.org/refpages/latest/refpages/source/vkCreateSurfaceOHOS.html>
type PfnCreateSurfaceOHOS = unsafe extern "system" fn(
vk::Instance,
*const VkSurfaceCreateInfoOHOS,
*const vk::AllocationCallbacks,
*mut vk::SurfaceKHR,
) -> vk::Result;
Comment thread
ErichDonGubler marked this conversation as resolved.

if !self
.shared
.extensions
.contains(&OHOS_SURFACE_EXTENSION_NAME)
{
return Err(crate::InstanceError::new(String::from(
"Vulkan driver does not support VK_OHOS_surface",
)));
}

let raw_instance = self.shared.raw.handle();

// SAFETY: This is safe because:
//
// - `raw_instance` is a valid Vulkan instance, and the string we're asking for is
// properly encoded and NUL-terminated.
let create = unsafe {
self.shared
.entry
.get_instance_proc_addr(raw_instance, c"vkCreateSurfaceOHOS".as_ptr())
};
let create =
// SAFETY: This function is safe, because we `transmute` between two function pointers
// with the same ABI, with the same validity, size, and alignment before and after.
unsafe { core::mem::transmute::<vk::PFN_vkVoidFunction, Option<PfnCreateSurfaceOHOS>>(create) };
let Some(create) = create else {
return Err(crate::InstanceError::new(String::from(
"vkCreateSurfaceOHOS not exposed by Vulkan driver",
)));
};

let info = VkSurfaceCreateInfoOHOS {
s_type: S_TYPE_SURFACE_CREATE_INFO_OHOS,
p_next: core::ptr::null(),
flags: 0,
window,
};
let mut surface = vk::SurfaceKHR::null();
// SAFETY: This is safe because:
//
// - This function signature is specced to match the signature we casted it to.
// - During the previous `transmute` operation, we took care to keep the same ABI (see also
// <https://doc.rust-lang.org/nightly/std/primitive.fn.html#abi-compatibility>).
let result = unsafe { create(raw_instance, &info, core::ptr::null(), &mut surface) };
if result != vk::Result::SUCCESS {
return Err(crate::InstanceError::new(format!(
"vkCreateSurfaceOHOS failed: {result:?}"
)));
}

Ok(self.create_surface_from_vk_surface_khr(surface, None))
}

fn create_surface_from_hwnd(
&self,
hinstance: vk::HINSTANCE,
Expand Down Expand Up @@ -995,6 +1097,8 @@ impl crate::Instance for super::Instance {
(Rwh::AndroidNdk(handle), _) => {
self.create_surface_android(handle.a_native_window.as_ptr())
}
#[cfg(target_env = "ohos")]
(Rwh::OhosNdk(handle), _) => self.create_surface_ohos(handle.native_window.as_ptr()),
(Rwh::Win32(handle), _) => {
let hinstance = handle.hinstance.ok_or_else(|| {
crate::InstanceError::new(String::from(
Expand Down
Loading