glfw: rework error handling system to prevent footguns
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
cf8922cc33
commit
abb1077052
12 changed files with 1136 additions and 1531 deletions
|
|
@ -49,13 +49,10 @@ pub const VKGetInstanceProcAddr = *const fn (vk_instance: c.VkInstance, name: [*
|
|||
///
|
||||
/// @return `true` if Vulkan is minimally available, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub inline fn vulkanSupported() bool {
|
||||
internal_debug.assertInitialized();
|
||||
const supported = c.glfwVulkanSupported();
|
||||
getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible
|
||||
return supported == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +70,8 @@ pub inline fn vulkanSupported() bool {
|
|||
/// 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.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.APIUnavailable.
|
||||
/// Possible errors include glfw.Error.APIUnavailable.
|
||||
/// Returns null in the event of an error.
|
||||
///
|
||||
/// 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
|
||||
|
|
@ -85,17 +83,11 @@ pub inline fn vulkanSupported() bool {
|
|||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: vulkan_ext, glfwCreateWindowSurface
|
||||
pub inline fn getRequiredInstanceExtensions() error{APIUnavailable}![][*:0]const u8 {
|
||||
pub inline fn getRequiredInstanceExtensions() ?[][*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
var count: u32 = 0;
|
||||
if (c.glfwGetRequiredInstanceExtensions(&count)) |extensions| return @ptrCast([*][*:0]const u8, extensions)[0..count];
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.APIUnavailable => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetRequiredInstanceExtensions` returns `null` only for errors
|
||||
unreachable;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Vulkan API function pointer type.
|
||||
|
|
@ -139,7 +131,6 @@ pub const VKProc = *const fn () callconv(.C) void;
|
|||
pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8) callconv(.C) ?VKProc {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetInstanceProcAddress(if (vk_instance) |v| @ptrCast(c.VkInstance, v) else null, proc_name)) |proc_address| return proc_address;
|
||||
getError() catch |err| @panic(@errorName(err));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +150,8 @@ pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8
|
|||
/// @param[in] queuefamily The index of the queue family to query.
|
||||
/// @return `true` if the queue family supports presentation, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.APIUnavailable and glfw.Error.PlatformError.
|
||||
/// Possible errors include glfw.Error.APIUnavailable and glfw.Error.PlatformError.
|
||||
/// Returns false in the event of an error.
|
||||
///
|
||||
/// 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.
|
||||
|
|
@ -172,19 +164,13 @@ pub inline fn getPhysicalDevicePresentationSupport(
|
|||
vk_instance: *anyopaque,
|
||||
vk_physical_device: *anyopaque,
|
||||
queue_family: u32,
|
||||
) error{ APIUnavailable, PlatformError }!bool {
|
||||
) bool {
|
||||
internal_debug.assertInitialized();
|
||||
const v = c.glfwGetPhysicalDevicePresentationSupport(
|
||||
return c.glfwGetPhysicalDevicePresentationSupport(
|
||||
@ptrCast(c.VkInstance, vk_instance),
|
||||
@ptrCast(c.VkPhysicalDevice, vk_physical_device),
|
||||
queue_family,
|
||||
);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.APIUnavailable, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return v == c.GLFW_TRUE;
|
||||
) == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Creates a Vulkan surface for the specified window.
|
||||
|
|
@ -217,7 +203,8 @@ pub inline fn getPhysicalDevicePresentationSupport(
|
|||
/// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an
|
||||
/// error occurred.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.APIUnavailable, glfw.Error.PlatformError and glfw.Error.InvalidValue
|
||||
/// Possible errors include glfw.Error.APIUnavailable, glfw.Error.PlatformError and glfw.Error.InvalidValue
|
||||
/// Returns a bool indicating success.
|
||||
///
|
||||
/// 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
|
||||
|
|
@ -241,7 +228,7 @@ pub inline fn getPhysicalDevicePresentationSupport(
|
|||
/// Vulkan objects, see the Vulkan specification.
|
||||
///
|
||||
/// see also: vulkan_surface, glfw.getRequiredInstanceExtensions
|
||||
pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) error{ APIUnavailable, PlatformError }!i32 {
|
||||
pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) i32 {
|
||||
internal_debug.assertInitialized();
|
||||
// zig-vulkan uses enums to represent opaque pointers:
|
||||
// pub const Instance = enum(usize) { null_handle = 0, _ };
|
||||
|
|
@ -250,26 +237,21 @@ pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_alloc
|
|||
else => @ptrCast(c.VkInstance, vk_instance),
|
||||
};
|
||||
|
||||
const v = c.glfwCreateWindowSurface(
|
||||
return c.glfwCreateWindowSurface(
|
||||
instance,
|
||||
window.handle,
|
||||
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)),
|
||||
);
|
||||
if (v == c.VK_SUCCESS) return v;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => @panic("Attempted to use window with client api to create vulkan surface."),
|
||||
Error.APIUnavailable, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwCreateWindowSurface` returns `!VK_SUCCESS` only for errors
|
||||
unreachable;
|
||||
) == c.VK_SUCCESS;
|
||||
}
|
||||
|
||||
test "vulkanSupported" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.getError() catch {}; // clear any error we generate
|
||||
if (!glfw.init(.{})) {
|
||||
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
||||
std.process.exit(1);
|
||||
}
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.vulkanSupported();
|
||||
|
|
@ -277,15 +259,23 @@ test "vulkanSupported" {
|
|||
|
||||
test "getRequiredInstanceExtensions" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.getError() catch {}; // clear any error we generate
|
||||
if (!glfw.init(.{})) {
|
||||
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
||||
std.process.exit(1);
|
||||
}
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.getRequiredInstanceExtensions() catch |err| std.debug.print("failed to get vulkan instance extensions, error={}\n", .{err});
|
||||
_ = glfw.getRequiredInstanceExtensions();
|
||||
}
|
||||
|
||||
test "getInstanceProcAddress" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.getError() catch {}; // clear any error we generate
|
||||
if (!glfw.init(.{})) {
|
||||
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
|
||||
std.process.exit(1);
|
||||
}
|
||||
defer glfw.terminate();
|
||||
|
||||
// syntax check only, we don't have a real vulkan instance and so this function would panic.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue