From ed50a39cb45698240fba9987379acedd8e81cdea Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Mon, 4 May 2026 03:35:53 +0200 Subject: [PATCH] working on Wayland surfaces --- README.md | 2 +- build.zig | 54 +++++++++++--- build.zig.zon | 8 +-- src/soft/SoftImage.zig | 4 +- src/soft/SoftPhysicalDevice.zig | 2 +- src/soft/c_includes.h | 1 + src/soft/lib.zig | 2 + src/vulkan/Dispatchable.zig | 4 +- src/vulkan/c_includes.h | 2 + src/vulkan/format.zig | 26 +++---- src/vulkan/lib.zig | 7 +- src/vulkan/lib_vulkan.zig | 6 +- src/vulkan/wsi/PresentImage.zig | 2 +- src/vulkan/wsi/SurfaceKHR.zig | 85 +++++++++++++++++++++- src/vulkan/wsi/SwapchainKHR.zig | 19 ++++- src/vulkan/wsi/WaylandSurfaceKHR.zig | 104 +++++++++++++++++++++++++++ src/vulkan/wsi/clients/wayland.zig | 73 +++++++++++++++++++ 17 files changed, 357 insertions(+), 44 deletions(-) create mode 100644 src/soft/c_includes.h create mode 100644 src/vulkan/c_includes.h create mode 100644 src/vulkan/wsi/clients/wayland.zig diff --git a/README.md b/README.md index 26a081d..0fc9ed7 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ vkGetPhysicalDeviceSurfaceFormatsKHR | ⚙️ WIP vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP -vkGetPhysicalDeviceWind32PresentationSupportKHR | ⚙️ WIP +vkGetPhysicalDeviceWin32PresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP vkGetPipelineCacheData | ⚙️ WIP diff --git a/build.zig b/build.zig index f9d118d..e8abe2c 100644 --- a/build.zig +++ b/build.zig @@ -6,7 +6,14 @@ const ImplementationDesc = struct { name: []const u8, root_source_file: []const u8, vulkan_version: std.SemanticVersion, - custom: ?*const fn (*std.Build, *std.Build.Step.Compile, *std.Build.Step.Options, bool) anyerror!void = null, + custom: ?*const fn ( + *std.Build, + *Step.Compile, + std.Build.ResolvedTarget, + std.builtin.OptimizeMode, + *Step.Options, + bool, + ) anyerror!void = null, }; const implementations = [_]ImplementationDesc{ @@ -56,8 +63,22 @@ pub fn build(b: *std.Build) !void { base_mod.addImport("zmath", zmath); base_mod.addImport("vulkan", vulkan); - base_mod.addSystemIncludePath(vulkan_headers.path("include")); - base_mod.addSystemIncludePath(vulkan_utility_libraries.path("include")); + + const base_c_includes = b.addTranslateC(.{ + .root_source_file = b.path("src/vulkan/c_includes.h"), + .target = target, + .optimize = optimize, + .link_libc = false, + }); + + base_c_includes.addIncludePath(vulkan_headers.path("include")); + base_c_includes.addIncludePath(vulkan_utility_libraries.path("include")); + + if (builtin.target.os.tag == .linux) { + base_c_includes.link_libc = true; + } + + base_mod.addImport("base_c", base_c_includes.createModule()); const use_llvm = b.option(bool, "use-llvm", "LLVM build") orelse (b.release_mode != .off); @@ -82,7 +103,7 @@ pub fn build(b: *std.Build) !void { }); if (impl.custom) |custom| { - custom(b, lib, options, use_llvm) catch continue; + custom(b, lib, target, optimize, options, use_llvm) catch continue; } const icd_file = b.addWriteFile( @@ -149,9 +170,15 @@ pub fn build(b: *std.Build) !void { docs_step.dependOn(&install_docs.step); } -fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.Step.Options, use_llvm: bool) !void { +fn customSoft( + b: *std.Build, + lib: *Step.Compile, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + options: *Step.Options, + use_llvm: bool, +) !void { const cpuinfo = b.lazyDependency("cpuinfo", .{}) orelse return error.UnresolvedDependency; - lib.root_module.addSystemIncludePath(cpuinfo.path("include")); lib.root_module.linkLibrary(cpuinfo.artifact("cpuinfo")); const spv = b.lazyDependency("SPIRV_Interpreter", .{ @@ -161,6 +188,17 @@ fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.S }) orelse return error.UnresolvedDependency; lib.root_module.addImport("spv", spv.module("spv")); + const c_includes = b.addTranslateC(.{ + .root_source_file = b.path("src/soft/c_includes.h"), + .target = target, + .optimize = optimize, + .link_libc = false, + }); + + c_includes.addIncludePath(cpuinfo.path("include")); + + lib.root_module.addImport("soft_c", c_includes.createModule()); + const single_threaded_option = b.option(bool, "single-threaded", "Single threaded runtime mode") orelse false; const debug_allocator_option = b.option(bool, "debug-allocator", "Debug device allocator") orelse false; const shaders_simd_option = b.option(bool, "shader-simd", "Shaders SIMD acceleration") orelse true; @@ -176,7 +214,7 @@ fn customSoft(b: *std.Build, lib: *std.Build.Step.Compile, options: *std.Build.S options.addOption(?u32, "compute_dump_final_results_table", compute_dump_final_results_table_option); } -fn addCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *std.Build.Step.Compile, comptime mode: RunningMode) !*std.Build.Step { +fn addCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *Step.Compile, comptime mode: RunningMode) !*Step { const cts = b.dependency("cts_bin", .{}); const cts_exe_name = cts.path(b.fmt("deqp-vk-{s}", .{ @@ -254,7 +292,7 @@ fn addCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const Implemen return &run.step; } -fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *std.Build.Step.Compile) !*std.Build.Step { +fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *Step.Compile) !*Step { const cts = b.dependency("cts_bin", .{}); const cts_exe_name = cts.path(b.fmt("deqp-vk-{s}", .{ diff --git a/build.zig.zon b/build.zig.zon index 2e8d922..fb30134 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -17,6 +17,10 @@ .url = "git+https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git#ba452bad58bb4d4c64d7fbd872bf69f70141510e", .hash = "N-V-__8AAE42fwC1FFw26LNZ8AaSuGMdgG4vfYkfV_227sET", }, + .zmath = .{ + .url = "git+https://github.com/zig-gamedev/zmath#3a5955b2b72cd081563fbb084eff05bffd1e3fbb", + .hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2", + }, .cts_bin = .{ .url = "git+https://git.kbz8.me/kbz_8/Vulkan-CTS-bin#19ce2da05f8176348064a9fc6688847e5f76a46e", .hash = "N-V-__8AAHDV0xtS93nAGaYd7YWxBLnvHDEplwIpC29izSGa", @@ -26,10 +30,6 @@ .hash = "cpuinfo-0.0.1-RLgIQYrTMgGqfQMOd1nAa2EuglXOh5gR9bNzwMzQTemt", .lazy = true, }, - .zmath = .{ - .url = "git+https://github.com/zig-gamedev/zmath#3a5955b2b72cd081563fbb084eff05bffd1e3fbb", - .hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2", - }, .SPIRV_Interpreter = .{ .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#5faf8fd30548f8bd96a18568fb21de698db64ca8", .hash = "SPIRV_Interpreter-0.0.1-ajmpn_crBQAl1X8EYgNQjoTn_3XZ1DDOBCZMpfyD6MTu", diff --git a/src/soft/SoftImage.zig b/src/soft/SoftImage.zig index 12fc023..dddea53 100644 --- a/src/soft/SoftImage.zig +++ b/src/soft/SoftImage.zig @@ -47,9 +47,9 @@ pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements } pub fn getClearFormat(self: *Self) VkError!vk.Format { - return if (base.vku.vkuFormatIsSINT(@intCast(@intFromEnum(self.interface.format)))) + return if (base.c.vkuFormatIsSINT(@intCast(@intFromEnum(self.interface.format)))) .r32g32b32a32_sint - else if (base.vku.vkuFormatIsUINT(@intCast(@intFromEnum(self.interface.format)))) + else if (base.c.vkuFormatIsUINT(@intCast(@intFromEnum(self.interface.format)))) .r32g32b32a32_uint else .r32g32b32a32_sfloat; diff --git a/src/soft/SoftPhysicalDevice.zig b/src/soft/SoftPhysicalDevice.zig index 756ea4f..6d296ba 100644 --- a/src/soft/SoftPhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -2,7 +2,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); const lib = @import("lib.zig"); -const cpuinfo = @cImport(@cInclude("cpuinfo.h")); +const cpuinfo = lib.c; const SoftDevice = @import("SoftDevice.zig"); diff --git a/src/soft/c_includes.h b/src/soft/c_includes.h new file mode 100644 index 0000000..e4d0278 --- /dev/null +++ b/src/soft/c_includes.h @@ -0,0 +1 @@ +#include diff --git a/src/soft/lib.zig b/src/soft/lib.zig index c5e813e..428e01e 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -2,6 +2,8 @@ const std = @import("std"); const vk = @import("vulkan"); pub const base = @import("base"); +pub const c = @import("soft_c"); + pub const Device = @import("device/Device.zig"); pub const SoftInstance = @import("SoftInstance.zig"); diff --git a/src/vulkan/Dispatchable.zig b/src/vulkan/Dispatchable.zig index 6bcabb4..d110f6c 100644 --- a/src/vulkan/Dispatchable.zig +++ b/src/vulkan/Dispatchable.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const c = @cImport({ - @cInclude("vulkan/vk_icd.h"); -}); +const c = @import("lib.zig").c; const VkError = @import("error_set.zig").VkError; diff --git a/src/vulkan/c_includes.h b/src/vulkan/c_includes.h new file mode 100644 index 0000000..cdb1bab --- /dev/null +++ b/src/vulkan/c_includes.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/vulkan/format.zig b/src/vulkan/format.zig index ed5bd42..b14fd44 100644 --- a/src/vulkan/format.zig +++ b/src/vulkan/format.zig @@ -25,9 +25,9 @@ pub fn fromAspect(format: vk.Format, aspect: vk.ImageAspectFlags) vk.Format { pub fn toAspect(format: vk.Format) vk.ImageAspectFlags { var aspect: vk.ImageAspectFlags = .{}; - if (lib.vku.vkuFormatHasDepth(@intCast(@intFromEnum(format)))) + if (lib.c.vkuFormatHasDepth(@intCast(@intFromEnum(format)))) aspect.depth_bit = true; - if (lib.vku.vkuFormatHasStencil(@intCast(@intFromEnum(format)))) + if (lib.c.vkuFormatHasStencil(@intCast(@intFromEnum(format)))) aspect.stencil_bit = true; if (aspect.toInt() == 0) @@ -37,7 +37,7 @@ pub fn toAspect(format: vk.Format) vk.ImageAspectFlags { } pub inline fn texelSize(format: vk.Format) usize { - return lib.vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatTexelBlockSize(@intCast(@intFromEnum(format))); } pub inline fn supportsColorAttachemendBlend(format: vk.Format) bool { @@ -89,43 +89,43 @@ pub inline fn sliceMemSize(format: vk.Format, width: usize, height: usize) usize } pub inline fn isDepthAndStencil(format: vk.Format) bool { - return lib.vku.vkuFormatIsDepthAndStencil(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsDepthAndStencil(@intCast(@intFromEnum(format))); } pub inline fn isDepth(format: vk.Format) bool { - return lib.vku.vkuFormatHasDepth(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatHasDepth(@intCast(@intFromEnum(format))); } pub inline fn isStencil(format: vk.Format) bool { - return lib.vku.vkuFormatHasStencil(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatHasStencil(@intCast(@intFromEnum(format))); } pub inline fn isSrgb(format: vk.Format) bool { - return lib.vku.vkuFormatIsSRGB(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsSRGB(@intCast(@intFromEnum(format))); } pub inline fn isSfloat(format: vk.Format) bool { - return lib.vku.vkuFormatIsSFLOAT(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsSFLOAT(@intCast(@intFromEnum(format))); } pub inline fn isSint(format: vk.Format) bool { - return lib.vku.vkuFormatIsSINT(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsSINT(@intCast(@intFromEnum(format))); } pub inline fn isSnorm(format: vk.Format) bool { - return lib.vku.vkuFormatIsSNORM(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsSNORM(@intCast(@intFromEnum(format))); } pub inline fn isUfloat(format: vk.Format) bool { - return lib.vku.vkuFormatIsUFLOAT(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsUFLOAT(@intCast(@intFromEnum(format))); } pub inline fn isUint(format: vk.Format) bool { - return lib.vku.vkuFormatIsUINT(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsUINT(@intCast(@intFromEnum(format))); } pub inline fn isUnorm(format: vk.Format) bool { - return lib.vku.vkuFormatIsUNORM(@intCast(@intFromEnum(format))); + return lib.c.vkuFormatIsUNORM(@intCast(@intFromEnum(format))); } pub inline fn isFloat(format: vk.Format) bool { diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 3488472..51f4434 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -3,9 +3,7 @@ const std = @import("std"); const builtin = @import("builtin"); const vk = @import("vulkan"); -pub const vku = @cImport({ - @cInclude("vulkan/utility/vk_format_utils.h"); -}); +pub const c = @import("base_c"); pub const zm = @import("zmath"); @@ -48,6 +46,9 @@ pub const RenderPass = @import("RenderPass.zig"); pub const Sampler = @import("Sampler.zig"); pub const ShaderModule = @import("ShaderModule.zig"); +pub const SurfaceKHR = @import("wsi/SurfaceKHR.zig"); +pub const SwapchainKHR = @import("wsi/SwapchainKHR.zig"); + pub const VULKAN_VENDOR_ID = @typeInfo(vk.VendorId).@"enum".fields[@typeInfo(vk.VendorId).@"enum".fields.len - 1].value + 1; pub const DRIVER_DEBUG_ALLOCATOR_ENV_NAME = "STROLL_DEBUG_ALLOCATOR"; diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index d646795..230f711 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -2194,7 +2194,7 @@ pub export fn strollResetCommandBuffer(p_cmd: vk.CommandBuffer, flags: vk.Comman // WSI functions =================================================================================================================================== -pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.SwapchainCreateInfoKHR, callbacks: ?*const vk.AllocationCallbacks, p_swapchain: *vk.Swapchain) callconv(vk.vulkan_call_conv) vk.Result { +pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.SwapchainCreateInfoKHR, callbacks: ?*const vk.AllocationCallbacks, p_swapchain: *vk.SwapchainKHR) callconv(vk.vulkan_call_conv) vk.Result { entryPointBeginLogTrace(.vkCreateSwapchainKHR); defer entryPointEndLogTrace(); @@ -2208,7 +2208,7 @@ pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.Swap return .success; } -pub export fn strollDestroySwapchainKHR(p_device: vk.Device, p_swapchain: vk.Swapchain, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { +pub export fn strollDestroySwapchainKHR(p_device: vk.Device, p_swapchain: vk.SwapchainKHR, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { entryPointBeginLogTrace(.vkDestroySwapchainKHR); defer entryPointEndLogTrace(); @@ -2223,7 +2223,7 @@ pub export fn strollCreateWaylandSurfaceKHR(p_device: vk.Device, info: *const vk entryPointBeginLogTrace(.vkCreateWaylandSurfaceKHR); defer entryPointEndLogTrace(); - if (info.s_type != .surface_create_info_khr) { + if (info.s_type != .wayland_surface_create_info_khr) { return .error_validation_failed; } const allocator = VulkanAllocator.init(callbacks, .object).allocator(); diff --git a/src/vulkan/wsi/PresentImage.zig b/src/vulkan/wsi/PresentImage.zig index e7b9ffb..0ce6143 100644 --- a/src/vulkan/wsi/PresentImage.zig +++ b/src/vulkan/wsi/PresentImage.zig @@ -23,7 +23,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image const image = try device.createImage(allocator, info); errdefer image.destroy(allocator); - const requirements: vk.MemoryRequirements = undefined; + var requirements: vk.MemoryRequirements = undefined; try image.getMemoryRequirements(&requirements); const memory = try device.allocateMemory(allocator, &.{ diff --git a/src/vulkan/wsi/SurfaceKHR.zig b/src/vulkan/wsi/SurfaceKHR.zig index c3faa23..b716c30 100644 --- a/src/vulkan/wsi/SurfaceKHR.zig +++ b/src/vulkan/wsi/SurfaceKHR.zig @@ -1,11 +1,92 @@ const std = @import("std"); const vk = @import("vulkan"); -const lib = @import("lib.zig"); +const lib = @import("../lib.zig"); const VkError = @import("../error_set.zig").VkError; const Device = @import("../Device.zig"); +const PresentImage = @import("PresentImage.zig"); +const SwapchainKHR = @import("SwapchainKHR.zig"); const Self = @This(); - pub const ObjectType: vk.ObjectType = .surface_khr; + +const formats = [_]vk.SurfaceFormatKHR{ + .{ .format = .b8g8r8a8_unorm, .color_space = .srgb_nonlinear_khr }, + .{ .format = .b8g8r8a8_srgb, .color_space = .srgb_nonlinear_khr }, +}; + +const present_modes = [_]vk.PresentModeKHR{ + .immediate_khr, +}; + +owner: *Device, +swapchain: ?*SwapchainKHR, + +vtable: *const VTable, + +pub const VTable = struct { + destroy: *const fn (*Self, std.mem.Allocator) void, + getCapabilities: *const fn (*const Self, *vk.SurfaceCapabilitiesKHR) VkError!void, + attachImage: *const fn (*Self, std.mem.Allocator, *PresentImage) VkError!void, + detachImage: *const fn (*Self, std.mem.Allocator, *PresentImage) VkError!void, + presentImage: *const fn (*Self, std.mem.Allocator, *PresentImage) VkError!void, +}; + +pub fn init(device: *Device, allocator: std.mem.Allocator) VkError!Self { + _ = allocator; + return .{ + .owner = device, + .swapchain = null, + .vtable = undefined, + }; +} + +pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + self.vtable.destroy(self, allocator); +} + +pub fn getCapabilities(self: *const Self) VkError!vk.SurfaceCapabilitiesKHR { + var capabilities: vk.SurfaceCapabilitiesKHR = .{ + .min_image_count = 1, + .max_image_count = 0, + .current_extent = .{ .width = std.math.maxInt(u32), .height = std.math.maxInt(u32) }, + .min_image_extent = .{ .width = 1, .height = 1 }, + .max_image_extent = .{ .width = std.math.maxInt(u32), .height = std.math.maxInt(u32) }, + .max_image_array_layers = 1, + .supported_transforms = .{ .identity_bit_khr = true }, + .current_transform = .{ .identity_bit_khr = true }, + .supported_composite_alpha = .{ .opaque_bit_khr = true }, + .supported_usage_flags = .{ + .color_attachment_bit = true, + .input_attachment_bit = true, + .transfer_src_bit = true, + .transfer_dst_bit = true, + .sampled_bit = true, + .storage_bit = true, + }, + }; + + try self.vtable.getCapabilities(self, &capabilities); + return capabilities; +} + +pub inline fn attachImage(self: *Self, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + try self.vtable.attachImage(self, allocator, image); +} + +pub inline fn detachImage(self: *Self, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + try self.vtable.detachImage(self, allocator, image); +} + +pub inline fn presentImage(self: *Self, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + try self.vtable.presentImage(self, allocator, image); +} + +pub inline fn getFormats() []vk.SurfaceFormatKHR { + return formats; +} + +pub inline fn getPresentModes() []vk.PresentModeKHR { + return present_modes; +} diff --git a/src/vulkan/wsi/SwapchainKHR.zig b/src/vulkan/wsi/SwapchainKHR.zig index 1ab6a32..1b4dae0 100644 --- a/src/vulkan/wsi/SwapchainKHR.zig +++ b/src/vulkan/wsi/SwapchainKHR.zig @@ -1,12 +1,13 @@ const std = @import("std"); const vk = @import("vulkan"); -const lib = @import("lib.zig"); +const lib = @import("../lib.zig"); const VkError = @import("../error_set.zig").VkError; const Device = @import("../Device.zig"); const SurfaceKHR = @import("SurfaceKHR.zig"); const PresentImage = @import("PresentImage.zig"); +const Image = @import("../Image.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .swapchain_khr; @@ -25,7 +26,7 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa } for (images) |*image| { - image.* = try .init(device, allocator, .{ + image.* = try .init(device, allocator, &.{ .format = info.image_format, .image_type = .@"2d", .extent = .{ @@ -35,7 +36,7 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa }, .mip_levels = 1, .array_layers = info.image_array_layers, - .samples = .@"1_bit", + .samples = .{ .@"1_bit" = true }, .tiling = .optimal, .usage = info.image_usage, .sharing_mode = info.image_sharing_mode, @@ -47,7 +48,19 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa self.* = .{ .owner = device, + .surface = undefined, .images = images, }; return self; } + +pub fn getImage(self: *const Self, index: usize) VkError!*Image { + return if (index < self.images.len) self.images[index].image else VkError.Incomplete; +} + +pub fn destroy(self: *Self, allocator: std.mem.Allocator) void { + for (self.images) |*image| { + image.deinit(allocator); + } + allocator.destroy(self); +} diff --git a/src/vulkan/wsi/WaylandSurfaceKHR.zig b/src/vulkan/wsi/WaylandSurfaceKHR.zig index e69de29..cdb9b94 100644 --- a/src/vulkan/wsi/WaylandSurfaceKHR.zig +++ b/src/vulkan/wsi/WaylandSurfaceKHR.zig @@ -0,0 +1,104 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const lib = @import("../lib.zig"); +const wayland = @import("clients/wayland.zig"); +const PresentImage = @import("PresentImage.zig"); + +const VkError = @import("../error_set.zig").VkError; +const Device = @import("../Device.zig"); + +const Self = @This(); +pub const Interface = @import("SurfaceKHR.zig"); + +const WaylandImage = struct { + buffer: *wayland.wl_buffer, + data: []u8, +}; + +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)); + if (std.mem.eql(u8, std.mem.span(interface), "wl_shm")) { + if (wayland.wl_registry_bind(registry, name, wayland.wl_shm_interface, 1)) |shm| { + pshm.* = @ptrCast(@alignCast(shm)); + } + } +} + +fn wlRegistryHandleGlobalRemove(_: *anyopaque, _: *wayland.wl_registry, _: c_uint) callconv(.c) void {} + +const wl_registry_listener: wayland.wl_registry_listener = .{ + .global = wlRegistryHandleGlobal, + .global_remove = wlRegistryHandleGlobalRemove, +}; + +interface: Interface, +display: *wayland.wl_display, +surface: *wayland.wl_surface, +shm: *wayland.wl_shm, +image_map: std.AutoHashMapUnmanaged(*PresentImage, *WaylandImage), + +pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.WaylandSurfaceCreateInfoKHR) VkError!*Interface { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + try wayland.load(); + + var interface = try Interface.init(device, allocator); + + interface.vtable = &.{ + .destroy = destroy, + .getCapabilities = getCapabilities, + .attachImage = attachImage, + .detachImage = detachImage, + .presentImage = presentImage, + }; + + self.* = .{ + .interface = interface, + .display = info.display, + .surface = info.surface, + .shm = undefined, + .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); + + return &self.interface; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.image_map.deinit(allocator); + allocator.destroy(self); + wayland.unload(); +} + +pub fn getCapabilities(interface: *const Interface, capabilities: *vk.SurfaceCapabilitiesKHR) VkError!void { + // No-op + _ = interface; + _ = capabilities; +} + +pub fn attachImage(interface: *Interface, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = image; + _ = allocator; +} + +pub fn detachImage(interface: *Interface, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = image; + _ = allocator; +} + +pub fn presentImage(interface: *Interface, allocator: std.mem.Allocator, image: *PresentImage) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = image; + _ = allocator; +} diff --git a/src/vulkan/wsi/clients/wayland.zig b/src/vulkan/wsi/clients/wayland.zig new file mode 100644 index 0000000..d70c618 --- /dev/null +++ b/src/vulkan/wsi/clients/wayland.zig @@ -0,0 +1,73 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const lib = @import("../../lib.zig"); + +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_buffer = opaque {}; +pub const wl_callback = opaque {}; +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_shm_interface: *wl_interface = undefined; + +pub var module: std.DynLib = undefined; + +pub var ref_count = std.atomic.Value(usize).init(0); + +pub fn load() VkError!void { + if (ref_count.load(.monotonic) != 0) + return; + + module = std.DynLib.open("libwayland-client.so.0") catch return VkError.Unknown; + errdefer module.close(); + + // 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_shm_interface = module.lookup(*wl_interface, "wl_shm_interface") orelse return VkError.Unknown; + + _ = ref_count.fetchAdd(1, .monotonic); +} + +pub fn unload() void { + if (ref_count.fetchSub(1, .release) == 1) { + module.close(); + } +}