Initial commit :3

This commit is contained in:
Luna 2025-02-09 18:48:25 +01:00
commit d820665f6c
41 changed files with 13764 additions and 0 deletions

32
Makefile Normal file
View file

@ -0,0 +1,32 @@
PKG_CONFIG?=pkg-config
PKGS=wayland-client xkbcommon vulkan
CFLAGS+=$(shell $(PKG_CONFIG) --cflags $(PKGS))
LIBS=$(shell $(PKG_CONFIG) --libs $(PKGS))
LDFLAGS+=-lm -lglfw -rdynamic
FLAGS=-g $(CFLAGS) $(LDFLAGS) $(LIBS)
S=main.c
S+=comp.c wayland.c glfw.c
S+=vulkan.c kitty.c
S+=hashmap.c io.c matrix.c dynarray.c image.c types.c allocator.c log.c
S+=object.c register.c
SO=$(addprefix build/,$(S:.c=.o))
# SC=$(addprefix src/,$(S))
SC=$S
clean:
rm -f build/*
install:
./main
build/%.o: %.c
gcc -c $(FLAGS) -o $@ $<
main: $(SO) Wayland/xdg-shell-protocol.c
gcc $(FLAGS) -o $@ $(SO) Wayland/xdg-shell-protocol.c
.DEFAULT_GOAL=main
.PHONY: clean

11
Shaders/shader.frag Normal file
View file

@ -0,0 +1,11 @@
#version 450
layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
layout(binding = 1) uniform sampler2D texSampler;
void main() {
outColor = texture(texSampler, fragUV) * vec4(fragColor, 1.0);
}

19
Shaders/shader.vert Normal file
View file

@ -0,0 +1,19 @@
#version 450
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(set = 0, binding = 0) uniform UBO {
mat3 model;
mat3 view;
mat3 proj;
} ubo;
layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragUV;
void main() {
gl_Position = vec4(ubo.proj * ubo.view * ubo.model * vec3(inPosition, 1.0), 1.0);
fragColor = inColor;
fragUV = inPosition;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,184 @@
/* Generated by wayland-scanner 1.23.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 6,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 6,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 6,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 6,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 6,
3, xdg_popup_requests,
3, xdg_popup_events,
};

88
allocator.c Normal file
View file

@ -0,0 +1,88 @@
#include "log.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define MAX_ALLOCS 256
struct Alloc {
void *start;
uint size;
struct Alloc *next;
};
struct Mem {
void *mem;
size_t mem_size;
uint count;
struct Alloc *alloc;
struct Alloc allocs[MAX_ALLOCS];
};
struct Mem *make_mem(size_t size) {
struct Mem *mem = malloc(sizeof(struct Mem));
mem->mem_size = size;
mem->mem = malloc(mem->mem_size);
memset(mem->mem, 0, mem->mem_size);
mem->count = 0;
memset(&mem->allocs, 0, sizeof(struct Alloc) * MAX_ALLOCS);
mem->allocs[0] = (struct Alloc){mem->mem + mem->mem_size, 0, NULL};
mem->allocs[1] = (struct Alloc){mem->mem, 0, &mem->allocs[0]};
mem->alloc = &mem->allocs[1];
return mem;
}
void uninit_mem(struct Mem *mem) {
free(mem->mem);
free(mem);
}
static struct Alloc *get_next_alloc(struct Mem *mem) {
uint index = mem->count;
mem->count++;
while (*(char *)&mem->allocs[mem->count] != 0) {
mem->count++;
if (mem->count >= MAX_ALLOCS) {
crash("out of allocs!");
}
}
return &mem->allocs[index];
}
void *mem_malloc(struct Mem *mem, size_t size) {
struct Alloc *prev = mem->alloc;
while (prev->next != NULL) {
struct Alloc *next = prev->next;
if (next->start - (prev->start + prev->size) > size) {
struct Alloc *new = get_next_alloc(mem);
*new = (struct Alloc){
prev->start + prev->size,
size,
next,
};
prev->next = new;
meow("MALLOC %p of size %zu, prev is at %p with size %u", new->start,
size, prev->start, prev->size);
/* print_backtrace(); */
return new->start;
} else {
prev = next;
}
}
crash("no big enaugh free space found!");
return NULL;
}
void mem_free(struct Mem *mem, void *p) {
struct Alloc *current = mem->alloc;
struct Alloc *prev = mem->alloc;
while (p < current->start) {
prev = current;
current = current->next;
}
prev->next = current->next;
int index = current - mem->allocs;
if (index < mem->count) {
mem->count = index;
}
memset(&mem->allocs[index], 0, sizeof(struct Alloc));
}

14
allocator.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef INCLUDE_WAYLANDCLIENT_ALLOCATOR_H_
#define INCLUDE_WAYLANDCLIENT_ALLOCATOR_H_
#include "sys/types.h"
struct Mem;
struct Mem *make_mem(size_t size);
void uninit_mem(struct Mem *mem);
void *mem_malloc(struct Mem *mem, size_t size);
void mem_free(struct Mem *mem, void *p);
#endif // INCLUDE_WAYLANDCLIENT_ALLOCATOR_H_

27
comp.c Normal file
View file

@ -0,0 +1,27 @@
#include "comp.h"
#ifdef WAYLAND
cat_Comp *cat_comp_init(const char *title, int width, int heigh,
struct Vk **vk) {
return cat_init_wl(title, width, heigh, vk);
}
void cat_comp_uninit(cat_Comp *state) { cat_uninit_wl(state); }
void cat_comp_draw(cat_Comp *state) { cat_wl_draw(state); }
bool cat_comp_should_close(cat_Comp *state) {
return cat_wl_should_close(state);
}
#else
cat_Comp *cat_comp_init(const char *title, int width, int heigh,
struct Vk **vk) {
return cat_init_glfw(title, width, heigh, vk);
}
void cat_comp_uninit(cat_Comp *state) { cat_uninit_glfw(state); }
void cat_comp_draw(cat_Comp *state) { cat_glfw_draw(state); }
bool cat_comp_should_close(cat_Comp *state) {
return cat_glfw_should_close(state);
}
#endif //! WAYLAND

27
comp.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef INCLUDE_WAYLANDCLIENT_CAT_COMP_H_
#define INCLUDE_WAYLANDCLIENT_CAT_COMP_H_
#define WAYLAND
#include <stdbool.h>
#ifdef WAYLAND
#include "vulkan.h"
#include "wayland.h"
typedef struct cat_Wl cat_Comp;
#else
#include "glfw.h"
typedef struct cat_GLFW cat_Comp;
#endif // !WAYLAND
cat_Comp *cat_comp_init(const char *title, int width, int heigh,
struct Vk **vk);
void cat_comp_uninit(cat_Comp *state);
void cat_comp_draw(cat_Comp *state);
bool cat_comp_should_close(cat_Comp *state);
#endif // INCLUDE_WAYLANDCLIENT_CAT_COMP_H_

20
dynarray.c Normal file
View file

@ -0,0 +1,20 @@
#include <stdlib.h>
struct da_template {
void *items;
int count;
int capacity;
};
void *dyn_array_create() {
struct da_template *da = malloc(sizeof(struct da_template));
da->items = malloc(0);
da->count = 0;
da->capacity = 0;
return da;
}
void dyn_array_create_inplace(void *array) {
struct da_template *da = array;
da->items = malloc(0);
da->count = 0;
da->capacity = 0;
}

42
dynarray.h Normal file
View file

@ -0,0 +1,42 @@
#ifndef INCLUDE_WAYLANDCLIENT_DYNARRAY_H_
#define INCLUDE_WAYLANDCLIENT_DYNARRAY_H_
#include <stdint.h>
#define dyn_array_append(array, item) \
do { \
if ((array)->count >= (array)->capacity) { \
(array)->capacity += 10; \
(array)->items = realloc((array)->items, \
(array)->capacity * sizeof(*(array)->items)); \
} \
(array)->items[(array)->count++] = (item); \
} while (0)
#define dyn_array_remove(array, index) \
do { \
(array)->items[(index)] = (array)->items[(array)->count - 1]; \
(array)->items[(array)->count] = NULL; \
(array)->count--; \
} while (0)
#define dyn_array_destroy(array) free((array)->items)
#define dyn_array_reset(array) \
do { \
(array)->capacity = 10; \
(array)->count = 0; \
(array)->items = \
realloc((array)->items, (array)->capacity * sizeof(*(array)->items)); \
} while (0)
#define dyn_array_define($name, $type) \
struct $name { \
$type *items; \
int count; \
int capacity; \
}
dyn_array_define(da_uint32_t, uint32_t);
void *dyn_array_create();
void dyn_array_create_inplace(void *array);
#endif // INCLUDE_WAYLANDCLIENT_DYNARRAY_H_

44
glfw.c Normal file
View file

@ -0,0 +1,44 @@
#include "log.h"
#include "vulkan.h"
#include <GLFW/glfw3.h>
#include <stdbool.h>
#include <stdlib.h>
struct cat_GLFW {
GLFWwindow *window;
struct Vk *vk;
};
VkSurfaceKHR create_glfw_surface(void *data, VkInstance instance) {
struct cat_GLFW *state = data;
VkSurfaceKHR surface;
meow("%d", glfwCreateWindowSurface(instance, state->window, NULL, &surface));
meow("created a surface at %p", surface);
return surface;
}
struct cat_GLFW *cat_init_glfw(const char *name, int width, int heigh,
struct Vk **vk) {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
struct cat_GLFW *state = malloc(sizeof(struct cat_GLFW));
state->window = glfwCreateWindow(width, heigh, "meooow", NULL, NULL);
state->vk = init_vk(state, 500, 500, create_glfw_surface);
*vk = state->vk;
return state;
}
void cat_glfw_draw(struct cat_GLFW *state) {
glfwPollEvents();
vk_draw(state->vk);
}
void cat_uninit_glfw(struct cat_GLFW *state) {
glfwDestroyWindow(state->window);
glfwTerminate();
}
bool cat_glfw_should_close(struct cat_GLFW *state) { return false; }

6
glfw.h Normal file
View file

@ -0,0 +1,6 @@
struct cat_GLFW;
struct cat_GLFW *cat_init_glfw(const char *name, int width, int heigh,
struct Vk **vk);
void cat_glfw_draw(struct cat_GLFW *state);
void cat_uninit_glfw(struct cat_GLFW *state);
bool cat_glfw_should_close(struct cat_GLFW *state);

89
hashmap.c Normal file
View file

@ -0,0 +1,89 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "log.h"
#define HASH_MASK 0b111111
#define TYPE uint32_t
struct Node_ui32 {
TYPE v;
struct Node_ui32 *next;
};
struct Bucket_ui32 {
struct Node_ui32 *nodes;
};
struct Hashmap_ui32 {
struct Bucket_ui32 buckets[HASH_MASK + 1];
};
struct Hashmap_ui32 *create_hashmap_ui32() {
struct Hashmap_ui32 *map = malloc(sizeof(struct Hashmap_ui32));
for (int i = 0; i <= HASH_MASK; i++) {
map->buckets[i].nodes = NULL;
}
return map;
}
void destroy_hashmap_ui32(struct Hashmap_ui32 *map) {
for (int i = 0; i <= HASH_MASK; i++) {
struct Node_ui32 *node = map->buckets[i].nodes;
while (node != NULL) {
struct Node_ui32 *tmp = node;
node = tmp->next;
free(tmp);
}
}
memset(map, 0, sizeof(struct Hashmap_ui32));
free(map);
}
int hash(TYPE v) { return v & HASH_MASK; }
void insert_hashmap_ui32(struct Hashmap_ui32 *map, TYPE v) {
int h = hash(v);
struct Node_ui32 *node = map->buckets[h].nodes;
while (node != NULL) {
if (node->v == v) {
meow("%d was already in hashmap", v);
return;
}
node = node->next;
}
struct Node_ui32 *n = malloc(sizeof(struct Node_ui32));
n->v = v;
n->next = map->buckets[h].nodes;
map->buckets[h].nodes = n;
}
void remove_hashmap_ui32(struct Hashmap_ui32 *map, TYPE v) {
int h = hash(v);
struct Node_ui32 *prev = NULL;
struct Node_ui32 *node = map->buckets[h].nodes;
while (node != NULL) {
if (node->v == v) {
if (prev == NULL) {
if (node->next == NULL) {
map->buckets[h].nodes = NULL;
} else {
map->buckets[h].nodes = node->next;
}
} else {
prev->next = node->next;
}
free(node);
return;
}
node = node->next;
}
meow("did not find %d in hashmap", v);
}
bool get_hashmap_ui32(struct Hashmap_ui32 *map, TYPE v) {
int h = hash(v);
struct Node_ui32 *node = map->buckets[h].nodes;
while (node != NULL) {
if (node->v == v) {
return true;
}
node = node->next;
}
return false;
}

