Starting Out

Signed-off-by: Robear Selwans <robear.selwans@outlook.com>
This commit is contained in:
2024-12-09 12:51:29 +02:00
parent 7e6be94c65
commit 4ec57bbd79
47 changed files with 2069 additions and 0 deletions

3
.gitignore vendored
View File

@@ -50,3 +50,6 @@ modules.order
Module.symvers Module.symvers
Mkfile.old Mkfile.old
dkms.conf dkms.conf
**/build
**/.cache

16
evk/evk.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
#include <volk.h>
#include "evkTypes.h"
#include "evkAllocator.h"
#include "evkInstance.h"
#include "evkDevice.h"
#include "evkSync.h"
#include "evkShader.h"
#include "evkSwapChain.h"
#include "evkCommand.h"
#include "evkPipeline.h"
#include "evkImage.h"

70
evk/evkAllocator.c Normal file
View File

@@ -0,0 +1,70 @@
#include "evkAllocator.h"
#include <stdio.h>
#include <malloc.h>
// 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)
{
puts("Allocation Failed");
}
return alloc;
}
// PFN_vkReallocationFunction
void* evkReallocationFunctionCallback(void* pUserData, void* pOriginal, size_t allocationSize, size_t allocationAlignment, VkSystemAllocationScope allocationScope)
{
/* puts("evkReallocationFunctionCallback"); */
return _aligned_realloc(pOriginal, allocationSize, allocationAlignment);
}
// PFN_vkFreeFucntion
void evkFreeFunctionCallback(void* pUserData, void* pMemory)
{
/* puts("evkFreeFunctionCallback"); */
_aligned_free(pMemory);
}
// PFN_vkInternalAllocaitonNotification
void evkInternalAllocationCallback(void* pUserData, size_t allocationSize, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
{
puts("evkInternalAllocationCallback");
}
// PFN_vkInternalFreeNotification
void evkInternalFreeCallback(void* pUserData, size_t allocationSize, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope)
{
puts("evkInternalFreeCallback");
}
TYPEDATA_GEN(
VkAllocationCallbacks,
DEFAULT(
.pUserData = &(evkAllocationUserData){ 0 }, // EV_INVALID(evkAllocationUserData)
.pfnAllocation = evkAllocationFunctionCallback,
.pfnReallocation = evkReallocationFunctionCallback,
.pfnFree = evkFreeFunctionCallback,
.pfnInternalAllocation = evkInternalAllocationCallback,
.pfnInternalFree = evkInternalFreeCallback
)
);
VkAllocationCallbacks def = {
.pUserData = NULL, // EV_INVALID(evkAllocationUserData)
.pfnAllocation = evkAllocationFunctionCallback,
.pfnReallocation = evkReallocationFunctionCallback,
.pfnFree = evkFreeFunctionCallback,
.pfnInternalAllocation = evkInternalAllocationCallback,
.pfnInternalFree = evkInternalFreeCallback
};
VkAllocationCallbacks* evkGetAllocationCallbacks()
{
/* return &EV_DEFAULT(VkAllocationCallbacks); */
/* return &def; */
return NULL;
}

6
evk/evkAllocator.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "evkCommon.h"
VkAllocationCallbacks* evkGetAllocationCallbacks();

29
evk/evkBuffer.c Normal file
View File

@@ -0,0 +1,29 @@
#include "evkImage.h"
#include "evk/evkMemory.h"
evkBuffer evkCreateBuffer(evkBufferCreateInfo createInfo)
{
VkBufferCreateInfo bufferCreateInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = NULL,
.flags = createInfo.flags,
.usage = createInfo.usage,
.sharingMode = createInfo.exclusive?VK_SHARING_MODE_EXCLUSIVE:VK_SHARING_MODE_CONCURRENT,
.queueFamilyIndexCount = vec_len(&createInfo.queueFamilyIndices),
.pQueueFamilyIndices = createInfo.queueFamilyIndices,
};
evkBuffer buffer = evkGPUCreateBuffer(createInfo.allocationCreateInfo, &bufferCreateInfo);
if(buffer.vk != VK_NULL_HANDLE)
{
buffer.sizeInBytes = createInfo.sizeInBytes;
}
return buffer;
}
void evkDestroyBuffer(evkBuffer buf)
{
evkGPUDestroyBuffer(buf);
}

6
evk/evkBuffer.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "evkCommon.h"
evkBuffer evkCreateBuffer(evkBufferCreateInfo createInfo);
void evkDestroyBuffer(evkBuffer buf);

51
evk/evkCommand.c Normal file
View File

@@ -0,0 +1,51 @@
#include "evkCommand.h"
evkCommandPool evkCreateCommandPool(evkCommandPoolCreateInfo createInfo)
{
evkCommandPool commandPool;
commandPool.queueFamily = createInfo.device.queueFamilies[createInfo.queueFlags];
VkCommandPoolCreateInfo vkCreateInfo = (VkCommandPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = createInfo.poolFlags,
.queueFamilyIndex = commandPool.queueFamily.familyIndex,
};
vkCreateCommandPool(createInfo.device.vk, &vkCreateInfo, NULL, &commandPool.vk);
return commandPool;
}
void evkDestroyCommandPool(evkDevice device, evkCommandPool commandPool)
{
vkDestroyCommandPool(device.vk, commandPool.vk, NULL);
}
vec(VkCommandBuffer) evkAllocateCommandBuffers(evkDevice device, evkCommandPool commandPool, u32 count, bool primary)
{
vec(VkCommandBuffer) buffers = vec_init(VkCommandBuffer);
vec_setlen(&buffers, count);
VkCommandBufferAllocateInfo allocateInfo = (VkCommandBufferAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = commandPool.vk,
.commandBufferCount = count,
.level = primary?VK_COMMAND_BUFFER_LEVEL_PRIMARY:VK_COMMAND_BUFFER_LEVEL_SECONDARY,
};
vkAllocateCommandBuffers(device.vk, &allocateInfo, buffers);
return buffers;
}
void evkBeginPrimaryCommandBuffer(VkCommandBuffer cmdBuf)
{
VkCommandBufferBeginInfo beginInfo = (VkCommandBufferBeginInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
};
vkBeginCommandBuffer(cmdBuf, &beginInfo);
}
void evkEndCommandBuffer(VkCommandBuffer cmdBuf)
{
vkEndCommandBuffer(cmdBuf);
}

15
evk/evkCommand.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include "evk.h"
#include "evkDevice.h"
[[nodiscard("Leaking VkCommandPool")]]
evkCommandPool evkCreateCommandPool(evkCommandPoolCreateInfo createInfo);
void evkDestroyCommandPool(evkDevice device, evkCommandPool commandPool);
[[nodiscard("Leaking allocated CommandBuffers")]]
vec(VkCommandBuffer) evkAllocateCommandBuffers(evkDevice device, evkCommandPool commandPool, u32 count, bool primary);
void evkBeginPrimaryCommandBuffer(VkCommandBuffer cmdBuf);
void evkEndCommandBuffer(VkCommandBuffer cmdBuf);

13
evk/evkCommon.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include "evk_buildconfig.h"
#include <volk.h>
#include "vk_mem_alloc.h"
#include <ev_numeric.h>
#include <ev_str.h>
#define EV_VEC_SHORTNAMES
#include <ev_vec.h>
#include "evkTypes.h"

43
evk/evkDescriptor.c Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include "evkDescriptor.h"
typedef struct {
VkDescriptorSetLayout descriptorSetLayouts[4];
} evkSetLayout;
evkSetLayout evkCreateDescriptorSetLayouts(vec(evkShader) shaders)
{
VkDescriptorSetLayoutCreateInfo createInfos[4];
for(int i = 0; i < 4; i++)
{
createInfos[i] = EV_DEFAULT(
VkDescriptorSetLayoutCreateInfo,
pBindings = vec_init(VkDescriptorSetLayoutBinding)
);
}
for(int i = 0; i < vec_len(&shaders); i++)
{
vec(evkDescriptorBinding) bindings = shaders[i].reflect.bindings;
for(int bi = 0; bi < vec_len(&bindings); bi++)
{
evkDescriptorBinding b = bindings[bi];
if(b.binding >= vec_len(&createInfos[b.set].pBindings))
{
u32 old_len = vec_len(&createInfos[b.set].pBindings);
vec_setlen(&createInfos[b.set].pBindings, b.binding+1);
for(int cs = old_len; cs < b.binding+1; cs++)
{
/* createInfos[b.set].pBindings[cs].binding */
}
}
}
}
for(int i = 0; i < 4; i++)
{
createInfos[i].bindingCount = vec_len(&createInfos[i].pBindings);
}
}

