mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-12-14 07:13:47 +01:00
wlbg: port to OpenGL and fix EGL deadlock/spinning crap
This commit is contained in:
parent
e84433ff11
commit
fd75681e2f
8 changed files with 101 additions and 27 deletions
|
@ -37,7 +37,7 @@ pub fn build(b: *std.Build) void {
|
|||
exe.root_module.linkSystemLibrary("wayland-client", .{});
|
||||
exe.root_module.linkSystemLibrary("wayland-egl", .{});
|
||||
exe.root_module.linkSystemLibrary("EGL", .{});
|
||||
exe.root_module.linkSystemLibrary("GLESv2", .{});
|
||||
exe.root_module.linkSystemLibrary("GL", .{});
|
||||
|
||||
b.installArtifact(exe);
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const c = @import("ffi.zig").c;
|
||||
const wayland = @import("wayland");
|
||||
|
||||
const glutil = @import("glutil.zig");
|
||||
const options = @import("options.zig");
|
||||
|
@ -9,12 +10,17 @@ const OutputInfo = @import("OutputInfo.zig");
|
|||
const OutputWindow = @import("OutputWindow.zig");
|
||||
const PointerState = @import("PointerState.zig");
|
||||
|
||||
const wl = wayland.client.wl;
|
||||
|
||||
dpy: *wl.Display,
|
||||
egl_dpy: c.EGLDisplay,
|
||||
bg_shader_program: c_uint,
|
||||
main_shader_program: c_uint,
|
||||
bg_bufs: std.MultiArrayList(BgBuf),
|
||||
time: i64,
|
||||
cursor_positions: [][2]c_int,
|
||||
vao: c_uint,
|
||||
vbo: c_uint,
|
||||
|
||||
const Gfx = @This();
|
||||
|
||||
|
@ -24,7 +30,7 @@ const BgBuf = struct {
|
|||
zbuffer: c_uint,
|
||||
};
|
||||
|
||||
pub fn init(egl_dpy: c.EGLDisplay, output_info: []const OutputInfo) !Gfx {
|
||||
pub fn init(dpy: *wl.Display, egl_dpy: c.EGLDisplay, output_info: []const OutputInfo) !Gfx {
|
||||
const bg_program = shader: {
|
||||
const vert_shader = try glutil.createShader(c.GL_VERTEX_SHADER, @embedFile("bg_vert.glsl"));
|
||||
defer c.glDeleteShader(vert_shader);
|
||||
|
@ -125,15 +131,24 @@ pub fn init(egl_dpy: c.EGLDisplay, output_info: []const OutputInfo) !Gfx {
|
|||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, 0);
|
||||
c.glBindRenderbuffer(c.GL_FRAMEBUFFER, 0);
|
||||
c.glBindRenderbuffer(c.GL_RENDERBUFFER, 0);
|
||||
|
||||
var vao: c_uint = 0;
|
||||
c.glGenVertexArrays(1, &vao);
|
||||
|
||||
var vbo: c_uint = 0;
|
||||
c.glGenBuffers(1, &vbo);
|
||||
|
||||
return .{
|
||||
.dpy = dpy,
|
||||
.egl_dpy = egl_dpy,
|
||||
.bg_shader_program = bg_program,
|
||||
.main_shader_program = main_program,
|
||||
.bg_bufs = bg_bufs,
|
||||
.time = 0,
|
||||
.cursor_positions = cursor_positions,
|
||||
.vao = vao,
|
||||
.vbo = vbo,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -197,6 +212,8 @@ pub fn draw(
|
|||
) !void {
|
||||
self.time += dt;
|
||||
dth.should_redraw[output_idx] = false;
|
||||
c.glBindVertexArray(self.vao);
|
||||
c.glBindBuffer(c.GL_ARRAY_BUFFER, self.vbo);
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); // use default framebuffer
|
||||
c.glUseProgram(self.main_shader_program);
|
||||
|
||||
|
@ -210,7 +227,8 @@ pub fn draw(
|
|||
-1.0, 1.0, 0.0, 0.0, 1.0,
|
||||
};
|
||||
|
||||
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, &vertices);
|
||||
c.glBufferData(c.GL_ARRAY_BUFFER, @sizeOf(f32) * vertices.len, &vertices, c.GL_STATIC_DRAW);
|
||||
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, @sizeOf(f32) * 5, null);
|
||||
c.glEnableVertexAttribArray(0);
|
||||
c.glVertexAttribPointer(
|
||||
1,
|
||||
|
@ -218,7 +236,7 @@ pub fn draw(
|
|||
c.GL_FLOAT,
|
||||
c.GL_FALSE,
|
||||
@sizeOf(f32) * 5,
|
||||
@ptrFromInt(@intFromPtr(&vertices) + @sizeOf(f32) * 3),
|
||||
@ptrFromInt(@sizeOf(f32) * 3),
|
||||
);
|
||||
c.glEnableVertexAttribArray(1);
|
||||
|
||||
|
@ -243,8 +261,25 @@ pub fn draw(
|
|||
|
||||
c.glDrawArrays(c.GL_TRIANGLES, 0, vertices.len / 3);
|
||||
|
||||
if (c.eglSwapInterval(self.egl_dpy, 0) != c.EGL_TRUE or
|
||||
c.eglSwapBuffers(self.egl_dpy, outputs[output_idx].egl_surface) != c.EGL_TRUE) return error.EGLError;
|
||||
// This is necessary because some EGL implementations (Mesa) will try reading the wayland
|
||||
// socket from eglSwapBuffers.
|
||||
// This causes a deadlock, is abysmal API design, and not preventable. It's gotten so bad
|
||||
// that another suggested workaround on the archive linked below is to put this on another
|
||||
// thread in order to force EGL to use its own wayland event queue.
|
||||
//
|
||||
// By cancelling the read operation first (which is always prep'd usually and handled by the
|
||||
// event loop), we can ensure that EGL gets to do its nonsense here before making libwayland
|
||||
// handle another read correctly by calling prepareRead again.
|
||||
//
|
||||
// Somehow the only trace of this BS on the entire internet and only reason I managed to figure
|
||||
// this out: https://lists.freedesktop.org/archives/wayland-devel/2013-March/007739.html
|
||||
self.dpy.cancelRead();
|
||||
if (c.eglSwapBuffers(
|
||||
self.egl_dpy,
|
||||
outputs[output_idx].egl_surface,
|
||||
) != c.EGL_TRUE) return error.EGLError;
|
||||
if (self.dpy.dispatchPending() != .SUCCESS) return error.RoundtipFail;
|
||||
std.debug.assert(self.dpy.prepareRead());
|
||||
}
|
||||
|
||||
pub fn drawBackground(
|
||||
|
@ -271,6 +306,8 @@ pub fn drawBackground(
|
|||
-1.0, 1.0, 0.0,
|
||||
};
|
||||
|
||||
c.glBindVertexArray(self.vao);
|
||||
c.glBindBuffer(c.GL_ARRAY_BUFFER, self.vbo);
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.bg_bufs.get(output_idx).framebuffer);
|
||||
|
||||
c.glClearColor(1.0, 0.0, 0.0, 1.0);
|
||||
|
@ -278,7 +315,8 @@ pub fn drawBackground(
|
|||
|
||||
c.glUseProgram(self.bg_shader_program);
|
||||
|
||||
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, 0, &vertices);
|
||||
c.glBufferData(c.GL_ARRAY_BUFFER, @sizeOf(f32) * vertices.len, &vertices, c.GL_STATIC_DRAW);
|
||||
c.glVertexAttribPointer(0, 3, c.GL_FLOAT, c.GL_FALSE, 0, null);
|
||||
c.glEnableVertexAttribArray(0);
|
||||
|
||||
c.glUniform2f(c.glGetUniformLocation(self.bg_shader_program, "offset"), off.x, off.y);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
#version 430
|
||||
|
||||
uniform float time;
|
||||
|
||||
|
@ -20,7 +18,7 @@ void main() {
|
|||
vec2 R = vec2(1);
|
||||
ivec4 b = ivec4(o -= o); // Initialize b=0
|
||||
float t = .1*time, B, h, z;
|
||||
vec4 g;
|
||||
vec4 g = vec4(0);
|
||||
|
||||
u =
|
||||
(5. + cos(t) * 1.5) * // * Camera push in/out
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
#version 430
|
||||
|
||||
uniform vec2 offset;
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
pub const c = @cImport({
|
||||
@cInclude("wayland-egl.h"); // required for egl include to work
|
||||
@cInclude("EGL/egl.h");
|
||||
@cInclude("GLES2/gl2.h");
|
||||
|
||||
@cDefine("GL_GLEXT_PROTOTYPES", "1");
|
||||
@cInclude("GL/gl.h");
|
||||
@cInclude("GL/glext.h");
|
||||
});
|
||||
|
|
|
@ -42,6 +42,8 @@ pub fn main() !void {
|
|||
|
||||
if (dpy.roundtrip() != .SUCCESS) return error.RoundtipFail;
|
||||
|
||||
if (c.eglBindAPI(c.EGL_OPENGL_API) == 0) return error.EGLError;
|
||||
|
||||
const egl_dpy = c.eglGetDisplay(@ptrCast(dpy)) orelse return error.EGLError;
|
||||
if (c.eglInitialize(egl_dpy, null, null) != c.EGL_TRUE) return error.EGLError;
|
||||
defer _ = c.eglTerminate(egl_dpy);
|
||||
|
@ -53,7 +55,7 @@ pub fn main() !void {
|
|||
egl_dpy,
|
||||
&[_]i32{
|
||||
c.EGL_SURFACE_TYPE, c.EGL_WINDOW_BIT,
|
||||
c.EGL_RENDERABLE_TYPE, c.EGL_OPENGL_ES2_BIT,
|
||||
c.EGL_RENDERABLE_TYPE, c.EGL_OPENGL_BIT,
|
||||
c.EGL_RED_SIZE, 8,
|
||||
c.EGL_GREEN_SIZE, 8,
|
||||
c.EGL_BLUE_SIZE, 8,
|
||||
|
@ -72,8 +74,10 @@ pub fn main() !void {
|
|||
config,
|
||||
c.EGL_NO_CONTEXT,
|
||||
&[_]i32{
|
||||
c.EGL_CONTEXT_MAJOR_VERSION, 2,
|
||||
c.EGL_CONTEXT_OPENGL_DEBUG, 1,
|
||||
c.EGL_CONTEXT_MAJOR_VERSION, 4,
|
||||
c.EGL_CONTEXT_MINOR_VERSION, 3,
|
||||
c.EGL_CONTEXT_OPENGL_DEBUG, c.EGL_TRUE,
|
||||
c.EGL_CONTEXT_OPENGL_PROFILE_MASK, c.EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
|
||||
c.EGL_NONE,
|
||||
},
|
||||
) orelse return error.EGLError;
|
||||
|
@ -188,7 +192,11 @@ pub fn main() !void {
|
|||
egl_ctx,
|
||||
) != c.EGL_TRUE) return error.EGLError;
|
||||
|
||||
var gfx = try Gfx.init(egl_dpy, output_info);
|
||||
c.glDebugMessageCallback(&glDebugCb, null);
|
||||
c.glEnable(c.GL_DEBUG_OUTPUT);
|
||||
std.log.info("initialized OpenGL {s}", .{c.glGetString(c.GL_VERSION)});
|
||||
|
||||
var gfx = try Gfx.init(dpy, egl_dpy, output_info);
|
||||
defer gfx.deinit();
|
||||
|
||||
var rdata = RenderData{
|
||||
|
@ -232,6 +240,9 @@ pub fn main() !void {
|
|||
};
|
||||
loop.add(&wl_poll_completion);
|
||||
|
||||
if (dpy.dispatchPending() != .SUCCESS) return error.RoundtipFail;
|
||||
std.debug.assert(dpy.prepareRead());
|
||||
|
||||
std.log.info("running event loop", .{});
|
||||
try loop.run(.until_done);
|
||||
}
|
||||
|
@ -349,12 +360,18 @@ fn wlPollCb(
|
|||
};
|
||||
|
||||
const dpy: *wl.Display = @ptrCast(@alignCast(userdata));
|
||||
if (dpy.dispatchPending() != .SUCCESS or dpy.flush() != .SUCCESS) {
|
||||
if (dpy.readEvents() != .SUCCESS or
|
||||
dpy.dispatchPending() != .SUCCESS or
|
||||
dpy.flush() != .SUCCESS)
|
||||
{
|
||||
std.log.err("error processing wayland events", .{});
|
||||
loop.stop();
|
||||
return .disarm;
|
||||
}
|
||||
|
||||
// This is only false if the queue is not empty, but we just emptied the queue.
|
||||
std.debug.assert(dpy.prepareRead());
|
||||
|
||||
return .rearm;
|
||||
}
|
||||
|
||||
|
@ -426,3 +443,27 @@ fn resetXevTimerCompletion(completion: *xev.Completion, now: i64, in: i64) void
|
|||
.tv_nsec = @mod(next_time, std.time.ms_per_s) * std.time.ns_per_ms,
|
||||
};
|
||||
}
|
||||
|
||||
fn glDebugCb(
|
||||
source: c.GLenum,
|
||||
@"type": c.GLenum,
|
||||
id: c.GLuint,
|
||||
severity: c.GLenum,
|
||||
len: c.GLsizei,
|
||||
msgp: ?[*:0]const u8,
|
||||
udata: ?*const anyopaque,
|
||||
) callconv(.C) void {
|
||||
_ = source;
|
||||
_ = @"type";
|
||||
_ = id;
|
||||
_ = udata;
|
||||
const log = std.log.scoped(.gl);
|
||||
// Mesa likes to include trailing newlines sometimes
|
||||
const msg = std.mem.trim(u8, msgp.?[0..@intCast(len)], &std.ascii.whitespace);
|
||||
switch (severity) {
|
||||
c.GL_DEBUG_SEVERITY_HIGH => log.err("{s}", .{msg}),
|
||||
c.GL_DEBUG_SEVERITY_MEDIUM, c.GL_DEBUG_SEVERITY_LOW => log.warn("{s}", .{msg}),
|
||||
c.GL_DEBUG_SEVERITY_NOTIFICATION => log.info("{s}", .{msg}),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
#version 430
|
||||
|
||||
uniform sampler2D bg;
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
#version 430
|
||||
|
||||
in vec4 vPos;
|
||||
in vec2 uv;
|
||||
|
|
Loading…
Reference in a new issue