10
hashmap.h Normal file
View file

@ -0,0 +1,10 @@
#include <stdbool.h>
#include <stdint.h>
struct Hashmap_ui32;
struct Hashmap_ui32 *create_hashmap_ui32();
void destroy_hashmap_ui32(struct Hashmap_ui32 *map);
void insert_hashmap_ui32(struct Hashmap_ui32 *map, uint32_t v);
void remove_hashmap_ui32(struct Hashmap_ui32 *map, uint32_t v);
bool get_hashmap_ui32(struct Hashmap_ui32 *map, uint32_t v);

9
image.c Normal file
View file

@ -0,0 +1,9 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "image.h"
uchar *load_image(const char *path, struct IVec2 *dims) {
int _channels;
return stbi_load(path, &dims->x, &dims->y, &_channels, STBI_rgb_alpha);
}

10
image.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef INCLUDE_WAYLANDCLIENT_CAT_IMAGE_H_
#define INCLUDE_WAYLANDCLIENT_CAT_IMAGE_H_
#include "types.h"
typedef unsigned char uchar;
uchar *load_image(const char *path, struct IVec2 *dims);
#endif // INCLUDE_WAYLANDCLIENT_CAT_IMAGE_H_

BIN
image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

47
io.c Normal file
View file

@ -0,0 +1,47 @@
#include "log.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
char *read_text_file(char *path) {
FILE *file = fopen(path, "r");
if (file == NULL) {
meow("Could not open file %s", path);
return NULL;
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
char *content = malloc((size + 1) * sizeof(char));
long count = fread(content, sizeof(char), size, file);
if (count < size) {
content = realloc(content, count + 1);
}
content[count] = 0x00;
fclose(file);
return content;
}
uint32_t *read_binary_file(char *path, int *size) {
FILE *file = fopen(path, "r");
if (file == NULL) {
meow("Could not open file %s", path);
return NULL;
}
fseek(file, 0, SEEK_END);
long fsize = ftell(file);
*size = fsize;
fseek(file, 0, SEEK_SET);
char *content = malloc((fsize) * sizeof(char));
long count = fread(content, sizeof(char), fsize, file);
if (count < fsize) {
content = realloc(content, count);
}
fclose(file);
return (uint32_t *)content;
}

9
io.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef INCLUDE_WAYLANDCLIENT_IO_H_
#define INCLUDE_WAYLANDCLIENT_IO_H_
#include <stdint.h>
char *read_text_file(char *path);
uint32_t *read_binary_file(char *path, int *size);
#endif // INCLUDE_WAYLANDCLIENT_IO_H_

579
kitty.c Normal file
View file

@ -0,0 +1,579 @@
#include <stdlib.h>
#include <string.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
#include "dynarray.h"
#include "image.h"
#include "io.h"
#include "vulkan.h"
#include "vulkan_helpers.c"
enum AttatchType {
CAT_ATTATCH_IMAGE,
CAT_ATTATCH_UBO,
};
struct Attatchment {
enum AttatchType type;
union {
struct {
const char *path;
uchar *pixels;
struct IVec2 dims;
VkDeviceSize size;
VkImage image;
VkImageView view;
VkSampler sampler;
VkDeviceMemory memory;
} image;
struct {
uint32_t size;
void *mapped[MAX_FRAMES_IN_FLIGHT];
VkBuffer buffer[MAX_FRAMES_IN_FLIGHT];
VkDeviceMemory memory[MAX_FRAMES_IN_FLIGHT];
} ubo;
};
};
dyn_array_define(da_Attatchment, struct Attatchment);
struct Kitty {
VkPipeline pipeline;
VkPipelineLayout pipeline_layout;
const char *vertex_path;
const char *fragment_path;
struct VertexBuffer vertex_buffer;
struct da_Attatchment attatchments;
uint32_t push_constant_size;
void *next_push_constant;
VkDescriptorPool descriptor_pool;
VkDescriptorSetLayout descriptor_set_layout;
VkDescriptorSet descriptor_sets[MAX_FRAMES_IN_FLIGHT];
};
struct Kitty *kitty_make() {
struct Kitty *thingy = malloc(sizeof(struct Kitty));
memset(thingy, 0, sizeof(struct Kitty));
dyn_array_create_inplace(&thingy->attatchments);
dyn_array_create_inplace(&thingy->vertex_buffer.format);
meow("alloced a thingy at %p", thingy);
return thingy;
}
void kitty_set_push_constant_size(struct Kitty *thingy, uint32_t size) {
thingy->push_constant_size = size;
}
void kitty_set_vertex_shader(struct Kitty *thingy, const char *path) {
thingy->vertex_path = path;
meow("vertex path is %s", path);
}
void kitty_set_fragment_shader(struct Kitty *thingy, const char *path) {
thingy->fragment_path = path;
meow("fragment path is %s", path);
}
void kitty_set_vertex_buffer(struct Kitty *thingy, void *data, uint32_t count,
int vertex_size) {
thingy->vertex_buffer.data = data;
thingy->vertex_buffer.count = count;
thingy->vertex_buffer.vertex_size = vertex_size;
}
void kitty_add_vertex_buffer_format(struct Kitty *thingy,
enum VkFormat format) {
meow("attatched %d to the buffer", format);
dyn_array_append(&thingy->vertex_buffer.format, format);
}
void kitty_attatch_image(struct Kitty *thingy, const char *path) {
struct Attatchment attatchment = {0};
attatchment.type = CAT_ATTATCH_IMAGE;
attatchment.image.path = path;
dyn_array_append(&thingy->attatchments, attatchment);
meow("image was attatched");
}
int kitty_attatch_ubo(struct Kitty *thingy, uint32_t size) {
struct Attatchment attatchment = {0};
attatchment.type = CAT_ATTATCH_UBO;
attatchment.ubo.size = size;
dyn_array_append(&thingy->attatchments, attatchment);
meow("ubo of size %d was attatched", size);
return thingy->attatchments.count - 1;
}
void kitty_finalise(struct Vk *state, struct Kitty *kitty) {
meow("this thingy has %d ubos", kitty->attatchments.count);
if (kitty->vertex_path == NULL) {
meow("a kitty has no vertex shader :c");
return;
}
if (kitty->fragment_path == NULL) {
meow("a kitty has no fragment shader :c");
return;
}
VkDescriptorSetLayoutBinding
descriptor_set_layout_binding[kitty->attatchments.count];
memset(descriptor_set_layout_binding, 0,
sizeof(VkDescriptorSetLayoutBinding) * kitty->attatchments.count);
for (int index = 0; index < kitty->attatchments.count; index++) {
if (kitty->attatchments.items[index].type == CAT_ATTATCH_UBO) {
descriptor_set_layout_binding[index].binding = index;
descriptor_set_layout_binding[index].descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_set_layout_binding[index].descriptorCount = 1;
descriptor_set_layout_binding[index].stageFlags = VK_SHADER_STAGE_ALL;
descriptor_set_layout_binding[index].pImmutableSamplers = NULL;
} else {
descriptor_set_layout_binding[index].binding = index;
descriptor_set_layout_binding[index].descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_set_layout_binding[index].descriptorCount = 1;
descriptor_set_layout_binding[index].stageFlags = VK_SHADER_STAGE_ALL;
descriptor_set_layout_binding[index].pImmutableSamplers = NULL;
}
}
VkDescriptorSetLayoutCreateInfo layout_info = {0};
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_info.bindingCount = kitty->attatchments.count;
layout_info.pBindings = descriptor_set_layout_binding;
CHECK_VK_RESULT(vkCreateDescriptorSetLayout(state->device, &layout_info, NULL,
&kitty->descriptor_set_layout));
int vert_size, frag_size;
uint32_t *vert_shader =
read_binary_file((char *)kitty->vertex_path, &vert_size);
uint32_t *frag_shader =
read_binary_file((char *)kitty->fragment_path, &frag_size);
VkShaderModule vert_module =
create_shader_module(state, vert_shader, vert_size);
VkShaderModule frag_module =
create_shader_module(state, frag_shader, frag_size);
VkPipelineShaderStageCreateInfo vert_stage_info = {0};
vert_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vert_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vert_stage_info.module = vert_module;
vert_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo frag_stage_info = {0};
frag_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
frag_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
frag_stage_info.module = frag_module;
frag_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo shader_stage_info[] = {vert_stage_info,
frag_stage_info};
VkVertexInputBindingDescription vertex_binding_description = {0};
vertex_binding_description.binding = 0;
vertex_binding_description.stride = kitty->vertex_buffer.vertex_size;
vertex_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription *vertex_attribute_descriptions =
alloca(sizeof(VkVertexInputAttributeDescription) *
kitty->vertex_buffer.format.count);
int offset = 0;
for (int i = 0; i < kitty->vertex_buffer.format.count; i++) {
vertex_attribute_descriptions[i].binding = 0;
vertex_attribute_descriptions[i].location = i;
vertex_attribute_descriptions[i].format =
kitty->vertex_buffer.format.items[i];
vertex_attribute_descriptions[i].offset = offset;
offset += get_size_of_format(kitty->vertex_buffer.format.items[i]);
}
VkPipelineVertexInputStateCreateInfo vertex_input_info = {0};
vertex_input_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description;
vertex_input_info.vertexAttributeDescriptionCount =
kitty->vertex_buffer.format.count;
vertex_input_info.pVertexAttributeDescriptions =
vertex_attribute_descriptions;
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {0};
input_assembly_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
input_assembly_info.primitiveRestartEnable = VK_FALSE;
VkPipelineViewportStateCreateInfo viewport_state_info = {0};
viewport_state_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state_info.viewportCount = 1;
viewport_state_info.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo rasterizer_info = {0};
rasterizer_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer_info.depthClampEnable = VK_FALSE;
rasterizer_info.rasterizerDiscardEnable = VK_FALSE;
rasterizer_info.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer_info.lineWidth = 1.0f;
rasterizer_info.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer_info.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo multisampling_info = {0};
multisampling_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling_info.sampleShadingEnable = VK_FALSE;
multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState color_blend_attachment = {0};
color_blend_attachment.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
color_blend_attachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo color_blend_info = {0};
color_blend_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blend_info.logicOpEnable = VK_FALSE;
color_blend_info.logicOp = VK_LOGIC_OP_COPY;
color_blend_info.attachmentCount = 1;
color_blend_info.pAttachments = &color_blend_attachment;
/* VkPushConstantRange push_constant_range = {0}; */
/* push_constant_range.offset = 0; */
/* push_constant_range.size = thingy->push_constant_size; */
/* push_constant_range.stageFlags = VK_SHADER_STAGE_ALL; */
VkPipelineLayoutCreateInfo pipeline_layout_info = {0};
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_info.setLayoutCount = 1;
pipeline_layout_info.pSetLayouts = &kitty->descriptor_set_layout;
pipeline_layout_info.pushConstantRangeCount = 0; // TODO
pipeline_layout_info.pPushConstantRanges = NULL;
CHECK_VK_RESULT(vkCreatePipelineLayout(state->device, &pipeline_layout_info,
NULL, &kitty->pipeline_layout));
VkDynamicState dynamic_states[] = {VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamic_state_info = {0};
dynamic_state_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state_info.pDynamicStates = dynamic_states;
dynamic_state_info.dynamicStateCount =
sizeof(dynamic_states) / sizeof(dynamic_states[0]);
VkGraphicsPipelineCreateInfo pipeline_info = {0};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = 2;
pipeline_info.pStages = shader_stage_info;
pipeline_info.pVertexInputState = &vertex_input_info;
pipeline_info.pInputAssemblyState = &input_assembly_info;
pipeline_info.pViewportState = &viewport_state_info;
pipeline_info.pRasterizationState = &rasterizer_info;
pipeline_info.pMultisampleState = &multisampling_info;
pipeline_info.pDepthStencilState = NULL;
pipeline_info.pColorBlendState = &color_blend_info;
pipeline_info.pDynamicState = &dynamic_state_info;
pipeline_info.layout = kitty->pipeline_layout;
pipeline_info.renderPass = state->render_pass;
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = NULL;
pipeline_info.basePipelineIndex = -1;
CHECK_VK_RESULT(vkCreateGraphicsPipelines(
state->device, NULL, 1, &pipeline_info, NULL, &kitty->pipeline));
int ubo_count = 0;
int image_count = 0;
for (int i = 0; i < kitty->attatchments.count; i++) {
switch (kitty->attatchments.items[i].type) {
case CAT_ATTATCH_UBO:
ubo_count++;
break;
case CAT_ATTATCH_IMAGE:
image_count++;
break;
}
}
VkDescriptorPoolSize pool_sizes[2] = {0};
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
pool_sizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT;
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_sizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT;
VkDescriptorPoolCreateInfo pool_info = {0};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.poolSizeCount = 2;
pool_info.pPoolSizes = pool_sizes;
pool_info.maxSets = 10;
CHECK_VK_RESULT(vkCreateDescriptorPool(state->device, &pool_info, NULL,
&kitty->descriptor_pool));
for (int index = 0; index < kitty->attatchments.count; index++) {
if (kitty->attatchments.items[index].type != CAT_ATTATCH_IMAGE) {
continue;
}
struct Attatchment *atch = &kitty->attatchments.items[index];
atch->image.pixels = load_image(atch->image.path, &atch->image.dims);
atch->image.size = atch->image.dims.x * atch->image.dims.y * 4;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, atch->image.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void *data;
vkMapMemory(state->device, staging_buffer_memory, 0, atch->image.size, 0,
&data);
memcpy(data, atch->image.pixels, atch->image.size);
vkUnmapMemory(state->device, staging_buffer_memory);
create_image(state, atch->image.dims, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &atch->image.image,
&atch->image.memory);
transition_image_layout(state, atch->image.image, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copy_buffer_to_image(state, staging_buffer, atch->image.image,
atch->image.dims);
transition_image_layout(state, atch->image.image, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
VkImageViewCreateInfo view_info = {0};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = atch->image.image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = VK_FORMAT_R8G8B8A8_SRGB;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
CHECK_VK_RESULT(
vkCreateImageView(state->device, &view_info, NULL, &atch->image.view));
VkSamplerCreateInfo sampler_info = {0};
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler_info.magFilter = VK_FILTER_NEAREST;
sampler_info.minFilter = VK_FILTER_NEAREST;
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.anisotropyEnable = VK_FALSE;
sampler_info.maxAnisotropy = 1.0f;
sampler_info.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
sampler_info.unnormalizedCoordinates = VK_FALSE;
sampler_info.compareEnable = VK_FALSE;
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
sampler_info.mipLodBias = 0.0f;
sampler_info.minLod = 0.0;
sampler_info.maxLod = 0.0;
CHECK_VK_RESULT(vkCreateSampler(state->device, &sampler_info, NULL,
&atch->image.sampler));
}
for (int index = 0; index < kitty->attatchments.count; index++) {
if (kitty->attatchments.items[index].type != CAT_ATTATCH_UBO) {
continue;
}
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
create_buffer(state, kitty->attatchments.items[index].ubo.size,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&kitty->attatchments.items[index].ubo.buffer[i],
&kitty->attatchments.items[index].ubo.memory[i]);
void *pointer_to_mapped;
vkMapMemory(state->device, kitty->attatchments.items[index].ubo.memory[i],
0, kitty->attatchments.items[index].ubo.size, 0,
&pointer_to_mapped);
kitty->attatchments.items[index].ubo.mapped[i] = pointer_to_mapped;
}
}
VkDescriptorSetLayout set_layouts[MAX_FRAMES_IN_FLIGHT];
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
set_layouts[i] = kitty->descriptor_set_layout;
}
VkDescriptorSetAllocateInfo alloc_info = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = kitty->descriptor_pool;
alloc_info.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
meow("allocing %d desc sets", MAX_FRAMES_IN_FLIGHT);
alloc_info.pSetLayouts = set_layouts;
CHECK_VK_RESULT(vkAllocateDescriptorSets(state->device, &alloc_info,
kitty->descriptor_sets));
for (int index = 0; index < kitty->attatchments.count; index++) {
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
switch (kitty->attatchments.items[index].type) {
case CAT_ATTATCH_UBO:;
VkDescriptorBufferInfo buffer_info = {0};
buffer_info.buffer = kitty->attatchments.items[index].ubo.buffer[i];
buffer_info.offset = 0;
buffer_info.range = kitty->attatchments.items[index].ubo.size;
VkWriteDescriptorSet write_buffer = {0};
write_buffer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_buffer.dstSet = kitty->descriptor_sets[i];
write_buffer.dstBinding = index;
write_buffer.dstArrayElement = 0;
write_buffer.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
write_buffer.descriptorCount = 1;
write_buffer.pBufferInfo = &buffer_info;
vkUpdateDescriptorSets(state->device, 1, &write_buffer, 0, NULL);
break;
case CAT_ATTATCH_IMAGE:;
VkDescriptorImageInfo image_info = {0};
image_info.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL;
image_info.imageView = kitty->attatchments.items[index].image.view;
image_info.sampler = kitty->attatchments.items[index].image.sampler;
VkWriteDescriptorSet write_image = {0};
write_image.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_image.dstSet = kitty->descriptor_sets[i];
write_image.dstBinding = index;
write_image.dstArrayElement = 0;
write_image.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_image.descriptorCount = 1;
write_image.pImageInfo = &image_info;
vkUpdateDescriptorSets(state->device, 1, &write_image, 0, NULL);
break;
}
}
}
VkDeviceSize size =
kitty->vertex_buffer.count * kitty->vertex_buffer.vertex_size;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void *data;
vkMapMemory(state->device, staging_buffer_memory, 0, size, 0, &data);
memcpy(data, kitty->vertex_buffer.data, size);
vkUnmapMemory(state->device, staging_buffer_memory);
create_buffer(state, size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&kitty->vertex_buffer.buffer, &kitty->vertex_buffer.memory);
copy_buffer(state, staging_buffer, kitty->vertex_buffer.buffer, size);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
vkDestroyShaderModule(state->device, vert_module, NULL);
vkDestroyShaderModule(state->device, frag_module, NULL);
free(vert_shader);
free(frag_shader);
dyn_array_append(&state->kitties, kitty);
meow("appended a kitty, len is now %d", state->kitties.count);
}
void free_kitty(struct Vk *state, struct Kitty *kitty) {
vkDeviceWaitIdle(state->device);
vkDestroyBuffer(state->device, kitty->vertex_buffer.buffer, NULL);
vkFreeMemory(state->device, kitty->vertex_buffer.memory, NULL);
vkDestroyDescriptorPool(state->device, kitty->descriptor_pool, NULL);
vkDestroyDescriptorSetLayout(state->device, kitty->descriptor_set_layout,
NULL);
vkDestroyPipelineLayout(state->device, kitty->pipeline_layout, NULL);
vkDestroyPipeline(state->device, kitty->pipeline, NULL);
for (int i = 0; i < kitty->attatchments.count; i++) {
switch (kitty->attatchments.items[i].type) {
case CAT_ATTATCH_UBO:
for (int j = 0; j < MAX_FRAMES_IN_FLIGHT; j++) {
vkDestroyBuffer(state->device,
kitty->attatchments.items[i].ubo.buffer[j], NULL);
vkFreeMemory(state->device, kitty->attatchments.items[i].ubo.memory[j],
NULL);
}
break;
case CAT_ATTATCH_IMAGE:
vkDestroyImage(state->device, kitty->attatchments.items[i].image.image,
NULL);
vkFreeMemory(state->device, kitty->attatchments.items[i].image.memory,
NULL);
vkDestroyImageView(state->device, kitty->attatchments.items[i].image.view,
NULL);
vkDestroySampler(state->device,
kitty->attatchments.items[i].image.sampler, NULL);
break;
}
}
dyn_array_destroy(&kitty->vertex_buffer.format);
dyn_array_destroy(&kitty->attatchments);
memset(kitty, 0, sizeof(struct Kitty));
free(kitty);
}
void kitty_set_next_push_constant(struct Kitty *thingy, void *data) {
thingy->next_push_constant = data;
}
void kitty_set_next_ubo(struct Vk *state, struct Kitty *thingy, int index,
void *data) {
void *dst =
thingy->attatchments.items[index].ubo.mapped[state->current_frame];
void *src = data;
int size = thingy->attatchments.items[index].ubo.size;
/* meow("index %d, number %f", index, *(float *)data); */
memcpy(dst, src, size);
}
void kitty_draw(struct Vk *state, uint32_t image_index, struct Kitty *thingy) {
struct InFlightObjects flight = state->flights[state->current_frame];
vkCmdBindPipeline(flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
thingy->pipeline);
VkViewport viewport = {0};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = state->width;
viewport.height = state->heigh;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(flight.command_buffer, 0, 1, &viewport);
VkRect2D scissor = {0};
scissor.offset = (VkOffset2D){0, 0};
scissor.extent = (VkExtent2D){state->width, state->heigh};
vkCmdSetScissor(flight.command_buffer, 0, 1, &scissor);
VkBuffer vertex_buffer[] = {thingy->vertex_buffer.buffer};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(flight.command_buffer, 0, 1, vertex_buffer, offsets);
vkCmdBindDescriptorSets(
flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
thingy->pipeline_layout, 0, 1,
&thingy->descriptor_sets[state->current_frame], 0, NULL);
vkCmdDraw(flight.command_buffer, thingy->vertex_buffer.count, 1, 0, 0);
}

26
kitty.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef INCLUDE_KITTY
#define INCLUDE_KITTY
#include <vulkan/vulkan.h>
struct Kitty;
struct Kitty *kitty_make();
void kitty_set_vertex_shader(struct Kitty *thingy, const char *path);
void kitty_set_fragment_shader(struct Kitty *thingy, const char *path);
void kitty_set_vertex_buffer(struct Kitty *thingy, void *data, uint32_t count,
int vertex_size);
void kitty_add_vertex_buffer_format(struct Kitty *thingy, enum VkFormat format);
int kitty_attatch_ubo(struct Kitty *thingy, uint32_t size);
void kitty_finalise(struct Vk *state, struct Kitty *thingy);
void kitty_set_next_push_constant(struct Kitty *thingy, void *data);
void kitty_set_next_ubo(struct Vk *state, struct Kitty *thingy, int index,
void *data);
void kitty_draw(struct Vk *state, uint32_t image_index, struct Kitty *thingy);
void free_kitty(struct Vk *state, struct Kitty *kitty);
void kitty_attatch_image(struct Kitty *thingy, const char *path);
void kitty_set_push_constant_size(struct Kitty *thingy, uint32_t size);
#endif // INCLUDE_KITTY

38
log.c Normal file
View file

@ -0,0 +1,38 @@
#include <errno.h>
#include <execinfo.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void full_write(int fd, const char *buf, size_t len) {
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t)ret;
len -= (size_t)ret;
}
}
void print_backtrace() {
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}

