From 7ae6de6e45056160d1c07b9c51e6d91ed66067f5 Mon Sep 17 00:00:00 2001 From: Robear Selwans Date: Mon, 7 Jul 2025 10:54:09 +0300 Subject: [PATCH] Initial changes to get a triangle on linux Signed-off-by: Robear Selwans --- build_options/meson-clang-linux | 11 +++ .../meson-clang-win | 0 evk/evkAllocator.c | 14 ++-- evk/evkCommon.h | 80 +++++++++++++++++++ evk/evkDevice.c | 20 ++--- evk/evkSwapChain.c | 6 +- evk/evkTypes.h | 1 + main.c | 54 +++++++++---- 8 files changed, 155 insertions(+), 31 deletions(-) create mode 100644 build_options/meson-clang-linux rename meson-native-clang => build_options/meson-clang-win (100%) diff --git a/build_options/meson-clang-linux b/build_options/meson-clang-linux new file mode 100644 index 0000000..9ad442e --- /dev/null +++ b/build_options/meson-clang-linux @@ -0,0 +1,11 @@ +[binaries] +c = 'clang-19' +c_ld = 'lld-19' +cpp = 'clang++-19' +cpp_ld = 'lld-19' + +[properties] +c_args = ['-DEV_CC_CLANG=1','-fcolor-diagnostics', '-fansi-escape-codes', '-fms-extensions'] + +[cmake] +CMAKE_C_COMPILER = 'clang-19' diff --git a/meson-native-clang b/build_options/meson-clang-win similarity index 100% rename from meson-native-clang rename to build_options/meson-clang-win diff --git a/evk/evkAllocator.c b/evk/evkAllocator.c index 534f1f9..6f99372 100644 --- a/evk/evkAllocator.c +++ b/evk/evkAllocator.c @@ -3,30 +3,34 @@ #include #include +// TODO Get this working on linux + // PFN_vkAllocationFunction void* evkAllocationFunctionCallback(void* pUserData, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope) { /* puts("evkAllocationFunctionCallback"); */ - void* alloc = _aligned_malloc(allocationSize, allocationAlignment); - if(alloc == NULL) + // void* alloc = _aligned_malloc(allocationSize, allocationAlignment); + // if(alloc == NULL) { puts("Allocation Failed"); } - return alloc; + // return alloc; + return NULL; } // PFN_vkReallocationFunction void* evkReallocationFunctionCallback(void* pUserData, void* pOriginal, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope) { /* puts("evkReallocationFunctionCallback"); */ - return _aligned_realloc(pOriginal, allocationSize, allocationAlignment); + // return _aligned_realloc(pOriginal, allocationSize, allocationAlignment); + return NULL; } // PFN_vkFreeFucntion void evkFreeFunctionCallback(void* pUserData, void* pMemory) { /* puts("evkFreeFunctionCallback"); */ - _aligned_free(pMemory); + // _aligned_free(pMemory); } // PFN_vkInternalAllocaitonNotification diff --git a/evk/evkCommon.h b/evk/evkCommon.h index 9ae23a8..b22392b 100644 --- a/evk/evkCommon.h +++ b/evk/evkCommon.h @@ -12,3 +12,83 @@ #include "evkConstants.h" #include "evkTypes.h" + +static inline const char* VkResultStrings(VkResult res) { + switch(res) { + case VK_SUCCESS: + return "VK_SUCCESS"; + case VK_NOT_READY: + return "VK_NOT_READY"; + case VK_TIMEOUT: + return "VK_TIMEOUT"; + case VK_EVENT_SET: + return "VK_EVENT_SET"; + case VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_UNKNOWN: + return "VK_ERROR_UNKNOWN"; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: + return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_NOT_PERMITTED_EXT: + return "VK_ERROR_NOT_PERMITTED_EXT"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_ERROR_OUT_OF_POOL_MEMORY_KHR: + return "VK_ERROR_OUT_OF_POOL_MEMORY_KHR"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR: + return "VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR"; + case VK_ERROR_FRAGMENTATION_EXT: + return "VK_ERROR_FRAGMENTATION_EXT"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR: + return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR / VK_ERROR_INVALID_DEVICE_ADDRESS"; + default: + return NULL; + } +}; + +#define EVK_ASSERT(fn) do { \ + VkResult __vk_assert_result_internal = fn; \ + if(__vk_assert_result_internal != VK_SUCCESS) { \ + printf("[VulkanError] `%s` returned error code %d ('%s')\n", EV_STRINGIZE(fn), __vk_assert_result_internal, VkResultStrings(__vk_assert_result_internal));\ + } \ +} while (0) diff --git a/evk/evkDevice.c b/evk/evkDevice.c index 9d41360..d7d2ede 100644 --- a/evk/evkDevice.c +++ b/evk/evkDevice.c @@ -11,20 +11,20 @@ #define EVK_ENABLE_EXTENSION_FEATURES(enabledExtensions,featuresStruct) \ EV_FOREACH_UDATA(EVK_ENABLE_EXTENSION_FEATURE, (enabledExtensions, featuresStruct), SUPPORTED_EXTENSION_FEATURE_PAIRS) -#define EVK_ENABLE_EXTENSION_FEATURE(ef_pair, name_flag_pair) \ - { \ - evstring name = evstr(EV_HEAD name_flag_pair); \ - if(ev_vec_find(&EV_HEAD ef_pair, &name) != -1) \ - EV_TAIL ef_pair.EV_TAIL name_flag_pair = true; \ +#define EVK_ENABLE_EXTENSION_FEATURE(ef_pair, name_flag_pair) \ + { \ + evstring name = evstr(EV_HEAD name_flag_pair); \ + if(ev_vec_find(&EV_HEAD ef_pair, &name) != -1) \ + EV_TAIL ef_pair.EV_TAIL name_flag_pair = true; \ } VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufFeature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT, .descriptorBuffer = VK_TRUE, - EV_DEBUG( - .descriptorBufferCaptureReplay = VK_TRUE, - ) + // EV_DEBUG( + // .descriptorBufferCaptureReplay = VK_TRUE, + // ) }; typedef struct { @@ -67,7 +67,7 @@ VkPhysicalDevice evkDetectPhysicalDevice(evkInstance instance, VkPhysicalDeviceT evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo) { - evkDevice device; + evkDevice device = {0}; device._physicalDevice = evkDetectPhysicalDevice(createInfo.instance, createInfo.physicalDeviceType); device._instance = createInfo.instance; @@ -210,7 +210,7 @@ evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo) } } - vkCreateDevice(device._physicalDevice, &vkDeviceCreateInfo, evkGetAllocationCallbacks(), &device.vk); + EVK_ASSERT(vkCreateDevice(device._physicalDevice, &vkDeviceCreateInfo, evkGetAllocationCallbacks(), &device.vk)); vec_fini(&queueCreateInfoList); vec_fini(&priorities); diff --git a/evk/evkSwapChain.c b/evk/evkSwapChain.c index 0cac496..6b6505b 100644 --- a/evk/evkSwapChain.c +++ b/evk/evkSwapChain.c @@ -9,6 +9,9 @@ evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo) VkSurfaceCapabilitiesKHR surfaceCaps; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceCaps); + if(surfaceCaps.maxImageCount == 0) + surfaceCaps.maxImageCount = UInt32.MAX; + VkCompositeAlphaFlagBitsKHR compositeAlpha = (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) ? VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR @@ -53,8 +56,9 @@ evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo) .oldSwapchain = VK_NULL_HANDLE, }; - vkCreateSwapchainKHR(createInfo.device.vk, &swapChainCreateInfo, NULL, &swapChain.vk); + EVK_ASSERT(vkCreateSwapchainKHR(createInfo.device.vk, &swapChainCreateInfo, NULL, &swapChain.vk)); + vkGetSwapchainImagesKHR(createInfo.device.vk, swapChain.vk, &buffering, NULL); VkImage swapChainVkImages[buffering]; vkGetSwapchainImagesKHR(createInfo.device.vk, swapChain.vk, &buffering, swapChainVkImages); diff --git a/evk/evkTypes.h b/evk/evkTypes.h index 3d17c5a..bd619eb 100644 --- a/evk/evkTypes.h +++ b/evk/evkTypes.h @@ -14,6 +14,7 @@ TYPEDATA_GEN(VkCommandBuffer); TYPEDATA_GEN(VkDynamicState); TYPEDATA_GEN(VkSurfaceFormatKHR); TYPEDATA_GEN(VkFormat); +TYPEDATA_GEN(VkSemaphore); TYPEDATA_GEN(VkClearValue, DEFAULT({{0.f,0.f,0.f,1.f}})); TYPEDATA_GEN(VkRenderingAttachmentInfoKHR, DEFAULT( diff --git a/main.c b/main.c index 71dea40..e85c300 100644 --- a/main.c +++ b/main.c @@ -19,7 +19,12 @@ int main(void) }), .extensions = svec_init(evstring, { evstr("VK_KHR_surface"), +// TODO Get these from GLFW +#if EV_OS_WINDOWS evstr("VK_KHR_win32_surface"), +#elif EV_OS_LINUX + evstr("VK_KHR_xcb_surface"), +#endif }), }); @@ -32,7 +37,9 @@ int main(void) evkDevice device = evkCreateDevice((evkDeviceCreateInfo) { .instance = instance, - .physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, + // TODO Add a fallback physical device option. + // .physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, + .physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, .queueRequirements = svec_init(evkDeviceQueueRequirement, { { VK_QUEUE_GRAPHICS_BIT, 1 }, { VK_QUEUE_COMPUTE_BIT , 1 }, @@ -54,6 +61,7 @@ int main(void) puts("Couldn't create a VkDevice"); goto DeviceCreationFailed; } + puts("Logical Device created successfully."); VkQueue graphicsQueue; vkGetDeviceQueue(device.vk, device.queueFamilies[VK_QUEUE_GRAPHICS_BIT].familyIndex, 0, &graphicsQueue); @@ -201,19 +209,30 @@ int main(void) evkPipeline graphicsPipeline = evkCreatePipeline(device, pipelineCreateInfo); - VkFence drawFence = evkCreateFence(device, false); - VkSemaphore imageAcquiredSemaphore = evkCreateSemaphore(device); - VkSemaphore drawFinishedSemaphore = evkCreateSemaphore(device); + u32 imageCount = vec_len(&swapChain.images); + VkFence drawFence = evkCreateFence(device, false); + vec(VkSemaphore) imageAcquiredSemaphores = vec_init(VkSemaphore); + vec(VkSemaphore) drawFinishedSemaphores = vec_init(VkSemaphore); + for(u32 i = 0; i < imageCount; i++) + { + imageAcquiredSemaphores[i] = evkCreateSemaphore(device); + drawFinishedSemaphores[i] = evkCreateSemaphore(device); + } + // VkSemaphore imageAcquiredSemaphore = evkCreateSemaphore(device); + // VkSemaphore drawFinishedSemaphore = evkCreateSemaphore(device); + + i32 imageIdx = -1; while(!glfwWindowShouldClose(window)) { - u32 imageIdx; - vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, &imageIdx); + imageIdx = (imageIdx + 1) % imageCount; + u32 swapChainImageIdx; + EVK_ASSERT(vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphores[imageIdx], VK_NULL_HANDLE, &swapChainImageIdx)); evkCommandBuffer cmdbuf = commandBuffers[imageIdx]; VkRenderingAttachmentInfoKHR colorAttachment = EV_DEFAULT(VkRenderingAttachmentInfoKHR, - imageView = swapChain.imageViews[imageIdx].vk, + imageView = swapChain.imageViews[swapChainImageIdx].vk, loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, storeOp= VK_ATTACHMENT_STORE_OP_STORE, ); @@ -243,7 +262,7 @@ int main(void) VkImageMemoryBarrier imageMemoryBarrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .image = swapChain.images[imageIdx].vk, + .image = swapChain.images[swapChainImageIdx].vk, .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, @@ -260,13 +279,13 @@ int main(void) VkSubmitInfo submitInfo = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .pCommandBuffers = &cmdbuf, // TODO This won't work with more than a single cmdbuf + .pCommandBuffers = &cmdbuf.vk, // TODO This won't work with more than a single cmdbuf .commandBufferCount = 1, .waitSemaphoreCount = 1, - .pWaitSemaphores = &imageAcquiredSemaphore, + .pWaitSemaphores = &imageAcquiredSemaphores[imageIdx], .pWaitDstStageMask = waitStages, .signalSemaphoreCount = 1, - .pSignalSemaphores = &drawFinishedSemaphore, + .pSignalSemaphores = &drawFinishedSemaphores[swapChainImageIdx], }; vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence); @@ -276,10 +295,10 @@ int main(void) VkPresentInfoKHR presentInfo = { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .waitSemaphoreCount = 1, - .pWaitSemaphores = &drawFinishedSemaphore, + .pWaitSemaphores = &drawFinishedSemaphores[swapChainImageIdx], .swapchainCount = 1, .pSwapchains = &swapChain.vk, - .pImageIndices = &imageIdx, + .pImageIndices = &swapChainImageIdx, }; vkQueuePresentKHR(graphicsQueue, &presentInfo); @@ -292,8 +311,13 @@ int main(void) vkQueueWaitIdle(graphicsQueue); vkDestroyFence(device.vk, drawFence, NULL); - vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL); - vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL); + for(u32 i = 0; i < imageCount; i++) + { + vkDestroySemaphore(device.vk, imageAcquiredSemaphores[i], NULL); + vkDestroySemaphore(device.vk, drawFinishedSemaphores[i], NULL); + } + // vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL); + // vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL); evkDestroyPipeline(graphicsPipeline);