Native Wayland support on Linux #669

Closed
opened 2023-01-10 23:58:58 +00:00 by Ristovski · 1 comment
Ristovski commented 2023-01-10 23:58:58 +00:00 (Migrated from github.com)

As I reported on the Discord, it is possible to get mach working natively on Wayland (i.e. without Xwayland, using native wayland surfaces) with a relatively simple patch. Reported here for tracking purposes/as a meta issue for Wayland support.

$ ldd zig-out/bin/triangle 
	linux-vdso.so.1 (0x00007ffee5965000)
	libm.so.6 => /lib64/libm.so.6 (0x00007ffa3a956000)
	libc.so.6 => /lib64/libc.so.6 (0x00007ffa3a77e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ffa3aa47000)

As you can see, Dawn loads wayland libs at runtime.

glfwGetWindowPos is not supported on Wayland, so that one is commented out - a better solution would be ignoring that specific "Feature not supported" error.

This patch is pretty hacky and serves merely as a proof of concept, hence why this is not a PR. I leave the final implementation to Stephen :).

diff --git i/build.zig w/build.zig
index f45798f..719c55c 100644
--- i/build.zig
+++ w/build.zig
@@ -9,7 +9,17 @@ pub fn build(b: *std.build.Builder) !void {
     const options = mach.Options{ .gpu_dawn_options = .{
         .from_source = b.option(bool, "dawn-from-source", "Build Dawn from source") orelse false,
         .debug = b.option(bool, "dawn-debug", "Use a debug build of Dawn") orelse false,
-    } };
+        .linux_window_manager = .Wayland,
+        .separate_libs = true,
+        .vulkan = true,
+        .desktop_gl = false,
+        .opengl_es = false,
+    }, .glfw_options = .{
+        .vulkan = true,
+        .wayland = true,
+        .x11 = false,
+        },
+    };
 
     try ensureDependencies(b.allocator);
 
Submodule libs/mach contains modified content
diff --git i/libs/mach/libs/gamemode/build.zig w/libs/mach/libs/gamemode/build.zig
index 03c21d4e..ee260818 100644
--- i/libs/mach/libs/gamemode/build.zig
+++ w/libs/mach/libs/gamemode/build.zig
@@ -2,7 +2,7 @@ const std = @import("std");
 
 pub const pkg = std.build.Pkg{
     .name = "gamemode",
-    .source = .{ .path = sdkPath("/gamemode.zig") },
+    .source = .{ .path = sdkPath("/src/main.zig") },
 };
 
 pub fn link(step: *std.build.LibExeObjStep) void {
diff --git i/libs/mach/libs/glfw/src/Window.zig w/libs/mach/libs/glfw/src/Window.zig
index 54d1e838..12098991 100644
--- i/libs/mach/libs/glfw/src/Window.zig
+++ w/libs/mach/libs/glfw/src/Window.zig
@@ -515,10 +515,11 @@ pub const Pos = struct {
 ///
 /// see also: window_pos glfw.Window.setPos
 pub inline fn getPos(self: Window) Pos {
+    _ = self;
     internal_debug.assertInitialized();
     var x: c_int = 0;
     var y: c_int = 0;
-    c.glfwGetWindowPos(self.handle, &x, &y);
+    //c.glfwGetWindowPos(self.handle, &x, &y);
     return Pos{ .x = @intCast(i64, x), .y = @intCast(i64, y) };
 }
 
diff --git i/libs/mach/libs/gpu-dawn/sdk.zig w/libs/mach/libs/gpu-dawn/sdk.zig
index 22bc4d60..4755c3da 100644
--- i/libs/mach/libs/gpu-dawn/sdk.zig
+++ w/libs/mach/libs/gpu-dawn/sdk.zig
@@ -76,6 +76,7 @@ pub fn Sdk(comptime deps: anytype) type {
                 }
                 if (is_cpp) try flags.append("-std=c++17");
                 if (self.linux_window_manager != null and self.linux_window_manager.? == .X11) try flags.append("-DDAWN_USE_X11");
+                if (self.linux_window_manager != null and self.linux_window_manager.? == .Wayland) try flags.append("-DDAWN_USE_WAYLAND");
             }
         };
 
diff --git i/libs/mach/libs/gpu/examples/sample_utils.zig w/libs/mach/libs/gpu/examples/sample_utils.zig
index 55d71d4b..6c9d5451 100644
--- i/libs/mach/libs/gpu/examples/sample_utils.zig
+++ w/libs/mach/libs/gpu/examples/sample_utils.zig
@@ -156,7 +156,7 @@ pub fn detectGLFWOptions() glfw.BackendOptions {
     if (target.isDarwin()) return .{ .cocoa = true };
     return switch (target.os.tag) {
         .windows => .{ .win32 = true },
-        .linux => .{ .x11 = true },
+        .linux => .{ .x11 = false, .wayland = true },
         else => .{},
     };
 }