14
log.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef INCLUDE_WAYLANDCLIENT_LOG_H_
#define INCLUDE_WAYLANDCLIENT_LOG_H_
#include <stdio.h>
#include <stdlib.h>
#define meow(fmt, ...) \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define crash(fmt, ...) \
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
*(int *)0 = 0;
void print_backtrace();
#endif // INCLUDE_WAYLANDCLIENT_LOG_H_

BIN
main Executable file

Binary file not shown.

32
main.c Normal file
View file

@ -0,0 +1,32 @@
#include "comp.h"
#include "object.h"
#include "register.h"
#include "trig.c"
#include <stdbool.h>
int main() {
struct Vk *vk;
cat_Comp *state = cat_comp_init("meooow", 500, 500, &vk);
struct Register *reg = make_register();
reg_attatch_type(reg, "trig", OBJ_MAKE make_trig, OBJ_FREE free_trig,
OBJ_TICK trig_tick);
struct Scene *scene = make_scene(vk, reg);
scene_queue_insert(scene, "trig", trig_make_args(scene));
while (!cat_comp_should_close(state)) {
scene_tick(scene);
cat_comp_draw(state);
}
free_scene(scene);
free_register(reg);
cat_comp_uninit(state);
state = NULL;
reg = NULL;
scene = NULL;
}

