summaryrefslogtreecommitdiff
path: root/src/screen.c
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-04-24 15:19:45 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-04-24 15:19:45 -0400
commit0aa6e65ea6ef044cf877ed6df8f3bf00141e0b23 (patch)
treedd1f9aa154fe0955274e2900f368b8f7e43634a3 /src/screen.c
parentwindow title (diff)
downloadraycaster-0aa6e65ea6ef044cf877ed6df8f3bf00141e0b23.tar.gz
raycaster-0aa6e65ea6ef044cf877ed6df8f3bf00141e0b23.tar.bz2
raycaster-0aa6e65ea6ef044cf877ed6df8f3bf00141e0b23.zip
i made a swapchain
Diffstat (limited to 'src/screen.c')
-rw-r--r--src/screen.c190
1 files changed, 136 insertions, 54 deletions
diff --git a/src/screen.c b/src/screen.c
index 762ecbc..eb2de87 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1,4 +1,5 @@
#include "screen.h"
+#include <sched.h>
#undef Screen
#include <math.h>
@@ -7,6 +8,8 @@
#include <string.h>
#include <time.h>
#include <sys/select.h>
+#include <pthread.h>
+#include <unistd.h>
#define XLIB_ILLEGAL_ACCESS
#include <X11/X.h>
@@ -28,8 +31,9 @@ typedef struct {
Window window;
GC graphics_ctx;
Pixmap pixel_map;
- XImage* image;
- int width, height;
+ XImage** images;
+ pthread_t update_thread;
+ pthread_mutex_t recreate_lock;
} WindowState;
static void init_x() {
@@ -89,43 +93,144 @@ static XImage* create_image(int width, int height, void* data) {
);
}
+static Swapchain create_swapchain(int width, int height, int frames, int bit_depth, WindowState* state) {
+ Swapchain swapchain;
+ swapchain.width = width;
+ swapchain.height = height;
+ swapchain.image_count = frames;
+ swapchain.image_front = 0;
+ swapchain.image_recent = 0;
+ swapchain.image_current = 0;
+ swapchain.images = malloc(sizeof(uint32_t*) * frames);
+
+ state->images = malloc(sizeof(XImage*) * frames);
+ state->pixel_map = XCreatePixmap(dpy, state->window, width, height, bit_depth);
+ state->graphics_ctx = XCreateGC(dpy, state->pixel_map, 0, NULL);
+
+ size_t pixel_count = width * height;
+ for (int i = 0; i < frames; i++) {
+ uint32_t* data = malloc(pixel_count * bit_depth / 8);
+ memset(data, 0, pixel_count * bit_depth / 8);
-void init_screen(struct Screen* screen, uint16_t width, uint16_t height, const char* title) {
+ swapchain.images[i] = data;
+ state->images[i] = create_image(width, height, data);
- if (dpy == NULL) {
- init_x();
}
- screen->width = width;
- screen->height = height;
- screen->delta = 0;
+ pthread_mutex_init(&state->recreate_lock, NULL);
+ pthread_mutex_init(&swapchain.lock, NULL);
+
+ return swapchain;
+}
+
+static void free_swapchain(Swapchain swapchain, WindowState* state) {
+ for (uint8_t i = 0; i < swapchain.image_count; i++) {
+ XDestroyImage(state->images[i]); // also frees pixel buffer :3
+ }
+
+ free(swapchain.images);
+ free(state->images);
- size_t pixel_count = screen->width * screen->height;
+ XFreePixmap(dpy, state->pixel_map);
+ XFreeGC(dpy, state->graphics_ctx);
+}
- screen->pixels = malloc(pixel_count * bit_depth / 8);
- memset(screen->pixels, 0, pixel_count * bit_depth / 8);
+static void recreate_swapchain(int width, int height, int bit_depth, Swapchain* swapchain, WindowState* state) {
+ pthread_mutex_lock(&state->recreate_lock);
- Window window = create_window(0, 0, width, height, bit_depth, title);
- XMapWindow(dpy, window);
+ swapchain->width = width;
+ swapchain->height = height;
+
+ XFreePixmap(dpy, state->pixel_map);
+ XFreeGC(dpy, state->graphics_ctx);
+
+ state->pixel_map = XCreatePixmap(dpy, state->window, width, height, bit_depth);
+ state->graphics_ctx = XCreateGC(dpy, state->pixel_map, 0, NULL);
+
+ size_t pixel_count = width * height;
+ for (uint8_t i = 0; i < swapchain->image_count; i++) {
+ XDestroyImage(state->images[i]); // also frees pixel buffer :3
+
+ uint32_t* data = malloc(pixel_count * bit_depth / 8);
+ memset(data, 0, pixel_count * bit_depth / 8);
+
+ swapchain->images[i] = data;
+ state->images[i] = create_image(width, height, data);
+ }
+
+ pthread_mutex_unlock(&state->recreate_lock);
+}
+
+void swapchain_next(Swapchain* swapchain) {
+ pthread_mutex_lock(&swapchain->lock);
+ uint8_t next = swapchain->image_current + 1;
+ next %= swapchain->image_count;
+
+ if (next == swapchain->image_front) {
+ next += 1;
+ next %= 3;
+ }
+
+ swapchain->image_current = next;
+ pthread_mutex_unlock(&swapchain->lock);
+}
+
+void swapchain_submit(Swapchain* swapchain) {
+ pthread_mutex_lock(&swapchain->lock);
+ swapchain->image_recent = swapchain->image_current;
+ pthread_mutex_unlock(&swapchain->lock);
+}
+
+static void* swapchain_thread(void* arg) {
+ struct Screen* screen = (struct Screen*) arg;
+ WindowState* state = (WindowState*) screen->internal;
- Pixmap pixel_map = XCreatePixmap(dpy, window, width, height, bit_depth);
+ while (1) {
+ pthread_mutex_lock(&state->recreate_lock);
+
+ pthread_mutex_lock(&screen->swapchain.lock);
+ int index = screen->swapchain.image_recent;
+ screen->swapchain.image_front = index;
+ pthread_mutex_unlock(&screen->swapchain.lock);
+
+ XPutImage(
+ dpy,
+ state->window,
+ state->graphics_ctx,
+ state->images[index],
+ 0, 0, 0, 0,
+ screen->swapchain.width,
+ screen->swapchain.height
+ );
+ XSync(dpy, 0);
+
+ pthread_mutex_unlock(&state->recreate_lock);
+
+ usleep(1000 * 1000 / 60);
+ }
- GC gc = XCreateGC(dpy, pixel_map, 0, NULL);
+ return NULL;
+}
+
+#define FRAMES 3
+
+void init_screen(struct Screen* screen, uint16_t width, uint16_t height, const char* title) {
+
+ if (dpy == NULL) {
+ init_x();
+ }
+
+ Window window = create_window(0, 0, width, height, bit_depth, title);
+ XMapWindow(dpy, window);
WindowState* state = malloc(sizeof(WindowState));
state->window = window;
- state->graphics_ctx = gc;
- state->pixel_map = pixel_map;
-
- XWindowAttributes xwa;
- XGetWindowAttributes(dpy, window, &xwa);
- state->width = xwa.width;
- state->height = xwa.height;
- screen->internal = state;
- XImage* image = create_image(state->width, state->height, screen->pixels);
- state->image = image;
+ screen->swapchain = create_swapchain(width, height, FRAMES, bit_depth, state);
+ pthread_create(&state->update_thread, NULL, &swapchain_thread, screen);
+ screen->delta = 0;
+ screen->internal = state;
count++;
}
@@ -147,27 +252,10 @@ static void update_delta(struct Screen* screen) {
last = now;
}
-static void draw_screen(struct Screen* screen) {
- WindowState* state = (WindowState*) screen->internal;
-
- XPutImage(
- dpy,
- state->window,
- state->graphics_ctx,
- state->image,
- 0, 0, 0, 0,
- state->width,
- state->height
- );
-}
-
-
-static void handle_event(WindowState* state) {
+static void handle_event(struct Screen* screen) {
XEvent event;
XNextEvent(dpy, &event);
-
switch(event.type) {
-
case KeyPress: {
XKeyEvent xkpe = event.xkey;
uint32_t code = xkpe.keycode - dpy->min_keycode;
@@ -185,9 +273,8 @@ static void handle_event(WindowState* state) {
case ConfigureNotify: {
XConfigureEvent xce = event.xconfigure;
- state->width = xce.width;
- state->height = xce.height;
-
+ if (xce.width != screen->swapchain.width || xce.height != screen->swapchain.height)
+ recreate_swapchain(xce.width, xce.height, bit_depth, &screen->swapchain, (WindowState*) screen->internal);
break;
}
@@ -196,13 +283,9 @@ static void handle_event(WindowState* state) {
}
bool poll_screen(struct Screen* screen) {
-
- draw_screen(screen);
- WindowState* state = (WindowState*) screen->internal;
-
while (XPending(dpy))
- handle_event(state);
+ handle_event(screen);
update_delta(screen);
return true;
@@ -211,10 +294,9 @@ bool poll_screen(struct Screen* screen) {
void free_screen(struct Screen* screen) {
WindowState* state = (WindowState*) screen->internal;
+ pthread_exit(&state->update_thread);
XUnmapWindow(dpy, state->window);
- XFreePixmap(dpy, state->pixel_map);
- XDestroyImage(state->image);
- XFreeGC(dpy, state->graphics_ctx);
+ free_swapchain(screen->swapchain, state);
XDestroyWindow(dpy, state->window);
free(screen->internal);