i made a swapchain

This commit is contained in:
Freya Murphy 2023-04-24 15:19:45 -04:00
parent 06389e7a7e
commit 0aa6e65ea6
4 changed files with 176 additions and 68 deletions

View file

@ -2,12 +2,13 @@ CC = gcc
INCFLAGS = -Isrc
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
CCFLAGS = -std=gnu99 -Wall -Wextra -pedantic -O2
CCFLAGS += $(INCFLAGS)
LDFLAGS += $(INCFLAGS)
LDFLAGS += -lX11
LDFLAGS += -lm
LDFLAGS += -lpthread
BIN = bin
APP = $(BIN)/app

View file

@ -3,6 +3,8 @@
#include "ray.h"
#include <math.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
@ -80,10 +82,11 @@ void update_camera(Camera* camera, Screen* screen) {
if (movey) camera->pos.y += move.y * MOVE_SPEED * screen->delta;
}
static void verline(Screen* screen, int x, int y0, int y1, uint32_t color) {
static void verline(Swapchain* swapchain, int x, int y0, int y1, uint32_t color) {
for (int y = y0; y <= y1; y++) {
screen->pixels[(y * screen->width) + x] = color;
swapchain->images[swapchain->image_current][(y * swapchain->width) + x] = color;
}
}
void render(Screen* screen, const Camera* camera) {
@ -93,9 +96,13 @@ void render(Screen* screen, const Camera* camera) {
cos(camera->angle)
};
for (int x = 0; x < screen->width; x++) {
Swapchain* swapchain = &screen->swapchain;
const float xcam = (2 * (x / (float) (screen->width))) - 1;
swapchain_next(swapchain);
for (int x = 0; x < screen->swapchain.width; x++) {
const float xcam = (2 * (x / (float) (swapchain->width))) - 1;
const float change = fov * atan(xcam);
const float theta = camera->angle + change;
@ -126,15 +133,18 @@ void render(Screen* screen, const Camera* camera) {
// }
const int
h = (int) (screen->height / len),
y0 = max((screen->height / 2) - (h / 2), 0),
y1 = min((screen->height / 2) + (h / 2), screen->height - 1);
h = (int) (swapchain->height / len),
y0 = max((swapchain->height / 2) - (h / 2), 0),
y1 = min((swapchain->height / 2) + (h / 2), swapchain->height - 1);
verline(swapchain, x, 0, y0, 0xFF202020);
verline(swapchain, x, y0, y1, color);
verline(swapchain, x, y1, swapchain->height - 1, 0xFF505050);
verline(screen, x, 0, y0, 0xFF202020);
verline(screen, x, y0, y1, color);
verline(screen, x, y1, screen->height - 1, 0xFF505050);
// verline(screen, x, 0, y0, 0x202020FF);
// verline(screen, x, y0, y1, color);
// verline(screen, x, y1, screen->height - 1, 0x505050FF);
}
swapchain_submit(swapchain);
}

View file

@ -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);
swapchain.images[i] = data;
state->images[i] = create_image(width, height, data);
}
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);
XFreePixmap(dpy, state->pixel_map);
XFreeGC(dpy, state->graphics_ctx);
}
static void recreate_swapchain(int width, int height, int bit_depth, Swapchain* swapchain, WindowState* state) {
pthread_mutex_lock(&state->recreate_lock);
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;
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);
}
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();
}
screen->width = width;
screen->height = height;
screen->delta = 0;
size_t pixel_count = screen->width * screen->height;
screen->pixels = malloc(pixel_count * bit_depth / 8);
memset(screen->pixels, 0, pixel_count * bit_depth / 8);
Window window = create_window(0, 0, width, height, bit_depth, title);
XMapWindow(dpy, window);
Pixmap pixel_map = XCreatePixmap(dpy, window, width, height, bit_depth);
GC gc = XCreateGC(dpy, pixel_map, 0, NULL);
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->swapchain = create_swapchain(width, height, FRAMES, bit_depth, state);
pthread_create(&state->update_thread, NULL, &swapchain_thread, screen);
screen->delta = 0;
screen->internal = state;
XImage* image = create_image(state->width, state->height, screen->pixels);
state->image = image;
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);

View file

@ -1,13 +1,28 @@
#pragma once
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 600
#define _POSIX_C_SOURCE 200112L
// #define _POSIX_C_SOURCE 200809L
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
struct Screen {
typedef struct {
uint16_t width;
uint16_t height;
uint32_t* pixels;
uint8_t image_count; // amount of frames in flight
uint8_t image_front; // image being drawn to screen
uint8_t image_recent; // last image that finished drawing
uint8_t image_current; // current image being drawn
pthread_mutex_t lock;
uint32_t** images;
} Swapchain;
void swapchain_next(Swapchain* swapchain);
void swapchain_submit(Swapchain* swapchain);
struct Screen {
Swapchain swapchain;
float delta;
void* internal;
};