42
matrix.c Normal file
View file

@ -0,0 +1,42 @@
#include "matrix.h"
#include <math.h>
struct mat3x3 multiply3x3(struct mat3x3 a, struct mat3x3 b) {
// c ij = a i1 · b 1j + a i2 · b 2j + a i3 · b 3j
struct mat3x3 res = {0};
res.m11 = a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31;
res.m12 = a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32;
res.m13 = a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33;
res.m21 = a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31;
res.m22 = a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32;
res.m23 = a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33;
res.m31 = a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31;
res.m32 = a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32;
res.m33 = a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33;
return res;
}
struct mat3x3 translate3x3(struct Vec2 offset) {
struct mat3x3 res = IDENT3x3;
res.m13 = offset.x;
res.m23 = offset.y;
return res;
}
struct mat3x3 rotate3x3(float alpha) {
struct mat3x3 res = IDENT3x3;
res.m11 = cosf(alpha);
res.m12 = -sinf(alpha);
res.m21 = sinf(alpha);
res.m22 = cosf(alpha);
return res;
}
struct mat3x3 scale3x3(struct Vec2 scale) {
struct mat3x3 res = IDENT3x3;
res.m11 = scale.x;
res.m22 = scale.y;
return res;
}

28
matrix.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef INCLUDE_WAYLANDCLIENT_MATRIX_H_
#define INCLUDE_WAYLANDCLIENT_MATRIX_H_
#include "types.h"
struct mat3x3 {
float m11, m21, m31, _p1;
float m12, m22, m32, _p2;
float m13, m23, m33, _p3;
};
#define IDENT3x3 \
(struct mat3x3){.m11 = 1.f, \
.m21 = 0.f, \
.m31 = 0.f, \
.m12 = 0.f, \
.m22 = 1.f, \
.m32 = 0.f, \
.m13 = 0.f, \
.m23 = 0.f, \
.m33 = 1.f}
struct mat3x3 multiply3x3(struct mat3x3 a, struct mat3x3 b);
struct mat3x3 translate3x3(struct Vec2 offset);
struct mat3x3 rotate3x3(float alpha);
struct mat3x3 scale3x3(struct Vec2 scale);
#endif // INCLUDE_WAYLANDCLIENT_MATRIX_H_

89
object.c Normal file
View file

@ -0,0 +1,89 @@
#include "object.h"
#include "allocator.h"
#include "log.h"
#include "register.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct Scene *make_scene(struct Vk *vk, struct Register *reg) {
struct Scene *scene = malloc(sizeof(struct Scene));
memset(scene, 0, sizeof(struct Scene));
scene->vk = vk;
scene->mem = make_mem(2048);
if (reg == NULL) {
scene->reg = make_register();
} else {
scene->reg = reg;
}
dyn_array_create_inplace(&scene->objects);
dyn_array_create_inplace(&scene->insert_queue);
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
scene->msecs = time.tv_sec * 1000000 + time.tv_nsec / 1000;
return scene;
}
void free_scene(struct Scene *scene) {
for (int i = 0; i < scene->objects.count; i++) {
scene->objects.items[i]->type->free(scene, scene->objects.items[i]->data);
mem_free(scene->mem, scene->objects.items[i]);
}
dyn_array_destroy(&scene->objects);
for (int i = 0; i < scene->insert_queue.count; i++) {
scene->insert_queue.items[i]->type->free(
scene, scene->insert_queue.items[i]->data);
mem_free(scene->mem, scene->insert_queue.items[i]);
}
dyn_array_destroy(&scene->insert_queue);
uninit_mem(scene->mem);
memset(scene, 0, sizeof(struct Scene));
free(scene);
}
void scene_tick(struct Scene *scene) {
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
long msecs = time.tv_sec * 1000000 + time.tv_nsec / 1000;
msecs *= 1.0f;
scene->delta_secs = (float)(msecs - scene->msecs) / 1000;
if (scene->insert_queue.count > 0) {
for (int i = 0; i < scene->insert_queue.count; i++) {
dyn_array_append(&scene->objects, scene->insert_queue.items[i]);
}
dyn_array_reset(&scene->insert_queue);
}
for (int i = 0; i < scene->objects.count; i++) {
scene->objects.items[i]->type->tick(scene, scene->objects.items[i]->data);
}
if (scene->insert_queue.count > 0) {
for (int i = 0; i < scene->insert_queue.count; i++) {
dyn_array_append(&scene->objects, scene->insert_queue.items[i]);
}
dyn_array_reset(&scene->insert_queue);
}
scene->msecs = msecs;
}
void scene_queue_insert(struct Scene *scene, char *name, void *object_data) {
struct Type *type = reg_get_type(scene->reg, name);
struct Object *object = mem_malloc(scene->mem, sizeof(struct Object));
object->type = type;
object->data = object_data;
dyn_array_append(&scene->insert_queue, object);
}
void scene_queue_insert_from_data(struct Scene *scene, char *name, char *data,
int len) {
struct Type *type = reg_get_type(scene->reg, name);
struct Object *object = mem_malloc(scene->mem, sizeof(struct Object));
object->type = type;
object->data = type->make(scene, data, len);
dyn_array_append(&scene->insert_queue, object);
}

30
object.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef INCLUDE_WAYLANDCLIENT_OBJECT_H_
#define INCLUDE_WAYLANDCLIENT_OBJECT_H_
#include "dynarray.h"
// #include "vulkan_internal.h"
dyn_array_define(da_Object, struct Object *);
struct Scene {
struct Vk *vk;
struct Mem *mem;
struct da_Object objects;
struct da_Object insert_queue;
struct Register *reg;
float delta_secs;
long msecs;
};
struct Object {
struct Type *type;
void *data;
};
struct Scene *make_scene(struct Vk *vk, struct Register *reg);
void free_scene(struct Scene *scene);
void scene_tick(struct Scene *scene);
void scene_queue_insert(struct Scene *scene, char *name, void *object_data);
#endif // INCLUDE_WAYLANDCLIENT_OBJECT_H_

36
register.c Normal file
View file

@ -0,0 +1,36 @@
#include "register.h"
#include "dynarray.h"
#include "log.h"
#include "object.h"
#include <stdlib.h>
#include <string.h>
struct Register *make_register() {
struct Register *reg = malloc(sizeof(struct Register));
dyn_array_create_inplace(&reg->reg);
return reg;
}
void free_register(struct Register *reg) {
dyn_array_destroy(&reg->reg);
free(reg);
}
void reg_attatch_type(struct Register *reg, char *name,
void *(*make)(struct Scene *, char *, int len),
void (*free)(struct Scene *, void *),
void (*tick)(struct Scene *, void *)) {
struct Type type = {name, make, free, tick};
dyn_array_append(&reg->reg, type);
}
struct Type *reg_get_type(struct Register *reg, char *name) {
for (int i = 0; i < reg->reg.count; i++) {
if (strcmp(reg->reg.items[i].name, name) == 0) {
return &reg->reg.items[i];
}
}
meow("did not find %s in register", name);
return NULL;
}

33
register.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef INCLUDE_WAYLANDCLIENT_REGISTER_H_
#define INCLUDE_WAYLANDCLIENT_REGISTER_H_
#include "dynarray.h"
#include "object.h"
dyn_array_define(da_Type, struct Type);
struct Type {
char *name;
void *(*make)(struct Scene *, char *, int len);
void (*free)(struct Scene *, void *);
void (*tick)(struct Scene *, void *);
};
struct Register {
struct da_Type reg;
};
#define OBJ_FREE (void (*)(struct Scene *, void *))
#define OBJ_TICK (void (*)(struct Scene *, void *))
#define OBJ_MAKE (void *(*)(struct Scene *, char *, int len))
struct Register *make_register();
void free_register(struct Register *reg);
struct Type *reg_get_type(struct Register *reg, char *name);
void reg_attatch_type(struct Register *reg, char *name,
void *(*make)(struct Scene *, char *, int len),
void (*free)(struct Scene *, void *),
void (*tick)(struct Scene *, void *));
#endif // INCLUDE_WAYLANDCLIENT_REGISTER_H_

7988
stb_image.h Normal file

File diff suppressed because it is too large Load diff

73
trig.c Normal file
View file

@ -0,0 +1,73 @@
#include "allocator.h"
#include "kitty.h"
#include "matrix.h"
#include "object.h"
#include "types.h"
#include <math.h>
struct Trig {
struct Kitty *kitty;
struct mat3x3 model;
};
#define TRIG_VERTEX_COUNT 6
struct Vertex trig_vertices[TRIG_VERTEX_COUNT] = {
(struct Vertex){(struct Vec2){.x = 0.0f, .y = 0.0f},
(struct Vec3){1.0f, 0.0f, 1.0f}},
(struct Vertex){(struct Vec2){.x = 1.0f, .y = 0.0f},
(struct Vec3){1.0f, 0.0f, 0.2f}},
(struct Vertex){(struct Vec2){.x = 1.0f, .y = 1.0f},
(struct Vec3){0.2f, 0.0f, 1.0f}},
(struct Vertex){(struct Vec2){.x = 0.0f, .y = 0.0f},
(struct Vec3){1.0f, 0.0f, 1.0f}},
(struct Vertex){(struct Vec2){.x = 1.0f, .y = 1.0f},
(struct Vec3){1.0f, 0.0f, 0.2f}},
(struct Vertex){(struct Vec2){.x = 0.0f, .y = 1.0f},
(struct Vec3){0.2f, 0.0f, 1.0f}},
};
struct TrigUBO {
struct mat3x3 model;
struct mat3x3 view;
struct mat3x3 proj;
};
struct Trig *trig_make_args(struct Scene *scene) {
struct Trig *trig = mem_malloc(scene->mem, sizeof(struct Trig));
trig->kitty = kitty_make();
kitty_set_vertex_shader(trig->kitty, "./Shaders/vert.spv");
kitty_set_fragment_shader(trig->kitty, "./Shaders/frag.spv");
kitty_set_vertex_buffer(trig->kitty, trig_vertices, TRIG_VERTEX_COUNT,
sizeof(struct Vertex));
kitty_add_vertex_buffer_format(trig->kitty, VK_FORMAT_R32G32_SFLOAT);
kitty_add_vertex_buffer_format(trig->kitty, VK_FORMAT_R32G32B32_SFLOAT);
kitty_attatch_ubo(trig->kitty, sizeof(struct TrigUBO));
kitty_attatch_image(trig->kitty, "./image.png");
kitty_finalise(scene->vk, trig->kitty);
return trig;
}
struct Trig *make_trig(struct Scene *scene, char *_data, int _len) {
return trig_make_args(scene);
}
void free_trig(struct Scene *scene, struct Trig *trig) {
free_kitty(scene->vk, trig->kitty);
mem_free(scene->mem, trig);
}
void trig_tick(struct Scene *scene, struct Trig *trig) {
struct TrigUBO ubo = {0};
ubo.model = multiply3x3(
translate3x3(
(struct Vec2){sinf((double)(scene->msecs) * 0.000001f), 0.f}),
multiply3x3(rotate3x3(PI / 2.f * (double)(scene->msecs) * 0.000001f),
scale3x3((struct Vec2){0.5f, 0.5f})));
ubo.view = IDENT3x3;
ubo.proj = scale3x3(
(struct Vec2){1.f, (float)scene->vk->width / (float)scene->vk->heigh});
kitty_set_next_ubo(scene->vk, trig->kitty, 0, &ubo);
}

