i made a swapchain
This commit is contained in:
parent
06389e7a7e
commit
0aa6e65ea6
4 changed files with 176 additions and 68 deletions
3
Makefile
3
Makefile
|
@ -2,12 +2,13 @@ CC = gcc
|
||||||
|
|
||||||
INCFLAGS = -Isrc
|
INCFLAGS = -Isrc
|
||||||
|
|
||||||
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
CCFLAGS = -std=gnu99 -Wall -Wextra -pedantic -O2
|
||||||
CCFLAGS += $(INCFLAGS)
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
LDFLAGS += $(INCFLAGS)
|
LDFLAGS += $(INCFLAGS)
|
||||||
LDFLAGS += -lX11
|
LDFLAGS += -lX11
|
||||||
LDFLAGS += -lm
|
LDFLAGS += -lm
|
||||||
|
LDFLAGS += -lpthread
|
||||||
|
|
||||||
BIN = bin
|
BIN = bin
|
||||||
APP = $(BIN)/app
|
APP = $(BIN)/app
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "ray.h"
|
#include "ray.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.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;
|
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++) {
|
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) {
|
void render(Screen* screen, const Camera* camera) {
|
||||||
|
@ -93,9 +96,13 @@ void render(Screen* screen, const Camera* camera) {
|
||||||
cos(camera->angle)
|
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 change = fov * atan(xcam);
|
||||||
const float theta = camera->angle + change;
|
const float theta = camera->angle + change;
|
||||||
|
|
||||||
|
@ -126,15 +133,18 @@ void render(Screen* screen, const Camera* camera) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const int
|
const int
|
||||||
h = (int) (screen->height / len),
|
h = (int) (swapchain->height / len),
|
||||||
y0 = max((screen->height / 2) - (h / 2), 0),
|
y0 = max((swapchain->height / 2) - (h / 2), 0),
|
||||||
y1 = min((screen->height / 2) + (h / 2), screen->height - 1);
|
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, 0, y0, 0x202020FF);
|
||||||
// verline(screen, x, y0, y1, color);
|
// verline(screen, x, y0, y1, color);
|
||||||
// verline(screen, x, y1, screen->height - 1, 0x505050FF);
|
// verline(screen, x, y1, screen->height - 1, 0x505050FF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
swapchain_submit(swapchain);
|
||||||
}
|
}
|
||||||
|
|
190
src/screen.c
190
src/screen.c
|
@ -1,4 +1,5 @@
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include <sched.h>
|
||||||
#undef Screen
|
#undef Screen
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -7,6 +8,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define XLIB_ILLEGAL_ACCESS
|
#define XLIB_ILLEGAL_ACCESS
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
|
@ -28,8 +31,9 @@ typedef struct {
|
||||||
Window window;
|
Window window;
|
||||||
GC graphics_ctx;
|
GC graphics_ctx;
|
||||||
Pixmap pixel_map;
|
Pixmap pixel_map;
|
||||||
XImage* image;
|
XImage** images;
|
||||||
int width, height;
|
pthread_t update_thread;
|
||||||
|
pthread_mutex_t recreate_lock;
|
||||||
} WindowState;
|
} WindowState;
|
||||||
|
|
||||||
static void init_x() {
|
static void init_x() {
|
||||||
|
@ -89,6 +93,126 @@ 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) {
|
void init_screen(struct Screen* screen, uint16_t width, uint16_t height, const char* title) {
|
||||||
|
|
||||||
|
@ -96,36 +220,17 @@ void init_screen(struct Screen* screen, uint16_t width, uint16_t height, const c
|
||||||
init_x();
|
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);
|
Window window = create_window(0, 0, width, height, bit_depth, title);
|
||||||
XMapWindow(dpy, window);
|
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));
|
WindowState* state = malloc(sizeof(WindowState));
|
||||||
state->window = window;
|
state->window = window;
|
||||||
state->graphics_ctx = gc;
|
|
||||||
state->pixel_map = pixel_map;
|
|
||||||
|
|
||||||
XWindowAttributes xwa;
|
screen->swapchain = create_swapchain(width, height, FRAMES, bit_depth, state);
|
||||||
XGetWindowAttributes(dpy, window, &xwa);
|
pthread_create(&state->update_thread, NULL, &swapchain_thread, screen);
|
||||||
state->width = xwa.width;
|
|
||||||
state->height = xwa.height;
|
screen->delta = 0;
|
||||||
screen->internal = state;
|
screen->internal = state;
|
||||||
|
|
||||||
XImage* image = create_image(state->width, state->height, screen->pixels);
|
|
||||||
state->image = image;
|
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,27 +252,10 @@ static void update_delta(struct Screen* screen) {
|
||||||
last = now;
|
last = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_screen(struct Screen* screen) {
|
static void handle_event(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) {
|
|
||||||
XEvent event;
|
XEvent event;
|
||||||
XNextEvent(dpy, &event);
|
XNextEvent(dpy, &event);
|
||||||
|
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
|
|
||||||
case KeyPress: {
|
case KeyPress: {
|
||||||
XKeyEvent xkpe = event.xkey;
|
XKeyEvent xkpe = event.xkey;
|
||||||
uint32_t code = xkpe.keycode - dpy->min_keycode;
|
uint32_t code = xkpe.keycode - dpy->min_keycode;
|
||||||
|
@ -185,9 +273,8 @@ static void handle_event(WindowState* state) {
|
||||||
|
|
||||||
case ConfigureNotify: {
|
case ConfigureNotify: {
|
||||||
XConfigureEvent xce = event.xconfigure;
|
XConfigureEvent xce = event.xconfigure;
|
||||||
state->width = xce.width;
|
if (xce.width != screen->swapchain.width || xce.height != screen->swapchain.height)
|
||||||
state->height = xce.height;
|
recreate_swapchain(xce.width, xce.height, bit_depth, &screen->swapchain, (WindowState*) screen->internal);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +284,8 @@ static void handle_event(WindowState* state) {
|
||||||
|
|
||||||
bool poll_screen(struct Screen* screen) {
|
bool poll_screen(struct Screen* screen) {
|
||||||
|
|
||||||
draw_screen(screen);
|
|
||||||
|
|
||||||
WindowState* state = (WindowState*) screen->internal;
|
|
||||||
|
|
||||||
while (XPending(dpy))
|
while (XPending(dpy))
|
||||||
handle_event(state);
|
handle_event(screen);
|
||||||
|
|
||||||
update_delta(screen);
|
update_delta(screen);
|
||||||
return true;
|
return true;
|
||||||
|
@ -211,10 +294,9 @@ bool poll_screen(struct Screen* screen) {
|
||||||
void free_screen(struct Screen* screen) {
|
void free_screen(struct Screen* screen) {
|
||||||
WindowState* state = (WindowState*) screen->internal;
|
WindowState* state = (WindowState*) screen->internal;
|
||||||
|
|
||||||
|
pthread_exit(&state->update_thread);
|
||||||
XUnmapWindow(dpy, state->window);
|
XUnmapWindow(dpy, state->window);
|
||||||
XFreePixmap(dpy, state->pixel_map);
|
free_swapchain(screen->swapchain, state);
|
||||||
XDestroyImage(state->image);
|
|
||||||
XFreeGC(dpy, state->graphics_ctx);
|
|
||||||
XDestroyWindow(dpy, state->window);
|
XDestroyWindow(dpy, state->window);
|
||||||
free(screen->internal);
|
free(screen->internal);
|
||||||
|
|
||||||
|
|
21
src/screen.h
21
src/screen.h
|
@ -1,13 +1,28 @@
|
||||||
#pragma once
|
#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 <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
struct Screen {
|
typedef struct {
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
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;
|
float delta;
|
||||||
void* internal;
|
void* internal;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue