Initial changes to get a triangle on linux

Signed-off-by: Robear Selwans <robear.selwans@outlook.com>
This commit is contained in:
2025-07-07 10:54:09 +03:00
parent f4d111c7e9
commit 7ae6de6e45
8 changed files with 155 additions and 31 deletions

View File

@@ -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'

View File

@@ -3,30 +3,34 @@
#include <stdio.h> #include <stdio.h>
#include <malloc.h> #include <malloc.h>
// TODO Get this working on linux
// PFN_vkAllocationFunction // PFN_vkAllocationFunction
void* evkAllocationFunctionCallback(void* pUserData, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope) void* evkAllocationFunctionCallback(void* pUserData, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope)
{ {
/* puts("evkAllocationFunctionCallback"); */ /* puts("evkAllocationFunctionCallback"); */
void* alloc = _aligned_malloc(allocationSize, allocationAlignment); // void* alloc = _aligned_malloc(allocationSize, allocationAlignment);
if(alloc == NULL) // if(alloc == NULL)
{ {
puts("Allocation Failed"); puts("Allocation Failed");
} }
return alloc; // return alloc;
return NULL;
} }
// PFN_vkReallocationFunction // PFN_vkReallocationFunction
void* evkReallocationFunctionCallback(void* pUserData, void* pOriginal, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope) void* evkReallocationFunctionCallback(void* pUserData, void* pOriginal, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope)
{ {
/* puts("evkReallocationFunctionCallback"); */ /* puts("evkReallocationFunctionCallback"); */
return _aligned_realloc(pOriginal, allocationSize, allocationAlignment); // return _aligned_realloc(pOriginal, allocationSize, allocationAlignment);
return NULL;
} }
// PFN_vkFreeFucntion // PFN_vkFreeFucntion
void evkFreeFunctionCallback(void* pUserData, void* pMemory) void evkFreeFunctionCallback(void* pUserData, void* pMemory)
{ {
/* puts("evkFreeFunctionCallback"); */ /* puts("evkFreeFunctionCallback"); */
_aligned_free(pMemory); // _aligned_free(pMemory);
} }
// PFN_vkInternalAllocaitonNotification // PFN_vkInternalAllocaitonNotification

View File

@@ -12,3 +12,83 @@
#include "evkConstants.h" #include "evkConstants.h"
#include "evkTypes.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)

View File

@@ -11,20 +11,20 @@
#define EVK_ENABLE_EXTENSION_FEATURES(enabledExtensions,featuresStruct) \ #define EVK_ENABLE_EXTENSION_FEATURES(enabledExtensions,featuresStruct) \
EV_FOREACH_UDATA(EVK_ENABLE_EXTENSION_FEATURE, (enabledExtensions, featuresStruct), SUPPORTED_EXTENSION_FEATURE_PAIRS) EV_FOREACH_UDATA(EVK_ENABLE_EXTENSION_FEATURE, (enabledExtensions, featuresStruct), SUPPORTED_EXTENSION_FEATURE_PAIRS)
#define EVK_ENABLE_EXTENSION_FEATURE(ef_pair, name_flag_pair) \ #define EVK_ENABLE_EXTENSION_FEATURE(ef_pair, name_flag_pair) \
{ \ { \
evstring name = evstr(EV_HEAD name_flag_pair); \ evstring name = evstr(EV_HEAD name_flag_pair); \
if(ev_vec_find(&EV_HEAD ef_pair, &name) != -1) \ if(ev_vec_find(&EV_HEAD ef_pair, &name) != -1) \
EV_TAIL ef_pair.EV_TAIL name_flag_pair = true; \ EV_TAIL ef_pair.EV_TAIL name_flag_pair = true; \
} }
VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufFeature = { VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufFeature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
.descriptorBuffer = VK_TRUE, .descriptorBuffer = VK_TRUE,
EV_DEBUG( // EV_DEBUG(
.descriptorBufferCaptureReplay = VK_TRUE, // .descriptorBufferCaptureReplay = VK_TRUE,
) // )
}; };
typedef struct { typedef struct {
@@ -67,7 +67,7 @@ VkPhysicalDevice evkDetectPhysicalDevice(evkInstance instance, VkPhysicalDeviceT
evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo) evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo)
{ {
evkDevice device; evkDevice device = {0};
device._physicalDevice = evkDetectPhysicalDevice(createInfo.instance, createInfo.physicalDeviceType); device._physicalDevice = evkDetectPhysicalDevice(createInfo.instance, createInfo.physicalDeviceType);
device._instance = createInfo.instance; 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(&queueCreateInfoList);
vec_fini(&priorities); vec_fini(&priorities);

View File

@@ -9,6 +9,9 @@ evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo)
VkSurfaceCapabilitiesKHR surfaceCaps; VkSurfaceCapabilitiesKHR surfaceCaps;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceCaps); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceCaps);
if(surfaceCaps.maxImageCount == 0)
surfaceCaps.maxImageCount = UInt32.MAX;
VkCompositeAlphaFlagBitsKHR compositeAlpha = VkCompositeAlphaFlagBitsKHR compositeAlpha =
(surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
? VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ? VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
@@ -53,8 +56,9 @@ evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo)
.oldSwapchain = VK_NULL_HANDLE, .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]; VkImage swapChainVkImages[buffering];
vkGetSwapchainImagesKHR(createInfo.device.vk, swapChain.vk, &buffering, swapChainVkImages); vkGetSwapchainImagesKHR(createInfo.device.vk, swapChain.vk, &buffering, swapChainVkImages);

View File