5
evk/evkDescriptor.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include "evkCommon.h"
// void evkFillSetLayoutCreateInfos(vec(evkShader) shaders, VkDescriptorSetLayoutCreateInfo layoutCreateInfos[4]);

176
evk/evkDevice.c Normal file
View File

@@ -0,0 +1,176 @@
#include "evkDevice.h"
#include "evkTypes.h"
#include "evkAllocator.h"
evstring VkDynamicRenderingExtName = evstr("VK_KHR_dynamic_rendering");
evstring VkSync2ExtName = evstr("VK_KHR_synchronization2");
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature = (VkPhysicalDeviceDynamicRenderingFeaturesKHR) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR,
.dynamicRendering = VK_TRUE,
};
VkPhysicalDeviceSynchronization2Features sync2Features = (VkPhysicalDeviceSynchronization2Features) {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
.synchronization2 = VK_TRUE,
};
VkPhysicalDevice evkDetectPhysicalDevice(evkInstance instance, VkPhysicalDeviceType deviceType)
{
VkPhysicalDevice chosenDevice = EV_INVALID(VkPhysicalDevice);
u32 deviceCount = 0;
vec(VkPhysicalDevice) physicalDevices = vec_init(VkPhysicalDevice);
vkEnumeratePhysicalDevices(instance.vk, &deviceCount, NULL);
vec_setlen(&physicalDevices, deviceCount);
vkEnumeratePhysicalDevices(instance.vk, &deviceCount, physicalDevices);
// TODO Add a more robust/flexible way to pick a GPU
for(u32 i = 0; i < deviceCount; i++)
{
VkPhysicalDeviceProperties deviceProperties;
vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties);
if(deviceProperties.deviceType == deviceType)
{
chosenDevice = physicalDevices[i];
break;
}
}
vec_fini(&physicalDevices);
return chosenDevice;
}
evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo)
{
evkDevice device;
device._physicalDevice = evkDetectPhysicalDevice(createInfo.instance, createInfo.physicalDeviceType);
device._instance = createInfo.instance;
VkPhysicalDeviceProperties physicalDeviceProperties;
vkGetPhysicalDeviceProperties(device._physicalDevice, &physicalDeviceProperties);
device.limits = physicalDeviceProperties.limits;
for (u32 i = 0; i < MAX_QUEUE_FAMILIES; i++) {
device.queueFamilies[i] = (evkDeviceQueueFamily){
.familyIndex = -1,
.allocatedQueueCount = 0
};
}
VkDeviceCreateInfo vkDeviceCreateInfo = __EV_VEC_EMPTY_ARRAY;
vkDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
void** pNext = &vkDeviceCreateInfo.pNext;
if(ev_vec_find(&createInfo.deviceExtensions, &VkDynamicRenderingExtName) != -1)
{
*pNext = &dynamicRenderingFeature;
pNext = &dynamicRenderingFeature.pNext;
}
if(ev_vec_find(&createInfo.deviceExtensions, &VkSync2ExtName) != -1)
{
*pNext = &sync2Features;
pNext = &sync2Features.pNext;
}
vkDeviceCreateInfo.enabledExtensionCount = vec_len(&createInfo.deviceExtensions);
vkDeviceCreateInfo.ppEnabledExtensionNames = createInfo.deviceExtensions;
// Getting the total number of queues requested from the device
u32 totalQueueCount = 0;
for (u32 i = 0; i < vec_len(&createInfo.queueRequirements); i++) {
totalQueueCount += createInfo.queueRequirements[i].count;
}
const f32 DEFAULT_PRIORITY = 1.0f;
// A priorities list that can be passed with any VkQueueCreteInfo (doable since we have no custom priorities)
vec(f32) priorities = vec_init(f32);
vec_setlen(&priorities, totalQueueCount);
for (u32 i = 0; i < totalQueueCount; i++) {
priorities[i] = DEFAULT_PRIORITY;
}
vec(VkDeviceQueueCreateInfo) queueCreateInfoList = vec_init(VkDeviceQueueCreateInfo);
if (createInfo.queueRequirements) {
// Retrieving the queue family properties into a vector
u32 queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device._physicalDevice, &queueFamilyCount, NULL);
vec(VkQueueFamilyProperties) queueFamilyProperties = vec_init(VkQueueFamilyProperties);
vec_setlen(&queueFamilyProperties, queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device._physicalDevice, &queueFamilyCount, queueFamilyProperties);
// Creating VkDeviceQueueCreateInfos from requirements and family properties
// NOTICE: Currently, there can be no queues of a specific type in 2 different
// families. While that can be considered a limitation, the application targeted
// by this abstraction aren't expected to be complex enough to need it.
for (u32 familyIndex = 0; familyIndex < queueFamilyCount; familyIndex++) {
VkQueueFamilyProperties currentFamilyProperties = queueFamilyProperties[familyIndex];
u32 availableQueuesInFamily = currentFamilyProperties.queueCount;
for (u32 reqIndex = 0; reqIndex < vec_len(&createInfo.queueRequirements); reqIndex++) {
evkDeviceQueueRequirement currentRequirement = createInfo.queueRequirements[reqIndex];
// Testing compatibility of queue family and requirement
if (currentRequirement.flags & currentFamilyProperties.queueFlags) {
u32 requiredCount = currentRequirement.count;
while (availableQueuesInFamily > 0 && requiredCount > 0) {
// If the queue family is not already in the vector, push it.
if (vec_len(&queueCreateInfoList) <= familyIndex) {
VkDeviceQueueCreateInfo newQueueCreateInfo = { 0 };
newQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
newQueueCreateInfo.queueFamilyIndex = familyIndex;
newQueueCreateInfo.pQueuePriorities = priorities;
vec_push(&queueCreateInfoList, &newQueueCreateInfo);
}
u32 allocationCount = (availableQueuesInFamily>requiredCount)?requiredCount:availableQueuesInFamily;
queueCreateInfoList[familyIndex].queueCount += allocationCount;
device.queueFamilies[currentRequirement.flags].familyIndex = familyIndex;
device.queueFamilies[currentRequirement.flags].allocatedQueueCount += allocationCount;
// Allowing retrieval of families according to their actual flags
device.queueFamilies[currentFamilyProperties.queueFlags].familyIndex = familyIndex;
device.queueFamilies[currentFamilyProperties.queueFlags].allocatedQueueCount += allocationCount;
// Updating the loop condition variables
availableQueuesInFamily -= allocationCount;
requiredCount -= allocationCount;
}
// Updating the requirement's count after allocation
createInfo.queueRequirements[reqIndex].count = requiredCount;
}
}
}
vkDeviceCreateInfo.pQueueCreateInfos = queueCreateInfoList;
vkDeviceCreateInfo.queueCreateInfoCount = (u32)vec_len(&queueCreateInfoList);
vec_fini(&queueFamilyProperties);
}
// Allowing the retrieval of non-requested, but allocated, queues is possible.
// Example: Allocating COMPUTE | GRAPHICS then requesting GRAPHICS should
// return the already allocated queue
for (i32 i = MAX_QUEUE_FAMILIES - 1; i >= 0; i--) {
for (i32 j = i - 1; j >= 0; j--) {
if (device.queueFamilies[j].familyIndex == -1 && (i & j) == j) {
device.queueFamilies[j] = device.queueFamilies[i];
}
}
}
vkCreateDevice(device._physicalDevice, &vkDeviceCreateInfo, evkGetAllocationCallbacks(), &device.vk);
vec_fini(&queueCreateInfoList);
vec_fini(&priorities);
return device;
}
void evkDestroyDevice(evkDevice device)
{
vkDestroyDevice(device.vk, evkGetAllocationCallbacks());
}

9
evk/evkDevice.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include "evkCommon.h"
VkPhysicalDevice evkDetectPhysicalDevice(evkInstance instance, VkPhysicalDeviceType deviceType);
[[nodiscard("Leaking VkDevice")]]
evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo);
void evkDestroyDevice(evkDevice device);

67
evk/evkImage.c Normal file
View File

