2021-10-16 17:30:56 -07:00
|
|
|
const std = @import("std");
|
2021-10-16 14:47:55 -07:00
|
|
|
|
2021-10-16 17:30:56 -07:00
|
|
|
const c = @import("c.zig").c;
|
2021-10-18 20:43:57 -07:00
|
|
|
const Window = @import("Window.zig");
|
2021-10-16 17:30:56 -07:00
|
|
|
|
2021-11-21 19:30:58 +01:00
|
|
|
const internal_debug = @import("internal_debug.zig");
|
|
|
|
|
2022-06-11 15:45:30 -07:00
|
|
|
/// Sets the desired Vulkan `vkGetInstanceProcAddr` function.
|
|
|
|
///
|
|
|
|
/// This function sets the `vkGetInstanceProcAddr` function that GLFW will use for all
|
|
|
|
/// Vulkan related entry point queries.
|
|
|
|
///
|
|
|
|
/// This feature is mostly useful on macOS, if your copy of the Vulkan loader is in
|
|
|
|
/// a location where GLFW cannot find it through dynamic loading, or if you are still
|
|
|
|
/// using the static library version of the loader.
|
|
|
|
///
|
|
|
|
/// If set to `NULL`, GLFW will try to load the Vulkan loader dynamically by its standard
|
|
|
|
/// name and get this function from there. This is the default behavior.
|
|
|
|
///
|
|
|
|
/// The standard name of the loader is `vulkan-1.dll` on Windows, `libvulkan.so.1` on
|
|
|
|
/// Linux and other Unix-like systems and `libvulkan.1.dylib` on macOS. If your code is
|
|
|
|
/// also loading it via these names then you probably don't need to use this function.
|
|
|
|
///
|
|
|
|
/// The function address you set is never reset by GLFW, but it only takes effect during
|
|
|
|
/// initialization. Once GLFW has been initialized, any updates will be ignored until the
|
|
|
|
/// library is terminated and initialized again.
|
|
|
|
///
|
|
|
|
/// remark: This function may be called before glfw.Init.
|
|
|
|
///
|
|
|
|
/// thread_safety: This function must only be called from the main thread.
|
|
|
|
pub fn initVulkanLoader(loader_function: ?VKGetInstanceProcAddr) void {
|
|
|
|
c.glfwInitVulkanLoader(loader_function orelse null);
|
|
|
|
}
|
|
|
|
|
2022-09-10 00:04:36 -07:00
|
|
|
pub const VKGetInstanceProcAddr = *const fn (vk_instance: c.VkInstance, name: [*c]const u8) callconv(.C) ?VKProc;
|
2022-06-11 15:45:30 -07:00
|
|
|
|
2021-10-16 17:34:16 -07:00
|
|
|
/// Returns whether the Vulkan loader and an ICD have been found.
|
|
|
|
///
|
|
|
|
/// This function returns whether the Vulkan loader and any minimally functional ICD have been
|
|
|
|
/// found.
|
|
|
|
///
|
|
|
|
/// The availability of a Vulkan loader and even an ICD does not by itself guarantee that surface
|
2021-12-23 17:47:56 +05:30
|
|
|
/// creation or even instance creation is possible. Call glfw.getRequiredInstanceExtensions
|
2021-10-16 17:34:16 -07:00
|
|
|
/// to check whether the extensions necessary for Vulkan surface creation are available and
|
|
|
|
/// glfw.getPhysicalDevicePresentationSupport to check whether a queue family of a physical device
|
|
|
|
/// supports image presentation.
|
|
|
|
///
|
|
|
|
/// @return `true` if Vulkan is minimally available, or `false` otherwise.
|
|
|
|
///
|
|
|
|
/// @thread_safety This function may be called from any thread.
|
2021-11-22 20:21:46 +01:00
|
|
|
pub inline fn vulkanSupported() bool {
|
2021-11-21 19:30:58 +01:00
|
|
|
internal_debug.assertInitialized();
|
2021-10-16 17:34:16 -07:00
|
|
|
const supported = c.glfwVulkanSupported();
|
|
|
|
return supported == c.GLFW_TRUE;
|
|
|
|
}
|
2021-10-16 14:47:55 -07:00
|
|
|
|
2021-10-18 20:08:46 -07:00
|
|
|
/// Returns the Vulkan instance extensions required by GLFW.
|
|
|
|
///
|
|
|
|
/// This function returns an array of names of Vulkan instance extensions required by GLFW for
|
|
|
|
/// creating Vulkan surfaces for GLFW windows. If successful, the list will always contain
|
|
|
|
/// `VK_KHR_surface`, so if you don't require any additional extensions you can pass this list
|
|
|
|
/// directly to the `VkInstanceCreateInfo` struct.
|
|
|
|
///
|
|
|
|
/// If Vulkan is not available on the machine, this function returns null and generates a
|
2023-01-10 23:25:00 +00:00
|
|
|
/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
|
|
|
|
/// least minimally available.
|
2021-10-18 20:08:46 -07:00
|
|
|
///
|
|
|
|
/// If Vulkan is available but no set of extensions allowing window surface creation was found,
|
|
|
|
/// this function returns null. You may still use Vulkan for off-screen rendering and compute work.
|
|
|
|
///
|
2023-01-10 23:25:00 +00:00
|
|
|
/// Possible errors include glfw.ErrorCode.APIUnavailable.
|
2022-12-27 04:20:16 -07:00
|
|
|
/// Returns null in the event of an error.
|
2021-10-18 20:08:46 -07:00
|
|
|
///
|
|
|
|
/// Additional extensions may be required by future versions of GLFW. You should check if any
|
|
|
|
/// extensions you wish to enable are already in the returned array, as it is an error to specify
|
|
|
|
/// an extension more than once in the `VkInstanceCreateInfo` struct.
|
|
|
|
///
|
|
|
|
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
|
|
|
|
/// yourself. It is guaranteed to be valid only until the library is terminated.
|
|
|
|
///
|
|
|
|
/// @thread_safety This function may be called from any thread.
|
|
|
|
///
|
|
|
|
/// see also: vulkan_ext, glfwCreateWindowSurface
|
2022-12-27 04:20:16 -07:00
|
|
|
pub inline fn getRequiredInstanceExtensions() ?[][*:0]const u8 {
|
2021-11-21 19:30:58 +01:00
|
|
|
internal_debug.assertInitialized();
|
2021-10-18 20:08:46 -07:00
|
|
|
var count: u32 = 0;
|
2022-02-08 01:49:22 +00:00
|
|
|
if (c.glfwGetRequiredInstanceExtensions(&count)) |extensions| return @ptrCast([*][*:0]const u8, extensions)[0..count];
|
2022-12-27 04:20:16 -07:00
|
|
|
return null;
|
2021-10-18 20:08:46 -07:00
|
|
|
}
|
2021-10-16 14:47:55 -07:00
|
|
|
|
2021-10-16 17:30:56 -07:00
|
|
|
/// Vulkan API function pointer type.
|
|
|
|
///
|
|
|
|
/// Generic function pointer used for returning Vulkan API function pointers.
|
|
|
|
///
|
|
|
|
/// see also: vulkan_proc, glfw.getInstanceProcAddress
|
2022-09-10 00:04:36 -07:00
|
|
|
pub const VKProc = *const fn () callconv(.C) void;
|
2021-10-16 17:30:56 -07:00
|
|
|
|
|
|
|
/// Returns the address of the specified Vulkan instance function.
|
|
|
|
///
|
|
|
|
/// This function returns the address of the specified Vulkan core or extension function for the
|
|
|
|
/// specified instance. If instance is set to null it can return any function exported from the
|
|
|
|
/// Vulkan loader, including at least the following functions:
|
|
|
|
///
|
|
|
|
/// - `vkEnumerateInstanceExtensionProperties`
|
|
|
|
/// - `vkEnumerateInstanceLayerProperties`
|
|
|
|
/// - `vkCreateInstance`
|
|
|
|
/// - `vkGetInstanceProcAddr`
|
|
|
|
///
|
|
|
|
/// If Vulkan is not available on the machine, this function returns null and generates a
|
2023-01-10 23:25:00 +00:00
|
|
|
/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
|
|
|
|
/// least minimally available.
|
2021-10-16 17:30:56 -07:00
|
|
|
///
|
|
|
|
/// This function is equivalent to calling `vkGetInstanceProcAddr` with a platform-specific query
|
|
|
|
/// of the Vulkan loader as a fallback.
|
|
|
|
///
|
|
|
|
/// @param[in] instance The Vulkan instance to query, or null to retrieve functions related to
|
|
|
|
/// instance creation.
|
|
|
|
/// @param[in] procname The ASCII encoded name of the function.
|
|
|
|
/// @return The address of the function, or null if an error occurred.
|
|
|
|
///
|
2021-10-29 16:08:56 -07:00
|
|
|
/// To maintain ABI compatability with the C glfwGetInstanceProcAddress, as it is commonly passed
|
|
|
|
/// into libraries expecting that exact ABI, this function does not return an error. Instead, if
|
2023-01-10 23:25:00 +00:00
|
|
|
/// glfw.ErrorCode.NotInitialized or glfw.ErrorCode.APIUnavailable would occur this function will panic.
|
2021-10-29 16:08:56 -07:00
|
|
|
/// You may check glfw.vulkanSupported prior to invoking this function.
|
2021-10-16 17:30:56 -07:00
|
|
|
///
|
|
|
|
/// @pointer_lifetime The returned function pointer is valid until the library is terminated.
|
|
|
|
///
|
|
|
|
/// @thread_safety This function may be called from any thread.
|
2022-01-10 22:55:10 +01:00
|
|
|
pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8) callconv(.C) ?VKProc {
|
2021-11-22 13:11:54 +01:00
|
|
|
internal_debug.assertInitialized();
|
2022-02-08 01:49:22 +00:00
|
|
|
if (c.glfwGetInstanceProcAddress(if (vk_instance) |v| @ptrCast(c.VkInstance, v) else null, proc_name)) |proc_address| return proc_address;
|
2021-10-16 17:30:56 -07:00
|
|
|
return null;
|
|
|
|
}
|
2021-10-16 14:47:55 -07:00
|
|
|
|
2021-10-18 20:11:27 -07:00
|
|
|
/// Returns whether the specified queue family can present images.
|
|
|
|
///
|
|
|
|
/// This function returns whether the specified queue family of the specified physical device
|
|
|
|
/// supports presentation to the platform GLFW was built for.
|
|
|
|
///
|
|
|
|
/// If Vulkan or the required window surface creation instance extensions are not available on the
|
|
|
|
/// machine, or if the specified instance was not created with the required extensions, this
|
2023-01-10 23:25:00 +00:00
|
|
|
/// function returns `GLFW_FALSE` and generates a glfw.ErrorCode.APIUnavailable error. Call
|
2021-10-18 20:11:27 -07:00
|
|
|
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available and
|
|
|
|
/// glfw.getRequiredInstanceExtensions to check what instance extensions are required.
|
|
|
|
///
|
|
|
|
/// @param[in] instance The instance that the physical device belongs to.
|
|
|
|
/// @param[in] device The physical device that the queue family belongs to.
|
|
|
|
/// @param[in] queuefamily The index of the queue family to query.
|
2021-10-18 20:43:57 -07:00
|
|
|
/// @return `true` if the queue family supports presentation, or `false` otherwise.
|
2021-10-18 20:11:27 -07:00
|
|
|
///
|
2023-01-10 23:25:00 +00:00
|
|
|
/// Possible errors include glfw.ErrorCode.APIUnavailable and glfw.ErrorCode.PlatformError.
|
2022-12-27 04:20:16 -07:00
|
|
|
/// Returns false in the event of an error.
|
2021-10-18 20:11:27 -07:00
|
|
|
///
|
2021-12-23 17:47:56 +05:30
|
|
|
/// macos: This function currently always returns `true`, as the `VK_MVK_macos_surface` and
|
|
|
|
/// 'VK_EXT_metal_surface' extension does not provide a `vkGetPhysicalDevice*PresentationSupport` type function.
|
2021-10-18 20:11:27 -07:00
|
|
|
///
|
|
|
|
/// @thread_safety This function may be called from any thread. For synchronization details of
|
|
|
|
/// Vulkan objects, see the Vulkan specification.
|
|
|
|
///
|
|
|
|
/// see also: vulkan_present
|
2021-12-07 05:52:15 +01:00
|
|
|
pub inline fn getPhysicalDevicePresentationSupport(
|
2022-01-12 18:51:48 +01:00
|
|
|
vk_instance: *anyopaque,
|
|
|
|
vk_physical_device: *anyopaque,
|
2021-12-07 05:52:15 +01:00
|
|
|
queue_family: u32,
|
2022-12-27 04:20:16 -07:00
|
|
|
) bool {
|
2021-11-21 19:30:58 +01:00
|
|
|
internal_debug.assertInitialized();
|
2022-12-27 04:20:16 -07:00
|
|
|
return c.glfwGetPhysicalDevicePresentationSupport(
|
2021-10-18 20:43:57 -07:00
|
|
|
@ptrCast(c.VkInstance, vk_instance),
|
2022-06-24 13:10:06 -04:00
|
|
|
@ptrCast(c.VkPhysicalDevice, vk_physical_device),
|
2021-10-18 20:43:57 -07:00
|
|
|
queue_family,
|
2022-12-27 04:20:16 -07:00
|
|
|
) == c.GLFW_TRUE;
|
2021-10-18 20:11:27 -07:00
|
|
|
}
|
2021-10-16 14:47:55 -07:00
|
|
|
|
2021-10-18 20:43:57 -07:00
|
|
|
/// Creates a Vulkan surface for the specified window.
|
|
|
|
///
|
|
|
|
/// This function creates a Vulkan surface for the specified window.
|
|
|
|
///
|
|
|
|
/// If the Vulkan loader or at least one minimally functional ICD were not found, this function
|
2023-01-10 23:25:00 +00:00
|
|
|
/// returns `VK_ERROR_INITIALIZATION_FAILED` and generates a glfw.ErrorCode.APIUnavailable error. Call
|
2021-10-18 20:43:57 -07:00
|
|
|
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available.
|
|
|
|
///
|
|
|
|
/// If the required window surface creation instance extensions are not available or if the
|
|
|
|
/// specified instance was not created with these extensions enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT`
|
2023-01-10 23:25:00 +00:00
|
|
|
/// and generates a glfw.ErrorCode.APIUnavailable error. Call glfw.getRequiredInstanceExtensions to
|
2021-10-18 20:43:57 -07:00
|
|
|
/// check what instance extensions are required.
|
|
|
|
///
|
|
|
|
/// The window surface cannot be shared with another API so the window must have been created with
|
2023-01-10 23:25:00 +00:00
|
|
|
/// the client api hint set to `GLFW_NO_API` otherwise it generates a glfw.ErrorCode.InvalidValue error
|
2021-10-18 20:43:57 -07:00
|
|
|
/// and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`.
|
|
|
|
///
|
|
|
|
/// The window surface must be destroyed before the specified Vulkan instance. It is the
|
|
|
|
/// responsibility of the caller to destroy the window surface. GLFW does not destroy it for you.
|
|
|
|
/// Call `vkDestroySurfaceKHR` to destroy the surface.
|
|
|
|
///
|
|
|
|
/// @param[in] vk_instance The Vulkan instance to create the surface in.
|
|
|
|
/// @param[in] window The window to create the surface for.
|
|
|
|
/// @param[in] vk_allocation_callbacks The allocator to use, or null to use the default
|
|
|
|
/// allocator.
|
|
|
|
/// @param[out] surface Where to store the handle of the surface. This is set
|
|
|
|
/// to `VK_NULL_HANDLE` if an error occurred.
|
|
|
|
/// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an
|
|
|
|
/// error occurred.
|
|
|
|
///
|
2023-01-10 23:25:00 +00:00
|
|
|
/// Possible errors include glfw.ErrorCode.APIUnavailable, glfw.ErrorCode.PlatformError and glfw.ErrorCode.InvalidValue
|
2022-12-27 04:20:16 -07:00
|
|
|
/// Returns a bool indicating success.
|
2021-10-18 20:43:57 -07:00
|
|
|
///
|
|
|
|
/// If an error occurs before the creation call is made, GLFW returns the Vulkan error code most
|
|
|
|
/// appropriate for the error. Appropriate use of glfw.vulkanSupported and glfw.getRequiredInstanceExtensions
|
|
|
|
/// should eliminate almost all occurrences of these errors.
|
|
|
|
///
|
2022-06-11 15:45:30 -07:00
|
|
|
/// macos: GLFW prefers the `VK_EXT_metal_surface` extension, with the `VK_MVK_macos_surface`
|
|
|
|
/// extension as a fallback. The name of the selected extension, if any, is included in the array
|
|
|
|
/// returned by glfw.getRequiredInstanceExtensions.
|
|
|
|
///
|
2021-10-18 20:43:57 -07:00
|
|
|
/// macos: This function currently only supports the `VK_MVK_macos_surface` extension from MoltenVK.
|
|
|
|
///
|
|
|
|
/// macos: This function creates and sets a `CAMetalLayer` instance for the window content view,
|
|
|
|
/// which is required for MoltenVK to function.
|
|
|
|
///
|
2022-06-11 15:45:30 -07:00
|
|
|
/// x11: By default GLFW prefers the `VK_KHR_xcb_surface` extension, with the `VK_KHR_xlib_surface`
|
|
|
|
/// extension as a fallback. You can make `VK_KHR_xlib_surface` the preferred extension by setting
|
|
|
|
/// glfw.InitHints.x11_xcb_vulkan_surface. The name of the selected extension, if any, is included
|
|
|
|
/// in the array returned by glfw.getRequiredInstanceExtensions.
|
|
|
|
///
|
2021-10-18 20:43:57 -07:00
|
|
|
/// @thread_safety This function may be called from any thread. For synchronization details of
|
|
|
|
/// Vulkan objects, see the Vulkan specification.
|
|
|
|
///
|
|
|
|
/// see also: vulkan_surface, glfw.getRequiredInstanceExtensions
|
2022-12-27 04:20:16 -07:00
|
|
|
pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) i32 {
|
2021-11-21 19:30:58 +01:00
|
|
|
internal_debug.assertInitialized();
|
2021-10-31 01:00:02 -07:00
|
|
|
// zig-vulkan uses enums to represent opaque pointers:
|
|
|
|
// pub const Instance = enum(usize) { null_handle = 0, _ };
|
|
|
|
const instance: c.VkInstance = switch (@typeInfo(@TypeOf(vk_instance))) {
|
2023-06-25 00:01:55 -07:00
|
|
|
.Enum => @ptrFromInt(c.VkInstance, @intFromEnum(vk_instance)),
|
2021-10-31 01:00:02 -07:00
|
|
|
else => @ptrCast(c.VkInstance, vk_instance),
|
|
|
|
};
|
|
|
|
|
2023-03-02 02:33:17 +01:00
|
|
|
return c.glfwCreateWindowSurface(
|
2021-10-31 01:00:02 -07:00
|
|
|
instance,
|
2021-10-18 20:43:57 -07:00
|
|
|
window.handle,
|
2021-11-29 19:41:48 +00:00
|
|
|
if (vk_allocation_callbacks == null) null else @ptrCast(*const c.VkAllocationCallbacks, @alignCast(@alignOf(c.VkAllocationCallbacks), vk_allocation_callbacks)),
|
|
|
|
@ptrCast(*c.VkSurfaceKHR, @alignCast(@alignOf(c.VkSurfaceKHR), vk_surface_khr)),
|
2023-03-02 02:33:17 +01:00
|
|
|
);
|
2021-10-18 20:43:57 -07:00
|
|
|
}
|
2021-10-16 17:30:56 -07:00
|
|
|
|
2021-10-16 17:34:16 -07:00
|
|
|
test "vulkanSupported" {
|
|
|
|
const glfw = @import("main.zig");
|
2023-01-10 23:25:00 +00:00
|
|
|
defer glfw.clearError(); // clear any error we generate
|
2022-12-27 04:20:16 -07:00
|
|
|
if (!glfw.init(.{})) {
|
|
|
|
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
|
|
|
std.process.exit(1);
|
|
|
|
}
|
2021-10-16 17:34:16 -07:00
|
|
|
defer glfw.terminate();
|
|
|
|
|
2021-11-22 20:21:46 +01:00
|
|
|
_ = glfw.vulkanSupported();
|
2021-10-16 17:34:16 -07:00
|
|
|
}
|
|
|
|
|
2021-10-18 20:08:46 -07:00
|
|
|
test "getRequiredInstanceExtensions" {
|
|
|
|
const glfw = @import("main.zig");
|
2023-01-10 23:25:00 +00:00
|
|
|
defer glfw.clearError(); // clear any error we generate
|
2022-12-27 04:20:16 -07:00
|
|
|
if (!glfw.init(.{})) {
|
|
|
|
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
|
|
|
std.process.exit(1);
|
|
|
|
}
|
2021-10-18 20:08:46 -07:00
|
|
|
defer glfw.terminate();
|
|
|
|
|
2022-12-27 04:20:16 -07:00
|
|
|
_ = glfw.getRequiredInstanceExtensions();
|
2021-10-18 20:08:46 -07:00
|
|
|
}
|
|
|
|
|
2021-10-16 17:30:56 -07:00
|
|
|
test "getInstanceProcAddress" {
|
|
|
|
const glfw = @import("main.zig");
|
2023-01-10 23:25:00 +00:00
|
|
|
defer glfw.clearError(); // clear any error we generate
|
2022-12-27 04:20:16 -07:00
|
|
|
if (!glfw.init(.{})) {
|
|
|
|
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
|
|
|
std.process.exit(1);
|
|
|
|
}
|
2021-10-16 17:30:56 -07:00
|
|
|
defer glfw.terminate();
|
|
|
|
|
2021-10-29 16:08:56 -07:00
|
|
|
// syntax check only, we don't have a real vulkan instance and so this function would panic.
|
|
|
|
_ = glfw.getInstanceProcAddress;
|
2021-10-16 17:30:56 -07:00
|
|
|
}
|
2021-10-18 20:43:57 -07:00
|
|
|
|
|
|
|
test "syntax" {
|
|
|
|
// Best we can do for these two functions in terms of testing in lieu of an actual Vulkan
|
|
|
|
// context.
|
|
|
|
_ = getPhysicalDevicePresentationSupport;
|
|
|
|
_ = createWindowSurface;
|
2022-06-11 15:45:30 -07:00
|
|
|
_ = initVulkanLoader;
|
2021-10-18 20:43:57 -07:00
|
|
|
}
|