@@ -14,6 +14,7 @@ TYPEDATA_GEN(VkCommandBuffer);
TYPEDATA_GEN(VkDynamicState); TYPEDATA_GEN(VkDynamicState);
TYPEDATA_GEN(VkSurfaceFormatKHR); TYPEDATA_GEN(VkSurfaceFormatKHR);
TYPEDATA_GEN(VkFormat); TYPEDATA_GEN(VkFormat);
TYPEDATA_GEN(VkSemaphore);
TYPEDATA_GEN(VkClearValue, DEFAULT({{0.f,0.f,0.f,1.f}})); TYPEDATA_GEN(VkClearValue, DEFAULT({{0.f,0.f,0.f,1.f}}));
TYPEDATA_GEN(VkRenderingAttachmentInfoKHR, TYPEDATA_GEN(VkRenderingAttachmentInfoKHR,
DEFAULT( DEFAULT(

54
main.c
View File

@@ -19,7 +19,12 @@ int main(void)
}), }),
.extensions = svec_init(evstring, { .extensions = svec_init(evstring, {
evstr("VK_KHR_surface"), evstr("VK_KHR_surface"),
// TODO Get these from GLFW
#if EV_OS_WINDOWS
evstr("VK_KHR_win32_surface"), 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) { evkDevice device = evkCreateDevice((evkDeviceCreateInfo) {
.instance = instance, .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, { .queueRequirements = svec_init(evkDeviceQueueRequirement, {
{ VK_QUEUE_GRAPHICS_BIT, 1 }, { VK_QUEUE_GRAPHICS_BIT, 1 },
{ VK_QUEUE_COMPUTE_BIT , 1 }, { VK_QUEUE_COMPUTE_BIT , 1 },
@@ -54,6 +61,7 @@ int main(void)
puts("Couldn't create a VkDevice"); puts("Couldn't create a VkDevice");
goto DeviceCreationFailed; goto DeviceCreationFailed;
} }
puts("Logical Device created successfully."); puts("Logical Device created successfully.");
VkQueue graphicsQueue; VkQueue graphicsQueue;
vkGetDeviceQueue(device.vk, device.queueFamilies[VK_QUEUE_GRAPHICS_BIT].familyIndex, 0, &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); evkPipeline graphicsPipeline = evkCreatePipeline(device, pipelineCreateInfo);
VkFence drawFence = evkCreateFence(device, false); u32 imageCount = vec_len(&swapChain.images);
VkSemaphore imageAcquiredSemaphore = evkCreateSemaphore(device);
VkSemaphore drawFinishedSemaphore = evkCreateSemaphore(device);
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)) while(!glfwWindowShouldClose(window))
{ {
u32 imageIdx; imageIdx = (imageIdx + 1) % imageCount;
vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, &imageIdx); u32 swapChainImageIdx;
EVK_ASSERT(vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphores[imageIdx], VK_NULL_HANDLE, &swapChainImageIdx));
evkCommandBuffer cmdbuf = commandBuffers[imageIdx]; evkCommandBuffer cmdbuf = commandBuffers[imageIdx];
VkRenderingAttachmentInfoKHR colorAttachment = EV_DEFAULT(VkRenderingAttachmentInfoKHR, VkRenderingAttachmentInfoKHR colorAttachment = EV_DEFAULT(VkRenderingAttachmentInfoKHR,
imageView = swapChain.imageViews[imageIdx].vk, imageView = swapChain.imageViews[swapChainImageIdx].vk,
loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp= VK_ATTACHMENT_STORE_OP_STORE, storeOp= VK_ATTACHMENT_STORE_OP_STORE,
); );
@@ -243,7 +262,7 @@ int main(void)
VkImageMemoryBarrier imageMemoryBarrier = { VkImageMemoryBarrier imageMemoryBarrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = swapChain.images[imageIdx].vk, .image = swapChain.images[swapChainImageIdx].vk,
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.subresourceRange = { .subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
@@ -260,13 +279,13 @@ int main(void)
VkSubmitInfo submitInfo = { VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .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, .commandBufferCount = 1,
.waitSemaphoreCount = 1, .waitSemaphoreCount = 1,
.pWaitSemaphores = &imageAcquiredSemaphore, .pWaitSemaphores = &imageAcquiredSemaphores[imageIdx],
.pWaitDstStageMask = waitStages, .pWaitDstStageMask = waitStages,
.signalSemaphoreCount = 1, .signalSemaphoreCount = 1,
.pSignalSemaphores = &drawFinishedSemaphore, .pSignalSemaphores = &drawFinishedSemaphores[swapChainImageIdx],
}; };
vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence); vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence);
@@ -276,10 +295,10 @@ int main(void)
VkPresentInfoKHR presentInfo = { VkPresentInfoKHR presentInfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1, .waitSemaphoreCount = 1,
.pWaitSemaphores = &drawFinishedSemaphore, .pWaitSemaphores = &drawFinishedSemaphores[swapChainImageIdx],
.swapchainCount = 1, .swapchainCount = 1,
.pSwapchains = &swapChain.vk, .pSwapchains = &swapChain.vk,
.pImageIndices = &imageIdx, .pImageIndices = &swapChainImageIdx,
}; };
vkQueuePresentKHR(graphicsQueue, &presentInfo); vkQueuePresentKHR(graphicsQueue, &presentInfo);
@@ -292,8 +311,13 @@ int main(void)
vkQueueWaitIdle(graphicsQueue); vkQueueWaitIdle(graphicsQueue);
vkDestroyFence(device.vk, drawFence, NULL); vkDestroyFence(device.vk, drawFence, NULL);
vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL); for(u32 i = 0; i < imageCount; i++)
vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL); {
vkDestroySemaphore(device.vk, imageAcquiredSemaphores[i], NULL);
vkDestroySemaphore(device.vk, drawFinishedSemaphores[i], NULL);
}
// vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL);
// vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL);
evkDestroyPipeline(graphicsPipeline); evkDestroyPipeline(graphicsPipeline);