@@ -0,0 +1,67 @@
#include "evkImage.h"
#include "evk/evkMemory.h"
void evkDestroyImage(evkDevice device, evkImage img)
{
evkGPUDestroyImage(img);
}
evkImageView evkCreateImageView(evkDevice device, evkImage img, evkImageViewCreateInfo createInfo)
{
evkImageView imgView;
VkImageViewCreateInfo imageViewCreateInfo = (VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = img.vk,
.viewType = VK_IMAGE_VIEW_TYPE_2D, // TODO Get from evkImage or allow overriding?
.format = img.format,
.components = {0,0,0,0}, // No swizzling use cases yet.
.subresourceRange = {
.aspectMask = createInfo.viewAspect,
.baseMipLevel = createInfo.mipBase,
.levelCount = createInfo.mipCount,
.baseArrayLayer = createInfo.baseLayer,
.layerCount = createInfo.layerCount,
}
};
vkCreateImageView(device.vk, &imageViewCreateInfo, NULL, &imgView.vk);
return imgView;
}
void evkDestroyImageView(evkDevice device, evkImageView imgv)
{
vkDestroyImageView(device.vk, imgv.vk, NULL);
}
evkImage evkCreateImage(evkImageCreateInfo createInfo)
{
VkImageCreateInfo vkImageCreateInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = createInfo.flags,
.imageType = createInfo.type,
.format = createInfo.format,
.extent = createInfo.extent,
.mipLevels = createInfo.mipCount,
.arrayLayers = createInfo.layerCount,
.samples = createInfo.sampleCount,
.tiling = createInfo.tiling,
.usage = createInfo.usage,
.sharingMode = createInfo.exclusive?VK_SHARING_MODE_EXCLUSIVE:VK_SHARING_MODE_CONCURRENT,
.initialLayout = createInfo.layout,
};
if(!createInfo.exclusive)
{
vkImageCreateInfo.queueFamilyIndexCount = vec_len(&createInfo.queueFamilyIndices);
vkImageCreateInfo.pQueueFamilyIndices = createInfo.queueFamilyIndices;
}
evkImage img = evkGPUCreateImage(createInfo.allocationCreateInfo, &vkImageCreateInfo);
if(img.vk != VK_NULL_HANDLE)
{
img.format = createInfo.format;
img.width = createInfo.extent.width;
img.height = createInfo.extent.height;
}
return img;
}

8
evk/evkImage.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "evkCommon.h"
evkImageView evkCreateImageView(evkDevice device, evkImage img, evkImageViewCreateInfo createInfo);
void evkDestroyImageView(evkDevice device, evkImageView imgv);
void evkDestroyImage(evkDevice device, evkImage img);

43
evk/evkInstance.c Normal file
View File

@@ -0,0 +1,43 @@
#include "evkInstance.h"
evkInstance evkCreateInstance(evkInstanceCreateInfo instanceCreateInfo)
{
evkInstance res = EV_INVALID(evkInstance);
if(volkInitialize() != VK_SUCCESS)
return res;
VkApplicationInfo vkAppInfo = __EV_VEC_EMPTY_ARRAY;
vkAppInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
vkAppInfo.pNext = 0;
vkAppInfo.pEngineName = instanceCreateInfo.applicationInfo.engineName;
vkAppInfo.pApplicationName = instanceCreateInfo.applicationInfo.applicationName;
vkAppInfo.engineVersion = instanceCreateInfo.applicationInfo.engineVersion;
vkAppInfo.applicationVersion = instanceCreateInfo.applicationInfo.applicationVersion;
vkAppInfo.apiVersion = instanceCreateInfo.applicationInfo.apiVersion;
VkInstanceCreateInfo vkInstanceCreateInfo = __EV_VEC_EMPTY_ARRAY;
vkInstanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
vkInstanceCreateInfo.pApplicationInfo = &vkAppInfo;
vkInstanceCreateInfo.enabledLayerCount = (u32)vec_len(&instanceCreateInfo.layers);
vkInstanceCreateInfo.ppEnabledLayerNames = instanceCreateInfo.layers;
vkInstanceCreateInfo.enabledExtensionCount = (u32)vec_len(&instanceCreateInfo.extensions);
vkInstanceCreateInfo.ppEnabledExtensionNames = instanceCreateInfo.extensions;
VkResult instanceCreationResult = vkCreateInstance(&vkInstanceCreateInfo, NULL, &res.vk);
/* VkResult instanceCreationResult = vkCreateInstance(&vkInstanceCreateInfo, evkGetAllocationCallbacks(), &res); */
/* printf("InstanceCreationResult: %d\n", instanceCreationResult); */
if(instanceCreationResult == VK_SUCCESS)
{
volkLoadInstance(res.vk);
res.apiVersion = vkAppInfo.apiVersion;
}
return res;
}
void evkDestroyInstance(evkInstance instance)
{
vkDestroyInstance(instance.vk, NULL);
/* vkDestroyInstance(vkInstance, evkGetAllocationCallbacks()); */
}

7
evk/evkInstance.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "evk.h"
[[nodiscard("Leaking VkInstance")]]
evkInstance evkCreateInstance(evkInstanceCreateInfo);
void evkDestroyInstance(evkInstance);

84
evk/evkMemory.c Normal file
View File

@@ -0,0 +1,84 @@
#pragma once
#include "evkMemory.h"
evkGPUAllocator evkGPUCreateAllocator(evkDevice device)
{
VmaVulkanFunctions vmaFunctions = {
.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties,
.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties,
.vkAllocateMemory = vkAllocateMemory,
.vkFreeMemory = vkFreeMemory,
.vkMapMemory = vkMapMemory,
.vkUnmapMemory = vkUnmapMemory,
.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges,
.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges,
.vkBindBufferMemory = vkBindBufferMemory,
.vkBindImageMemory = vkBindImageMemory,
.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements,
.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements,
.vkCreateBuffer = vkCreateBuffer,
.vkDestroyBuffer = vkDestroyBuffer,
.vkCreateImage = vkCreateImage,
.vkDestroyImage = vkDestroyImage,
.vkCmdCopyBuffer = vkCmdCopyBuffer,
};
VmaAllocatorCreateInfo createInfo = {
.physicalDevice = device._physicalDevice,
.device = device.vk,
.instance = device._instance.vk,
.vulkanApiVersion = device._instance.apiVersion,
.pVulkanFunctions = &vmaFunctions,
};
evkGPUAllocator alloc;
vmaCreateAllocator(&createInfo, &alloc.vma);
return alloc;
}
void evkGPUDestroyAllocator(evkGPUAllocator alloc)
{
vmaDestroyAllocator(alloc.vma);
}
evkImage evkGPUCreateImage(evkGPUAllocationCreateInfo allocationCreateInfo, VkImageCreateInfo* imageCreateInfo)
{
evkImage img;
VmaAllocationCreateInfo vmaAllocCreateInfo = {
.usage = allocationCreateInfo.memoryUsage,
.flags = allocationCreateInfo.allocationFlags,
.pool = allocationCreateInfo.pool.vma,
};
vmaCreateImage(allocationCreateInfo.allocator.vma, imageCreateInfo, &vmaAllocCreateInfo, &img.vk, &img.allocData.allocation.vma, &img.allocData.allocationInfo.vma);
return img;
}
void evkGPUDestroyImage(evkImage img)
{
vmaDestroyImage(img.allocData.allocator.vma, img.vk, img.allocData.allocation.vma);
}
evkBuffer evkGPUCreateBuffer(evkGPUAllocationCreateInfo allocationCreateInfo, VkBufferCreateInfo* imageCreateInfo)
{
evkBuffer buf;
VmaAllocationCreateInfo vmaAllocCreateInfo = {
.usage = allocationCreateInfo.memoryUsage,
.flags = allocationCreateInfo.allocationFlags,
.pool = allocationCreateInfo.pool.vma,
};
vmaCreateBuffer(allocationCreateInfo.allocator.vma, imageCreateInfo, &vmaAllocCreateInfo, &buf.vk, &buf.allocData.allocation.vma, &buf.allocData.allocationInfo.vma);
return buf;
}
void evkGPUDestroyBuffer(evkBuffer buf)
{
vmaDestroyBuffer(buf.allocData.allocator.vma, buf.vk, buf.allocData.allocation.vma);
}

12
evk/evkMemory.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "evkCommon.h"
evkImage evkGPUCreateImage(evkGPUAllocationCreateInfo, VkImageCreateInfo*);
void evkGPUDestroyImage(evkImage);
evkBuffer evkGPUCreateBuffer(evkGPUAllocationCreateInfo, VkBufferCreateInfo*);
void evkGPUDestroyBuffer(evkBuffer);
evkGPUAllocator evkGPUCreateAllocator(evkDevice device);
void evkGPUDestroyAllocator(evkGPUAllocator alloc);

163
evk/evkPipeline.c Normal file
View File

