wayland resize

This commit is contained in:
IoIxD 2025-12-05 14:50:04 -07:00
commit 0fc8b09913
2 changed files with 180 additions and 81 deletions

View file

@ -81,7 +81,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 +90,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 {

View file

@ -64,13 +64,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 +136,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,
@ -178,7 +170,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 +183,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 +192,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 +218,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 +246,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 +327,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 +445,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 +457,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,11 +513,9 @@ 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_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);
@ -496,8 +523,12 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) {
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,15 +547,19 @@ 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;
@ -532,6 +567,13 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h
r->wayland.surface = wl_compositor_create_surface(compositor);
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);
wl_subsurface_set_position(r->wayland.subsurface, x, y);
@ -540,8 +582,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 +596,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 +629,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 +663,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 +677,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 +764,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);