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 <malloc.h>
// 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

View File

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

View File

@@ -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);

View File

@@ -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);

View File

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

54
main.c
View File

@@ -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);