@@ -0,0 +1,163 @@
#include "evkPipeline.h"
#include "evk/evkTypes.h"
#include "evkShader.h"
const u32 DESCRIPTOR_SET_LAYOUT_COUNT = 4;
evkPipelineLayout evkCreatePipelineLayout(evkDevice device, evkPipelineLayoutCreateInfo createInfo)
{
evkPipelineLayout layout;
VkPipelineLayoutCreateInfo vkCreateInfo = (VkPipelineLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
};
vkCreatePipelineLayout(device.vk, &vkCreateInfo, NULL, &layout.vk);
return layout;
}
void evkDestroyPipelineLayout(evkDevice device, evkPipelineLayout layout)
{
vkDestroyPipelineLayout(device.vk, layout.vk, NULL);
}
evkPipeline evkCreatePipeline(evkDevice device, evkPipelineCreateInfo createInfo)
{
u32 shaderStageCount = vec_len(&createInfo.shaderStages);
u32 colorAttachmentCount = vec_len(&createInfo.colorAttachments);
u32 dynamicStateCount = vec_len(&createInfo.dynamicStates);
evkPipeline res;
VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = dynamicStateCount,
.pDynamicStates = createInfo.dynamicStates,
};
VkFormat colorAttachmentFormats[colorAttachmentCount];
for(int i = 0; i < colorAttachmentCount; i++)
colorAttachmentFormats[i] = createInfo.colorAttachments[i].format;
VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
.colorAttachmentCount = colorAttachmentCount,
.pColorAttachmentFormats = colorAttachmentFormats,
.depthAttachmentFormat = createInfo.depthAttachmentFormat,
.stencilAttachmentFormat = createInfo.stencilAttachmentFormat,
.viewMask = createInfo.viewMask,
};
VkPipelineColorBlendAttachmentState colorAttachmentBlendStates[colorAttachmentCount];
for(int i = 0; i < colorAttachmentCount; i++)
colorAttachmentBlendStates[i] = createInfo.colorAttachments[i].blendState;
VkPipelineColorBlendStateCreateInfo colorBlending = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.pNext = NULL,
.flags = 0, // Update if VK_EXT_rasterization_order_attachment_access is supported
.logicOpEnable = createInfo.blendingOp != VK_LOGIC_OP_NO_OP,
.logicOp = createInfo.blendingOp,
.attachmentCount = colorAttachmentCount,
.pAttachments = colorAttachmentBlendStates,
};
memcpy(colorBlending.blendConstants, createInfo.blendConstants, sizeof(f32) * 4);
u32 viewportCount = createInfo.viewportCountOverride;
if(viewportCount == 0 && createInfo.viewports)
viewportCount = vec_len(&createInfo.viewports);
VkViewport viewports[viewportCount];
VkRect2D scissors[viewportCount];
if(createInfo.viewports)
{
for(int i = 0; i < viewportCount; i++)
{
viewports[i] = createInfo.viewports[i].vkViewport;
VkRect2D currScis = createInfo.viewports[i].vkScissor;
scissors[i].offset.x = max(currScis.offset.x, viewports[i].x);
scissors[i].offset.y = max(currScis.offset.y, viewports[i].y);
scissors[i].extent.width = currScis.extent.width == 0? viewports[i].width : currScis.extent.width;
scissors[i].extent.height = currScis.extent.height == 0? viewports[i].height : currScis.extent.height;
}
}
VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = viewportCount,
.scissorCount = viewportCount,
.pViewports = viewports,
.pScissors = scissors,
};
VkPipelineShaderStageCreateInfo shaderStageCreateInfos[shaderStageCount];
for(int i = 0; i < vec_len(&createInfo.shaderStages); i++)
shaderStageCreateInfos[i] = evkGetShaderStageCreateInfo(createInfo.shaderStages[i]);
VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 0,
.vertexAttributeDescriptionCount = 0,
};
/* VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfos[DESCRIPTOR_SET_LAYOUT_COUNT] = {}; */
/* for(u32 di = 0; di < DESCRIPTOR_SET_LAYOUT_COUNT; di++) */
/* { */
/* descriptorSetLayoutCreateInfos[di].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; */
/* for(u32 si = 0; si < vec_len(&createInfo.shaderStages); si++) */
/* { */
/**/
/* } */
/* } */
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfos[4];
svec(VkDescriptorSetLayout) descriptorSetLayouts = svec_init_w_len(VkDescriptorSetLayout, 4);
for(int i = 0; i < 4; i++)
{
VkDescriptorSetLayoutCreateInfo dsCreateInfo = {};
// Fill descriptorSetLayoutCreateInfos[i] from shader reflection data + Create descriptorSetLayouts[i]
}
res.layout = evkCreatePipelineLayout(device,
EV_DEFAULT(evkPipelineLayoutCreateInfo,
descriptorSetLayouts = descriptorSetLayouts
)
);
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &pipelineRenderingCreateInfo,
.stageCount = shaderStageCount,
.pStages = shaderStageCreateInfos,
.pVertexInputState = &vertexInputStateCreateInfo,
.pInputAssemblyState = &EV_DEFAULT(VkPipelineInputAssemblyStateCreateInfo),
.pViewportState = &viewportStateCreateInfo,
.pRasterizationState = &EV_DEFAULT(VkPipelineRasterizationStateCreateInfo),
.pMultisampleState = &EV_DEFAULT(VkPipelineMultisampleStateCreateInfo),
.pColorBlendState = &colorBlending,
.pDynamicState = &dynamicStateCreateInfo,
.layout = res.layout.vk,
};
vkCreateGraphicsPipelines(device.vk, VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, NULL, &res.vk);
res._device = device;
return res;
}
void evkDestroyPipeline(evkPipeline pipeline)
{
vkDestroyPipeline(pipeline._device.vk, pipeline.vk, NULL);
evkDestroyPipelineLayout(pipeline._device, pipeline.layout);
}

10
evk/evkPipeline.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "evkCommon.h"
[[nodiscard("Leaking VkPipelineLayout")]]
evkPipelineLayout evkCreatePipelineLayout(evkDevice device, evkPipelineLayoutCreateInfo createInfo);
void evkDestroyPipelineLayout(evkDevice device, evkPipelineLayout layout);
evkPipeline evkCreatePipeline(evkDevice device, evkPipelineCreateInfo createInfo);
void evkDestroyPipeline(evkPipeline pipeline);

1
evk/evkRender.c Normal file
View File

@@ -0,0 +1 @@
#include "evkRender.h"

3
evk/evkRender.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
#include "evkCommon.h"

138
evk/evkShader.c Normal file
View File

@@ -0,0 +1,138 @@
#include "evk/evkShader.h"
#include "shaderc/shaderc.h"
#include "ev_helpers.h"
evkShader evkInitShaderFromBytes(evkDevice device, const u8* shaderBytes, u32 shaderLen)
{
evkShader shader;
VkShaderModuleCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.pCode = (u32*)shaderBytes,
.codeSize = shaderLen,
};
vkCreateShaderModule(device.vk, &createInfo, NULL, &shader.vk);
shader.reflect = evkGenerateShaderReflectionData(shaderBytes, shaderLen);
return shader;
}
evkShaderReflectionData evkGenerateShaderReflectionData(const u8* shaderBytes, u32 shaderLen)
{
evkShaderReflectionData res;
SpvReflectShaderModule spvref;
SpvReflectResult result = spvReflectCreateShaderModule(shaderLen, shaderBytes, &spvref);
assert(result == SPV_REFLECT_RESULT_SUCCESS);
// Fill evkShaderReflectionData
res.stage = spvref.shader_stage;
res.bindings = vec_init(evkDescriptorBinding);
uint32_t descSetCount = 0;
SpvReflectResult descSetResult = spvReflectEnumerateDescriptorSets(&spvref, &descSetCount, NULL);
if(descSetResult == SPV_REFLECT_RESULT_SUCCESS)
{
SpvReflectDescriptorSet* refDescriptorSets[descSetCount] = {};
spvReflectEnumerateDescriptorSets(&spvref, &descSetCount, refDescriptorSets);
for(int setIdx = 0; setIdx < descSetCount; setIdx++)
{
SpvReflectDescriptorSet* currentSet = refDescriptorSets[setIdx];
for(int bindingIdx = 0; bindingIdx < currentSet->binding_count; bindingIdx++)
{
evkDescriptorBinding binding = {
.stageFlags = res.stage,
.binding = currentSet->bindings[bindingIdx]->binding,
.descriptorType = (VkDescriptorType) currentSet->bindings[bindingIdx]->descriptor_type,
.descriptorCount = currentSet->bindings[bindingIdx]->count,
.set = currentSet->set,
};
vec_push(&res.bindings, &binding);
}
}
}
spvReflectDestroyShaderModule(&spvref);
return res;
}
void evkDestroyShaderReflectionData(evkShaderReflectionData data)
{
vec_fini(&data.bindings);
}
void evkDestroyShader(evkDevice device, evkShader shader)
{
vkDestroyShaderModule(device.vk, shader.vk, NULL);
evkDestroyShaderReflectionData(shader.reflect);
}
shaderc_include_result* _shader_include_resolve(void* user_data, const char* requested_source, int type, const char* requesting_source, size_t include_depth)
{
shaderc_include_result* result = malloc(sizeof(shaderc_include_result));
result->source_name = evstring_new(requested_source);
result->source_name_length = evstring_getLength((evstring)result->source_name);
result->content = evstring_readFile((evstring)result->source_name);
result->content_length = evstring_getLength((evstring)result->content);
return result;
}
void _shader_include_release(void* user_data, shaderc_include_result* include_result)
{
evstring_free((evstring)include_result->content);
evstring_free((evstring)include_result->source_name);
free(include_result);
}
evkShaderCompiler evkCreateShaderCompiler()
{
evkShaderCompiler compiler;
compiler.sc = shaderc_compiler_initialize();
compiler.scopt = shaderc_compile_options_initialize();
shaderc_compile_options_set_include_callbacks(compiler.scopt, _shader_include_resolve, _shader_include_release, NULL);
return compiler;
}
void evkDestroyShaderCompiler(evkShaderCompiler compiler)
{
shaderc_compile_options_release(compiler.scopt);
shaderc_compiler_release(compiler.sc);
}
evkShader evkInitShaderFromFile(evkDevice device, evkShaderCompiler compiler, evstring shaderPath)
{
evstring shaderText = evstring_readFile(shaderPath);
shaderc_compilation_result_t compilation_result = shaderc_compile_into_spv(compiler.sc, shaderText, evstring_getLength(shaderText), shaderc_glsl_infer_from_source, shaderPath, "main", compiler.scopt);
shaderc_compilation_status status = shaderc_result_get_compilation_status(compilation_result);
u32 errorCount = shaderc_result_get_num_errors(compilation_result);
u32 warnCount = shaderc_result_get_num_warnings(compilation_result);
printf("[[evkShader]] %s Compilation Status: %d ( %d Errors, %d Warnings )\n", shaderPath, status, errorCount, warnCount);
if(errorCount + warnCount > 0)
{
printf("Errors:\n%s\n", shaderc_result_get_error_message(compilation_result));
}
evkShader shader = evkInitShaderFromBytes(device, (u8*)shaderc_result_get_bytes(compilation_result), shaderc_result_get_length(compilation_result));
evstring_free(shaderText);
return shader;
}
VkPipelineShaderStageCreateInfo evkGetShaderStageCreateInfo(evkShader shader)
{
return (VkPipelineShaderStageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = shader.reflect.stage,
.module = shader.vk,
.pName = "main",
};
}

