From 2b9389ae016c8048a16ba033f27ca5c256985e4d Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 11 Jan 2024 20:18:34 +0100 Subject: Display windows with minimal delay, locked to 60 fps --- src/compositor.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/compositor.c (limited to 'src/compositor.c') diff --git a/src/compositor.c b/src/compositor.c new file mode 100644 index 0000000..4b622c0 --- /dev/null +++ b/src/compositor.c @@ -0,0 +1,150 @@ +#include "compositor.h" +#include +#include +#include +#include + +static double clock_get_monotonic_seconds(void) { + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double)ts.tv_sec + (double)ts.tv_nsec * 0.000000001; +} + +static ngxc_window* ngxc_compositor_get_window_by_id(ngxc_compositor *self, Window window) { + for(int i = 0; i < self->num_windows; ++i) { + ngxc_window *window_obj = &self->windows[i]; + if(window_obj->texture.window == window) + return window_obj; + } + return NULL; +} + +void ngxc_compositor_init(ngxc_compositor *self, Display *dpy, Window composite_window) { + memset(self, 0, sizeof(*self)); + self->dpy = dpy; + self->composite_window = composite_window; + self->frame_timer = clock_get_monotonic_seconds(); +} + +void ngxc_compositor_deinit(ngxc_compositor *self) { + +} + +void ngxc_compositor_add_window(ngxc_compositor *self, Window window) { + if(self->num_windows == NGXC_COMPOSITOR_MAX_WINDOWS) { + fprintf(stderr, "error: reached max number of trackable windows (%d), ignoring window with id %ld\n", NGXC_COMPOSITOR_MAX_WINDOWS, window); + return; + } + + XWindowAttributes xattr; + if(!XGetWindowAttributes(self->dpy, window, &xattr)) { + fprintf(stderr, "error: failed to get window attributes, ignoring window with id %ld\n", window); + return; + } + + //Window c; + //XTranslateCoordinates(self->dpy, window, DefaultRootWindow(self->dpy), 0, 0, &xattr.x, &xattr.y, &c); + + ngxc_window *window_obj = &self->windows[self->num_windows]; + if(window_texture_init(&window_obj->texture, self->dpy, window) != 0) { + fprintf(stderr, "error: failed to create window texture, ignoring window with id %ld\n", window); + return; + } + + window_obj->x = xattr.x; + window_obj->y = xattr.y; + ++self->num_windows; + + fprintf(stderr, "ADDED WINDOW: %ld, x: %d, y: %d\n", window, xattr.x, xattr.y); +} + +void ngxc_compositor_remove_window(ngxc_compositor *self, Window window) { + for(int i = 0; i < self->num_windows; ++i) { + if(self->windows[i].texture.window != window) + continue; + + window_texture_deinit(&self->windows[i].texture); + for(int j = i + 1; j < self->num_windows; ++j) { + self->windows[j - 1] = self->windows[j]; + } + break; + } +} + +static void render_texture(const ngxc_window *window) { + float matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + matrix[0] = 1.0f / (float)window->texture.width; + matrix[5] = 1.0f / (float)window->texture.height; + + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(matrix); + glMatrixMode(GL_MODELVIEW); + glBindTexture(GL_TEXTURE_2D, window->texture.texture_id); + + glColor4ub(255, 255, 255, 255); + //glTranslatef(window->x, window->y, 0.0f); + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(window->x, window->y); + + glTexCoord2f(window->texture.width, 0.0f); + glVertex2f(window->x + window->texture.width, window->y); + + glTexCoord2f(window->texture.width, window->texture.height); + glVertex2f(window->x + window->texture.width, window->y + window->texture.height); + + glTexCoord2f(0.0f, window->texture.height); + glVertex2f(window->x, window->y + window->texture.height); + glEnd(); + glLoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, 0); +} + +/* TODO: Skip windows that are not visible on the screen */ +/* TODO: Disable compositing for fullscreen windows, if that option is enabled */ +void ngxc_compositor_render(ngxc_compositor *self) { + glClearColor(1.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + for(int i = 0; i < self->num_windows; ++i) { + const ngxc_window *window_obj = &self->windows[i]; + render_texture(window_obj); + } + + const double now = clock_get_monotonic_seconds(); + const double frame_duration = now - self->frame_timer; + + glXSwapBuffers(self->dpy, self->composite_window); + glFlush(); + glFinish(); + + const double time_limit = 1.0f / 60.0f; // TODO: Get from randr + const double delayed_update = time_limit - frame_duration - 0.002; + //fprintf(stderr, "delayed update: %f\n", delayed_update); + if(delayed_update > 0.0) + usleep(delayed_update * 1000000.0); + + self->frame_timer = clock_get_monotonic_seconds(); +} + +void ngxc_compositor_on_configure(ngxc_compositor *self, const XConfigureEvent *configure_event) { + ngxc_window *window_obj = ngxc_compositor_get_window_by_id(self, configure_event->window); + if(!window_obj) + return; + + window_obj->x = configure_event->x; + window_obj->y = configure_event->y; + + if(configure_event->width != window_obj->texture.width || configure_event->height != window_obj->texture.height) { + window_texture_on_resize(&window_obj->texture); + } +} -- cgit v1.2.3