diff --git i/libs/mach/src/platform/util.zig w/libs/mach/src/platform/util.zig
index d8878268..6e4133ae 100644
--- i/libs/mach/src/platform/util.zig
+++ w/libs/mach/src/platform/util.zig
@@ -90,7 +90,7 @@ pub fn detectGLFWOptions() glfw.BackendOptions {
     if (target.isDarwin()) return .{ .cocoa = true };
     return switch (target.os.tag) {
         .windows => .{ .win32 = true },
-        .linux => .{ .x11 = true },
+        .linux => .{ .x11 = false, .wayland = true },
         else => .{},
     };
 }
@@ -126,8 +126,11 @@ pub fn createSurfaceForWindow(
         msgSend(layer.?, "setContentsScale:", .{scale_factor}, void); // [layer setContentsScale:scale_factor]
 
         break :blk gpu.Surface.Descriptor.NextInChain{ .from_metal_layer = &.{ .layer = layer.? } };
-    } else if (glfw_options.wayland) {
-        @panic("TODO: this example does not support Wayland");
+    } else if (glfw_options.wayland) gpu.Surface.Descriptor.NextInChain{
+        .from_wayland_surface = &.{
+            .display = glfw_native.getWaylandDisplay(),
+            .surface = glfw_native.getWaylandWindow(window),
+        },
     } else unreachable;
 
     return instance.createSurface(&gpu.Surface.Descriptor{
diff --git i/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp w/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp
index 7f8b16e37d..69ad98da88 100644
--- i/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp
+++ w/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp
@@ -74,6 +74,7 @@ MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance,
         wgpu::SType::SurfaceDescriptorFromMetalLayer, wgpu::SType::SurfaceDescriptorFromWindowsHWND,
         wgpu::SType::SurfaceDescriptorFromWindowsCoreWindow,
         wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel,
+        wgpu::SType::SurfaceDescriptorFromWaylandSurface,
         wgpu::SType::SurfaceDescriptorFromXlibWindow));
 
 #if defined(DAWN_ENABLE_BACKEND_METAL)
@@ -187,6 +188,7 @@ Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor)
     FindInChain(descriptor->nextInChain, &hwndDesc);
     FindInChain(descriptor->nextInChain, &coreWindowDesc);
     FindInChain(descriptor->nextInChain, &swapChainPanelDesc);