18
evk/evkShader.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "evk/evkCommon.h"
[[nodiscard("Leaking VkShaderModule")]]
evkShader evkInitShaderFromBytes(evkDevice device, const u8* shaderBytes, u32 shaderLen);
evkShader evkInitShaderFromFile(evkDevice device, evkShaderCompiler compiler, evstring shaderPath);
void evkDestroyShader(evkDevice device, evkShader shader);
[[nodiscard("Leaking Shader Compiler")]]
evkShaderCompiler evkCreateShaderCompiler();
void evkDestroyShaderCompiler(evkShaderCompiler compiler);
VkPipelineShaderStageCreateInfo evkGetShaderStageCreateInfo(evkShader shader);
[[nodiscard("Leaking Shader Reflection Data")]]
evkShaderReflectionData evkGenerateShaderReflectionData(const u8* shaderBytes, u32 shaderLen);
void evkDestroyShaderReflectionData(evkShaderReflectionData data);

93
evk/evkSwapChain.c Normal file
View File

@@ -0,0 +1,93 @@
#include "evkSwapChain.h"
#include "evk.h"
evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo)
{
evkSwapChain swapChain;
swapChain.surface = createInfo.surface;
VkSurfaceCapabilitiesKHR surfaceCaps;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceCaps);
VkCompositeAlphaFlagBitsKHR compositeAlpha =
(surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
? VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
: (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR
: (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
? VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR
: VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
u32 surfaceFormatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceFormatCount, NULL);
VkSurfaceFormatKHR surfaceFormats[surfaceFormatCount];
vkGetPhysicalDeviceSurfaceFormatsKHR(createInfo.device._physicalDevice, createInfo.surface, &surfaceFormatCount, surfaceFormats);
// TODO Add format picking logic
swapChain.surfaceFormat = surfaceFormats[0];
u32 buffering = min(max(createInfo.imageCount, surfaceCaps.minImageCount), surfaceCaps.maxImageCount);
VkExtent2D imageExtent = surfaceCaps.currentExtent;
if(imageExtent.width == UInt32.MAX)
imageExtent.width = createInfo.width;
if(imageExtent.height == UInt32.MAX)
imageExtent.height = createInfo.width;
VkSwapchainCreateInfoKHR swapChainCreateInfo = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = swapChain.surface,
.minImageCount = buffering,
.imageFormat = swapChain.surfaceFormat.format,
.imageColorSpace = swapChain.surfaceFormat.colorSpace,
.imageExtent = imageExtent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.preTransform = surfaceCaps.currentTransform,
.compositeAlpha = compositeAlpha,
.presentMode = VK_PRESENT_MODE_MAILBOX_KHR,
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE,
};
vkCreateSwapchainKHR(createInfo.device.vk, &swapChainCreateInfo, NULL, &swapChain.vk);
VkImage swapChainVkImages[buffering];
vkGetSwapchainImagesKHR(createInfo.device.vk, swapChain.vk, &buffering, swapChainVkImages);
swapChain.images = vec_init(evkImage);
swapChain.imageViews = vec_init(evkImageView);
vec_setlen(&swapChain.images, buffering);
vec_setlen(&swapChain.imageViews, buffering);
for(u32 i = 0; i < buffering; i++)
{
swapChain.images[i] = (evkImage) {
.vk = swapChainVkImages[i],
.width = imageExtent.width,
.height = imageExtent.height,
.format = swapChain.surfaceFormat.format
};
swapChain.imageViews[i] = evkCreateImageView(createInfo.device, swapChain.images[i],
EV_DEFAULT(evkImageViewCreateInfo,
viewAspect = VK_IMAGE_ASPECT_COLOR_BIT
)
);
}
return swapChain;
}
void evkDestroySwapChain(evkDevice device, evkSwapChain swapChain)
{
for(i32 i = 0; i < vec_len(&swapChain.imageViews); i++)
{
vkDestroyImageView(device.vk, swapChain.imageViews[i].vk, NULL);
}
vec_fini(&swapChain.imageViews);
vec_fini(&swapChain.images);
vkDestroySwapchainKHR(device.vk, swapChain.vk, NULL);
}

8
evk/evkSwapChain.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "evkCommon.h"
[[nodiscard("Leaking VkSwapChain")]]
evkSwapChain evkCreateSwapChain(evkSwapChainCreateInfo createInfo);
void evkDestroySwapChain(evkDevice device, evkSwapChain swapChain);

20
evk/evkSync.c Normal file
View File

@@ -0,0 +1,20 @@
#include "evk/evkSync.h"
VkSemaphore evkCreateSemaphore(evkDevice device)
{
VkSemaphore semaphore;
VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
vkCreateSemaphore(device.vk, &semaphoreCreateInfo, NULL, &semaphore);
return semaphore;
}
VkFence evkCreateFence(evkDevice device, bool signaled)
{
VkFence fence;
VkFenceCreateInfo fenceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = signaled?VK_FENCE_CREATE_SIGNALED_BIT:0,
};
vkCreateFence(device.vk, &fenceCreateInfo, NULL, &fence);
return fence;
}

10
evk/evkSync.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "evk.h"
#include "evkDevice.h"
[[nodiscard("Leaking VkSemaphore")]]
VkSemaphore evkCreateSemaphore(evkDevice device);
[[nodiscard("Leaking VkFence")]]
VkFence evkCreateFence(evkDevice device, bool signaled);

448
evk/evkTypes.h Normal file
View File