1
types.c Normal file
View file

@ -0,0 +1 @@
#include "types.h"

44
types.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef INCLUDE_WAYLANDCLIENT_TYPES_H_
#define INCLUDE_WAYLANDCLIENT_TYPES_H_
#define PI 3.141592653589793238462643f
// struct vec2 {
// union {
// struct {
// float x, y;
// };
// float arr[2];
// };
// };
struct Vec2 {
float x, y;
};
struct IVec2 {
int x, y;
};
// struct vec3 {
// union {
// struct {
// float x, y, z;
// };
// struct {
// float r, g, b;
// };
// float arr[3];
// };
// };
struct Vec3 {
float x, y, z;
};
struct Vec4 {
float x, y, z, w;
};
struct Vertex {
struct Vec2 pos;
struct Vec3 col;
};
#endif // INCLUDE_WAYLANDCLIENT_TYPES_H_

955
vulkan.c Normal file
View file

@ -0,0 +1,955 @@
#include "vulkan.h"
#include "kitty.h"
#include "log.h"
#include "matrix.h"
#include "types.h"
#include "image.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
#define VERTEX_ATTRIBUTE_COUNT 2
#define QUAD_VERTEX_COUNT 3
struct Vertex quad_vertices[QUAD_VERTEX_COUNT] = {
(struct Vertex){(struct Vec2){.x = 0.0f, .y = -0.5f},
(struct Vec3){1.0f, 0.0f, 1.0f}},
(struct Vertex){(struct Vec2){.x = 0.5f, .y = 0.5f},
(struct Vec3){1.0f, 0.0f, 0.2f}},
(struct Vertex){(struct Vec2){.x = -0.5f, .y = 0.5f},
(struct Vec3){0.2f, 0.0f, 1.0f}},
};
struct UBO {
struct mat3x3 model;
struct mat3x3 view;
struct mat3x3 proj;
};
VkVertexInputBindingDescription get_vertex_binding_description() {
VkVertexInputBindingDescription description = {0};
description.binding = 0;
description.stride = sizeof(struct Vertex);
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
return description;
}
// return value owned by caller
VkVertexInputAttributeDescription *get_vertex_attribute_description() {
VkVertexInputAttributeDescription *description = malloc(
sizeof(VkVertexInputAttributeDescription) * VERTEX_ATTRIBUTE_COUNT);
description[0].binding = 0;
description[0].location = 0;
description[0].format = VK_FORMAT_R32G32_SFLOAT;
description[0].offset = offsetof(struct Vertex, pos);
description[1].binding = 0;
description[1].location = 1;
description[1].format = VK_FORMAT_R32G32B32_SFLOAT;
description[1].offset = offsetof(struct Vertex, col);
return description;
}
static const char *const extensions[] = {
"VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_wayland_surface",
/* "VK_KHR_xcb_surface", */
};
static const char *const layers[] = {"VK_LAYER_KHRONOS_validation"};
static const char *const device_extensions[] = {"VK_KHR_swapchain"};
static VkBool32
handle_vulkan_error(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
void *userData) {
bool backtrace = false;
printf("Vulkan ");
switch (type) {
case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
printf("general ");
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
printf("validation ");
break;
case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
printf("performance ");
break;
}
switch (severity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
printf("(verbose): ");
break;
default:
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
printf("(info): ");
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
printf("(warning): ");
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
printf("(error): ");
backtrace = true;
break;
}
printf("%s\n", callbackData->pMessage);
if (backtrace) {
print_backtrace();
}
return 0;
}
void create_swapchain(struct Vk *state) {
VkSurfaceCapabilitiesKHR capabilities;
CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
state->phys_device, state->vulkan_surface, &capabilities));
uint32_t format_count;
CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(
state->phys_device, state->vulkan_surface, &format_count, NULL));
VkSurfaceFormatKHR formats[format_count];
CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(
state->phys_device, state->vulkan_surface, &format_count, formats));
VkSurfaceFormatKHR chosen_format = formats[0];
for (uint32_t i = 0; i < format_count; i++) {
if (formats[i].format == VK_FORMAT_R8G8B8A8_SRGB) {
chosen_format = formats[i];
break;
}
}
state->format = chosen_format.format;
state->image_count = capabilities.minImageCount + 1;
if (capabilities.maxImageCount > 0 &&
capabilities.maxImageCount < state->image_count) {
state->image_count = capabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR swapchain_info = {0};
swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchain_info.surface = state->vulkan_surface;
swapchain_info.minImageCount = state->image_count;
swapchain_info.imageFormat = chosen_format.format;
swapchain_info.imageColorSpace = chosen_format.colorSpace;
swapchain_info.imageExtent.width = state->width;
swapchain_info.imageExtent.height = state->heigh;
swapchain_info.imageArrayLayers = 1;
swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (state->queue_family_index_present != state->queue_family_index_graphics) {
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchain_info.queueFamilyIndexCount = 2;
uint32_t indices[] = {state->queue_family_index_graphics,
state->queue_family_index_present};
swapchain_info.pQueueFamilyIndices = indices;
} else {
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
swapchain_info.preTransform = capabilities.currentTransform;
swapchain_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapchain_info.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
swapchain_info.clipped = VK_TRUE;
swapchain_info.oldSwapchain = VK_NULL_HANDLE;
CHECK_VK_RESULT(vkCreateSwapchainKHR(state->device, &swapchain_info, NULL,
&state->swapchain));
CHECK_VK_RESULT(vkGetSwapchainImagesKHR(state->device, state->swapchain,
&state->image_count, NULL));
VkImage images[state->image_count];
CHECK_VK_RESULT(vkGetSwapchainImagesKHR(state->device, state->swapchain,
&state->image_count, images));
state->elements = malloc(state->image_count * sizeof(struct SwapchainElm));
for (int i = 0; i < state->image_count; i++) {
state->elements[i].image = images[i];
VkImageViewCreateInfo image_view_info = {0};
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_info.subresourceRange.baseMipLevel = 0;
image_view_info.subresourceRange.levelCount = 1;
image_view_info.subresourceRange.baseArrayLayer = 0;
image_view_info.subresourceRange.layerCount = 1;
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_view_info.image = state->elements[i].image;
image_view_info.format = state->format;
CHECK_VK_RESULT(vkCreateImageView(state->device, &image_view_info, NULL,
&state->elements[i].image_view));
}
}
VkCommandBuffer begin_single_time_commands(struct Vk *state) {
VkCommandBufferAllocateInfo alloc_info = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandPool = state->command_pool;
alloc_info.commandBufferCount = 1;
VkCommandBuffer command_buffer;
vkAllocateCommandBuffers(state->device, &alloc_info, &command_buffer);
VkCommandBufferBeginInfo begin_info = {0};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(command_buffer, &begin_info);
return command_buffer;
}
void end_single_time_commands(struct Vk *state,
VkCommandBuffer command_buffer) {
vkEndCommandBuffer(command_buffer);
VkSubmitInfo submit_info = {0};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
vkQueueSubmit(state->queue_graphics, 1, &submit_info, VK_NULL_HANDLE);
vkQueueWaitIdle(state->queue_graphics);
vkFreeCommandBuffers(state->device, state->command_pool, 1, &command_buffer);
}
void setup_framebuffers(struct Vk *state) {
for (int i = 0; i < state->image_count; i++) {
VkFramebufferCreateInfo framebuffer_info = {0};
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_info.renderPass = state->render_pass;
framebuffer_info.attachmentCount = 1;
framebuffer_info.pAttachments = &state->elements[i].image_view;
framebuffer_info.width = state->width;
framebuffer_info.height = state->heigh;
framebuffer_info.layers = 1;
CHECK_VK_RESULT(vkCreateFramebuffer(state->device, &framebuffer_info, NULL,
&state->elements[i].framebuffer));
}
}
void destroy_swapchain(struct Vk *state) {
for (int i = 0; i < state->image_count; i++) {
vkDestroyFramebuffer(state->device, state->elements[i].framebuffer, NULL);
vkDestroyImageView(state->device, state->elements[i].image_view, NULL);
}
free(state->elements);
vkDestroySwapchainKHR(state->device, state->swapchain, NULL);
}
void recreate_swapchain(struct Vk *state) {
destroy_swapchain(state);
create_swapchain(state);
setup_framebuffers(state);
}
VkShaderModule create_shader_module(struct Vk *state, uint32_t *data,
int size) {
VkShaderModuleCreateInfo shader_module_info = {0};
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_info.codeSize = size;
shader_module_info.pCode = data;
VkShaderModule shader_module;
CHECK_VK_RESULT(vkCreateShaderModule(state->device, &shader_module_info, NULL,
&shader_module));
return shader_module;
}
VkInstance create_instance() {
VkApplicationInfo app_info = {0};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = "meooow";
app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 1);
app_info.pEngineName = "Cat Engine";
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 1);
app_info.apiVersion = VK_API_VERSION_1_3;
VkInstanceCreateInfo instance_info = {0};
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_info.pApplicationInfo = &app_info;
instance_info.enabledExtensionCount =
sizeof(extensions) / sizeof(const char *);
instance_info.ppEnabledExtensionNames = extensions;
size_t found_layers = 0;
uint32_t instance_layer_count;
CHECK_VK_RESULT(
vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL));
VkLayerProperties *instance_layer_properties =
malloc(instance_layer_count * sizeof(VkLayerProperties));
CHECK_VK_RESULT(vkEnumerateInstanceLayerProperties(
&instance_layer_count, instance_layer_properties));
for (uint32_t i = 0; i < instance_layer_count; i++) {
for (int j = 0; j < sizeof(layers) / sizeof(const char *); j++) {
if (strcmp(instance_layer_properties[i].layerName, layers[j]) == 0) {
found_layers++;
}
}
}
free(instance_layer_properties);
if (found_layers >= sizeof(layers) / sizeof(const char *)) {
instance_info.enabledLayerCount = sizeof(layers) / sizeof(const char *);
instance_info.ppEnabledLayerNames = layers;
}
VkInstance instance;
CHECK_VK_RESULT(vkCreateInstance(&instance_info, NULL, &instance));
return instance;
}
void setup_debug_messenger(struct Vk *state) {
VkDebugUtilsMessengerCreateInfoEXT debug_utils_info = {0};
debug_utils_info.sType =
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
debug_utils_info.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
debug_utils_info.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
debug_utils_info.pfnUserCallback = handle_vulkan_error;
CHECK_VK_RESULT(
GET_EXTENSION_FUNCTION(state->instance, vkCreateDebugUtilsMessengerEXT)(
state->instance, &debug_utils_info, NULL, &state->debug_messenger));
}
VkPhysicalDevice create_physical_device(struct Vk *state) {
uint32_t phys_device_count;
vkEnumeratePhysicalDevices(state->instance, &phys_device_count, NULL);
VkPhysicalDevice phys_devices[phys_device_count];
vkEnumeratePhysicalDevices(state->instance, &phys_device_count, phys_devices);
VkPhysicalDevice device;
int best_score = 0;
for (int i = 0; i < phys_device_count; i++) {
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(phys_devices[i], &properties);
int score;
switch (properties.deviceType) {
case VK_PHYSICAL_DEVICE_TYPE_OTHER:
score = 1;
break;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
score = 4;
break;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
score = 5;
break;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
score = 3;
break;
case VK_PHYSICAL_DEVICE_TYPE_CPU:
score = 2;
default:
break;
}
if (score > best_score) {
best_score = score;
device = phys_devices[i];
}
}
return device;
}
void setup_device_and_queues(struct Vk *state) {
uint32_t queue_family_count;
vkGetPhysicalDeviceQueueFamilyProperties(state->phys_device,
&queue_family_count, NULL);
VkQueueFamilyProperties queue_families[queue_family_count];
vkGetPhysicalDeviceQueueFamilyProperties(state->phys_device,
&queue_family_count, queue_families);
for (int i = 0; i < queue_family_count; i++) {
VkBool32 present = 0;
CHECK_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(
state->phys_device, i, state->vulkan_surface, &present));
if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
state->queue_family_index_graphics = i;
}
if (present) {
state->queue_family_index_present = i;
}
}
uint32_t *indices;
int index_count;
if (state->queue_family_index_present != state->queue_family_index_graphics) {
index_count = 2;
indices = alloca(sizeof(uint32_t) * index_count);
indices[0] = state->queue_family_index_graphics;
indices[1] = state->queue_family_index_present;
} else {
index_count = 1;
indices = alloca(sizeof(uint32_t) * index_count);
indices[0] = state->queue_family_index_graphics;
}
VkDeviceQueueCreateInfo queue_infos[index_count];
memset(queue_infos, 0, sizeof(VkDeviceQueueCreateInfo) * index_count);
state->queue_priority = 1.0f;
for (int i = 0; i < index_count; i++) {
queue_infos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_infos[i].queueFamilyIndex = indices[i];
queue_infos[i].queueCount = 1;
queue_infos[i].pQueuePriorities = &state->queue_priority;
}
VkPhysicalDeviceFeatures device_features = {0};
VkDeviceCreateInfo device_info = {0};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.queueCreateInfoCount = index_count;
device_info.pQueueCreateInfos = queue_infos;
device_info.enabledExtensionCount =
sizeof(device_extensions) / sizeof(const char *);
device_info.ppEnabledExtensionNames = device_extensions;
device_info.pEnabledFeatures = &device_features;
CHECK_VK_RESULT(
vkCreateDevice(state->phys_device, &device_info, NULL, &state->device));
vkGetDeviceQueue(state->device, state->queue_family_index_present, 0,
&state->queue_present);
vkGetDeviceQueue(state->device, state->queue_family_index_graphics, 0,
&state->queue_graphics);
}
VkRenderPass create_render_pass(struct Vk *state) {
VkAttachmentDescription color_attachment = {0};
color_attachment.format = state->format;
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference color_attachment_ref = {0};
color_attachment_ref.attachment = 0;
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {0};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_attachment_ref;
VkSubpassDependency dependency = {0};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo render_pass_info = {0};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.attachmentCount = 1;
render_pass_info.pAttachments = &color_attachment;
render_pass_info.subpassCount = 1;
render_pass_info.pSubpasses = &subpass;
render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = &dependency;
VkRenderPass render_pass;
CHECK_VK_RESULT(
vkCreateRenderPass(state->device, &render_pass_info, NULL, &render_pass));
return render_pass;
}
void setup_command_pool(struct Vk *state) {
VkCommandPoolCreateInfo command_pool_info = {0};
command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
command_pool_info.queueFamilyIndex = state->queue_family_index_graphics;
command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
CHECK_VK_RESULT(vkCreateCommandPool(state->device, &command_pool_info, NULL,
&state->command_pool));
}
void setup_command_buffers(struct Vk *state) {
VkCommandBufferAllocateInfo command_buffer_alloc_info = {0};
command_buffer_alloc_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_alloc_info.commandPool = state->command_pool;
command_buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_alloc_info.commandBufferCount = 1;
command_buffer_alloc_info.commandBufferCount = MAX_FRAMES_IN_FLIGHT;
VkCommandBuffer buffers[MAX_FRAMES_IN_FLIGHT];
CHECK_VK_RESULT(vkAllocateCommandBuffers(
state->device, &command_buffer_alloc_info, buffers));
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
state->flights[i].command_buffer = buffers[i];
}
}
void setup_sync_objects(struct Vk *state) {
VkSemaphoreCreateInfo semaphore_info = {0};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkFenceCreateInfo fence_info = {0};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkSemaphore ias, rfs;
VkFence iff;
CHECK_VK_RESULT(
vkCreateSemaphore(state->device, &semaphore_info, NULL, &ias));
CHECK_VK_RESULT(
vkCreateSemaphore(state->device, &semaphore_info, NULL, &rfs));
CHECK_VK_RESULT(vkCreateFence(state->device, &fence_info, NULL, &iff));
state->flights[i].image_available_semaphore = ias;
state->flights[i].render_finished_semaphore = rfs;
state->flights[i].in_flight_fence = iff;
}
}
uint32_t find_memory_type(struct Vk *state, uint32_t memory_type_bits,
uint32_t properties) {
VkPhysicalDeviceMemoryProperties phys_mem_props;
vkGetPhysicalDeviceMemoryProperties(state->phys_device, &phys_mem_props);
uint32_t memory_type_index = -1;
for (uint32_t i = 0; i < phys_mem_props.memoryTypeCount; i++) {
if (memory_type_bits & (1 << i) &&
(phys_mem_props.memoryTypes[i].propertyFlags & properties) ==
properties) {
memory_type_index = i;
break;
}
}
if (memory_type_index == -1) {
meow("failed to find memory type");
}
return memory_type_index;
}
void create_buffer(struct Vk *state, VkDeviceSize size,
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties,
VkBuffer *buffer, VkDeviceMemory *buffer_memory) {
VkBufferCreateInfo buffer_info = {0};
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_info.size = size;
buffer_info.usage = usage;
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
CHECK_VK_RESULT(vkCreateBuffer(state->device, &buffer_info, NULL, buffer));
VkMemoryRequirements mem_reqs;
vkGetBufferMemoryRequirements(state->device, *buffer, &mem_reqs);
VkMemoryAllocateInfo alloc_info = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = mem_reqs.size;
alloc_info.memoryTypeIndex =
find_memory_type(state, mem_reqs.memoryTypeBits, properties);
CHECK_VK_RESULT(
vkAllocateMemory(state->device, &alloc_info, NULL, buffer_memory));
vkBindBufferMemory(state->device, *buffer, *buffer_memory, 0);
}
void copy_buffer(struct Vk *state, VkBuffer src_buffer, VkBuffer dst_buffer,
VkDeviceSize size) {
VkCommandBuffer command_buffer = begin_single_time_commands(state);
VkBufferCopy copy_region = {
.srcOffset = 0,
.dstOffset = 0,
.size = size,
};
vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, 1, &copy_region);
end_single_time_commands(state, command_buffer);
}
void transition_image_layout(struct Vk *state, VkImage image, VkFormat format,
VkImageLayout old_layout,
VkImageLayout new_layout) {
VkCommandBuffer command_buffer = begin_single_time_commands(state);
VkImageMemoryBarrier barrier = {0};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = old_layout;
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
VkPipelineStageFlags source_stage;
VkPipelineStageFlags dest_stage;
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dest_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
dest_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else {
meow("invalid transition OwO rudeeee");
}
vkCmdPipelineBarrier(command_buffer, source_stage, dest_stage, 0, 0, NULL, 0,
NULL, 1, &barrier);
end_single_time_commands(state, command_buffer);
}
void copy_buffer_to_image(struct Vk *state, VkBuffer buffer, VkImage image,
struct IVec2 size) {
VkCommandBuffer command_buffer = begin_single_time_commands(state);
VkBufferImageCopy region = {0};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = (VkOffset3D){0, 0, 0};
region.imageExtent = (VkExtent3D){size.x, size.y, 1};
vkCmdCopyBufferToImage(command_buffer, buffer, image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
end_single_time_commands(state, command_buffer);
}
struct ImageBuffer {
VkImage image;
VkDeviceMemory memory;
struct IVec2 dims;
VkDeviceSize size;
VkImageView view;
VkSampler sampler;
};
void create_image(struct Vk *state, struct IVec2 dims, VkFormat format,
VkImageTiling tiling, VkImageUsageFlags usage,
VkMemoryPropertyFlags properties, VkImage *image,
VkDeviceMemory *memory) {
VkImageCreateInfo image_info = {0};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.extent.width = dims.x;
image_info.extent.height = dims.y;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = format;
image_info.tiling = tiling;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = usage;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
CHECK_VK_RESULT(vkCreateImage(state->device, &image_info, NULL, image));
VkMemoryRequirements mem_reqs;
vkGetImageMemoryRequirements(state->device, *image, &mem_reqs);
VkMemoryAllocateInfo alloc_info = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
alloc_info.allocationSize = mem_reqs.size;
alloc_info.memoryTypeIndex =
find_memory_type(state, mem_reqs.memoryTypeBits, properties);
CHECK_VK_RESULT(vkAllocateMemory(state->device, &alloc_info, NULL, memory));
vkBindImageMemory(state->device, *image, *memory, 0);
}
struct ImageBuffer create_image_buffer(struct Vk *state) {
struct ImageBuffer buffer = {0};
uchar *image_data = load_image("image.png", &buffer.dims);
buffer.size = buffer.dims.x * buffer.dims.y * 4;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, buffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void *data;
vkMapMemory(state->device, staging_buffer_memory, 0, buffer.size, 0, &data);
memcpy(data, image_data, buffer.size);
vkUnmapMemory(state->device, staging_buffer_memory);
free(image_data);
create_image(
state, buffer.dims, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &buffer.image, &buffer.memory);
transition_image_layout(state, buffer.image, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copy_buffer_to_image(state, staging_buffer, buffer.image, buffer.dims);
transition_image_layout(state, buffer.image, VK_FORMAT_R8G8B8A8_SRGB,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
VkImageViewCreateInfo view_info = {0};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = buffer.image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = VK_FORMAT_R8G8B8A8_SRGB;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
CHECK_VK_RESULT(
vkCreateImageView(state->device, &view_info, NULL, &buffer.view));
VkSamplerCreateInfo sampler_info = {0};
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler_info.magFilter = VK_FILTER_NEAREST;
sampler_info.minFilter = VK_FILTER_NEAREST;
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.anisotropyEnable = VK_FALSE;
sampler_info.maxAnisotropy = 1.0f;
sampler_info.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
sampler_info.unnormalizedCoordinates = VK_FALSE;
sampler_info.compareEnable = VK_FALSE;
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
sampler_info.mipLodBias = 0.0f;
sampler_info.minLod = 0.0;
sampler_info.maxLod = 0.0;
CHECK_VK_RESULT(
vkCreateSampler(state->device, &sampler_info, NULL, &buffer.sampler));
return buffer;
}
struct VertexBuffer create_vertex_buffer(struct Vk *state, int count,
struct Vertex *vertex_data) {
VkDeviceSize size = count * sizeof(struct Vertex);
struct VertexBuffer buffer = {0};
buffer.count = count;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void *data;
vkMapMemory(state->device, staging_buffer_memory, 0, size, 0, &data);
memcpy(data, vertex_data, size);
vkUnmapMemory(state->device, staging_buffer_memory);
create_buffer(
state, size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &buffer.buffer, &buffer.memory);
copy_buffer(state, staging_buffer, buffer.buffer, size);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
return buffer;
}
struct Vk *init_vk(void *data, int width, int heigh,
VkSurfaceKHR (*surface)(void *, VkInstance)) {
struct Vk *state = malloc(sizeof(struct Vk));
memset(state, 0, sizeof(struct Vk));
memset(state->flights, 0, sizeof(state->flights));
state->width = width;
state->heigh = heigh;
state->instance = create_instance();
setup_debug_messenger(state);
state->vulkan_surface = surface(data, state->instance);
meow("got a surface at %p", state->vulkan_surface);
state->phys_device = create_physical_device(state);
setup_device_and_queues(state);
create_swapchain(state);
state->render_pass = create_render_pass(state);
setup_command_pool(state);
setup_framebuffers(state);
setup_command_buffers(state);
setup_sync_objects(state);
dyn_array_create_inplace(&state->kitties);
return state;
}
void uninit_vk(struct Vk *state) {
CHECK_VK_RESULT(vkDeviceWaitIdle(state->device));
dyn_array_destroy(&state->kitties);
destroy_swapchain(state);
vkDestroyRenderPass(state->device, state->render_pass, NULL);
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
vkDestroySemaphore(state->device,
state->flights[i].render_finished_semaphore, NULL);
vkDestroySemaphore(state->device,
state->flights[i].image_available_semaphore, NULL);
vkDestroyFence(state->device, state->flights[i].in_flight_fence, NULL);
}
vkDestroyCommandPool(state->device, state->command_pool, NULL);
vkDestroyDevice(state->device, NULL);
GET_EXTENSION_FUNCTION(state->instance, vkDestroyDebugUtilsMessengerEXT)(
state->instance, state->debug_messenger, NULL);
vkDestroySurfaceKHR(state->instance, state->vulkan_surface, NULL);
vkDestroyInstance(state->instance, NULL);
memset(state, 0, sizeof(struct Vk));
free(state);
meow("unmade a vk, nini :3");
}
void vk_draw(struct Vk *state) {
CHECK_VK_RESULT(vkWaitForFences(
state->device, 1, &state->flights[state->current_frame].in_flight_fence,
VK_TRUE, UINT64_MAX));
CHECK_VK_RESULT(vkResetFences(
state->device, 1, &state->flights[state->current_frame].in_flight_fence));
uint32_t image_index;
VkResult result = vkAcquireNextImageKHR(
state->device, state->swapchain, UINT64_MAX,
state->flights[state->current_frame].image_available_semaphore, NULL,
&image_index);
struct SwapchainElm *element = &state->elements[image_index];
struct InFlightObjects flight = state->flights[state->current_frame];
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
meow("recreating swapchain");
CHECK_VK_RESULT(vkDeviceWaitIdle(state->device));
recreate_swapchain(state);
return;
} else if (result < 0) {
CHECK_VK_RESULT(result);
}
vkResetCommandBuffer(flight.command_buffer, 0);
VkCommandBufferBeginInfo command_buffer_begin_info = {0};
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
CHECK_VK_RESULT(
vkBeginCommandBuffer(flight.command_buffer, &command_buffer_begin_info));
VkClearValue clear_value = {{0.0f, 0.0f, 0.0f, 1.0f}};
VkRenderPassBeginInfo begin_info = {0};
begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
begin_info.renderPass = state->render_pass;
begin_info.framebuffer = element->framebuffer;
begin_info.renderArea.offset = (VkOffset2D){0, 0};
begin_info.renderArea.extent = (VkExtent2D){state->width, state->heigh};
begin_info.clearValueCount = 1;
begin_info.pClearValues = &clear_value;
vkCmdBeginRenderPass(flight.command_buffer, &begin_info,
VK_SUBPASS_CONTENTS_INLINE);
for (int i = 0; i < state->kitties.count; i++) {
kitty_draw(state, image_index, state->kitties.items[i]);
}
vkCmdEndRenderPass(flight.command_buffer);
CHECK_VK_RESULT(vkEndCommandBuffer(flight.command_buffer));
VkPipelineStageFlags wait_stage[] = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSemaphore wait_semaphore[] = {flight.image_available_semaphore};
VkSemaphore signal_semaphore[] = {flight.render_finished_semaphore};
VkSubmitInfo submit_info = {0};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = wait_semaphore;
submit_info.pWaitDstStageMask = wait_stage;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &flight.command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = signal_semaphore;
CHECK_VK_RESULT(vkQueueSubmit(state->queue_graphics, 1, &submit_info,
flight.in_flight_fence));
VkSwapchainKHR swapchain[] = {state->swapchain};
VkPresentInfoKHR present_info = {0};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphore;
present_info.swapchainCount = 1;
present_info.pSwapchains = swapchain;
present_info.pImageIndices = &image_index;
result = vkQueuePresentKHR(state->queue_present, &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
CHECK_VK_RESULT(vkDeviceWaitIdle(state->device));
recreate_swapchain(state);
meow("recreated swapchain");
} else if (result < 0) {
CHECK_VK_RESULT(result);
}
state->current_frame = (state->current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
}
void vk_resize(struct Vk *state, int width, int heigh) {
state->width = width;
state->heigh = heigh;
CHECK_VK_RESULT(vkDeviceWaitIdle(state->device));
recreate_swapchain(state);
state->current_frame = 0;
}

100
vulkan.h Normal file
View file

@ -0,0 +1,100 @@
#ifndef INCLUDE_WAYLANDCLIENT_CAT_VULKAN_H_
#define INCLUDE_WAYLANDCLIENT_CAT_VULKAN_H_
#include <vulkan/vulkan.h>
#include "dynarray.h"
#include "types.h"
#define CHECK_VK_RESULT(_expr) \
do { \
VkResult result = _expr; \
if (result != VK_SUCCESS) { \
meow("Error executing %s: %i\n", #_expr, result); \
} \
} while (0);
#define GET_EXTENSION_FUNCTION($instance, _id) \
((PFN_##_id)(vkGetInstanceProcAddr($instance, #_id)))
#define MAX_FRAMES_IN_FLIGHT 2
dyn_array_define(da_VK_FORMAT, enum VkFormat);
dyn_array_define(da_Kitty, struct Kitty *);
struct VertexBuffer {
void *data;
VkBuffer buffer;
VkDeviceMemory memory;
uint32_t count;
int vertex_size;
int binding;
struct da_VK_FORMAT format;
};
struct InFlightObjects {
VkSemaphore image_available_semaphore;
VkSemaphore render_finished_semaphore;
VkFence in_flight_fence;
VkCommandBuffer command_buffer;
};
struct SwapchainElm {
VkImage image;
VkImageView image_view;
VkFramebuffer framebuffer;
};
struct Vk {
VkInstance instance;
VkPhysicalDevice phys_device;
VkDevice device;
VkDebugUtilsMessengerEXT debug_messenger;
VkSurfaceKHR vulkan_surface;
uint32_t queue_family_index_present;
VkQueue queue_present;
uint32_t queue_family_index_graphics;
VkQueue queue_graphics;
float queue_priority;
VkCommandPool command_pool;
VkFormat format;
uint32_t image_count;
VkSwapchainKHR swapchain;
struct SwapchainElm *elements;
struct InFlightObjects flights[MAX_FRAMES_IN_FLIGHT];
int current_frame;
uint32_t width;
uint32_t heigh;
VkRenderPass render_pass;
struct da_Kitty kitties;
};
struct Vk *init_vk(void *data, int width, int heigh,
VkSurfaceKHR (*surface)(void *, VkInstance));
void uninit_vk(struct Vk *state);
void vk_draw(struct Vk *state);
void vk_resize(struct Vk *state, int width, int heigh);
void create_buffer(struct Vk *state, VkDeviceSize size,
VkBufferUsageFlags usage, VkMemoryPropertyFlags properties,
VkBuffer *buffer, VkDeviceMemory *buffer_memory);
void copy_buffer(struct Vk *state, VkBuffer src_buffer, VkBuffer dst_buffer,
VkDeviceSize size);
void create_image(struct Vk *state, struct IVec2 dims, VkFormat format,
VkImageTiling tiling, VkImageUsageFlags usage,
VkMemoryPropertyFlags properties, VkImage *image,
VkDeviceMemory *memory);
void transition_image_layout(struct Vk *state, VkImage image, VkFormat format,
VkImageLayout old_layout,
VkImageLayout new_layout);
void copy_buffer_to_image(struct Vk *state, VkBuffer buffer, VkImage image,
struct IVec2 size);
VkShaderModule create_shader_module(struct Vk *state, uint32_t *data, int size);
#endif // INCLUDE_WAYLANDCLIENT_CAT_VULKAN_H_

265
vulkan_helpers.c Normal file
View file

@ -0,0 +1,265 @@
#include "log.h"
#include <vulkan/vulkan.h>
int get_size_of_format(enum VkFormat format) {
switch (format) {
case VK_FORMAT_R32_UINT:
case VK_FORMAT_R32_SINT:
case VK_FORMAT_R32_SFLOAT:
return 4;
case VK_FORMAT_R32G32_UINT:
case VK_FORMAT_R32G32_SINT:
case VK_FORMAT_R32G32_SFLOAT:
return 8;
case VK_FORMAT_R32G32B32_UINT:
case VK_FORMAT_R32G32B32_SINT:
case VK_FORMAT_R32G32B32_SFLOAT:
return 12;
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
return 16;
case VK_FORMAT_UNDEFINED:
case VK_FORMAT_R4G4_UNORM_PACK8:
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_B5G6R5_UNORM_PACK16:
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8_SNORM:
case VK_FORMAT_R8_USCALED:
case VK_FORMAT_R8_SSCALED:
case VK_FORMAT_R8_UINT:
case VK_FORMAT_R8_SINT:
case VK_FORMAT_R8_SRGB:
case VK_FORMAT_R8G8_UNORM:
case VK_FORMAT_R8G8_SNORM:
case VK_FORMAT_R8G8_USCALED:
case VK_FORMAT_R8G8_SSCALED:
case VK_FORMAT_R8G8_UINT:
case VK_FORMAT_R8G8_SINT:
case VK_FORMAT_R8G8_SRGB:
case VK_FORMAT_R8G8B8_UNORM:
case VK_FORMAT_R8G8B8_SNORM:
case VK_FORMAT_R8G8B8_USCALED:
case VK_FORMAT_R8G8B8_SSCALED:
case VK_FORMAT_R8G8B8_UINT:
case VK_FORMAT_R8G8B8_SINT:
case VK_FORMAT_R8G8B8_SRGB:
case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8_SNORM:
case VK_FORMAT_B8G8R8_USCALED:
case VK_FORMAT_B8G8R8_SSCALED:
case VK_FORMAT_B8G8R8_UINT:
case VK_FORMAT_B8G8R8_SINT:
case VK_FORMAT_B8G8R8_SRGB:
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_USCALED:
case VK_FORMAT_R8G8B8A8_SSCALED:
case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_SRGB:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SNORM:
case VK_FORMAT_B8G8R8A8_USCALED:
case VK_FORMAT_B8G8R8A8_SSCALED:
case VK_FORMAT_B8G8R8A8_UINT:
case VK_FORMAT_B8G8R8A8_SINT:
case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
case VK_FORMAT_R16_UNORM:
case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16_USCALED:
case VK_FORMAT_R16_SSCALED:
case VK_FORMAT_R16_UINT:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_SFLOAT:
case VK_FORMAT_R16G16_UNORM:
case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16_USCALED:
case VK_FORMAT_R16G16_SSCALED:
case VK_FORMAT_R16G16_UINT:
case VK_FORMAT_R16G16_SINT:
case VK_FORMAT_R16G16_SFLOAT:
case VK_FORMAT_R16G16B16_UNORM:
case VK_FORMAT_R16G16B16_SNORM:
case VK_FORMAT_R16G16B16_USCALED:
case VK_FORMAT_R16G16B16_SSCALED:
case VK_FORMAT_R16G16B16_UINT:
case VK_FORMAT_R16G16B16_SINT:
case VK_FORMAT_R16G16B16_SFLOAT:
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16G16B16A16_SNORM:
case VK_FORMAT_R16G16B16A16_USCALED:
case VK_FORMAT_R16G16B16A16_SSCALED:
case VK_FORMAT_R16G16B16A16_UINT:
case VK_FORMAT_R16G16B16A16_SINT:
case VK_FORMAT_R16G16B16A16_SFLOAT:
case VK_FORMAT_R64_UINT:
case VK_FORMAT_R64_SINT:
case VK_FORMAT_R64_SFLOAT:
case VK_FORMAT_R64G64_UINT:
case VK_FORMAT_R64G64_SINT:
case VK_FORMAT_R64G64_SFLOAT:
case VK_FORMAT_R64G64B64_UINT:
case VK_FORMAT_R64G64B64_SINT:
case VK_FORMAT_R64G64B64_SFLOAT:
case VK_FORMAT_R64G64B64A64_UINT:
case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT:
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_S8_UINT:
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
case VK_FORMAT_G8B8G8R8_422_UNORM:
case VK_FORMAT_B8G8R8G8_422_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
case VK_FORMAT_R10X6_UNORM_PACK16:
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_R12X4_UNORM_PACK16:
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G16B16G16R16_422_UNORM:
case VK_FORMAT_B16G16R16G16_422_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_R16G16_SFIXED5_NV:
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
case VK_FORMAT_A8_UNORM_KHR:
case VK_FORMAT_MAX_ENUM:
crash("unsuported format %d", format);
break;
}
}

361
wayland.c Normal file
View file

@ -0,0 +1,361 @@
#include "Wayland/xdg-shell-client-protocol.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <wayland-client-core.h>
#include <wayland-client-protocol.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon.h>
#include "dynarray.h"
#include "hashmap.h"
#include "log.h"
#include "vulkan.h"
#include <vulkan/vulkan_wayland.h>
struct cat_Wl {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct xdg_wm_base *wm_base;
struct wl_seat *seat;
struct wl_surface *wl_surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_keyboard *keyboard;
struct wl_pointer *pointer;
struct xkb_context *xkb_context;
struct xkb_keymap *keymap;
struct xkb_state *xkb_state;
int width, heigh;
int new_width, new_heigh;
bool resize_coming;
bool resize_ready;
bool should_close;
struct Vk *vk;
struct Hashmap_ui32 *keys;
struct da_uint32_t pressed;
struct da_uint32_t released;
};
static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) {
/* Sent by the compositor when it's no longer using this buffer */
wl_buffer_destroy(wl_buffer);
}
static const struct wl_buffer_listener wl_buffer_listener = {
.release = wl_buffer_release,
};
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
uint32_t serial) {
struct cat_Wl *state = data;
xdg_surface_ack_configure(xdg_surface, serial);
if (state->resize_coming) {
state->resize_ready = true;
}
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base,
uint32_t serial) {
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener wm_base_listener = {
.ping = xdg_wm_base_ping,
};
static void keyboard_event_keymap(void *data, struct wl_keyboard *wl_keyboard,
uint32_t format, int32_t fd, uint32_t size) {
struct cat_Wl *state = data;
if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
meow("there is xkb");
void *data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
const char *keymap = data;
state->keymap = xkb_keymap_new_from_string(state->xkb_context, keymap,
XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
munmap(data, size);
close(fd);
state->xkb_state = xkb_state_new(state->keymap);
} else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
meow("keymap is none");
}
}
static void keyboard_event_enter(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface,
struct wl_array *keys) {}
static void keyboard_event_leave(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, struct wl_surface *surface) {}
static void keyboard_event_key(void *data, struct wl_keyboard *wl_keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t key_state) {
key += 8;
struct cat_Wl *state = data;
if (state->xkb_state == NULL) {
meow("there is no xkb");
return;
}
xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb_state, key);
char buffer[128];
xkb_state_key_get_utf8(state->xkb_state, key, buffer, sizeof(buffer));
if (key_state == 1) {
insert_hashmap_ui32(state->keys, sym);
dyn_array_append(&state->pressed, sym);
} else if (key_state == 0) {
remove_hashmap_ui32(state->keys, sym);
dyn_array_append(&state->released, sym);
} else {
meow("bad wayland, a key can either go up or down, not %d", key_state);
}
}
static void keyboard_event_modifiers(void *data,
struct wl_keyboard *wl_keyboard,
uint32_t serial, uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked, uint32_t group) {
struct cat_Wl *client_state = data;
xkb_state_update_mask(client_state->xkb_state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
}
static void keyboard_event_repeat_info(void *data,
struct wl_keyboard *wl_keyboard,
int32_t rate, int32_t delay) {}
static const struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_event_keymap,
.enter = keyboard_event_enter,
.leave = keyboard_event_leave,
.key = keyboard_event_key,
.modifiers = keyboard_event_modifiers,
.repeat_info = keyboard_event_repeat_info,
};
static void seat_capabilities_listener(void *data, struct wl_seat *wl_seat,
uint32_t capabilities) {
struct cat_Wl *state = data;
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
state->keyboard = wl_seat_get_keyboard(wl_seat);
wl_keyboard_add_listener(state->keyboard, &keyboard_listener, state);
} else {
meow("uuuh there is no keyboard");
if (state->keyboard != NULL) {
wl_keyboard_destroy(state->keyboard);
}
}
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
state->pointer = wl_seat_get_pointer(wl_seat);
} else {
meow("uuuh there is no mouse");
if (state->pointer != NULL) {
wl_pointer_destroy(state->pointer);
}
}
}
static void seat_name_listener(void *data, struct wl_seat *wl_seat,
const char *name) {
meow("the seat is named %s", name);
}
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_capabilities_listener,
.name = seat_name_listener,
};
void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states) {
struct cat_Wl *state = data;
if (width != 0 && height != 0) {
state->resize_coming = true;
state->new_width = width;
state->new_heigh = height;
}
}
void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
struct cat_Wl *state = data;
state->should_close = true;
}
static const struct xdg_toplevel_listener toplevel_listener = {
.configure = xdg_toplevel_configure,
.close = xdg_toplevel_close,
};
static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version) {
struct cat_Wl *state = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor =
wl_registry_bind(registry, name, &wl_compositor_interface, 6);
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
state->wm_base =
wl_registry_bind(registry, name, &xdg_wm_base_interface, 3);
xdg_wm_base_add_listener(state->wm_base, &wm_base_listener, state);
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
state->seat = wl_registry_bind(registry, name, &wl_seat_interface, 8);
wl_seat_add_listener(state->seat, &seat_listener, state);
}
meow("interface %s: version %d", interface, version);
}
static void registry_global_remove(void *data, struct wl_registry *wl_registry,
uint32_t name) {
/* This space deliberately left blank */
}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
VkSurfaceKHR create_wayland_surface(void *data, VkInstance instance) {
struct cat_Wl *state = data;
VkSurfaceKHR surface;
VkWaylandSurfaceCreateInfoKHR surface_info = {0};
surface_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
surface_info.display = state->display;
surface_info.surface = state->wl_surface;
vkCreateWaylandSurfaceKHR(instance, &surface_info, NULL, &surface);
return surface;
}
struct cat_Wl *cat_init_wl(const char *name, int width, int heigh,
struct Vk **vk) {
struct cat_Wl *state = malloc(sizeof(struct cat_Wl));
memset(state, 0, sizeof(struct cat_Wl));
state->keys = create_hashmap_ui32();
dyn_array_create_inplace(&state->pressed);
dyn_array_create_inplace(&state->released);
state->should_close = state->resize_ready = state->resize_coming = false;
state->width = width;
state->heigh = heigh;
state->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
state->display = wl_display_connect(NULL);
state->registry = wl_display_get_registry(state->display);
wl_registry_add_listener(state->registry, &registry_listener, state);
wl_display_roundtrip(state->display);
state->wl_surface = wl_compositor_create_surface(state->compositor);
state->xdg_surface =
xdg_wm_base_get_xdg_surface(state->wm_base, state->wl_surface);
xdg_surface_add_listener(state->xdg_surface, &xdg_surface_listener, state);
state->xdg_toplevel = xdg_surface_get_toplevel(state->xdg_surface);
xdg_toplevel_add_listener(state->xdg_toplevel, &toplevel_listener, state);
xdg_toplevel_set_title(state->xdg_toplevel, name);
xdg_toplevel_set_app_id(state->xdg_toplevel, name);
wl_surface_commit(state->wl_surface);
wl_display_roundtrip(state->display);
wl_surface_commit(state->wl_surface);
state->vk = init_vk(state, width, heigh, create_wayland_surface);
*vk = state->vk;
return state;
}
void cat_wl_draw(struct cat_Wl *state) {
dyn_array_reset(&state->pressed);
dyn_array_reset(&state->released);
if (state->resize_ready && state->resize_coming) {
meow("resizing to %d x %d", state->new_width, state->new_heigh);
state->resize_coming = false;
state->resize_ready = false;
state->width = state->new_width;
state->heigh = state->new_heigh;
vk_resize(state->vk, state->width, state->heigh);
wl_surface_commit(state->wl_surface);
}
vk_draw(state->vk);
wl_surface_damage_buffer(state->wl_surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(state->wl_surface);
wl_display_roundtrip(state->display);
}
void cat_uninit_wl(struct cat_Wl *state) {
uninit_vk(state->vk);
destroy_hashmap_ui32(state->keys);
dyn_array_destroy(&state->pressed);
dyn_array_destroy(&state->released);
if (state->xkb_state != NULL) {
xkb_state_unref(state->xkb_state);
xkb_keymap_unref(state->keymap);
xkb_context_unref(state->xkb_context);
}
if (state->keyboard != NULL) {
wl_keyboard_release(state->keyboard);
}
if (state->pointer != NULL) {
wl_pointer_release(state->pointer);
}
if (state->seat != NULL) {
wl_seat_release(state->seat);
}
xdg_toplevel_destroy(state->xdg_toplevel);
xdg_surface_destroy(state->xdg_surface);
wl_surface_destroy(state->wl_surface);
xdg_wm_base_destroy(state->wm_base);
wl_compositor_destroy(state->compositor);
wl_registry_destroy(state->registry);
wl_display_disconnect(state->display);
memset(state, 0, sizeof(struct cat_Wl));
free(state);
meow("unmade a wl, nini :3");
}
bool cat_wl_should_close(struct cat_Wl *state) { return state->should_close; }
bool cat_wl_is_key_pressed(struct cat_Wl *state, uint32_t key) {
return get_hashmap_ui32(state->keys, key);
}
bool cat_wl_was_key_just_pressed(struct cat_Wl *state, uint32_t key) {
for (int i = 0; i < state->pressed.count; i++) {
if (state->pressed.items[i] == key) {
return true;
}
}
return false;
}
bool cat_wl_was_key_just_released(struct cat_Wl *state, uint32_t key) {
for (int i = 0; i < state->released.count; i++) {
if (state->released.items[i] == key) {
return true;
}
}
return false;
}

17
wayland.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef INCLUDE_WAYLANDCLIENT_CAT_WAYLAND_H_
#define INCLUDE_WAYLANDCLIENT_CAT_WAYLAND_H_
#include <stdbool.h>
#include <stdint.h>
struct cat_Wl;
struct cat_Wl *cat_init_wl(const char *name, int width, int heigh,
struct Vk **vk);
void cat_wl_draw(struct cat_Wl *state);
void cat_uninit_wl(struct cat_Wl *state);
bool cat_wl_should_close(struct cat_Wl *state);
bool cat_wl_is_key_pressed(struct cat_Wl *state, uint32_t key);
bool cat_wl_was_key_just_pressed(struct cat_Wl *state, uint32_t key);
bool cat_wl_was_key_just_released(struct cat_Wl *state, uint32_t key);
#endif // INCLUDE_WAYLANDCLIENT_CAT_WAYLAND_H_