From d4d4835fd111de0e8fa16249359ff815d1c2bc50 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 5 Dec 2025 14:49:05 -0700 Subject: [PATCH] wayland resize --- include/Mw/LowLevel/Wayland.h | 9 +- src/backend/wayland.c | 279 ++++++++++++++++++++++++---------- 2 files changed, 205 insertions(+), 83 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 2ed3909..02f2b90 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -41,6 +41,7 @@ struct _MwLLWaylandTopLevel { struct xdg_toplevel* xdg_top_level; struct xdg_toplevel_listener xdg_toplevel_listener; struct xdg_surface_listener xdg_surface_listener; + struct wl_surface_listener surface_listener; struct xkb_context* xkb_context; @@ -81,7 +82,8 @@ struct _MwLLWayland { MwBool configured; MwBool force_redraw; - MwBool do_clear; + MwBool egl_setup; + MwBool egl_do_resetup; MwU32 x, y, ww, wh; int z_index; @@ -89,15 +91,12 @@ struct _MwLLWayland { 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; - GLuint vertex_buffer; - GLuint vertex_array; + EGLConfig egl_config; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 77669f1..443692d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -30,6 +30,12 @@ PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus; +EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_CONTEXT_MAJOR_VERSION, 1, + EGL_CONTEXT_MINOR_VERSION, 1, + EGL_NONE}; + #define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) static void new_protocol(void* data, struct wl_registry* registry, @@ -52,6 +58,19 @@ static void protocol_removed(void* data, }; +static void surface_enter(void* data, + struct wl_surface* wl_surface, + struct wl_output* output) { + MwLL self = data; + + printf("yhdhfgh\n"); +}; +static void surface_leave(void* data, + struct wl_surface* wl_surface, + struct wl_output* output) { + printf("yhdhfgh\n"); +}; + static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) {}; @@ -64,13 +83,6 @@ void xdg_wm_base_ping(void* data, xdg_wm_base_pong(xdg_wm_base, serial); }; -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) { -// } - static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); proto->listener = malloc(sizeof(struct wl_seat_listener)); @@ -143,7 +155,6 @@ static MwBool egl_setup(MwLL self, int width, int height) { EGLint minorVersion; EGLContext context; EGLSurface surface; - EGLConfig config; EGLint fbAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, @@ -153,11 +164,6 @@ static MwBool egl_setup(MwLL self, int width, int height) { 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) { @@ -178,7 +184,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { } // Choose config - if((eglChooseConfig(display, fbAttribs, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + if((eglChooseConfig(display, fbAttribs, &self->wayland.egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); return MwFALSE; } @@ -191,7 +197,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { } // Create a surface - surface = eglCreateWindowSurface(display, config, self->wayland.egl_window_native, NULL); + surface = eglCreateWindowSurface(display, self->wayland.egl_config, self->wayland.egl_window_native, NULL); if(surface == EGL_NO_SURFACE) { printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); return MwFALSE; @@ -200,7 +206,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { eglBindAPI(EGL_OPENGL_API); // Create a GL context - context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + context = eglCreateContext(display, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs); if(context == EGL_NO_CONTEXT) { printf("ERROR: eglCreateContext, %0X\n", eglGetError()); return MwFALSE; @@ -226,24 +232,15 @@ static MwBool egl_setup(MwLL self, int width, int height) { 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; @@ -263,6 +260,66 @@ static MwBool egl_setup(MwLL self, int width, int height) { return MwTRUE; } +static void egl_resetup(MwLL handle) { + int err; + + if(!handle->wayland.egl_do_resetup) { + return; + } + + if(!eglMakeCurrent(handle->wayland.egl_display, 0, 0, handle->wayland.egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + return; + } + + if(!eglDestroySurface(handle->wayland.egl_display, handle->wayland.egl_surface)) { + printf("ERROR: eglDestroySurface, %0X\n", eglGetError()); + return; + }; + + handle->wayland.egl_surface = eglCreateWindowSurface(handle->wayland.egl_display, handle->wayland.egl_config, handle->wayland.egl_window_native, NULL); + if(handle->wayland.egl_surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return; + } + + if(!eglMakeCurrent(handle->wayland.egl_display, handle->wayland.egl_surface, handle->wayland.egl_surface, handle->wayland.egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + return; + } + + glDeleteTextures(1, &handle->wayland.fbo_texture); + glGenTextures(1, &handle->wayland.fbo_texture); + glBindTexture(GL_TEXTURE_2D, handle->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, handle->wayland.ww, handle->wayland.wh, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glGenFramebuffers(1, &handle->wayland.fbo); + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, handle->wayland.fbo); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); + + if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { + printf("Error binding framebuffer: %0X\n", err); + return; + } + + glBindFramebuffer(GL_FRAMEBUFFER_BINDING, 0); + + glBindTexture(GL_TEXTURE_2D, 0); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, handle->wayland.ww, handle->wayland.wh, 0, -1, 1); + glViewport(0, 0, handle->wayland.ww, handle->wayland.wh); + + handle->wayland.egl_do_resetup = MwFALSE; +} + static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, @@ -284,26 +341,12 @@ static void xdg_toplevel_configure(void* data, if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, width, height); MwLLForceRender(self); - } else { - wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -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); } + wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); + self->wayland.egl_do_resetup = MwTRUE; + egl_resetup(self); + return; }; @@ -416,7 +459,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { wayland->wl_protocol_setup_map = NULL; wayland->wl_protocol_map = NULL; - WL_INTERFACE(wl_shm); WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_subcompositor); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { @@ -429,8 +471,9 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { #undef WL_INTERFACE -static void setup_toplevel(MwLL r, int x, int y, int width, int height) { - int i; +static void setup_toplevel(MwLL r, int x, int y) { + int i; + struct wl_region* region; r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); @@ -484,20 +527,29 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); // setup mandatory listeners - r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + + r->wayland.toplevel->surface_listener.enter = surface_enter; + r->wayland.toplevel->surface_listener.leave = surface_leave; + r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, r); + wl_surface_add_listener(r->wayland.surface, &r->wayland.toplevel->surface_listener, r); xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko Wayland App"); xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); // Perform the initial commit and wait for the first configure event + region = wl_compositor_create_region(r->wayland.compositor); + wl_region_add(region, 0, 0, r->wayland.ww, r->wayland.wh); + wl_surface_set_opaque_region(r->wayland.surface, region); wl_surface_commit(r->wayland.surface); event_loop(&r->wayland); + wl_region_destroy(region); printf("%p\n", shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name)); @@ -516,21 +568,33 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { // buffer_setup(&r->wayland); - wl_surface_commit(r->wayland.surface); - // glGenBuffers(1, &vertex_buffer); } -static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int height) { +static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { struct wl_compositor* compositor = parent->wayland.compositor; struct wl_subcompositor* subcompositor = parent->wayland.subcompositor; struct wl_surface* parent_surface = parent->wayland.surface; + MwLL topmost_parent = parent; + struct wl_region* region; + + while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } r->wayland.type = MWLL_WAYLAND_SUBSURFACE; r->wayland.display = parent->wayland.display; r->wayland.surface = wl_compositor_create_surface(compositor); + wl_surface_add_listener(r->wayland.surface, &topmost_parent->wayland.toplevel->surface_listener, r); + + region = wl_compositor_create_region(compositor); + wl_region_add(region, 0, 0, r->wayland.ww, r->wayland.wh); + wl_surface_set_opaque_region(r->wayland.surface, region); + wl_surface_commit(r->wayland.surface); + event_loop(&r->wayland); + wl_region_destroy(region); r->wayland.subsurface = wl_subcompositor_get_subsurface(subcompositor, r->wayland.surface, parent_surface); @@ -540,8 +604,8 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h setup_callbacks(&r->wayland); - r->wayland.registry = wl_display_get_registry(parent->wayland.display); - r->wayland.display = parent->wayland.display; + r->wayland.registry = wl_display_get_registry(topmost_parent->wayland.display); + r->wayland.display = topmost_parent->wayland.display; wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); if(wl_display_roundtrip(r->wayland.display) == -1) { @@ -554,13 +618,24 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h 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; + r->wayland.egl_context = topmost_parent->wayland.egl_context; + r->wayland.egl_display = topmost_parent->wayland.egl_display; + r->wayland.egl_surface = topmost_parent->wayland.egl_surface; + r->wayland.fbo = topmost_parent->wayland.fbo; + r->wayland.fbo_texture = topmost_parent->wayland.fbo_texture; } + +static void framebuffer_action_begin(MwLL handle) { + 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); +} + +static void framebuffer_action_end(MwLL handle) { + glFinish(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -576,13 +651,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.parent = parent; r->wayland.force_redraw = MwFALSE; - r->wayland.do_clear = MwFALSE; r->common.success = MwTRUE; if(parent == NULL) { - setup_toplevel(r, x, y, width, height); + setup_toplevel(r, x, y); } else { - setup_subsurface(parent, r, x, y, width, height); + setup_subsurface(parent, r, x, y); } return r; @@ -611,6 +685,10 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { + /* Prevent an integer underflow when the w/h is too low */ + if(w < 10 || h < 10) { + return; + } handle->wayland.ww = w; handle->wayland.wh = h; @@ -621,29 +699,74 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i; + int i, n; + float maxX = 0, maxY = 0; + float centerX, centerY; - 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); + if(points_count > 3) { + /* To avoid having to do a real triangulation algorithim: + 1.) loop through the points once to determine the bounds of the polygon + 2.) calculate the center of the polygon - if(points_count == 3) { - glBegin(GL_TRIANGLES); - } else if(points_count == 4) { - glBegin(GL_QUADS); - } else { - glBegin(GL_QUAD_STRIP); + */ + for(i = 0; i < points_count; i++) { + float x = round(handle->wayland.x) + round(points[i].x); + float y = round(handle->wayland.y) + round(points[i].y); + if(x >= maxX) { + maxX = x; + } + if(y >= maxY) { + maxY = y; + } + } } + centerX = (handle->wayland.x + maxX / 2); + centerY = (handle->wayland.y + maxY / 2); + /* Efficient? No. But at the end of the day it's still not that many polygons, and if a computer can't handle 12 polygons over 6 then it should not be using Wayland anyways */ + + framebuffer_action_begin(handle); + glBegin(GL_TRIANGLE_FAN); for(i = 0; i < points_count; i++) { + float x = round(handle->wayland.x) + round(points[i].x); + float y = round(handle->wayland.y) + round(points[i].y); + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - glVertex2f( - ceil(handle->wayland.x) + ceil(points[i].x), - ceil(handle->wayland.y) + ceil(points[i].y)); + + /* If we have a polygon that's covering the whole screen, we want to do glClear + */ + if(x == 0 && y == 0) { + /* + We determine this by checking if all of the points are at the edge of the screen (and if there's more then 6 points). + Not a pretty solution, but unless the user does something weird like draw a triangle over itself twice, I'm pretty sure this is effective. + */ + if(points_count >= 6) { + MwBool doClear = MwTRUE; + for(n = 0; n < points_count; n++) { + if((points[n].x >= (handle->wayland.ww) - 1 || points[n].x <= 1) && (points[n].y >= (handle->wayland.wh) - 1 || points[n].y <= 1)) { + } else { + doClear = MwFALSE; + break; + } + } + if(doClear) { + glEnd(); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1); + glBegin(GL_TRIANGLE_FAN); + } + } + } + + glVertex2f(x, y); + if(points_count > 3) { + glVertex2f(maxX, maxY); + glVertex2f(x, y); + } } glEnd(); - glFinish(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + + framebuffer_action_end(handle); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -663,8 +786,8 @@ static void MwLLEndDrawImpl(MwLL handle) { } glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 1); + // glClear(GL_COLOR_BUFFER_BIT); + // glClearColor(0, 0, 0, 1); glColor3f(1.0, 1.0, 1.0);