WSI is finally working
Build / build (push) Failing after 30s
Test / build_and_test (push) Failing after 1m1s

This commit is contained in:
2026-05-05 13:58:01 +02:00
parent e93aa8d034
commit 95810d6163
13 changed files with 98 additions and 83 deletions
-2
View File
@@ -25,11 +25,9 @@ fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties {
}
pub const EXTENSIONS = [_]vk.ExtensionProperties{
//castExtension(vk.extensions.lunarg_direct_driver_loading),
castExtension(vk.extensions.khr_get_physical_device_properties_2),
castExtension(vk.extensions.khr_surface),
castExtension(vk.extensions.khr_wayland_surface),
castExtension(vk.extensions.khr_swapchain),
};
pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) VkError!*Interface {
+27
View File
@@ -13,6 +13,19 @@ const SurfaceKHR = base.SurfaceKHR;
const Self = @This();
pub const Interface = base.PhysicalDevice;
fn castExtension(comptime ext: vk.ApiInfo) vk.ExtensionProperties {
var props: vk.ExtensionProperties = .{
.extension_name = @splat(0),
.spec_version = @bitCast(ext.version),
};
@memcpy(props.extension_name[0..ext.name.len], ext.name);
return props;
}
const EXTENSIONS = [_]vk.ExtensionProperties{
castExtension(vk.extensions.khr_swapchain),
};
// Device name should always be the same so avoid reprocessing it multiple times
var device_name: [vk.MAX_PHYSICAL_DEVICE_NAME_SIZE]u8 = @splat(0);
@@ -31,6 +44,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance) VkError!*S
.getFormatProperties = getFormatProperties,
.getImageFormatProperties = getImageFormatProperties,
.getSparseImageFormatProperties = getSparseImageFormatProperties,
.enumerateExtensionProperties = enumerateExtensionProperties,
.release = destroy,
// VK_KHR_get_physical_device_properties_2
@@ -234,6 +248,19 @@ pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos:
return &device.interface;
}
pub fn enumerateExtensionProperties(_: *const Interface, layer_name: ?[]const u8, count: *u32, p_properties: ?[*]vk.ExtensionProperties) VkError!void {
if (layer_name) |_| {
return VkError.LayerNotPresent;
}
count.* = EXTENSIONS.len;
if (p_properties) |properties| {
for (EXTENSIONS, properties[0..]) |ext, *prop| {
prop.* = ext;
}
}
}
pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.FormatProperties {
_ = interface;
var properties: vk.FormatProperties = .{};
+1 -1
View File
@@ -72,7 +72,7 @@ pub fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkE
pub fn getMemoryRequirements(self: *Self, requirements: *vk.MemoryRequirements) VkError!void {
requirements.size = try self.getTotalSize();
requirements.memory_type_bits = self.allowed_memory_types.mask;
requirements.memory_type_bits = 0;
try self.vtable.getMemoryRequirements(self, requirements);
}
+1 -1
View File
@@ -67,7 +67,7 @@ pub fn enumerateExtensionProperties(layer_name: ?[]const u8, count: *u32, p_prop
return VkError.LayerNotPresent;
}
if (comptime @hasDecl(root, "Instance") and @hasDecl(root.Instance, "EXTENSIONS")) {
if (comptime !builtin.is_test and @hasDecl(root.Instance, "EXTENSIONS")) {
count.* = root.Instance.EXTENSIONS.len;
if (p_properties) |properties| {
for (root.Instance.EXTENSIONS, properties[0..]) |ext, *prop| {
-4
View File
@@ -39,10 +39,6 @@ pub fn NonDispatchable(comptime T: type) type {
return @enumFromInt(@intFromPtr(self));
}
pub fn fromObject(object: *T) *Self {
return @alignCast(@constCast(@fieldParentPtr("object", &object)));
}
pub fn fromHandle(vk_handle: anytype) VkError!*Self {
const handle = @intFromEnum(vk_handle);
if (handle == 0) {
+5
View File
@@ -22,6 +22,7 @@ pub const DispatchTable = struct {
getFormatProperties: *const fn (*Self, vk.Format) VkError!vk.FormatProperties,
getImageFormatProperties: *const fn (*Self, vk.Format, vk.ImageType, vk.ImageTiling, vk.ImageUsageFlags, vk.ImageCreateFlags) VkError!vk.ImageFormatProperties,
getSparseImageFormatProperties: *const fn (*Self, vk.Format, vk.ImageType, vk.SampleCountFlags, vk.ImageTiling, vk.ImageUsageFlags, ?[*]vk.SparseImageFormatProperties) VkError!u32,
enumerateExtensionProperties: *const fn (*const Self, ?[]const u8, *u32, ?[*]vk.ExtensionProperties) VkError!void,
release: *const fn (*Self, std.mem.Allocator) VkError!void,
// VK_KHR_get_physical_device_properties_2
@@ -66,6 +67,10 @@ pub inline fn getFormatProperties(self: *Self, format: vk.Format) VkError!vk.For
return try self.dispatch_table.getFormatProperties(self, format);
}
pub inline fn enumerateExtensionProperties(self: *const Self, layer_name: ?[]const u8, count: *u32, p_properties: ?[*]vk.ExtensionProperties) VkError!void {
return try self.dispatch_table.enumerateExtensionProperties(self, layer_name, count, p_properties);
}
pub inline fn getImageFormatProperties(
self: *Self,
format: vk.Format,
+4
View File
@@ -1,2 +1,6 @@
#include <vulkan/vk_icd.h>
#include <vulkan/utility/vk_format_utils.h>
#ifdef STROLL_ENABLE_WAYLAND
#include <wayland-client.h>
#endif
+9 -11
View File
@@ -382,7 +382,7 @@ pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, info: *co
return .success;
}
pub export fn strollEnumerateDeviceExtensionProperties(p_physical_device: vk.PhysicalDevice, p_layer_name: ?[*:0]const u8, property_count: *u32, properties: ?*vk.ExtensionProperties) callconv(vk.vulkan_call_conv) vk.Result {
pub export fn strollEnumerateDeviceExtensionProperties(p_physical_device: vk.PhysicalDevice, p_layer_name: ?[*:0]const u8, property_count: *u32, properties: ?[*]vk.ExtensionProperties) callconv(vk.vulkan_call_conv) vk.Result {
entryPointBeginLogTrace(.vkEnumerateDeviceExtensionProperties);
defer entryPointEndLogTrace();
@@ -390,9 +390,8 @@ pub export fn strollEnumerateDeviceExtensionProperties(p_physical_device: vk.Phy
if (p_layer_name) |layer_name| {
name = std.mem.span(layer_name);
}
_ = p_physical_device;
property_count.* = 0;
_ = properties;
const physical_device = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err);
physical_device.enumerateExtensionProperties(name, property_count, properties) catch |err| return toVkResult(err);
return .success;
}
@@ -2213,8 +2212,8 @@ pub export fn strollAcquireNextImageKHR(p_device: vk.Device, p_swapchain: vk.Swa
Dispatchable(Device).checkHandleValidity(p_device) catch |err| return toVkResult(err);
const swapchain = NonDispatchable(SwapchainKHR).fromHandleObject(p_swapchain) catch |err| return toVkResult(err);
const semaphore = NonDispatchable(BinarySemaphore).fromHandleObject(p_semaphore) catch |err| return toVkResult(err);
const fence = NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err);
const semaphore = if (p_semaphore != .null_handle) NonDispatchable(BinarySemaphore).fromHandleObject(p_semaphore) catch |err| return toVkResult(err) else null;
const fence = if (p_fence != .null_handle) NonDispatchable(Fence).fromHandleObject(p_fence) catch |err| return toVkResult(err) else null;
swapchain.getNextImage(timeout, semaphore, fence, image_index) catch |err| return toVkResult(err);
return .success;
}
@@ -2235,9 +2234,7 @@ pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.Swap
const allocator = VulkanAllocator.init(callbacks, .object).allocator();
const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err);
const surface = NonDispatchable(SurfaceKHR).fromHandleObject(info.surface) catch |err| return toVkResult(err);
const swapchain = SwapchainKHR.create(device, allocator, info) catch |err| return toVkResult(err);
swapchain.surface = surface;
surface.swapchain = swapchain;
const swapchain = SwapchainKHR.create(device, allocator, surface, info) catch |err| return toVkResult(err);
p_swapchain.* = (NonDispatchable(SwapchainKHR).wrap(allocator, swapchain) catch |err| return toVkResult(err)).toVkHandle(vk.SwapchainKHR);
return .success;
}
@@ -2318,6 +2315,7 @@ pub export fn strollGetPhysicalDeviceSurfaceSupportKHR(p_physical_device: vk.Phy
return .success;
}
/// TODO: proper implementation when adding new drivers
pub export fn strollGetPhysicalDeviceWaylandPresentationSupportKHR(p_physical_device: vk.PhysicalDevice, _: u32, _: *anyopaque) callconv(vk.vulkan_call_conv) vk.Bool32 {
entryPointBeginLogTrace(.vkGetPhysicalDeviceWaylandPresentationSupportKHR);
defer entryPointEndLogTrace();
@@ -2335,8 +2333,8 @@ pub export fn strollGetSwapchainImagesKHR(p_device: vk.Device, p_swapchain: vk.S
const swapchain = NonDispatchable(SwapchainKHR).fromHandleObject(p_swapchain) catch |err| return toVkResult(err);
count.* = @intCast(swapchain.images.len);
if (p_images) |images| {
for (images[0..], swapchain.images[0..]) |*image, swapchain_image| {
image.* = NonDispatchable(Image).fromObject(swapchain_image.image).toVkHandle(vk.Image);
for (images[0..], swapchain.images[0..]) |*image, *swapchain_image| {
image.* = swapchain_image.non_dispatchable_image.toVkHandle(vk.Image);
}
}
+4 -1
View File
@@ -6,6 +6,7 @@ const VkError = @import("../error_set.zig").VkError;
const Device = @import("../Device.zig");
const DeviceMemory = @import("../DeviceMemory.zig");
const Image = @import("../Image.zig");
const NonDispatchable = @import("../NonDispatchable.zig").NonDispatchable;
pub const State = enum {
Available,
@@ -16,6 +17,7 @@ pub const State = enum {
const Self = @This();
image: *Image,
non_dispatchable_image: *NonDispatchable(Image),
memory: *DeviceMemory,
state: State,
@@ -36,12 +38,13 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image
return .{
.image = image,
.non_dispatchable_image = try NonDispatchable(Image).wrap(allocator, image),
.memory = memory,
.state = .Available,
};
}
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
self.image.destroy(allocator);
self.non_dispatchable_image.intrusiveDestroy(allocator);
self.memory.destroy(allocator);
}
+10 -4
View File
@@ -18,7 +18,7 @@ owner: *Device,
surface: ?*SurfaceKHR,
images: []PresentImage,
pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.SwapchainCreateInfoKHR) VkError!*Self {
pub fn create(device: *Device, allocator: std.mem.Allocator, surface: *SurfaceKHR, info: *const vk.SwapchainCreateInfoKHR) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
errdefer allocator.destroy(self);
@@ -46,17 +46,22 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa
.queue_family_index_count = info.queue_family_index_count,
.initial_layout = .general,
});
try surface.attachImage(allocator, image);
}
self.* = .{
.owner = device,
.surface = null,
.surface = surface,
.images = images,
};
surface.swapchain = self;
return self;
}
pub fn getNextImage(self: *const Self, timeout: u64, semaphore: *BinarySemaphore, fence: *Fence, index: *u32) VkError!void {
pub fn getNextImage(self: *const Self, timeout: u64, semaphore: ?*BinarySemaphore, fence: ?*Fence, index: *u32) VkError!void {
// TODO: handle timeout correctly
for (self.images, 0..) |*image, i| {
@@ -65,7 +70,8 @@ pub fn getNextImage(self: *const Self, timeout: u64, semaphore: *BinarySemaphore
index.* = @intCast(i);
// TODO: signal semaphore
_ = semaphore;
try fence.signal();
if (fence) |f|
try f.signal();
return;
}
}
+16 -19
View File
@@ -19,16 +19,16 @@ const WaylandImage = struct {
stride: u32,
};
fn wlRegistryHandleGlobal(data: *anyopaque, registry: *wayland.wl_registry, name: c_uint, interface: [*:0]const u8, _: c_uint) callconv(.c) void {
const pshm: **wayland.wl_shm = @ptrCast(@alignCast(data));
fn wlRegistryHandleGlobal(data: ?*anyopaque, registry: ?*wayland.wl_registry, name: u32, interface: [*c]const u8, _: u32) callconv(.c) void {
const pshm: **wayland.wl_shm = @ptrCast(@alignCast(data orelse return));
if (std.mem.eql(u8, std.mem.span(interface), "wl_shm")) {
if (wayland.wl_registry_bind(registry, name, wayland.wl_shm_interface, 1)) |shm| {
if (wayland.c.wl_registry_bind(registry orelse return, name, wayland.wl_shm_interface, 1)) |shm| {
pshm.* = @ptrCast(@alignCast(shm));
}
}
}
fn wlRegistryHandleGlobalRemove(_: *anyopaque, _: *wayland.wl_registry, _: c_uint) callconv(.c) void {}
fn wlRegistryHandleGlobalRemove(_: ?*anyopaque, _: ?*wayland.wl_registry, _: u32) callconv(.c) void {}
const wl_registry_listener: wayland.wl_registry_listener = .{
.global = wlRegistryHandleGlobal,
@@ -65,9 +65,9 @@ pub fn create(instance: *Instance, allocator: std.mem.Allocator, info: *const vk
.image_map = .empty,
};
const registry = wayland.wl_display_get_registry(self.display) orelse return VkError.Unknown;
_ = wayland.wl_registry_add_listener(registry, &wl_registry_listener, @ptrCast(&self.shm));
_ = wayland.wl_display_dispatch(self.display);
const registry = wayland.c.wl_display_get_registry(@ptrCast(self.display)) orelse return VkError.Unknown;
_ = wayland.c.wl_registry_add_listener(registry, &wl_registry_listener, @ptrCast(&self.shm));
_ = wayland.c.wl_display_dispatch(@ptrCast(self.display));
return &self.interface;
}
@@ -106,11 +106,11 @@ pub fn attachImage(interface: *Interface, allocator: std.mem.Allocator, image: *
const data = std.posix.mmap(null, size, .{ .READ = true, .WRITE = true }, .{ .TYPE = .SHARED }, fd, 0) catch return VkError.OutOfHostMemory;
errdefer std.posix.munmap(data);
const pool = wayland.wl_shm_create_pool(self.shm, fd, @intCast(size)) orelse return VkError.Unknown;
defer wayland.wl_shm_pool_destroy(pool);
const pool = wayland.c.wl_shm_create_pool(self.shm, fd, @intCast(size)) orelse return VkError.Unknown;
defer wayland.c.wl_shm_pool_destroy(pool);
const buffer = wayland.wl_shm_pool_create_buffer(pool, 0, @intCast(width), @intCast(height), @intCast(stride), wayland.WL_SHM_FORMAT_ARGB8888) orelse return VkError.Unknown;
errdefer wayland.wl_buffer_destroy(buffer);
const buffer = wayland.c.wl_shm_pool_create_buffer(pool, 0, @intCast(width), @intCast(height), @intCast(stride), wayland.WL_SHM_FORMAT_ARGB8888) orelse return VkError.Unknown;
errdefer wayland.c.wl_buffer_destroy(buffer);
wl_image.* = .{
.buffer = buffer,
@@ -128,7 +128,7 @@ pub fn detachImage(interface: *Interface, allocator: std.mem.Allocator, image: *
const entry = self.image_map.fetchRemove(image) orelse return;
const wl_image = entry.value;
wayland.wl_buffer_destroy(wl_image.buffer);
wayland.c.wl_buffer_destroy(wl_image.buffer);
std.posix.munmap(wl_image.data);
allocator.destroy(wl_image);
}
@@ -146,14 +146,11 @@ pub fn presentImage(interface: *Interface, allocator: std.mem.Allocator, image:
.layer_count = 1,
});
wayland.wl_surface_attach(self.surface, wl_image.buffer, 0, 0);
wayland.wl_surface_damage(self.surface, 0, 0, @intCast(wl_image.width), @intCast(wl_image.height));
wayland.wl_surface_commit(self.surface);
wayland.c.wl_surface_attach(@ptrCast(self.surface), wl_image.buffer, 0, 0);
wayland.c.wl_surface_damage(@ptrCast(self.surface), 0, 0, @intCast(wl_image.width), @intCast(wl_image.height));
wayland.c.wl_surface_commit(@ptrCast(self.surface));
// Better: bind wl_display_flush in wayland.zig and call it here.
// With the currently available bindings, roundtrip forces the commit out,
// but it is heavier than necessary.
_ = wayland.wl_display_roundtrip(self.display);
_ = wayland.c.wl_display_flush(@ptrCast(self.display));
image.state = .Available;
}
+20 -40
View File
@@ -2,37 +2,29 @@ const std = @import("std");
const vk = @import("vulkan");
const lib = @import("../../lib.zig");
pub const c = lib.c;
const VkError = lib.VkError;
pub const wl_registry_listener = extern struct {
global: *const fn (*anyopaque, *wl_registry, c_uint, [*:0]const u8, c_uint) callconv(.c) void,
global_remove: *const fn (*anyopaque, *wl_registry, c_uint) callconv(.c) void,
};
pub const wl_registry_listener = c.wl_registry_listener;
pub const WL_SHM_FORMAT_ARGB8888 = 0;
pub const WL_SHM_FORMAT_ARGB8888 = c.WL_SHM_FORMAT_ARGB8888;
pub const wl_buffer = opaque {};
pub const wl_callback = opaque {};
pub const wl_buffer = c.wl_buffer;
pub const wl_callback = c.wl_buffer;
pub const wl_interface = c.wl_interface;
pub const wl_registry = c.wl_registry;
pub const wl_shm = c.wl_shm;
pub const wl_shm_pool = c.wl_shm_pool;
pub const wl_proxy = c.wl_proxy;
// vk.wl_XXX instead of c.wl_XXX to avoid casts with Zig Vulkan bindings functions
pub const wl_display = vk.wl_display;
pub const wl_interface = opaque {};
pub const wl_registry = opaque {};
pub const wl_shm = opaque {};
pub const wl_shm_pool = opaque {};
pub const wl_surface = vk.wl_surface;
pub var wl_display_dispatch: *const fn (d: *wl_display) callconv(.c) c_int = undefined;
pub var wl_display_get_registry: *const fn (d: *wl_display) callconv(.c) ?*wl_registry = undefined;
pub var wl_display_roundtrip: *const fn (d: *wl_display) callconv(.c) c_int = undefined;
pub var wl_display_sync: *const fn (d: *wl_display) callconv(.c) ?*wl_callback = undefined;
pub var wl_registry_add_listener: *const fn (r: *wl_registry, l: *const wl_registry_listener, data: *anyopaque) callconv(.c) c_int = undefined;
pub var wl_registry_bind: *const fn (r: *wl_registry, name: u32, i: *const wl_interface, version: u32) callconv(.c) ?*anyopaque = undefined;
pub var wl_buffer_destroy: *const fn (b: *wl_buffer) callconv(.c) void = undefined;
pub var wl_shm_create_pool: *const fn (shm: *wl_shm, fd: i32, size: i32) callconv(.c) ?*wl_shm_pool = undefined;
pub var wl_shm_pool_create_buffer: *const fn (p: *wl_shm_pool, offset: i32, width: i32, height: i32, stride: i32, format: u32) callconv(.c) ?*wl_buffer = undefined;
pub var wl_shm_pool_destroy: *const fn (p: *wl_shm_pool) callconv(.c) void = undefined;
pub var wl_surface_attach: *const fn (s: *wl_surface, b: *wl_buffer, x: i32, y: i32) callconv(.c) void = undefined;
pub var wl_surface_damage: *const fn (s: *wl_surface, x: i32, y: i32, width: i32, height: i32) callconv(.c) void = undefined;
pub var wl_surface_commit: *const fn (s: *wl_surface) callconv(.c) void = undefined;
pub var wl_display_dispatch: *const fn (*wl_display) callconv(.c) c_int = undefined;
pub var wl_proxy_marshal_flags: *const fn (*wl_proxy, u32, *const wl_interface, u32, u32, ...) callconv(.c) ?*wl_proxy = undefined;
pub var wl_display_flush: *const fn (*wl_display) callconv(.c) c_int = undefined;
pub var wl_shm_interface: *wl_interface = undefined;
@@ -49,23 +41,11 @@ pub fn load() VkError!void {
return VkError.Unknown;
};
errdefer module.close();
errdefer std.debug.print("test {s}\n", .{std.c.dlerror().?});
errdefer std.log.scoped(.WaylandClient).err("Could not open 'libwayland-client.so.0': {s}", .{std.c.dlerror() orelse "unknown error"});
// zig fmt: off
wl_display_dispatch = module.lookup(@TypeOf(wl_display_dispatch), "wl_display_dispatch" ) orelse return VkError.Unknown;
wl_display_get_registry = module.lookup(@TypeOf(wl_display_get_registry), "wl_display_get_registry" ) orelse return VkError.Unknown;
wl_display_roundtrip = module.lookup(@TypeOf(wl_display_roundtrip), "wl_display_roundtrip" ) orelse return VkError.Unknown;
wl_display_sync = module.lookup(@TypeOf(wl_display_sync), "wl_display_sync" ) orelse return VkError.Unknown;
wl_registry_add_listener = module.lookup(@TypeOf(wl_registry_add_listener), "wl_registry_add_listener" ) orelse return VkError.Unknown;
wl_registry_bind = module.lookup(@TypeOf(wl_registry_bind), "wl_registry_bind" ) orelse return VkError.Unknown;
wl_buffer_destroy = module.lookup(@TypeOf(wl_buffer_destroy), "wl_buffer_destroy" ) orelse return VkError.Unknown;
wl_shm_create_pool = module.lookup(@TypeOf(wl_shm_create_pool), "wl_shm_create_pool" ) orelse return VkError.Unknown;
wl_shm_pool_create_buffer = module.lookup(@TypeOf(wl_shm_pool_create_buffer), "wl_shm_pool_create_buffer") orelse return VkError.Unknown;
wl_shm_pool_destroy = module.lookup(@TypeOf(wl_shm_pool_destroy), "wl_shm_pool_destroy" ) orelse return VkError.Unknown;
wl_surface_attach = module.lookup(@TypeOf(wl_surface_attach), "wl_surface_attach" ) orelse return VkError.Unknown;
wl_surface_damage = module.lookup(@TypeOf(wl_surface_damage), "wl_surface_damage" ) orelse return VkError.Unknown;
wl_surface_commit = module.lookup(@TypeOf(wl_surface_commit), "wl_surface_commit" ) orelse return VkError.Unknown;
// zig fmt: on
wl_display_dispatch = module.lookup(@TypeOf(wl_display_dispatch), "wl_display_dispatch") orelse return VkError.Unknown;
wl_proxy_marshal_flags = module.lookup(@TypeOf(wl_proxy_marshal_flags), "wl_proxy_marshal_flags") orelse return VkError.Unknown;
wl_display_flush = module.lookup(@TypeOf(wl_display_flush), "wl_display_flush") orelse return VkError.Unknown;
wl_shm_interface = module.lookup(*wl_interface, "wl_shm_interface") orelse return VkError.Unknown;