Unfinished Wayland PR #1

Merged
IoI_xD merged 55 commits from IoI_xD/milsko:wayland into master 2025-12-10 11:11:02 +09:00
6 changed files with 310 additions and 119 deletions
Showing only changes of commit 0adc98a2a2 - Show all commits

wayland: give up on cairo and switch to OpenGL

IoIxD 2025-12-03 18:17:27 -07:00

View file

@ -12,11 +12,14 @@
#include <Mw/TypeDefs.h>
#include <Mw/LowLevel.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <cairo/cairo.h>
MWDECL int MwLLWaylandCallInit(void);
#ifndef WL_PROTOCOLS_DEFINED
@ -58,21 +61,6 @@ struct _MwLLWayland {
MWLL_WAYLAND_SUBSURFACE = 1,
} type;
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_surface* surface;
struct wl_shm* shm;
struct wl_registry_listener registry_listener;
int mapped_buffer_size;
cairo_surface_t* cairo_surface;
// cairo_t* cairo;
MwU8* mapped_buffer;
struct {
const char* key;
wl_setup_func* value;
@ -83,9 +71,32 @@ struct _MwLLWayland {
wayland_protocol_t* value;
}* wl_protocol_map;
/*MwLL* subsurfaces;*/
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
struct wl_subcompositor* subcompositor;
struct wl_surface* surface;
struct wl_shm* shm;
struct wl_registry_listener registry_listener;
// cairo_surface_t* cairo_surface;
MwBool configured;
MwBool force_redraw;
MwBool do_clear;
MwU32 x, y, ww, wh;
MwLL parent;
GLuint fbo;
unsigned int fbo_texture;
unsigned int rbo;
MwBool egl_setup;
EGLNativeWindowType egl_window_native;
EGLDisplay egl_display;
EGLContext egl_context;
EGLSurface egl_surface;
};
struct _MwLLWaylandColor {

View file

@ -30,7 +30,7 @@ if (grep(/^gdi$/, @backends)) {
if (grep(/^wayland$/, @backends)) {
add_cflags("-DUSE_WAYLAND");
new_object("src/backend/wayland.c");
add_libs("-lcairo -lwayland-client -lxkbcommon");
add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon");
scan_wayland_protocol("stable", "xdg-shell","");
scan_wayland_protocol("stable", "tablet","-v2");

View file

@ -1,5 +1,6 @@
/* $Id$ */
#include <GL/gl.h>
#include <Mw/Milsko.h>
#include <assert.h>
@ -18,6 +19,17 @@
#include "Mw/LowLevel.h"
#include <sys/mman.h>
#include <wayland-egl-core.h>
#include <wayland-util.h>
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
// PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus;
#define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name)
@ -57,57 +69,8 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland
wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
return NULL;
}
static void buffer_setup(struct _MwLLWayland* wayland) {
struct wl_shm_pool* pool;
struct wl_buffer* buffer;
int x, y;
int stride = wayland->ww * 4;
int fd;
MwU32 size = wayland->ww * wayland->wh * 4;
char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX";
fd = mkstemp(temp_name);
unlink(temp_name);
if(posix_fallocate(fd, 0, size) != 0) {
printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno));
close(fd);
return;
}
if(ftruncate(fd, size) != 0) {
printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno));
close(fd);
return;
}
wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
memset(wayland->mapped_buffer, 0xFF, size);
// wayland->mapped_buffer_size = size;
wayland->cairo_surface = cairo_image_surface_create_for_data(wayland->mapped_buffer,
CAIRO_FORMAT_ARGB32,
wayland->ww,
wayland->wh,
stride);
fsync(fd);
if(!(pool = wl_shm_create_pool(wayland->shm, fd, size))) {
printf("failure setting up wl_shm: could not create pool.\n");
}
buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888);
if(wayland->configured) {
wl_surface_attach(wayland->surface, buffer, 0, 0);
wl_surface_commit(wayland->surface);
}
wl_buffer_destroy(buffer);
wl_shm_pool_destroy(pool);
close(fd);
}
// static void buffer_setup(struct _MwLLWayland* wayland) {
// }
static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
@ -174,20 +137,171 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _
return proto;
}
static MwBool egl_setup(MwLL self, int width, int height) {
int err;
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint fbAttribs[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE};
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_CONTEXT_MAJOR_VERSION, 1,
EGL_CONTEXT_MINOR_VERSION, 1,
EGL_NONE};
EGLDisplay display = eglGetDisplay(self->wayland.display);
if(display == EGL_NO_DISPLAY) {
printf("ERROR: eglGetDisplay, %0X\n", eglGetError());
return MwFALSE;
}
// Initialize EGL
if(!eglInitialize(display, &majorVersion, &minorVersion)) {
printf("ERROR: eglInitialize, %0X\n", eglGetError());
return MwFALSE;
}
// Get configs
if((eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0)) {
printf("ERROR: eglGetConfigs, %0X\n", eglGetError());
return MwFALSE;
}
// Choose config
if((eglChooseConfig(display, fbAttribs, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) {
printf("ERROR: eglChooseConfig, %0X\n", eglGetError());
return MwFALSE;
}
self->wayland.egl_window_native =
wl_egl_window_create(self->wayland.surface, width, height);
if(self->wayland.egl_window_native == EGL_NO_SURFACE) {
printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n");
return MwFALSE;
}
// Create a surface
surface = eglCreateWindowSurface(display, config, self->wayland.egl_window_native, NULL);
if(surface == EGL_NO_SURFACE) {
printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError());
return MwFALSE;
}
eglBindAPI(EGL_OPENGL_API);
// Create a GL context
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if(context == EGL_NO_CONTEXT) {
printf("ERROR: eglCreateContext, %0X\n", eglGetError());
return MwFALSE;
}
// Make the context current
if(!eglMakeCurrent(display, surface, surface, context)) {
printf("ERROR: eglMakeCurrent, %0X\n", eglGetError());
return MwFALSE;
}
glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)eglGetProcAddress("glGenFramebuffers");
glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D");
glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)eglGetProcAddress("glGenRenderbuffers");
// glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)eglGetProcAddress("glRenderbufferStorage");
glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)eglGetProcAddress("glFramebufferRenderbuffer");
glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer");
glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer");
glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)eglGetProcAddress("glCheckFramebufferStatus");
glGenTextures(1, &self->wayland.fbo_texture);
glBindTexture(GL_TEXTURE_2D, self->wayland.fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenRenderbuffers(1, &self->wayland.rbo);
// glBindRenderbuffer(GL_RENDERBUFFER, self->wayland.rbo));
// glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 768, 1024);
// glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &self->wayland.fbo);
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, self->wayland.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->wayland.fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self->wayland.rbo);
if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
printf("Error binding framebuffer: %0X\n", err);
return MwFALSE;
}
glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, -13, -1, 1);
self->wayland.egl_display = display;
self->wayland.egl_surface = surface;
self->wayland.egl_context = context;
printf("EGL success\n");
return MwTRUE;
}
static void xdg_toplevel_configure(void* data,
struct xdg_toplevel* xdg_toplevel,
MwI32 width, MwI32 height,
struct wl_array* states) {
MwLL self = data;
MwLL self = data;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D");
if(width != 0 && height != 0) {
self->wayland.ww = width;
self->wayland.wh = height;
xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh);
if(width == 0 && height == 0) {
width = self->wayland.ww;
height = self->wayland.wh;
}
self->wayland.ww = width;
self->wayland.wh = height;
xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh);
MwLLSetWH(self, width, height);
MwLLDispatch(self, resize, NULL);
};
MwLLSetWH(self, width, height);
MwLLDispatch(self, resize, NULL);
if(!self->wayland.egl_setup) {
self->wayland.egl_setup = egl_setup(self, width, height);
} else {
wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, height, -13, -1, 1);
self->wayland.do_clear = MwTRUE;
// glDeleteTextures(1, &self->wayland.fbo_texture);
// glGenTextures(1, &self->wayland.fbo_texture);
// glBindTexture(GL_TEXTURE_2D, self->wayland.fbo_texture);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
// glBindTexture(GL_TEXTURE_2D, 0);
}
MwLLForceRender(self);
@ -335,7 +449,7 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) {
printf("zxdg null\n");
}
buffer_setup(&r->wayland);
// buffer_setup(&r->wayland);
wl_surface_commit(r->wayland.surface);
}
@ -369,23 +483,34 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h
return;
}
// arrpush(parent->wayland.subsurfaces, r);
r->wayland.configured = MwTRUE;
r->wayland.egl_context = parent->wayland.egl_context;
r->wayland.egl_display = parent->wayland.egl_display;
r->wayland.egl_surface = parent->wayland.egl_surface;
r->wayland.fbo = parent->wayland.fbo;
r->wayland.fbo_texture = parent->wayland.fbo_texture;
r->wayland.rbo = parent->wayland.rbo;
}
static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
MwLL r;
r = malloc(sizeof(*r));
MwLLCreateCommon(r);
// r->common.copy_buffer = 1;
r->common.type = MwLLBackendWayland;
if(width == 0) width = parent->wayland.ww;
if(height == 0) height = parent->wayland.wh;
if(width == 0) width = 1;
if(height == 0) height = 1;
r->wayland.ww = width;
r->wayland.wh = height;
r->wayland.ww = width;
r->wayland.wh = height;
r->wayland.parent = parent;
r->common.success = MwTRUE;
r->wayland.force_redraw = MwFALSE;
r->wayland.do_clear = MwFALSE;
r->common.success = MwTRUE;
if(parent == NULL) {
setup_toplevel(r, x, y, width, height);
@ -393,7 +518,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
setup_subsurface(parent, r, x, y, width, height);
}
buffer_setup(&r->wayland);
// buffer_setup(&r->wayland);
return r;
}
@ -412,6 +537,13 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign
}
static void MwLLSetXYImpl(MwLL handle, int x, int y) {
if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
handle->wayland.x = x;
handle->wayland.y = y;
wl_subsurface_set_position(handle->wayland.subsurface, x, y);
MwLLForceRender(handle);
}
}
static void MwLLSetWHImpl(MwLL handle, int w, int h) {
@ -421,45 +553,82 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) {
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh);
} else {
// setup the buffer again with the new size.
// buffer_setup(&handle->wayland);
}
}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
int i = 0;
/*
* TODO: this function sucks shit, ioi needs to make it not suck shit :)
*/
int i;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer");
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer");
int w, h;
cairo_t* cairo = cairo_create(handle->wayland.cairo_surface);
cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.);
cairo_set_line_width(cairo, 0.1);
cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD);
cairo_new_path(cairo);
for(; i < points_count; i++) {
cairo_line_to(cairo, points[i].x, points[i].y);
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
w = handle->wayland.ww;
h = handle->wayland.wh;
} else {
MwLL parent = handle->wayland.parent;
while(parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
parent = parent->wayland.parent;
}
w = parent->wayland.ww;
h = parent->wayland.wh;
}
cairo_close_path(cairo);
// cairo_paint(cairo);
cairo_stroke_preserve(cairo);
cairo_fill(cairo);
cairo_destroy(cairo);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0);
glBegin(GL_TRIANGLE_FAN);
for(i = 0; i < points_count; i++) {
glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0);
glVertex2f(
(handle->wayland.x + points[i].x),
(handle->wayland.y + points[i].y));
if((i % 3) == 0 && i != 0) {
glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0);
glVertex2f(
(handle->wayland.x + points[i].x),
(handle->wayland.y + points[i].y));
}
}
glEnd();
glFinish();
glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0, 0, 0, 1);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1);
glVertex2f(0, 0);
glTexCoord2f(1, 1);
glVertex2f(w, 0);
glTexCoord2f(1, 0.0f);
glVertex2f(w, h);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, h);
glEnd();
glFinish();
if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) {
printf("error swapping buffers! %0X\n", eglGetError());
} else {
wl_surface_commit(handle->wayland.surface);
}
glDisable(GL_TEXTURE_2D);
handle->wayland.do_clear = MwFALSE;
}
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
MwPoint p1 = points[0];
MwPoint p2 = points[1];
int i;
cairo_t* cairo = cairo_create(handle->wayland.cairo_surface);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_line_width(cairo, 1);
cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.);
cairo_paint(cairo);
cairo_move_to(cairo, p1.x, p1.y);
cairo_line_to(cairo, p2.x, p2.y);
cairo_fill(cairo);
cairo_destroy(cairo);
//
}
static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) {
@ -536,9 +705,7 @@ static int MwLLPendingImpl(MwLL handle) {
}
static void MwLLNextEventImpl(MwLL handle) {
MwBool render;
render = handle->wayland.force_redraw;
MwBool render = handle->wayland.force_redraw;
if(render) {
int x, y;
@ -580,9 +747,16 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {
}
static void MwLLForceRenderImpl(MwLL handle) {
// event_loop(handle);
wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
if(handle->wayland.egl_setup) {
if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) {
printf("error swapping buffers! %0X\n", eglGetError());
}
}
wl_surface_commit(handle->wayland.surface);
handle->wayland.force_redraw = MwTRUE;
}

View file

@ -131,6 +131,7 @@ static XVisualInfo* get_visual_info(Display* display) {
}
static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
printf("%d %d\n", width, height);
MwLL r;
Window p;
XVisualInfo* xvi;

View file

@ -1,7 +1,9 @@
/* $Id$ */
#include <Mw/Milsko.h>
#include <wayland-util.h>
#include "../external/stb_ds.h"
#include "Mw/LowLevel.h"
static void lldrawhandler(MwLL handle, void* data) {
MwWidget h = (MwWidget)handle->common.user;
@ -295,6 +297,7 @@ int MwStep(MwWidget handle) {
arrfree(widgets);
handle->prop_event = 0;
if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel))
MwLLNextEvent(handle->lowlevel);

View file

@ -1,4 +1,5 @@
/* $Id$ */
#include "Mw/LowLevel.h"
#include <Mw/Milsko.h>
#include <stdio.h>
@ -485,6 +486,7 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert,
p4[2].y = rect->y + s * border;
}
MwLLPolygon(handle->lowlevel, p4, 3, col);
if(color != col) MwLLFreeColor(col);
MwLLFreeColor(lighter);