working on Wayland surfaces
Build / build (push) Successful in 1m41s
Test / build_and_test (push) Successful in 35m15s

This commit is contained in:
2026-05-04 03:35:53 +02:00
parent f87fae29e8
commit ed50a39cb4
17 changed files with 357 additions and 44 deletions
+1 -1
View File
@@ -173,7 +173,7 @@ vkGetPhysicalDeviceSurfaceFormatsKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWind32PresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceWin32PresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP
vkGetPipelineCacheData | ⚙️ WIP vkGetPipelineCacheData | ⚙️ WIP
+46 -8
View File
@@ -6,7 +6,14 @@ const ImplementationDesc = struct {
name: []const u8, name: []const u8,
root_source_file: []const u8, root_source_file: []const u8,
vulkan_version: std.SemanticVersion, 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{ const implementations = [_]ImplementationDesc{
@@ -56,8 +63,22 @@ pub fn build(b: *std.Build) !void {
base_mod.addImport("zmath", zmath); base_mod.addImport("zmath", zmath);
base_mod.addImport("vulkan", vulkan); 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); 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| { 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( const icd_file = b.addWriteFile(
@@ -149,9 +170,15 @@ pub fn build(b: *std.Build) !void {
docs_step.dependOn(&install_docs.step); 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; const cpuinfo = b.lazyDependency("cpuinfo", .{}) orelse return error.UnresolvedDependency;
lib.root_module.addSystemIncludePath(cpuinfo.path("include"));
lib.root_module.linkLibrary(cpuinfo.artifact("cpuinfo")); lib.root_module.linkLibrary(cpuinfo.artifact("cpuinfo"));
const spv = b.lazyDependency("SPIRV_Interpreter", .{ 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; }) orelse return error.UnresolvedDependency;
lib.root_module.addImport("spv", spv.module("spv")); 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 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 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; 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); 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 = b.dependency("cts_bin", .{});
const cts_exe_name = cts.path(b.fmt("deqp-vk-{s}", .{ 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; 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 = b.dependency("cts_bin", .{});
const cts_exe_name = cts.path(b.fmt("deqp-vk-{s}", .{ const cts_exe_name = cts.path(b.fmt("deqp-vk-{s}", .{
+4 -4
View File
@@ -17,6 +17,10 @@
.url = "git+https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git#ba452bad58bb4d4c64d7fbd872bf69f70141510e", .url = "git+https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git#ba452bad58bb4d4c64d7fbd872bf69f70141510e",
.hash = "N-V-__8AAE42fwC1FFw26LNZ8AaSuGMdgG4vfYkfV_227sET", .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 = .{ .cts_bin = .{
.url = "git+https://git.kbz8.me/kbz_8/Vulkan-CTS-bin#19ce2da05f8176348064a9fc6688847e5f76a46e", .url = "git+https://git.kbz8.me/kbz_8/Vulkan-CTS-bin#19ce2da05f8176348064a9fc6688847e5f76a46e",
.hash = "N-V-__8AAHDV0xtS93nAGaYd7YWxBLnvHDEplwIpC29izSGa", .hash = "N-V-__8AAHDV0xtS93nAGaYd7YWxBLnvHDEplwIpC29izSGa",
@@ -26,10 +30,6 @@
.hash = "cpuinfo-0.0.1-RLgIQYrTMgGqfQMOd1nAa2EuglXOh5gR9bNzwMzQTemt", .hash = "cpuinfo-0.0.1-RLgIQYrTMgGqfQMOd1nAa2EuglXOh5gR9bNzwMzQTemt",
.lazy = true, .lazy = true,
}, },
.zmath = .{
.url = "git+https://github.com/zig-gamedev/zmath#3a5955b2b72cd081563fbb084eff05bffd1e3fbb",
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
},
.SPIRV_Interpreter = .{ .SPIRV_Interpreter = .{
.url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#5faf8fd30548f8bd96a18568fb21de698db64ca8", .url = "git+https://git.kbz8.me/kbz_8/SPIRV-Interpreter#5faf8fd30548f8bd96a18568fb21de698db64ca8",
.hash = "SPIRV_Interpreter-0.0.1-ajmpn_crBQAl1X8EYgNQjoTn_3XZ1DDOBCZMpfyD6MTu", .hash = "SPIRV_Interpreter-0.0.1-ajmpn_crBQAl1X8EYgNQjoTn_3XZ1DDOBCZMpfyD6MTu",
+2 -2
View File
@@ -47,9 +47,9 @@ pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements
} }
pub fn getClearFormat(self: *Self) VkError!vk.Format { 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 .r32g32b32a32_sint
else if (base.vku.vkuFormatIsUINT(@intCast(@intFromEnum(self.interface.format)))) else if (base.c.vkuFormatIsUINT(@intCast(@intFromEnum(self.interface.format))))
.r32g32b32a32_uint .r32g32b32a32_uint
else else
.r32g32b32a32_sfloat; .r32g32b32a32_sfloat;
+1 -1
View File
@@ -2,7 +2,7 @@ const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const base = @import("base"); const base = @import("base");
const lib = @import("lib.zig"); const lib = @import("lib.zig");
const cpuinfo = @cImport(@cInclude("cpuinfo.h")); const cpuinfo = lib.c;
const SoftDevice = @import("SoftDevice.zig"); const SoftDevice = @import("SoftDevice.zig");
+1
View File
@@ -0,0 +1 @@
#include <cpuinfo.h>
+2
View File
@@ -2,6 +2,8 @@ const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
pub const base = @import("base"); pub const base = @import("base");
pub const c = @import("soft_c");
pub const Device = @import("device/Device.zig"); pub const Device = @import("device/Device.zig");
pub const SoftInstance = @import("SoftInstance.zig"); pub const SoftInstance = @import("SoftInstance.zig");
+1 -3
View File
@@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const c = @cImport({ const c = @import("lib.zig").c;
@cInclude("vulkan/vk_icd.h");
});
const VkError = @import("error_set.zig").VkError; const VkError = @import("error_set.zig").VkError;
+2
View File
@@ -0,0 +1,2 @@
#include <vulkan/vk_icd.h>
#include <vulkan/utility/vk_format_utils.h>
+13 -13
View File
@@ -25,9 +25,9 @@ pub fn fromAspect(format: vk.Format, aspect: vk.ImageAspectFlags) vk.Format {
pub fn toAspect(format: vk.Format) vk.ImageAspectFlags { pub fn toAspect(format: vk.Format) vk.ImageAspectFlags {
var aspect: vk.ImageAspectFlags = .{}; var aspect: vk.ImageAspectFlags = .{};
if (lib.vku.vkuFormatHasDepth(@intCast(@intFromEnum(format)))) if (lib.c.vkuFormatHasDepth(@intCast(@intFromEnum(format))))
aspect.depth_bit = true; aspect.depth_bit = true;
if (lib.vku.vkuFormatHasStencil(@intCast(@intFromEnum(format)))) if (lib.c.vkuFormatHasStencil(@intCast(@intFromEnum(format))))
aspect.stencil_bit = true; aspect.stencil_bit = true;
if (aspect.toInt() == 0) if (aspect.toInt() == 0)
@@ -37,7 +37,7 @@ pub fn toAspect(format: vk.Format) vk.ImageAspectFlags {
} }
pub inline fn texelSize(format: vk.Format) usize { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { pub inline fn isFloat(format: vk.Format) bool {
+4 -3
View File
@@ -3,9 +3,7 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const vk = @import("vulkan"); const vk = @import("vulkan");
pub const vku = @cImport({ pub const c = @import("base_c");
@cInclude("vulkan/utility/vk_format_utils.h");
});
pub const zm = @import("zmath"); pub const zm = @import("zmath");
@@ -48,6 +46,9 @@ pub const RenderPass = @import("RenderPass.zig");
pub const Sampler = @import("Sampler.zig"); pub const Sampler = @import("Sampler.zig");
pub const ShaderModule = @import("ShaderModule.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 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"; pub const DRIVER_DEBUG_ALLOCATOR_ENV_NAME = "STROLL_DEBUG_ALLOCATOR";
+3 -3
View File
@@ -2194,7 +2194,7 @@ pub export fn strollResetCommandBuffer(p_cmd: vk.CommandBuffer, flags: vk.Comman
// WSI functions =================================================================================================================================== // 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); entryPointBeginLogTrace(.vkCreateSwapchainKHR);
defer entryPointEndLogTrace(); defer entryPointEndLogTrace();
@@ -2208,7 +2208,7 @@ pub export fn strollCreateSwapchainKHR(p_device: vk.Device, info: *const vk.Swap
return .success; 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); entryPointBeginLogTrace(.vkDestroySwapchainKHR);
defer entryPointEndLogTrace(); defer entryPointEndLogTrace();
@@ -2223,7 +2223,7 @@ pub export fn strollCreateWaylandSurfaceKHR(p_device: vk.Device, info: *const vk
entryPointBeginLogTrace(.vkCreateWaylandSurfaceKHR); entryPointBeginLogTrace(.vkCreateWaylandSurfaceKHR);
defer entryPointEndLogTrace(); defer entryPointEndLogTrace();
if (info.s_type != .surface_create_info_khr) { if (info.s_type != .wayland_surface_create_info_khr) {
return .error_validation_failed; return .error_validation_failed;
} }
const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const allocator = VulkanAllocator.init(callbacks, .object).allocator();
+1 -1
View File
@@ -23,7 +23,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image
const image = try device.createImage(allocator, info); const image = try device.createImage(allocator, info);
errdefer image.destroy(allocator); errdefer image.destroy(allocator);
const requirements: vk.MemoryRequirements = undefined; var requirements: vk.MemoryRequirements = undefined;
try image.getMemoryRequirements(&requirements); try image.getMemoryRequirements(&requirements);
const memory = try device.allocateMemory(allocator, &.{ const memory = try device.allocateMemory(allocator, &.{
+83 -2
View File
@@ -1,11 +1,92 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const lib = @import("lib.zig"); const lib = @import("../lib.zig");
const VkError = @import("../error_set.zig").VkError; const VkError = @import("../error_set.zig").VkError;
const Device = @import("../Device.zig"); const Device = @import("../Device.zig");
const PresentImage = @import("PresentImage.zig");
const SwapchainKHR = @import("SwapchainKHR.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .surface_khr; 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;
}
+16 -3
View File
@@ -1,12 +1,13 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const lib = @import("lib.zig"); const lib = @import("../lib.zig");
const VkError = @import("../error_set.zig").VkError; const VkError = @import("../error_set.zig").VkError;
const Device = @import("../Device.zig"); const Device = @import("../Device.zig");
const SurfaceKHR = @import("SurfaceKHR.zig"); const SurfaceKHR = @import("SurfaceKHR.zig");
const PresentImage = @import("PresentImage.zig"); const PresentImage = @import("PresentImage.zig");
const Image = @import("../Image.zig");
const Self = @This(); const Self = @This();
pub const ObjectType: vk.ObjectType = .swapchain_khr; 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| { for (images) |*image| {
image.* = try .init(device, allocator, .{ image.* = try .init(device, allocator, &.{
.format = info.image_format, .format = info.image_format,
.image_type = .@"2d", .image_type = .@"2d",
.extent = .{ .extent = .{
@@ -35,7 +36,7 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa
}, },
.mip_levels = 1, .mip_levels = 1,
.array_layers = info.image_array_layers, .array_layers = info.image_array_layers,
.samples = .@"1_bit", .samples = .{ .@"1_bit" = true },
.tiling = .optimal, .tiling = .optimal,
.usage = info.image_usage, .usage = info.image_usage,
.sharing_mode = info.image_sharing_mode, .sharing_mode = info.image_sharing_mode,
@@ -47,7 +48,19 @@ pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.Swa
self.* = .{ self.* = .{
.owner = device, .owner = device,
.surface = undefined,
.images = images, .images = images,
}; };
return self; 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);
}
+104
View File
@@ -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;
}
+73
View File
@@ -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();
}
}