+5
crone/_vk/.h
+5
crone/_vk/.h
+12
-4
crone/_vk/basics.c
+12
-4
crone/_vk/basics.c
···
76
76
ptrs_cleanup(requiredExtensions);
77
77
78
78
#ifdef DO_VALIDATION
79
-
PFN_vkCreateDebugUtilsMessengerEXT createFn = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk->instance, "vkCreateDebugUtilsMessengerEXT");
79
+
PFN_vkCreateDebugUtilsMessengerEXT createFn =
80
+
(PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk->instance, "vkCreateDebugUtilsMessengerEXT");
81
+
80
82
if (createFn == NULL) {
81
83
CRASH("failed to find debug messenger procAddr");
82
84
}
···
87
89
88
90
uint32_t deviceCount = 0;
89
91
vkEnumeratePhysicalDevices(vk->instance, &deviceCount, NULL);
90
-
vk->physicalDevices = ptrs_allocate(deviceCount);
92
+
vk->physicalDevices = list_allocate(deviceCount, sizeof(VkPhysicalDevice));
93
+
vk->pdeviceMetas = list_allocate(deviceCount, sizeof(pdevice_meta));
91
94
vkEnumeratePhysicalDevices(vk->instance, &deviceCount, (VkPhysicalDevice*) vk->physicalDevices.data);
95
+
vk->physicalDevices.count = deviceCount;
96
+
vk->pdeviceMetas.count = deviceCount;
92
97
93
98
return vk;
94
99
}
···
97
102
vulkan_state *vk = handle;
98
103
99
104
#ifdef DO_VALIDATION
100
-
PFN_vkDestroyDebugUtilsMessengerEXT destroyFn = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk->instance, "vkDestroyDebugUtilsMessengerEXT");
105
+
PFN_vkDestroyDebugUtilsMessengerEXT destroyFn =
106
+
(PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(vk->instance, "vkDestroyDebugUtilsMessengerEXT");
107
+
101
108
if (destroyFn == NULL) {
102
109
CRASH("failed to find debug messenger destroyer");
103
110
}
···
106
113
107
114
vkDestroyInstance(vk->instance, vk->pAllocator);
108
115
109
-
ptrs_cleanup(vk->physicalDevices);
116
+
list_cleanup(vk->pdeviceMetas);
117
+
list_cleanup(vk->physicalDevices);
110
118
free(vk);
111
119
}
112
120
+69
crone/_vk/graphics.c
+69
crone/_vk/graphics.c
···
1
1
2
2
#include ".h"
3
+
#include "pdevice.h"
3
4
4
5
graphics_handle graphics_init(vulkan_handle vulkan, window_handle window) {
5
6
graphics_state *graphics = malloc(sizeof(graphics_state));
···
8
9
graphics->vulkan = vulkan;
9
10
graphics->window = window;
10
11
12
+
// create surface
13
+
xlibSurfaceInfo(createInfo,
14
+
.flags = 0,
15
+
.dpy = window_display_ptr(window),
16
+
.window = *((Window*) window_window_ptr(window))
17
+
);
18
+
19
+
vulkan_state *vk = vulkan;
20
+
VkSurfaceKHR surface;
21
+
22
+
if (vkCreateXlibSurfaceKHR(vk->instance, &createInfo, vk->pAllocator, &surface) != VK_SUCCESS) {
23
+
CRASH("failed to create Xlib window surface");
24
+
}
25
+
26
+
vk->surface = surface;
27
+
28
+
ptr_list requiredExtensions = ptrs_allocate(1);
29
+
ptrs_append(&requiredExtensions, VK_KHR_SWAPCHAIN_EXTENSION_NAME);
30
+
31
+
fillDeviceProperties(vk);
32
+
33
+
selectPhysicalDevice(vk, surface, requiredExtensions);
34
+
35
+
// get surface details
36
+
37
+
38
+
// select swap extent
39
+
40
+
// find queue fams
41
+
42
+
// create log dev
43
+
44
+
// acquire queueueeueues
45
+
46
+
// pipeline layout
47
+
48
+
// render pass
49
+
50
+
// pipeline
51
+
52
+
// command pool
53
+
54
+
// command BUFFER
55
+
56
+
// sync stuff
57
+
58
+
// swapchain!!!
59
+
60
+
// lfg!!!!
61
+
62
+
ptrs_cleanup(requiredExtensions);
63
+
11
64
return graphics;
12
65
}
13
66
14
67
void graphics_cleanup(graphics_handle graphics) {
68
+
graphics_state *state = graphics;
69
+
vulkan_state *vk = state->vulkan;
70
+
71
+
for (size_t i = 0; i < vk->pdeviceMetas.count; ++i) {
72
+
pdevice_meta *meta = list_element(vk->pdeviceMetas, i);
73
+
if (meta->extensionProperties.data != 0) {
74
+
list_cleanup(meta->extensionProperties);
75
+
}
76
+
if (meta->queueFamilyProperties.data != 0) {
77
+
list_cleanup(meta->queueFamilyProperties);
78
+
}
79
+
// TODO cleanup for formats & presentmodes of surface details
80
+
}
81
+
82
+
vkDestroySurfaceKHR(vk->instance, vk->surface, vk->pAllocator);
83
+
15
84
free(graphics);
16
85
}
17
86
+134
crone/_vk/pdevice.h
+134
crone/_vk/pdevice.h
···
1
+
2
+
// TODO: break this down into components, rename to something like "loadDeviceMetadata",
3
+
// make suitability a later check based on the loaded metadata
4
+
5
+
void getExtensionProperties(VkPhysicalDevice device, pdevice_meta *meta) {
6
+
uint32_t extensionCount;
7
+
vkEnumerateDeviceExtensionProperties(device, NULL /* layer */, &extensionCount, NULL);
8
+
meta->extensionProperties = list_allocate(extensionCount, sizeof(VkExtensionProperties));
9
+
vkEnumerateDeviceExtensionProperties(device, NULL /* layer */, &extensionCount, meta->extensionProperties.data);
10
+
}
11
+
12
+
void getQueueFamilyProperties(VkPhysicalDevice device, pdevice_meta *meta) {
13
+
uint32_t queueFamilyCount;
14
+
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, NULL);
15
+
meta->queueFamilyProperties = list_allocate(queueFamilyCount, sizeof(VkQueueFamilyProperties));
16
+
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, meta->queueFamilyProperties.data);
17
+
}
18
+
19
+
bool hasRequiredExtensions(VkPhysicalDevice device, pdevice_meta *meta, ptr_list requiredExtensions) {
20
+
uint32_t failedRequirements = 0;
21
+
22
+
for (size_t i = 0; i < requiredExtensions.count; ++i) {
23
+
bool requirementMet = false;
24
+
char *requirement = (char*)requiredExtensions.data[i];
25
+
for (size_t j = 0; j < meta->extensionProperties.count; ++j) {
26
+
VkExtensionProperties *extension = list_element(meta->extensionProperties, j);
27
+
28
+
requirementMet = !strcmp(requirement, extension->extensionName);
29
+
if (requirementMet) break;
30
+
}
31
+
if (!requirementMet) {
32
+
failedRequirements += 1;
33
+
}
34
+
}
35
+
36
+
return failedRequirements == 0;
37
+
}
38
+
39
+
bool hasGraphicsQueue(VkPhysicalDevice device, pdevice_meta *meta) {
40
+
meta->hasGraphicsQueue = false;
41
+
42
+
for (size_t i = 0; i < meta->queueFamilyProperties.count; ++i) {
43
+
VkQueueFamilyProperties *properties = list_element(meta->queueFamilyProperties, i);
44
+
if (properties->queueFlags & VK_QUEUE_GRAPHICS_BIT) {
45
+
meta->hasGraphicsQueue = true;
46
+
meta->graphicsQueueIndex = i;
47
+
break;
48
+
}
49
+
}
50
+
51
+
return meta->hasGraphicsQueue;
52
+
}
53
+
54
+
bool hasSurfaceQueue(VkPhysicalDevice device, pdevice_meta *meta, VkSurfaceKHR surface) {
55
+
meta->hasSurfaceQueue = false;
56
+
57
+
for (size_t i = 0; i < meta->queueFamilyProperties.count; ++i) {
58
+
VkBool32 vkSurfaceSupported = false;
59
+
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surfaceOrNull, &vkSurfaceSupported);
60
+
if (vkSurfaceSupported) {
61
+
meta->hasSurfaceQueue = true;
62
+
meta->surfaceQueueIndex = i;
63
+
break;
64
+
}
65
+
}
66
+
67
+
return meta->hasSurfaceQueue;
68
+
}
69
+
70
+
int fillSurfaceDetails(VkPhysicalDevice device, pdevice_meta *meta, VkSurfaceKHR surface) {
71
+
72
+
uint32_t formatCount;
73
+
74
+
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, NULL);
75
+
76
+
if (formatCount == 0) failedRequirements += 1;
77
+
78
+
uint32_t presentModeCount;
79
+
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, NULL);
80
+
81
+
if (presentModeCount == 0) failedRequirements += 1;
82
+
83
+
}
84
+
85
+
void fillDeviceProperties(vulkan_state *vk) {
86
+
for (size_t i = 0; i < vk->physicalDevices.count; ++i) {
87
+
VkPhysicalDevice *device = list_element(vk->physicalDevices, i);
88
+
pdevice_meta *meta = list_element(vk->pdeviceMetas, i);
89
+
90
+
getExtensionProperties(device, meta);
91
+
getQueueFamilyProperties(device, meta);
92
+
}
93
+
}
94
+
95
+
96
+
97
+
void selectRenderingDevice(vulkan_state *vk, VkSurfaceKHR surface, ptr_list requiredExtensions) {
98
+
vk->renderDevice = VK_NULL_HANDLE;
99
+
100
+
// iterate over devices, seek suitable
101
+
for (size_t i = 0; i < vk->physicalDevices.count; ++i) {
102
+
VkPhysicalDevice *consideredDevice = list_element(vk->physicalDevices, i);
103
+
pdevice_meta *meta = list_element(vk->pdeviceMetas, i);
104
+
105
+
uint32_t failedRequirements = 0;
106
+
107
+
if (!hasRequiredExtensions(device, meta, requiredExtensions)) {
108
+
failedRequirements += 1;
109
+
}
110
+
111
+
if (!hasGraphicsQueue(device, meta)) {
112
+
failedRequirements += 1;
113
+
}
114
+
115
+
if (!hasSurfaceQueue(device, meta, surface)) {
116
+
failedRequirements += 1;
117
+
} else {
118
+
failedRequirements += fillSurfaceDetails(device, meta, surface);
119
+
}
120
+
121
+
122
+
if (failedRequirements == 0) {
123
+
vk->renderDevice = *consideredDevice;
124
+
vk->renderDeviceMeta = meta;
125
+
break;
126
+
} else {
127
+
meta->score = 0;
128
+
}
129
+
}
130
+
131
+
if (vk->renderDevice == VK_NULL_HANDLE) CRASH("no suitable physical device");
132
+
}
133
+
134
+
+30
-1
crone/_vk/structs.h
+30
-1
crone/_vk/structs.h
···
1
+
2
+
typedef struct surface_details {
3
+
VkSurfaceCapabilitiesKHR capabilities;
4
+
list formats;
5
+
list presentModes;
6
+
VkSurfaceFormatKHR selectedFormat;
7
+
VkPresentModeKHR selectedMode;
8
+
VkExtent2D selectedExtent;
9
+
} surface_details;
10
+
11
+
typedef struct pdevice_meta {
12
+
uint32_t graphicsQueueIndex;
13
+
uint32_t surfaceQueueIndex;
14
+
list extensionProperties;
15
+
list queueFamilyProperties;
16
+
surface_details surfaceDetails;
17
+
bool hasGraphicsQueue;
18
+
bool hasSurfaceQueue;
19
+
uint32_t score;
20
+
} pdevice_meta;
1
21
2
22
typedef struct vulkan_state {
3
23
VkInstance instance;
4
-
ptr_list physicalDevices;
24
+
25
+
list physicalDevices;
26
+
list pdeviceMetas;
27
+
28
+
VkSurfaceKHR surface;
29
+
30
+
VkPhysicalDevice renderDevice;
31
+
pdevice_meta *renderDeviceMeta;
32
+
5
33
VkAllocationCallbacks *pAllocator;
6
34
#ifdef DO_VALIDATION
7
35
VkDebugUtilsMessengerEXT debugMessenger;
···
12
40
vulkan_handle vulkan;
13
41
window_handle window;
14
42
} graphics_state;
43
+
+10
crone/_x11/window.c
+10
crone/_x11/window.c
···
4
4
#include <stdlib.h>
5
5
6
6
#include <X11/Xlib.h>
7
+
#include <X11/Xlibint.h>
7
8
#include <X11/Xutil.h>
8
9
9
10
#include <core.h>
···
84
85
85
86
inline void window_cleanup(void *window_void) {
86
87
XWindow *window = window_void;
88
+
89
+
/*
90
+
// Print all extensions before cleanup
91
+
fprintf(stderr, "[DEBUG] Extensions before cleanup:\n");
92
+
for (_XExtension *ext = window->display->ext_procs; ext; ext = ext->next) {
93
+
fprintf(stderr, " Extension: close_display=%p, | name=%s\n", (void*)ext->close_display, (char*)ext->name);
94
+
}
95
+
*/
96
+
87
97
XDestroyWindow(window->display, window->window);
88
98
XCloseDisplay(window->display);
89
99
free(window);
+9
-2
crone/core/list.h
+9
-2
crone/core/list.h
···
4
4
.count = 0,
5
5
.capacity = initial_capacity,
6
6
.element_size = element_size,
7
-
.data = malloc(element_size * initial_capacity)
7
+
.data = calloc(initial_capacity, element_size)
8
8
};
9
9
if (list.data == NULL) { CRASH("failed malloc: list"); }
10
10
return list;
11
11
}
12
12
13
-
// potentially invalidates pointers to entries
13
+
// potentially invalidates pointers to entries. maybe better to refactor away the implicit side effect
14
14
void list_append(list *list, void *item) {
15
15
list->count += 1;
16
16
if (list->count > list->capacity) {
···
27
27
++list->capacity;
28
28
/*=====================================*/
29
29
list->data = realloc(list->data, list->element_size * list->capacity);
30
+
/*
31
+
memset(
32
+
(uint8_t*)list->data + (list->count) * list->element_size,
33
+
0,
34
+
(list->capacity - list->count) * list->element_size
35
+
); // TODO double-check for off-by-one errors
36
+
*/
30
37
if (list->data == NULL) { CRASH("failed realloc: list"); }
31
38
}
32
39
+1
crone/interface/core/segment.h
+1
crone/interface/core/segment.h
···
1
+
+5
-4
makefile
+5
-4
makefile
···
9
9
10
10
LINKS = -lX11 -lvulkan
11
11
HEADERS = -I $(PROJECT_NAME)/interface
12
-
ERRORS = -Wfatal-errors -Wall -Wextra -Werror=use-after-free -Wno-unused-variable -Wpedantic
13
-
%_dev: VERSION_FLAGS = -Og -DDO_VALIDATION -fsanitize=address,undefined
12
+
ERRORS = -Wfatal-errors -Wall -Wextra -Werror=use-after-free -Wno-unused-variable -Wpedantic -fno-common -Wshadow -Wconversion -Wdouble-promotion -Wvla
13
+
SANITY = -fwrapv -fno-strict-aliasing -fno-delete-null-pointer-checks
14
+
%_dev: VERSION_FLAGS = -Og -DDO_VALIDATION -fsanitize=undefined,address -g -fno-omit-frame-pointer -fstack-protector-strong
14
15
%_release: VERSION_FLAGS = -O3
15
-
FLAGS = -std=c23 $(ERRORS) $(VERSION_FLAGS) $(HEADERS) -DUSE_X11
16
+
FLAGS = -std=c23 $(ERRORS) $(SANITY) $(VERSION_FLAGS) $(HEADERS) -DUSE_X11
16
17
17
18
GCC = gcc $(FLAGS) -o
18
19
NVCC = nvcc -Xcompiler $(FLAGS) -o
···
54
55
55
56
test: objects program/$(PROJECT_NAME)_dev
56
57
@echo -e "\n[makefile] launching..."
57
-
@program/$(PROJECT_NAME)_dev
58
+
@LSAN_OPTIONS=suppressions=san.supp program/$(PROJECT_NAME)_dev
58
59
59
60
DATE := $(shell date '+%d.%m.%Y')
60
61
release: objects program/$(PROJECT_NAME)_release
+8
-2
program.c
+8
-2
program.c
···
12
12
13
13
14
14
int main() {
15
+
/* lang
15
16
int fileDesc = open("./crone/core/core.cr", O_RDONLY, 0);
16
17
//int fileDesc = open("./crone/lang/parseme.cr", O_RDONLY, 0);
17
18
···
44
45
if (result == -1) {
45
46
CRASH("bad munmap");
46
47
}
47
-
48
+
// */
48
49
49
50
50
51
///* graphics
···
52
53
53
54
vulkan_handle vk = vulkan_init();
54
55
graphics_handle graphics = graphics_init(vk, window);
56
+
57
+
fprintf(stderr, "[PROGRAM] entering main loop\n");
58
+
55
59
56
60
while (!window_shouldClose(window)) {
57
61
window_pollEvents(window);
58
62
}
59
63
64
+
fprintf(stderr, "[PROGRAM] exiting main loop\n");
65
+
66
+
window_cleanup(window);
60
67
graphics_cleanup(graphics);
61
68
vulkan_cleanup(vk);
62
69
63
-
window_cleanup(window);
64
70
65
71
fprintf(stderr, "[PROGRAM] done\n");
66
72