+    FindInChain(descriptor->nextInChain, &waylandDesc);
     FindInChain(descriptor->nextInChain, &xDesc);
     if (metalDesc) {
         mType = Type::MetalLayer;

Note that two missing lines in Dawn itself, which are required to get wayland surfaces working.

As I reported on the Discord, it is possible to get `mach` working natively on Wayland (i.e. without Xwayland, using native wayland surfaces) with a relatively simple patch. Reported here for tracking purposes/as a meta issue for Wayland support. ``` $ ldd zig-out/bin/triangle linux-vdso.so.1 (0x00007ffee5965000) libm.so.6 => /lib64/libm.so.6 (0x00007ffa3a956000) libc.so.6 => /lib64/libc.so.6 (0x00007ffa3a77e000) /lib64/ld-linux-x86-64.so.2 (0x00007ffa3aa47000) ``` As you can see, Dawn loads wayland libs at runtime. `glfwGetWindowPos` is not supported on Wayland, so that one is commented out - a better solution would be ignoring that specific "Feature not supported" error. This patch is pretty hacky and serves merely as a proof of concept, hence why this is not a PR. I leave the final implementation to Stephen :). ```diff diff --git i/build.zig w/build.zig index f45798f..719c55c 100644 --- i/build.zig +++ w/build.zig @@ -9,7 +9,17 @@ pub fn build(b: *std.build.Builder) !void { const options = mach.Options{ .gpu_dawn_options = .{ .from_source = b.option(bool, "dawn-from-source", "Build Dawn from source") orelse false, .debug = b.option(bool, "dawn-debug", "Use a debug build of Dawn") orelse false, - } }; + .linux_window_manager = .Wayland, + .separate_libs = true, + .vulkan = true, + .desktop_gl = false, + .opengl_es = false, + }, .glfw_options = .{ + .vulkan = true, + .wayland = true, + .x11 = false, + }, + }; try ensureDependencies(b.allocator); Submodule libs/mach contains modified content diff --git i/libs/mach/libs/gamemode/build.zig w/libs/mach/libs/gamemode/build.zig index 03c21d4e..ee260818 100644 --- i/libs/mach/libs/gamemode/build.zig +++ w/libs/mach/libs/gamemode/build.zig @@ -2,7 +2,7 @@ const std = @import("std"); pub const pkg = std.build.Pkg{ .name = "gamemode", - .source = .{ .path = sdkPath("/gamemode.zig") }, + .source = .{ .path = sdkPath("/src/main.zig") }, }; pub fn link(step: *std.build.LibExeObjStep) void { diff --git i/libs/mach/libs/glfw/src/Window.zig w/libs/mach/libs/glfw/src/Window.zig index 54d1e838..12098991 100644 --- i/libs/mach/libs/glfw/src/Window.zig +++ w/libs/mach/libs/glfw/src/Window.zig @@ -515,10 +515,11 @@ pub const Pos = struct { /// /// see also: window_pos glfw.Window.setPos pub inline fn getPos(self: Window) Pos { + _ = self; internal_debug.assertInitialized(); var x: c_int = 0; var y: c_int = 0; - c.glfwGetWindowPos(self.handle, &x, &y); + //c.glfwGetWindowPos(self.handle, &x, &y); return Pos{ .x = @intCast(i64, x), .y = @intCast(i64, y) }; } diff --git i/libs/mach/libs/gpu-dawn/sdk.zig w/libs/mach/libs/gpu-dawn/sdk.zig index 22bc4d60..4755c3da 100644 --- i/libs/mach/libs/gpu-dawn/sdk.zig +++ w/libs/mach/libs/gpu-dawn/sdk.zig @@ -76,6 +76,7 @@ pub fn Sdk(comptime deps: anytype) type { } if (is_cpp) try flags.append("-std=c++17"); if (self.linux_window_manager != null and self.linux_window_manager.? == .X11) try flags.append("-DDAWN_USE_X11"); + if (self.linux_window_manager != null and self.linux_window_manager.? == .Wayland) try flags.append("-DDAWN_USE_WAYLAND"); } }; diff --git i/libs/mach/libs/gpu/examples/sample_utils.zig w/libs/mach/libs/gpu/examples/sample_utils.zig index 55d71d4b..6c9d5451 100644 --- i/libs/mach/libs/gpu/examples/sample_utils.zig +++ w/libs/mach/libs/gpu/examples/sample_utils.zig @@ -156,7 +156,7 @@ pub fn detectGLFWOptions() glfw.BackendOptions { if (target.isDarwin()) return .{ .cocoa = true }; return switch (target.os.tag) { .windows => .{ .win32 = true }, - .linux => .{ .x11 = true }, + .linux => .{ .x11 = false, .wayland = true }, else => .{}, }; } diff --git i/libs/mach/src/platform/util.zig w/libs/mach/src/platform/util.zig index d8878268..6e4133ae 100644 --- i/libs/mach/src/platform/util.zig +++ w/libs/mach/src/platform/util.zig @@ -90,7 +90,7 @@ pub fn detectGLFWOptions() glfw.BackendOptions { if (target.isDarwin()) return .{ .cocoa = true }; return switch (target.os.tag) { .windows => .{ .win32 = true }, - .linux => .{ .x11 = true }, + .linux => .{ .x11 = false, .wayland = true }, else => .{}, }; } @@ -126,8 +126,11 @@ pub fn createSurfaceForWindow( msgSend(layer.?, "setContentsScale:", .{scale_factor}, void); // [layer setContentsScale:scale_factor] break :blk gpu.Surface.Descriptor.NextInChain{ .from_metal_layer = &.{ .layer = layer.? } }; - } else if (glfw_options.wayland) { - @panic("TODO: this example does not support Wayland"); + } else if (glfw_options.wayland) gpu.Surface.Descriptor.NextInChain{ + .from_wayland_surface = &.{ + .display = glfw_native.getWaylandDisplay(), + .surface = glfw_native.getWaylandWindow(window), + }, } else unreachable; return instance.createSurface(&gpu.Surface.Descriptor{ diff --git i/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp w/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp index 7f8b16e37d..69ad98da88 100644 --- i/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp +++ w/libs/mach/libs/gpu-dawn/libs/dawn/src/dawn/native/Surface.cpp @@ -74,6 +74,7 @@ MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance, wgpu::SType::SurfaceDescriptorFromMetalLayer, wgpu::SType::SurfaceDescriptorFromWindowsHWND, wgpu::SType::SurfaceDescriptorFromWindowsCoreWindow, wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel, + wgpu::SType::SurfaceDescriptorFromWaylandSurface, wgpu::SType::SurfaceDescriptorFromXlibWindow)); #if defined(DAWN_ENABLE_BACKEND_METAL) @@ -187,6 +188,7 @@ Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) FindInChain(descriptor->nextInChain, &hwndDesc); FindInChain(descriptor->nextInChain, &coreWindowDesc); FindInChain(descriptor->nextInChain, &swapChainPanelDesc); + FindInChain(descriptor->nextInChain, &waylandDesc); FindInChain(descriptor->nextInChain, &xDesc); if (metalDesc) { mType = Type::MetalLayer; ``` Note that two missing lines in Dawn itself, which are required to get wayland surfaces working.
emidoots commented 2023-01-12 17:53:30 +00:00 (Migrated from github.com)

Closing in favor of #376 (until we update Dawn to the latest version and it actually works)

I think Ali merged most of these changes via #670 though

Closing in favor of #376 (until we update Dawn to the latest version and it actually works) I think Ali merged most of these changes via #670 though
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
hexops/mach#669
No description provided.