improve compiler settings, continue work on basic vulkan boilerplate

autumn c5224030 347001c0

Changed files
+290 -13
crone
+5
crone/_vk/.h
··· 5 5 6 6 #include <vulkan/vulkan.h> 7 7 8 + #if USE_X11 9 + #include <X11/Xlib.h> 10 + #include <vulkan/vulkan_xlib.h> 11 + #endif 12 + 8 13 #include <core.h> 9 14 #include <vk.h> 10 15
+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
··· 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
··· 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
··· 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 +
+3
crone/_vk/surface.h
··· 1 + 2 + 3 +
+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
··· 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 +
+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
··· 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
+4
san.supp
··· 1 + 2 + leak:libdbus-1.so 3 + leak:<unknown module> 4 +