548 lines
18 KiB
C
548 lines
18 KiB
C
/*
|
|
* Copyright (c) 2017 Eric Arnebäck
|
|
* Copyright (c) 2017-2019 Collabora Ltd.
|
|
* Copyright (c) 2024 mittorn
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef VULKAN_UTL_H
|
|
#define VULKAN_UTL_H
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
// Used for validating return values of Vulkan API calls.
|
|
#ifndef VK_CHECK_RESULT
|
|
#define VK_CHECK_RESULT(f) \
|
|
{ \
|
|
VkResult res = (f); \
|
|
if (res != VK_SUCCESS) \
|
|
{ \
|
|
printf("Fatal : VkResult is %d in %s at line %d\n", res, __FILE__, __LINE__); \
|
|
assert(res == VK_SUCCESS); \
|
|
} \
|
|
}
|
|
#endif
|
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
struct VulkanContext
|
|
{
|
|
VkInstance instance = NULL;
|
|
const char * enabledLayers[16];
|
|
uint32_t enabledLayersCount = 0;
|
|
VkDebugReportCallbackEXT debugCallbackHandle = NULL;
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallbackFn(
|
|
VkDebugReportFlagsEXT flags,
|
|
VkDebugReportObjectTypeEXT objectType,
|
|
uint64_t object,
|
|
size_t location,
|
|
int32_t messageCode,
|
|
const char* pLayerPrefix,
|
|
const char* pMessage,
|
|
void* pUserData) {
|
|
|
|
printf("Debug Report: %s: %s\n", pLayerPrefix, pMessage);
|
|
//_exit(1);
|
|
|
|
return VK_FALSE;
|
|
}
|
|
|
|
VkResult Create(const char *engine, const char *app, bool enableValidationLayers)
|
|
{
|
|
VkApplicationInfo app_info = {
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
.pApplicationName = app,
|
|
.applicationVersion = 0,
|
|
.pEngineName = engine,
|
|
.engineVersion = 0,
|
|
.apiVersion = VK_MAKE_VERSION(1, 0, 2),
|
|
};
|
|
const char * enabledExtensions[16];
|
|
uint32_t enabledExtensionsCount = 0;
|
|
enabledExtensions[enabledExtensionsCount++] = VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME;
|
|
enabledExtensions[enabledExtensionsCount++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
|
|
enabledExtensions[enabledExtensionsCount++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME;
|
|
enabledExtensions[enabledExtensionsCount++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
|
|
enabledExtensions[enabledExtensionsCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
|
|
enabledExtensions[enabledExtensionsCount++] = "VK_KHR_xlib_surface";
|
|
|
|
if (enableValidationLayers) {
|
|
/*
|
|
We get all supported layers with vkEnumerateInstanceLayerProperties.
|
|
*/
|
|
uint32_t layerCount;
|
|
vkEnumerateInstanceLayerProperties(&layerCount, NULL);
|
|
|
|
VkLayerProperties layerProperties[layerCount];
|
|
vkEnumerateInstanceLayerProperties(&layerCount, layerProperties);
|
|
|
|
/*
|
|
And then we simply check if VK_LAYER_LUNARG_standard_validation is among the supported layers.
|
|
*/
|
|
bool foundLayer = false;
|
|
for (VkLayerProperties prop : layerProperties) {
|
|
|
|
if (strcmp("VK_LAYER_KHRONOS_validation", prop.layerName) == 0) {
|
|
foundLayer = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (!foundLayer) {
|
|
printf("Layer VK_LAYER_LUNARG_standard_validation not supported\n");
|
|
}
|
|
else
|
|
enabledLayers[enabledLayersCount++] = "VK_LAYER_KHRONOS_validation"; // Alright, we can use this layer.
|
|
|
|
/*
|
|
We need to enable an extension named VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
|
|
in order to be able to print the warnings emitted by the validation layer.
|
|
|
|
So again, we just check if the extension is among the supported extensions.
|
|
*/
|
|
|
|
uint32_t extensionCount;
|
|
|
|
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL);
|
|
VkExtensionProperties extensionProperties[extensionCount];
|
|
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties);
|
|
|
|
bool foundExtension = false;
|
|
for (VkExtensionProperties prop : extensionProperties) {
|
|
if (strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, prop.extensionName) == 0) {
|
|
foundExtension = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundExtension) {
|
|
printf("Extension VK_EXT_DEBUG_REPORT_EXTENSION_NAME not supported\n");
|
|
}
|
|
else enabledExtensions[enabledExtensionsCount++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
|
|
|
|
}
|
|
|
|
VkInstanceCreateInfo instance_info = {
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
.pApplicationInfo = &app_info,
|
|
.enabledLayerCount = enabledLayersCount,
|
|
.ppEnabledLayerNames = enabledLayers,
|
|
.enabledExtensionCount = enabledExtensionsCount,
|
|
.ppEnabledExtensionNames = (const char* const*)enabledExtensions,
|
|
};
|
|
|
|
VkResult res1 = vkCreateInstance(&instance_info, NULL, &instance);
|
|
VK_CHECK_RESULT(res1);
|
|
if (enableValidationLayers) {
|
|
VkDebugReportCallbackCreateInfoEXT createInfo = {};
|
|
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
|
|
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
|
|
createInfo.pfnCallback = &DebugReportCallbackFn;
|
|
|
|
|
|
// We have to explicitly load this function.
|
|
auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
|
|
if (vkCreateDebugReportCallbackEXT != nullptr) {
|
|
if(vkCreateDebugReportCallbackEXT(instance, &createInfo, NULL, &debugCallbackHandle) != VK_SUCCESS)
|
|
printf("Failed to register debug callback\n");
|
|
}
|
|
else
|
|
printf("Failed to register debug callback: null function\n");
|
|
}
|
|
return res1;
|
|
}
|
|
VkPhysicalDevice FindPhysicalDevice()
|
|
{
|
|
uint32_t deviceCount;
|
|
vkEnumeratePhysicalDevices(instance, &deviceCount, NULL);
|
|
if (deviceCount == 0) {
|
|
printf("could not find a device with vulkan support\n");
|
|
return NULL;
|
|
}
|
|
|
|
VkPhysicalDevice devices[deviceCount];
|
|
vkEnumeratePhysicalDevices(instance, &deviceCount, devices);
|
|
for (VkPhysicalDevice device : devices) {
|
|
if (true) { // accept any device for now
|
|
return device;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
void Destroy()
|
|
{
|
|
if (debugCallbackHandle) {
|
|
// destroy callback.
|
|
auto func = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
|
|
if (func == nullptr) {
|
|
printf("Could not load vkDestroyDebugReportCallbackEXT\n");
|
|
//return;
|
|
}
|
|
else
|
|
func(instance, debugCallbackHandle, NULL);
|
|
debugCallbackHandle = NULL;
|
|
}
|
|
vkDestroyInstance(instance, NULL);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
struct VulkanBuffer
|
|
{
|
|
VkDevice device;
|
|
VkBuffer buffer = NULL;
|
|
VkDeviceMemory memory = NULL;
|
|
VkDescriptorBufferInfo descriptor;
|
|
VkDeviceSize size;
|
|
VkDeviceSize alignment;
|
|
void *mapped = NULL;
|
|
|
|
VkBufferUsageFlags usage_flags;
|
|
VkMemoryPropertyFlags memory_property_flags;
|
|
VkResult Map()
|
|
{
|
|
VkDeviceSize size = VK_WHOLE_SIZE;
|
|
VkDeviceSize offset = 0;
|
|
return vkMapMemory(device, memory, offset, size, 0,&mapped);
|
|
}
|
|
void Unmap()
|
|
{
|
|
if (mapped) {
|
|
vkUnmapMemory(device, memory);
|
|
mapped = NULL;
|
|
}
|
|
}
|
|
VkResult Bind()
|
|
{
|
|
return vkBindBufferMemory(device, buffer, memory, 0);
|
|
}
|
|
void SetupDescriptor()
|
|
{
|
|
descriptor = VkDescriptorBufferInfo{
|
|
.buffer = buffer,
|
|
.offset = 0,
|
|
.range = VK_WHOLE_SIZE,
|
|
};
|
|
|
|
}
|
|
void Destroy()
|
|
{
|
|
if (buffer)
|
|
vkDestroyBuffer(device, buffer, NULL);
|
|
if (memory)
|
|
vkFreeMemory(device, memory, NULL);
|
|
}
|
|
};
|
|
|
|
struct VulkanDevice
|
|
{
|
|
VkPhysicalDevice physicalDevice = NULL;
|
|
VkDevice device = NULL;
|
|
VkPhysicalDeviceProperties properties;
|
|
VkPhysicalDeviceFeatures features;
|
|
VkPhysicalDeviceMemoryProperties memoryProperties;
|
|
|
|
VkCommandPool cmd_pool = NULL;
|
|
|
|
uint32_t defaultFamilyIndex;
|
|
VkQueue defaultQueue;
|
|
|
|
// Returns the index of a queue family that supports compute operations.
|
|
uint32_t GetQueueFamilyIndex(VkQueueFlags bits) {
|
|
uint32_t queueFamilyCount;
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
|
|
|
|
// Retrieve all queue families.
|
|
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
|
|
|
|
// Now find a family that supports compute.
|
|
uint32_t i = 0;
|
|
for (; i < queueFamilyCount; ++i) {
|
|
VkQueueFamilyProperties props = queueFamilies[i];
|
|
|
|
if (props.queueCount > 0 && (props.queueFlags & bits)) {
|
|
// found a queue with compute. We're done!
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == queueFamilyCount) {
|
|
printf("could not find a queue family that supports operations\n");
|
|
return 0;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
bool Create(VkPhysicalDevice physical_device_, VkQueueFlags defaultQueueBits)
|
|
{
|
|
physicalDevice = physical_device_;
|
|
assert(physicalDevice);
|
|
|
|
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
|
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
|
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
|
|
|
defaultFamilyIndex = GetQueueFamilyIndex(defaultQueueBits);
|
|
if(!defaultFamilyIndex)
|
|
return false;
|
|
cmd_pool = NULL;
|
|
return true;
|
|
}
|
|
|
|
void Destroy()
|
|
{
|
|
if (cmd_pool)
|
|
vkDestroyCommandPool(device, cmd_pool, NULL);
|
|
cmd_pool = NULL;
|
|
if (device)
|
|
vkDestroyDevice(device, NULL);
|
|
device = NULL;
|
|
}
|
|
|
|
bool GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties, uint32_t *out_index)
|
|
{
|
|
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
|
|
if ((typeBits & 1) == 1) {
|
|
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
|
*out_index = i;
|
|
return true;
|
|
}
|
|
}
|
|
typeBits >>= 1;
|
|
}
|
|
|
|
*out_index = 0;
|
|
return false;
|
|
}
|
|
|
|
int GetAvailiableModifiersList(uint64_t *modifiers2, size_t len, VkFormat fmt)
|
|
{
|
|
VkDrmFormatModifierPropertiesEXT modifiers[len];
|
|
VkDrmFormatModifierPropertiesListEXT formatList = {VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT};
|
|
VkFormatProperties2 prop = {VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2};
|
|
prop.pNext = &formatList;
|
|
formatList.drmFormatModifierCount = len;
|
|
formatList.pDrmFormatModifierProperties = modifiers;
|
|
int count = 0;
|
|
vkGetPhysicalDeviceFormatProperties2(physicalDevice, fmt, &prop);
|
|
for(int i = 0; i < formatList.drmFormatModifierCount; i++)
|
|
{
|
|
modifiers2[count++] = modifiers[i].drmFormatModifier;
|
|
printf("mod %llx %d %d\n", modifiers[i].drmFormatModifier, modifiers[i].drmFormatModifierPlaneCount, (int)modifiers[i].drmFormatModifierTilingFeatures);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
VkResult CreateDevice(VulkanContext &ctx)
|
|
{
|
|
const float defaultQueuePriority(1.0f);
|
|
|
|
VkDeviceQueueCreateInfo queue_info {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
.queueFamilyIndex = defaultFamilyIndex,
|
|
.queueCount = 1,
|
|
.pQueuePriorities = &defaultQueuePriority,
|
|
};
|
|
const char *deviceExtensions[16];
|
|
uint32_t deviceExtensionsCount = 0;
|
|
uint32_t avCount = 0;
|
|
vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &avCount, NULL);
|
|
VkExtensionProperties props[avCount];
|
|
vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &avCount, props);
|
|
auto addExtension = [&](const char *Name){
|
|
int j;
|
|
for(j = 0; j < avCount; j++)
|
|
{
|
|
if(!strcmp(Name,props[j].extensionName))
|
|
break;
|
|
}
|
|
if(j == avCount)
|
|
printf("Extension %s not availaible\n", Name);
|
|
else
|
|
deviceExtensions[deviceExtensionsCount++] = Name;
|
|
};
|
|
addExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
|
|
//addExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
|
|
addExtension(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
|
|
addExtension(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
|
|
addExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
|
|
addExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
|
|
addExtension(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
|
|
addExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
|
|
addExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
|
|
addExtension(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
|
|
addExtension(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
|
|
addExtension(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
|
|
addExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
VkPhysicalDeviceFeatures enabled_features = {
|
|
.samplerAnisotropy = VK_TRUE
|
|
};
|
|
VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcrFeat = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, .samplerYcbcrConversion = VK_TRUE};
|
|
|
|
VkDeviceCreateInfo device_info = {
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
.pNext = &ycbcrFeat,
|
|
.queueCreateInfoCount = 1,
|
|
.pQueueCreateInfos = &queue_info,
|
|
.enabledLayerCount = ctx.enabledLayersCount,
|
|
.ppEnabledLayerNames = ctx.enabledLayers,
|
|
.enabledExtensionCount = deviceExtensionsCount,
|
|
.ppEnabledExtensionNames = (const char *const *)deviceExtensions,
|
|
.pEnabledFeatures = &enabled_features,
|
|
};
|
|
|
|
VkResult result =
|
|
vkCreateDevice(physicalDevice, &device_info, NULL, &device);
|
|
|
|
if (result != VK_SUCCESS) {
|
|
printf("Could not create device.\n");
|
|
return result;
|
|
}
|
|
// Get a handle to the only member of the queue family.
|
|
vkGetDeviceQueue(device, defaultFamilyIndex, 0, &defaultQueue);
|
|
return result;
|
|
|
|
}
|
|
VkResult CreateBuffer(VulkanBuffer &buffer, VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_flags, VkDeviceSize size, const void *data = NULL)
|
|
{
|
|
buffer.device = device;
|
|
|
|
// Create the buffer handle
|
|
VkBufferCreateInfo bufferCreateInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
|
|
bufferCreateInfo.size = size;
|
|
bufferCreateInfo.usage = usage;
|
|
VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, NULL, &buffer.buffer));
|
|
|
|
// Create the memory backing up the buffer handle
|
|
VkMemoryRequirements memReqs;
|
|
vkGetBufferMemoryRequirements(device, buffer.buffer, &memReqs);
|
|
|
|
VkMemoryAllocateInfo memAlloc = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
|
|
memAlloc.allocationSize = memReqs.size;
|
|
|
|
// Find a memory type index that fits the properties of the buffer
|
|
if (!GetMemoryType(memReqs.memoryTypeBits, memory_flags, &memAlloc.memoryTypeIndex))
|
|
printf("Could not find memory type.\n");
|
|
|
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, NULL, &buffer.memory));
|
|
|
|
buffer.alignment = memReqs.alignment;
|
|
buffer.size = memAlloc.allocationSize;
|
|
buffer.usage_flags = usage;
|
|
buffer.memory_property_flags = memory_flags;
|
|
|
|
// If a pointer to the buffer data has been passed, map the buffer and copy
|
|
// over the data
|
|
if (data != NULL) {
|
|
VK_CHECK_RESULT(buffer.Map());
|
|
memcpy(buffer.mapped, data, size);
|
|
buffer.Unmap();
|
|
}
|
|
|
|
// Initialize a default descriptor that covers the whole buffer size
|
|
buffer.SetupDescriptor();
|
|
|
|
// Attach the memory to the buffer object
|
|
return buffer.Bind();
|
|
|
|
}
|
|
void CreateAndMap(VulkanBuffer &buffer, VkDeviceSize size)
|
|
{
|
|
VkMemoryPropertyFlags memory_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
VK_CHECK_RESULT(CreateBuffer(buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, memory_flags, size, NULL));
|
|
|
|
// Map persistent
|
|
VK_CHECK_RESULT(buffer.Map());
|
|
}
|
|
|
|
VkCommandPool _CreateCommandPool()
|
|
{
|
|
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
|
VkCommandPoolCreateInfo cmdPoolInfo = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};
|
|
cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
cmdPoolInfo.queueFamilyIndex = defaultFamilyIndex;
|
|
|
|
VkCommandPool cmdPool;
|
|
VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, NULL, &cmdPool));
|
|
return cmdPool;
|
|
}
|
|
VkCommandBuffer CreateCommandBuffer()
|
|
{
|
|
if (!cmd_pool) {
|
|
cmd_pool = _CreateCommandPool();
|
|
};
|
|
|
|
VkCommandBufferAllocateInfo cmdBufAllocateInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};
|
|
cmdBufAllocateInfo.commandPool = cmd_pool;
|
|
cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
cmdBufAllocateInfo.commandBufferCount = 1;
|
|
|
|
VkCommandBuffer cmdBuffer;
|
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &cmdBuffer));
|
|
|
|
VkCommandBufferBeginInfo cmdBufInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
|
|
};
|
|
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
|
|
|
|
return cmdBuffer;
|
|
}
|
|
void FlushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue)
|
|
{
|
|
if (commandBuffer == VK_NULL_HANDLE)
|
|
return;
|
|
|
|
if (!cmd_pool)
|
|
return;
|
|
|
|
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
|
|
|
VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
|
|
submitInfo.commandBufferCount = 1;
|
|
submitInfo.pCommandBuffers = &commandBuffer;
|
|
|
|
// Create fence to ensure that the command buffer has finished executing
|
|
VkFenceCreateInfo fenceInfo = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
|
VkFence fence;
|
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, NULL, &fence));
|
|
|
|
// Submit to the queue
|
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
|
|
// Wait for the fence to signal that command buffer has finished executing
|
|
VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, INT64_MAX));
|
|
|
|
vkDestroyFence(device, fence, NULL);
|
|
vkFreeCommandBuffers(device, cmd_pool, 1, &commandBuffer);
|
|
}
|
|
};
|
|
|
|
#endif // VULKAN_UTL_H
|