@@ -0,0 +1,448 @@
#pragma once
#include "evkCommon.h"
#include "shaderc/shaderc.h"
#include "spirv_reflect.h"
TYPEDATA_GEN(VkInstance, INVALID(VK_NULL_HANDLE));
TYPEDATA_GEN(VkDevice, INVALID(VK_NULL_HANDLE));
TYPEDATA_GEN(VkPhysicalDevice);
TYPEDATA_GEN(VkDeviceQueueCreateInfo);
TYPEDATA_GEN(VkQueueFamilyProperties);
TYPEDATA_GEN(VkImage);
TYPEDATA_GEN(VkCommandBufferBeginInfo);
TYPEDATA_GEN(VkCommandBuffer);
TYPEDATA_GEN(VkDynamicState);
TYPEDATA_GEN(VkSurfaceFormatKHR);
TYPEDATA_GEN(VkFormat);
TYPEDATA_GEN(VkClearValue, DEFAULT(0.f,0.f,0.f,1.f));
TYPEDATA_GEN(VkRenderingAttachmentInfoKHR,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR,
.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, // Requires VK_KHR_synchronization2
.loadOp = VK_ATTACHMENT_LOAD_OP_NONE_KHR,
.storeOp = VK_ATTACHMENT_STORE_OP_NONE,
.clearValue = (VkClearValue){0.f, 0.f, 0.f, 1.f},
)
);
TYPEDATA_GEN(VkViewport,
DEFAULT(
.x = 0,
.y = 0,
.maxDepth = 1.0f,
.minDepth = 0.f,
.width = 0,
.height = 0
)
)
TYPEDATA_GEN(VkRect2D,
DEFAULT(0)
)
TYPEDATA_GEN(VkRenderingInfo,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.flags = 0,
.renderArea = {0, 0, 0, 0},
.layerCount = 1,
.viewMask = 0,
.colorAttachmentCount = 0,
.pColorAttachments = VK_NULL_HANDLE,
.pDepthAttachment = VK_NULL_HANDLE,
.pStencilAttachment = VK_NULL_HANDLE,
)
)
TYPEDATA_GEN(VkPipelineInputAssemblyStateCreateInfo,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_FALSE,
)
);
TYPEDATA_GEN(VkPipelineRasterizationStateCreateInfo,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = VK_FALSE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = VK_POLYGON_MODE_FILL,
.lineWidth = 1.0f,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_CLOCKWISE,
.depthBiasEnable = VK_FALSE,
)
);
TYPEDATA_GEN(VkPipelineColorBlendAttachmentState,
DEFAULT(
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
.blendEnable = VK_FALSE,
)
);
TYPEDATA_GEN(VkPipelineMultisampleStateCreateInfo,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.sampleShadingEnable = VK_FALSE,
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
)
);
TYPEDATA_GEN(VkPipelineShaderStageCreateInfo);
TYPEDATA_GEN(VkDescriptorSetLayout);
TYPEDATA_GEN(VkDescriptorSetLayoutBinding);
TYPEDATA_GEN(VkDescriptorSetLayoutCreateInfo,
DEFAULT(
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
)
);
// ========================================================================================================= //
// =================================evk Types=============================================================== //
// ========================================================================================================= //
typedef u32 evkApiVersion;
typedef struct {
VkInstance vk;
evkApiVersion apiVersion;
} evkInstance;
typedef struct {
VkQueueFlags flags;
u32 count;
} evkDeviceQueueRequirement;
typedef struct {
evkInstance instance;
VkPhysicalDeviceType physicalDeviceType;
ev_vec(evkDeviceQueueRequirement) queueRequirements;
ev_vec(evstring) deviceExtensions;
} evkDeviceCreateInfo;
typedef struct {
i32 familyIndex;
u32 allocatedQueueCount;
} evkDeviceQueueFamily;
typedef struct {
bool dynamicRendering;
bool multiViewport;
} evkPhysicalDeviceFeatures;
#define MAX_QUEUE_FAMILIES ((VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT) + 1)
typedef struct {
VkDevice vk;
VkPhysicalDevice _physicalDevice;
evkInstance _instance;
evkDeviceQueueFamily queueFamilies[MAX_QUEUE_FAMILIES];
VkPhysicalDeviceLimits limits;
evkPhysicalDeviceFeatures enabledFeatures;
} evkDevice;
typedef struct {
VkCommandPool vk;
evkDeviceQueueFamily queueFamily;
} evkCommandPool;
typedef struct {
evkDevice device;
VkCommandPoolCreateFlags poolFlags;
VkQueueFlags queueFlags;
} evkCommandPoolCreateInfo;
typedef u32 evkAPIVersion;
typedef struct {
evkAPIVersion apiVersion;
u32 applicationVersion;
u32 engineVersion;
evstring applicationName;
evstring engineName;
} evkApplicationInfo;
typedef struct {
evkApplicationInfo applicationInfo;
ev_vec(evstring) extensions;
ev_vec(evstring) layers;
} evkInstanceCreateInfo;
typedef struct {
VkPipelineLayout vk;
} evkPipelineLayout;
typedef struct {
vec(VkDescriptorSetLayout) descriptorSetLayouts;
vec(VkPushConstantRange) pushConstantRanges;
} evkPipelineLayoutCreateInfo;
typedef struct {
VkOffset2D renderOffset;
VkExtent2D renderExtents;
u32 layerCount;
u32 viewMask;
VkRenderingFlags renderingFlags;
vec(VkRenderingAttachmentInfoKHR) colorAttachments;
VkRenderingAttachmentInfoKHR depthAttachment;
VkRenderingAttachmentInfoKHR stencilAttachment;
} evkRenderingInfo;
typedef union {
struct {
VkViewport;
VkRect2D scissor;
};
struct {
VkViewport vkViewport;
VkRect2D vkScissor;
};
} evkViewport;
typedef union {
VkDescriptorSetLayoutBinding vk;
struct {
VkDescriptorSetLayoutBinding;
u32 set;
};
} evkDescriptorBinding;
typedef struct {
VkShaderStageFlags stage;
vec(evkDescriptorBinding) bindings;
} evkShaderReflectionData;
typedef struct {
VkShaderModule vk;
evkShaderReflectionData reflect;
} evkShader;
typedef struct {
shaderc_compiler_t sc;
shaderc_compile_options_t scopt;
} evkShaderCompiler;
typedef struct {
u32 dummy;
} evkAllocationUserData;
typedef struct {
VmaAllocator vma;
} evkGPUAllocator;
typedef struct {
VmaAllocation vma;
} evkGPUAllocation;
typedef struct {
VmaAllocationInfo vma;
} evkGPUAllocationInfo;
typedef struct {
evkGPUAllocator allocator;
evkGPUAllocation allocation;
evkGPUAllocationInfo allocationInfo;
} evkGPUAllocationData;
typedef enum {
EVK_GPU_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
EVK_GPU_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT,
EVK_GPU_ALLOCATION_CREATE_MAPPED_BIT = VMA_ALLOCATION_CREATE_MAPPED_BIT,
EVK_GPU_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT,
EVK_GPU_ALLOCATION_CREATE_DONT_BIND_BIT = VMA_ALLOCATION_CREATE_DONT_BIND_BIT,
EVK_GPU_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT,
EVK_GPU_ALLOCATION_CREATE_CAN_ALIAS_BIT = VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT,
EVK_GPU_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
EVK_GPU_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
EVK_GPU_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT,
EVK_GPU_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT,
} evkGPUAllocationFlags;
typedef enum evkGPUMemoryUsage
{
EVK_GPU_MEMORY_USAGE_UNKNOWN = VMA_MEMORY_USAGE_UNKNOWN,
EVK_GPU_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED,
EVK_GPU_MEMORY_USAGE_AUTO = VMA_MEMORY_USAGE_AUTO,
EVK_GPU_MEMORY_USAGE_AUTO_PREFER_DEVICE = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
EVK_GPU_MEMORY_USAGE_AUTO_PREFER_HOST = VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
EVK_GPU_MEMORY_USAGE_MAX_ENUM = VMA_MEMORY_USAGE_MAX_ENUM
} evkGPUMemoryUsage;
typedef struct {
VmaPool vma;
} evkGPUMemoryPool;
typedef struct {
evkGPUAllocationFlags allocationFlags;
evkGPUMemoryUsage memoryUsage;
evkGPUAllocator allocator;
evkGPUMemoryPool pool;
} evkGPUAllocationCreateInfo;
typedef struct {
VkImage vk;
u32 width;
u32 height;
VkFormat format;
evkGPUAllocationData allocData;
} evkImage;
typedef struct {
VkImageAspectFlags viewAspect;
u32 mipBase;
u32 mipCount;
u32 baseLayer;
u32 layerCount;
} evkImageViewCreateInfo;
typedef struct {
VkImageView vk;
} evkImageView;
typedef struct {
evkGPUAllocationCreateInfo allocationCreateInfo;
VkBufferCreateFlags flags;
VkDeviceSize sizeInBytes;
VkBufferUsageFlags usage;
bool exclusive;
vec(u32) queueFamilyIndices;
} evkBufferCreateInfo;
typedef struct {
VkBuffer vk;
evkGPUAllocationData allocData;
u32 sizeInBytes;
} evkBuffer;
typedef struct {
evkGPUAllocationCreateInfo allocationCreateInfo;
VkImageCreateFlags flags;
VkImageType type;
VkFormat format;
VkExtent3D extent;
u32 mipCount;
u32 layerCount;
u32 sampleCount;
VkImageTiling tiling;
VkImageUsageFlags usage;
bool exclusive;
vec(u32) queueFamilyIndices;
VkImageLayout layout;
} evkImageCreateInfo;
typedef struct {
VkSurfaceFormatKHR surfaceFormat;
VkSurfaceKHR surface;
VkSwapchainKHR vk;
vec(evkImage) images;
vec(evkImageView) imageViews;
} evkSwapChain;
typedef struct {
evkDevice device;
VkSurfaceKHR surface;
u32 width;
u32 height;
u32 imageCount;
// Add more stuff when needed
} evkSwapChainCreateInfo;
typedef struct {
VkFormat format;
VkPipelineColorBlendAttachmentState blendState;
} evkColorAttachment;
typedef struct {
vec(VkDynamicState) dynamicStates;
vec(evkShader) shaderStages;
vec(evkColorAttachment) colorAttachments;
VkFormat depthAttachmentFormat;
VkFormat stencilAttachmentFormat;
u32 viewMask;
VkLogicOp blendingOp;
f32 blendConstants[4];
u32 viewportCountOverride;
vec(evkViewport) viewports;
} evkPipelineCreateInfo;
typedef struct {
VkPipeline vk;
evkPipelineLayout layout;
evkDevice _device;
} evkPipeline;
TYPEDATA_GEN(evkInstance,
INVALID(
.vk = VK_NULL_HANDLE,
)
);
TYPEDATA_GEN(evkShader);
TYPEDATA_GEN(evkPipelineLayoutCreateInfo,
DEFAULT(
.descriptorSetLayouts = EV_VEC_EMPTY,
.pushConstantRanges = EV_VEC_EMPTY,
)
);
TYPEDATA_GEN(evkApplicationInfo,
DEFAULT(
.apiVersion = VK_API_VERSION_1_1,
.applicationVersion = 0,
.engineVersion = 0,
.applicationName = evstr("Test Application"),
.engineName = evstr("evk")
)
);
TYPEDATA_GEN(evkImage);
TYPEDATA_GEN(evkImageView);
TYPEDATA_GEN(evkImageViewCreateInfo,
DEFAULT(
.layerCount = 1,
.baseLayer = 0,
.mipCount = 1,
.mipBase = 0,
.viewAspect = VK_IMAGE_ASPECT_NONE,
)
);
TYPEDATA_GEN(evkAllocationUserData, INVALID(__EV_VEC_EMPTY_ARRAY));
TYPEDATA_GEN(evkDeviceQueueRequirement);
TYPEDATA_GEN(evkViewport,
DEFAULT(
.x = 0,
.y = 0,
.maxDepth = 1.0f,
.minDepth = 0.f,
.width = 0,
.height = 0,
.scissor.offset.x = 0,
.scissor.offset.y = 0,
.scissor.extent.width = 0,
.scissor.extent.height = 0,
)
);
TYPEDATA_GEN(evkColorAttachment);
TYPEDATA_GEN(evkPipelineCreateInfo,
DEFAULT(
.dynamicStates = EV_VEC_EMPTY,
.shaderStages = EV_VEC_EMPTY,
.colorAttachments = EV_VEC_EMPTY,
.viewMask = 0,
.blendingOp = VK_LOGIC_OP_NO_OP
)
);
TYPEDATA_GEN(evkDescriptorBinding);

