Initial commit :3
This commit is contained in:
commit
d820665f6c
41 changed files with 13764 additions and 0 deletions
32
Makefile
Normal file
32
Makefile
Normal 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
11
Shaders/shader.frag
Normal 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
19
Shaders/shader.vert
Normal 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;
|
||||||
|
}
|
2325
Wayland/xdg-shell-client-protocol.h
Normal file
2325
Wayland/xdg-shell-client-protocol.h
Normal file
File diff suppressed because it is too large
Load diff
184
Wayland/xdg-shell-protocol.c
Normal file
184
Wayland/xdg-shell-protocol.c
Normal 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
88
allocator.c
Normal 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
14
allocator.h
Normal 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
27
comp.c
Normal 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
27
comp.h
Normal 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
20
dynarray.c
Normal 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
42
dynarray.h
Normal 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
44
glfw.c
Normal 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
6
glfw.h
Normal 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
89
hashmap.c
Normal 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
10
hashmap.h
Normal 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
9
image.c
Normal 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
10
image.h
Normal 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
BIN
image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
47
io.c
Normal file
47
io.c
Normal 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
9
io.h
Normal 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
579
kitty.c
Normal 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
26
kitty.h
Normal 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
38
log.c
Normal 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
14
log.h
Normal 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
BIN
main
Executable file
Binary file not shown.
32
main.c
Normal file
32
main.c
Normal 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
42
matrix.c
Normal 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
28
matrix.h
Normal 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
89
object.c
Normal 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
30
object.h
Normal 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
36
register.c
Normal 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);
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_register(struct Register *reg) {
|
||||||
|
dyn_array_destroy(®->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, 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.items[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
meow("did not find %s in register", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
33
register.h
Normal file
33
register.h
Normal 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
7988
stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
73
trig.c
Normal file
73
trig.c
Normal 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
1
types.c
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include "types.h"
|
44
types.h
Normal file
44
types.h
Normal 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
955
vulkan.c
Normal 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, ©_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, ®ion);
|
||||||
|
|
||||||
|
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
100
vulkan.h
Normal 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
265
vulkan_helpers.c
Normal 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
361
wayland.c
Normal 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, ®istry_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
17
wayland.h
Normal 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_
|
Loading…
Add table
Reference in a new issue