249
main.c Normal file
View File

@@ -0,0 +1,249 @@
#include <evk/evk.h>
#include <ev_numeric.h>
#include <ev_helpers.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
evstring PROJECT_NAME = evstr("evk");
float vertexPositions[] = {
0.f,-.5f,
.5f, .5f,
-.5f, .5f
};
int main(void)
{
u32 width = 1024;
u32 height = 1024;
evkInstance instance = evkCreateInstance((evkInstanceCreateInfo){
.applicationInfo = EV_DEFAULT(evkApplicationInfo),
.layers = svec_init(evstring, {
evstr("VK_LAYER_KHRONOS_validation"),
}),
.extensions = svec_init(evstring, {
evstr("VK_KHR_surface"),
evstr("VK_KHR_win32_surface"),
}),
});
if(instance.vk == EV_INVALID(VkInstance))
{
puts("Instance creation failed.");
goto InstanceCreationFailed;
}
puts("Instance was created successfully.");
evkDevice device = evkCreateDevice((evkDeviceCreateInfo) {
.instance = instance,
.physicalDeviceType = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU,
.queueRequirements = svec_init(evkDeviceQueueRequirement, {
{ VK_QUEUE_GRAPHICS_BIT, 1 },
{ VK_QUEUE_COMPUTE_BIT , 1 },
}),
.deviceExtensions = svec_init(evstring, {
evstr("VK_KHR_swapchain"),
evstr("VK_KHR_dynamic_rendering"),
evstr("VK_KHR_depth_stencil_resolve"),
evstr("VK_KHR_create_renderpass2"),
evstr("VK_KHR_synchronization2"),
evstr("VK_KHR_buffer_device_address"),
evstr("VK_EXT_descriptor_indexing"),
}),
});
if(device.vk == EV_INVALID(VkDevice))
{
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);
if (!glfwInit())
{
puts("GLFW Initialization failed.");
goto GLFWInitFailed;
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(1024,1024, "evk", NULL, NULL);
if(!window)
{
puts("Window Creation Failed.");
goto WindowCreationFailed;
}
VkSurfaceKHR surface;
VkResult err = glfwCreateWindowSurface(instance.vk, window, NULL, &surface);
if (err)
{
goto VKSurfaceCreationFailed;
puts("Surface creation failed.");
}
evkSwapChain swapChain = evkCreateSwapChain((evkSwapChainCreateInfo){
.device = device,
.surface = surface,
.width = width,
.height = height,
.imageCount = 3,
});
evkCommandPool commandPool = evkCreateCommandPool((evkCommandPoolCreateInfo) {
.device = device,
.queueFlags = VK_QUEUE_GRAPHICS_BIT,
.poolFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
});
vec(VkCommandBuffer) commandBuffers = evkAllocateCommandBuffers(device, commandPool, vec_len(&swapChain.images), true);
evkShaderCompiler compiler = evkCreateShaderCompiler();
evkShader vertShader = evkInitShaderFromFile(device, compiler, "shaders/tri.vert");
evkShader fragShader = evkInitShaderFromFile(device, compiler, "shaders/tri.frag");
evkDestroyShaderCompiler(compiler);
evkColorAttachment colorAttachment0 = {
swapChain.surfaceFormat.format,
EV_DEFAULT(VkPipelineColorBlendAttachmentState)
};
evkPipelineCreateInfo pipelineCreateInfo = EV_DEFAULT(evkPipelineCreateInfo,
dynamicStates = svec_init(VkDynamicState, {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
}),
shaderStages = svec_init(evkShader, {
vertShader,
fragShader,
}),
colorAttachments = svec_init(evkColorAttachment, {
colorAttachment0,
}),
viewportCountOverride = 1,
);
VkViewport viewport = EV_DEFAULT(VkViewport, width=width, height=height);
VkRect2D scissor = EV_DEFAULT(VkRect2D,extent.width=width, extent.height=height);
evkPipeline graphicsPipeline = evkCreatePipeline(device, pipelineCreateInfo);
VkFence drawFence = evkCreateFence(device, false);
VkSemaphore imageAcquiredSemaphore = evkCreateSemaphore(device);
VkSemaphore drawFinishedSemaphore = evkCreateSemaphore(device);
while(!glfwWindowShouldClose(window))
{
u32 imageIdx;
vkAcquireNextImageKHR(device.vk, swapChain.vk, UInt64.MAX, imageAcquiredSemaphore, VK_NULL_HANDLE, &imageIdx);
VkCommandBuffer cmdbuf = commandBuffers[imageIdx];
VkRenderingAttachmentInfoKHR colorAttachment = EV_DEFAULT(VkRenderingAttachmentInfoKHR,
imageView = swapChain.imageViews[imageIdx].vk,
loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
storeOp= VK_ATTACHMENT_STORE_OP_STORE,
);
VkRenderingInfo renderingInfo = EV_DEFAULT(VkRenderingInfo,
renderArea.extent = ((VkExtent2D){width, height}),
pColorAttachments = &colorAttachment,
colorAttachmentCount = 1,
);
evkBeginPrimaryCommandBuffer(cmdbuf);
vkCmdSetScissor(cmdbuf, 0, 1, &scissor);
vkCmdSetViewport(cmdbuf, 0, 1, &viewport);
vkCmdBeginRenderingKHR(cmdbuf, &renderingInfo);
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.vk);
vkCmdDraw(cmdbuf, 3, 1, 0, 0);
vkCmdEndRenderingKHR(cmdbuf);
VkImageMemoryBarrier imageMemoryBarrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = swapChain.images[imageIdx].vk,
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.layerCount = 1,
.levelCount = 1,
},
};
vkCmdPipelineBarrier(cmdbuf, 0, 0, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier);
evkEndCommandBuffer(cmdbuf);
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pCommandBuffers = &cmdbuf,
.commandBufferCount = 1,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &imageAcquiredSemaphore,
.pWaitDstStageMask = waitStages,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &drawFinishedSemaphore,
};
vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence);
vkWaitForFences(device.vk, 1, &drawFence, VK_TRUE, UInt64.MAX);
vkResetFences(device.vk, 1, &drawFence);
VkPresentInfoKHR presentInfo = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &drawFinishedSemaphore,
.swapchainCount = 1,
.pSwapchains = &swapChain.vk,
.pImageIndices = &imageIdx,
};
vkQueuePresentKHR(graphicsQueue, &presentInfo);
vkResetCommandBuffer(cmdbuf,VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
// Main Loop
glfwPollEvents();
}
vkQueueWaitIdle(graphicsQueue);
vkDestroyFence(device.vk, drawFence, NULL);
vkDestroySemaphore(device.vk, imageAcquiredSemaphore, NULL);
vkDestroySemaphore(device.vk, drawFinishedSemaphore, NULL);
evkDestroyPipeline(graphicsPipeline);
evkDestroyShader(device, vertShader);
evkDestroyShader(device, fragShader);
vkFreeCommandBuffers(device.vk, commandPool.vk, vec_len(&commandBuffers), commandBuffers);
evkDestroyCommandPool(device, commandPool);
evkDestroySwapChain(device, swapChain);
SwapchainCreationFailed:
vkDestroySurfaceKHR(instance.vk, swapChain.surface, NULL);
VKSurfaceCreationFailed:
WindowCreationFailed:
glfwTerminate();
GLFWInitFailed:
evkDestroyDevice(device);
DeviceCreationFailed:
evkDestroyInstance(instance);
InstanceCreationFailed:
return 0;
}

8
meson-native-clang Normal file
View File

@@ -0,0 +1,8 @@
[binaries]
c = 'clang.exe'
c_ld = 'lld'
cpp = 'clang++.exe'
cpp_ld = 'lld'
[properties]
c_args = ['-DEV_CC_CLANG=1']

69
meson.build Normal file
View File

@@ -0,0 +1,69 @@
project('evk', ['c','cpp'],
version : '0.1',
default_options : ['c_std=gnu23'])
build_config = configuration_data()
buildtype = get_option('buildtype')
if buildtype == 'debug'
build_config.set('EV_BUILDTYPE_DEBUG', 1)
elif buildtype == 'debugoptimized'
build_config.set('EV_BUILDTYPE_DEBUGOPT', 1)
else
build_config.set('EV_BUILDTYPE_RELEASE', 1)
endif
configure_file(output: 'evk_buildconfig.h', configuration: build_config)
subproject('evol-headers')
evh_c_args = []
cc = meson.get_compiler('c')
if cc.get_id() == 'msvc'
evh_c_args += '/Zc:preprocessor'
elif cc.get_id() == 'clang'
evh_c_args += '-DEV_CC_CLANG=1'
endif
evk_incdir = [
'.',
]
evk_src = [
'main.c',
'evk/evkInstance.c',
'evk/evkDevice.c',
'evk/evkAllocator.c',
'evk/evkSync.c',
'evk/evkShader.c',
'evk/evkSwapChain.c',
'evk/evkAllocator.c',
'evk/evkCommand.c',
'evk/evkPipeline.c',
'evk/evkDescriptor.c',
'evk/evkRender.c',
'evk/evkImage.c',
'evk/evkMemory.c',
]
executable(
'evk',
evk_src,
include_directories: include_directories(evk_incdir),
dependencies: [
dependency('ev_vec'),
dependency('ev_str'),
dependency('ev_helpers'),
dependency('vma'),
dependency('volk'),
dependency('glfw3'),
dependency('shaderc'),
dependency('spvref'),
],
c_args: evh_c_args,
)

9
shaders/tri.frag Normal file
View File

@@ -0,0 +1,9 @@
#version 450
#pragma shader_stage(fragment)
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(0.f, 1.f, 0.f, 1.f);
}

15
shaders/tri.vert Normal file
View File

@@ -0,0 +1,15 @@
#version 450
#pragma shader_stage(vertex)
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
// in layout(location=0) vec2 position;
void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
// gl_Position = vec4(position, 0.0, 1.0);
}

View File

@@ -0,0 +1,7 @@
[wrap-git]
directory = evol-headers
url = https://github.com/evol3d/evol-headers
revision = master
[provide]
dependency_names = ev_str, ev_vec, evol-headers

13
subprojects/glfw.wrap Normal file
View File

@@ -0,0 +1,13 @@
[wrap-file]
directory = glfw-3.3.10
source_url = https://github.com/glfw/glfw/archive/refs/tags/3.3.10.tar.gz
source_filename = glfw-3.3.10.tar.gz
source_hash = 4ff18a3377da465386374d8127e7b7349b685288cb8e17122f7e1179f73769d5
patch_filename = glfw_3.3.10-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/glfw_3.3.10-1/get_patch
patch_hash = 3567f96c2576a5fc8c9cafd9059f919d7da404f6c22450c6c2ce3f9938909b8b
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/glfw_3.3.10-1/glfw-3.3.10.tar.gz
wrapdb_version = 3.3.10-1
[provide]
glfw3 = glfw_dep

View File

@@ -0,0 +1,13 @@
project('libshaderc', 'cpp', default_options: ['buildtype=release'])
fs = import('fs')
cxxc = meson.get_compiler('cpp')
shaderc_inc = include_directories('install/include')
shaderc_dep = declare_dependency(
dependencies: cxxc.find_library('shaderc_combined', dirs: meson.current_source_dir()/'install/lib'),
include_directories: shaderc_inc,
)
meson.override_dependency('shaderc', shaderc_dep)

View File

@@ -0,0 +1,22 @@
project('spvref', 'c')
vulkan_dep = dependency('vulkan').partial_dependency(compile_args : true)
spvref_inc = include_directories('.')
spvref_src = files('spirv_reflect.c')
spvref_lib = static_library(
'spvref',
spvref_src,
include_directories: spvref_inc,
dependencies: vulkan_dep
)
spvref_dep = declare_dependency(
link_with: spvref_lib,
include_directories: spvref_inc,
dependencies: vulkan_dep
)
meson.override_dependency('spvref', spvref_dep)

View File

@@ -0,0 +1,22 @@
project('vma', ['c','cpp'])
vulkan_dep = dependency('vulkan').partial_dependency(compile_args : true)
vma_inc = include_directories('include')
vma_src = files('vk_mem_alloc.cpp')
vma_lib = static_library(
'vma',
vma_src,
include_directories: vma_inc,
dependencies: vulkan_dep
)
vma_dep = declare_dependency(
link_with: vma_lib,
include_directories: vma_inc,
dependencies: vulkan_dep
)
meson.override_dependency('vma', vma_dep)

View File

@@ -0,0 +1,4 @@
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#define VMA_IMPLEMENTATION
#include <vk_mem_alloc.h>

View File

@@ -0,0 +1,26 @@
project('volk', 'c',
default_options: [
'default_library=static',
],
)
vulkan_dep = dependency('vulkan').partial_dependency(compile_args : true)
volk_inc = include_directories('.')
volk_src = files('volk_impl.c')
volk_lib = library(
'volk',
volk_src,
include_directories: volk_inc,
dependencies: vulkan_dep
)
volk_dep = declare_dependency(
link_with: volk_lib,
include_directories: volk_inc,
dependencies: vulkan_dep
)
meson.override_dependency('volk', volk_dep)

View File

@@ -0,0 +1,2 @@
#define VOLK_IMPLEMENTATION
#include "volk.h"

12
subprojects/shaderc.wrap Normal file
View File

@@ -0,0 +1,12 @@
[wrap-file]
directory = libshaderc
source_url = https://storage.googleapis.com/shaderc/artifacts/prod/graphics_shader_compiler/shaderc/windows/continuous_release_2019/64/20241106-090939/install.zip
source_filename = libshaderc-upstream-msvc.zip
source_hash = a6879869e580d5991ebd9909f3665d1f6fe39cdb9830adf4f48b35dfd3782a78
lead_directory_missing = libshaderc
patch_directory = libshaderc
[provide]
dependency_names = shaderc

7
subprojects/spvref.wrap Normal file
View File

@@ -0,0 +1,7 @@
[wrap-git]
directory = spvref
url = https://github.com/KhronosGroup/SPIRV-Reflect
revision = main
depth = 1
patch_directory = spvref

7
subprojects/vma.wrap Normal file
View File

@@ -0,0 +1,7 @@
[wrap-git]
directory = vma
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
revision = master
depth = 1
patch_directory = vma

9
subprojects/volk.wrap Normal file
View File

@@ -0,0 +1,9 @@
[wrap-git]
directory = volk
url = https://github.com/zeux/volk
revision = master
patch_directory = volk
[provide]
dependency_names = volk