Created
March 5, 2020 22:55
-
-
Save AregevDev/eaf15a6092699841fb469fd13ce4343b to your computer and use it in GitHub Desktop.
Dummy Vulkan compute application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 450 core | |
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; | |
layout (set = 0, binding = 5, std430) buffer MyBuffer | |
{ | |
uint array[]; | |
} myBuffer; | |
layout (push_constant) uniform Scalar | |
{ | |
uint x; | |
} scalar; | |
void main() | |
{ | |
myBuffer.array[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x * scalar.x; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "volk.h" | |
#include <vector> | |
#include <string> | |
#include <sstream> | |
#include <iostream> | |
#include <fstream> | |
#define BUFFER_ELEMENTS 20 | |
#define BUFFER_SIZE BUFFER_ELEMENTS * sizeof(unsigned int) | |
#define FACTOR 100 | |
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessageCallback( | |
VkDebugUtilsMessageSeverityFlagBitsEXT, | |
VkDebugUtilsMessageTypeFlagsEXT, | |
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, | |
void * | |
) | |
{ | |
std::cerr << pCallbackData->pMessage << std::endl; | |
return VK_FALSE; | |
} | |
static unsigned int FindMemoryType(VkPhysicalDevice device, unsigned int type, VkMemoryPropertyFlags flags) | |
{ | |
VkPhysicalDeviceMemoryProperties properties; | |
vkGetPhysicalDeviceMemoryProperties(device, &properties); | |
for (unsigned int i = 0; i < properties.memoryTypeCount; i++) | |
{ | |
if (type & (1 << i) && (properties.memoryTypes[i].propertyFlags & flags) == flags) | |
return i; | |
} | |
return -1; | |
} | |
std::vector<char> ReadSpv(const char *filename) | |
{ | |
std::fstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); | |
if (file.fail()) | |
std::cout << "No" << std::endl; | |
file.seekg(0, file.end); | |
int len = file.tellg(); | |
file.seekg(0, file.beg); | |
std::vector<char> buf(len); | |
file.read(buf.data(), len); | |
return buf; | |
} | |
static std::string ArrayToString(unsigned int *arr, size_t size) | |
{ | |
std::stringstream s; | |
s << '['; | |
for (int i = 0; i < size; i++) | |
{ | |
if (i < size - 1) | |
s << arr[i] << ", "; | |
else | |
s << arr[i] << ']' << std::endl; | |
} | |
return s.str(); | |
} | |
class VulkanDummy | |
{ | |
private: | |
VkInstance m_instance; | |
VkDebugUtilsMessengerEXT m_messenger; | |
VkPhysicalDevice m_physicalDevice; | |
VkDevice m_device; | |
unsigned int m_familyIndex; | |
VkQueue m_computeQueue; | |
VkCommandPool m_commandPool; | |
VkCommandBuffer m_commandBuffer; | |
VkBuffer m_hostBuffer; | |
VkDeviceMemory m_hostMemory; | |
VkBuffer m_deviceBuffer; | |
VkDeviceMemory m_deviceMemory; | |
VkDescriptorPool m_descriptorPool; | |
VkDescriptorSetLayout m_descriptorSetLayout; | |
VkDescriptorSet m_descriptorSet; | |
VkShaderModule m_shader; | |
VkPipelineCache m_pipelineCache; | |
VkPipelineLayout m_pipelineLayout; | |
VkPipeline m_pipeline; | |
VkFence m_waitFence; | |
unsigned int m_inputArray[BUFFER_ELEMENTS]{}; | |
unsigned int m_outputArray[BUFFER_ELEMENTS]{}; | |
public: | |
void Run() | |
{ | |
CreateInstance(); | |
CreateValidationLayers(); | |
CreateDevice(); | |
CreateCommandBuffers(); | |
CreateInputs(); | |
CreateDescriptorSets(); | |
CreatePipeline(); | |
DoWork(); | |
OutputData(); | |
Cleanup(); | |
} | |
void CreateInstance() | |
{ | |
// Initialize volk loader | |
volkInitialize(); | |
// Application information | |
VkApplicationInfo appI = { | |
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
.pApplicationName = "VulkanDummy", | |
.applicationVersion = VK_MAKE_VERSION(0, 0, 0), | |
.pEngineName = "None", | |
.engineVersion = VK_MAKE_VERSION(0, 0, 0), | |
.apiVersion = VK_API_VERSION_1_2, | |
}; | |
// Instance layers | |
std::vector<const char *> layers = { | |
"VK_LAYER_KHRONOS_validation", | |
}; | |
std::vector<const char *> extensions = { | |
VK_EXT_DEBUG_UTILS_EXTENSION_NAME, | |
}; | |
// Create instance | |
VkInstanceCreateInfo instanceCI = { | |
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
.pApplicationInfo = &appI, | |
.enabledLayerCount = static_cast<uint32_t>(layers.size()), | |
.ppEnabledLayerNames = layers.data(), | |
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()), | |
.ppEnabledExtensionNames = extensions.data(), | |
}; | |
vkCreateInstance(&instanceCI, nullptr, &m_instance); | |
// Load instance extension functions | |
volkLoadInstance(m_instance); | |
} | |
void CreateValidationLayers() | |
{ | |
// Create validation messenger | |
VkDebugUtilsMessengerCreateInfoEXT messengerCI = { | |
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, | |
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | | |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, | |
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | | |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | | |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, | |
.pfnUserCallback = DebugMessageCallback, | |
}; | |
vkCreateDebugUtilsMessengerEXT(m_instance, &messengerCI, nullptr, &m_messenger); | |
} | |
void CreateDevice() | |
{ | |
// Pick physical device | |
std::vector<VkPhysicalDevice> devices; | |
unsigned int deviceCount; | |
vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr); | |
devices.resize(deviceCount); | |
vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data()); | |
// Pick the first physical device | |
m_physicalDevice = devices.front(); | |
// Find queue families | |
std::vector<VkQueueFamilyProperties> families; | |
unsigned int familyCount; | |
vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &familyCount, nullptr); | |
families.resize(familyCount); | |
vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &familyCount, families.data()); | |
// Request one compute queue | |
for (unsigned int i = 0; i < familyCount; i++) | |
{ | |
if (families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) | |
{ | |
m_familyIndex = i; | |
break; | |
} | |
} | |
// Create queue definition | |
const float priorities[] = {0.0f}; | |
VkDeviceQueueCreateInfo queueCI = { | |
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | |
.queueFamilyIndex = m_familyIndex, | |
.queueCount = 1, | |
.pQueuePriorities = priorities, | |
}; | |
// Device extensions | |
std::vector<const char *> extensions; | |
// Create device | |
VkDeviceCreateInfo deviceCI = { | |
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
.queueCreateInfoCount = 1, | |
.pQueueCreateInfos = &queueCI, | |
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()), | |
.ppEnabledExtensionNames = extensions.data(), | |
}; | |
vkCreateDevice(m_physicalDevice, &deviceCI, nullptr, &m_device); | |
// Load device extension functions | |
volkLoadDevice(m_device); | |
// Fetch the requested queue | |
vkGetDeviceQueue(m_device, queueCI.queueFamilyIndex, 0, &m_computeQueue); | |
} | |
void CreateCommandBuffers() | |
{ | |
// Create command pool | |
VkCommandPoolCreateInfo commandPoolCI = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, | |
.queueFamilyIndex = m_familyIndex, | |
}; | |
vkCreateCommandPool(m_device, &commandPoolCI, nullptr, &m_commandPool); | |
// Allocate command buffers | |
VkCommandBufferAllocateInfo commandBufferAI = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
.commandPool = m_commandPool, | |
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
.commandBufferCount = 1, | |
}; | |
vkAllocateCommandBuffers(m_device, &commandBufferAI, &m_commandBuffer); | |
} | |
void CreateInputs() | |
{ | |
// Fill input | |
for (int i = 0; i < BUFFER_ELEMENTS; i++) | |
{ | |
m_inputArray[i] = i; | |
} | |
// Create host buffer | |
VkBufferCreateInfo hostBufferCI = { | |
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | |
.size = BUFFER_SIZE, | |
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | | |
VK_BUFFER_USAGE_TRANSFER_DST_BIT, | |
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, | |
.queueFamilyIndexCount = 1, | |
.pQueueFamilyIndices = &m_familyIndex, | |
}; | |
vkCreateBuffer(m_device, &hostBufferCI, nullptr, &m_hostBuffer); | |
// Allocate host buffer | |
VkMemoryRequirements requirements; | |
vkGetBufferMemoryRequirements(m_device, m_hostBuffer, &requirements); | |
VkMemoryAllocateInfo allocateI = { | |
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
.allocationSize = requirements.size, | |
.memoryTypeIndex = FindMemoryType(m_physicalDevice, requirements.memoryTypeBits, | |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT), | |
}; | |
vkAllocateMemory(m_device, &allocateI, nullptr, &m_hostMemory); | |
void *mapped; | |
vkMapMemory(m_device, m_hostMemory, 0, BUFFER_SIZE, 0, &mapped); | |
memcpy(mapped, m_inputArray, BUFFER_SIZE); | |
vkUnmapMemory(m_device, m_hostMemory); | |
vkBindBufferMemory(m_device, m_hostBuffer, m_hostMemory, 0); | |
// Create device buffer | |
VkBufferCreateInfo deviceBufferCI = { | |
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | |
.size = BUFFER_SIZE, | |
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | | |
VK_BUFFER_USAGE_TRANSFER_DST_BIT, | |
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, | |
.queueFamilyIndexCount = 1, | |
.pQueueFamilyIndices = &m_familyIndex, | |
}; | |
vkCreateBuffer(m_device, &deviceBufferCI, nullptr, &m_deviceBuffer); | |
// Allocate device buffer | |
vkGetBufferMemoryRequirements(m_device, m_deviceBuffer, &requirements); | |
allocateI = { | |
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
.allocationSize = requirements.size, | |
.memoryTypeIndex = FindMemoryType(m_physicalDevice, requirements.memoryTypeBits, | |
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), | |
}; | |
vkAllocateMemory(m_device, &allocateI, nullptr, &m_deviceMemory); | |
vkBindBufferMemory(m_device, m_deviceBuffer, m_deviceMemory, 0); | |
// Copy host buffer content to device buffer | |
VkBufferCopy copy = { | |
.size = BUFFER_SIZE, | |
}; | |
VkCommandBufferBeginInfo commandBufferBI = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, | |
.pInheritanceInfo = nullptr, | |
}; | |
vkBeginCommandBuffer(m_commandBuffer, &commandBufferBI); | |
vkCmdCopyBuffer(m_commandBuffer, m_hostBuffer, m_deviceBuffer, 1, ©); | |
vkEndCommandBuffer(m_commandBuffer); | |
VkFenceCreateInfo fenceCI = { | |
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
}; | |
vkCreateFence(m_device, &fenceCI, nullptr, &m_waitFence); | |
VkSubmitInfo submitI = { | |
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
.commandBufferCount = 1, | |
.pCommandBuffers = &m_commandBuffer, | |
}; | |
vkQueueSubmit(m_computeQueue, 1, &submitI, m_waitFence); | |
vkWaitForFences(m_device, 1, &m_waitFence, true, UINT64_MAX); | |
} | |
void CreateDescriptorSets() | |
{ | |
// Define descriptor layout | |
// Storage buffer binding | |
VkDescriptorSetLayoutBinding binding = { | |
.binding = 5, | |
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, | |
.descriptorCount = 1, | |
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | |
}; | |
VkDescriptorSetLayoutCreateInfo layoutCI = { | |
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | |
.bindingCount = 1, | |
.pBindings = &binding, | |
}; | |
vkCreateDescriptorSetLayout(m_device, &layoutCI, nullptr, &m_descriptorSetLayout); | |
// Create descriptor pool and sets | |
VkDescriptorPoolSize size = { | |
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, | |
.descriptorCount = 1, | |
}; | |
VkDescriptorPoolCreateInfo poolCI = { | |
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, | |
.maxSets = 10, | |
.poolSizeCount = 1, | |
.pPoolSizes = &size, | |
}; | |
vkCreateDescriptorPool(m_device, &poolCI, nullptr, &m_descriptorPool); | |
VkDescriptorSetAllocateInfo allocateI = { | |
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, | |
.descriptorPool = m_descriptorPool, | |
.descriptorSetCount = 1, | |
.pSetLayouts = &m_descriptorSetLayout, | |
}; | |
vkAllocateDescriptorSets(m_device, &allocateI, &m_descriptorSet); | |
// Write to the descriptor set | |
VkDescriptorBufferInfo bufferI = { | |
.buffer = m_deviceBuffer, | |
.offset = 0, | |
.range = VK_WHOLE_SIZE, | |
}; | |
VkWriteDescriptorSet write = { | |
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, | |
.dstSet = m_descriptorSet, | |
.dstBinding = 5, | |
.descriptorCount = 1, | |
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, | |
.pBufferInfo = &bufferI, | |
}; | |
vkUpdateDescriptorSets(m_device, 1, &write, 0, nullptr); | |
// Create pipeline cache | |
VkPipelineCacheCreateInfo pipelineCacheCI = { | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, | |
}; | |
vkCreatePipelineCache(m_device, &pipelineCacheCI, nullptr, &m_pipelineCache); | |
} | |
void CreatePipeline() | |
{ | |
// Load shader | |
std::vector<char> code = ReadSpv("shaders/inc.comp.spv"); | |
VkShaderModuleCreateInfo shaderCI = { | |
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
.codeSize = code.size(), | |
.pCode = reinterpret_cast<const uint32_t *>(code.data()), | |
}; | |
vkCreateShaderModule(m_device, &shaderCI, nullptr, &m_shader); | |
VkPipelineShaderStageCreateInfo stageCI = { | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
.stage = VK_SHADER_STAGE_COMPUTE_BIT, | |
.module = m_shader, | |
.pName = "main", | |
}; | |
// Declare push constants | |
VkPushConstantRange range = { | |
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, | |
.size = sizeof(unsigned int), | |
}; | |
// Create pipeline layout | |
VkPipelineLayoutCreateInfo layoutCI = { | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | |
.setLayoutCount = 1, | |
.pSetLayouts = &m_descriptorSetLayout, | |
.pushConstantRangeCount = 1, | |
.pPushConstantRanges = &range, | |
}; | |
vkCreatePipelineLayout(m_device, &layoutCI, nullptr, &m_pipelineLayout); | |
// Create pipeline layout | |
VkComputePipelineCreateInfo computePipelineCI = { | |
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, | |
.stage = stageCI, | |
.layout = m_pipelineLayout, | |
}; | |
vkCreateComputePipelines(m_device, m_pipelineCache, 1, &computePipelineCI, nullptr, &m_pipeline); | |
} | |
void DoWork() | |
{ | |
unsigned int fac = FACTOR; | |
VkCommandBufferBeginInfo commandBufferBI = { | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
}; | |
vkBeginCommandBuffer(m_commandBuffer, &commandBufferBI); | |
VkBufferMemoryBarrier barrier = { | |
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | |
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT, | |
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT, | |
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.buffer = m_deviceBuffer, | |
}; | |
vkCmdPipelineBarrier(m_commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, | |
0, nullptr, | |
1, &barrier, | |
0, nullptr); | |
vkCmdBindPipeline(m_commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline); | |
vkCmdBindDescriptorSets(m_commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, 1, | |
&m_descriptorSet, 0, | |
nullptr); | |
vkCmdPushConstants(m_commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(unsigned int), &fac); | |
vkCmdDispatch(m_commandBuffer, BUFFER_ELEMENTS, 1, 1); | |
barrier = { | |
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | |
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, | |
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | |
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.buffer = m_deviceBuffer, | |
}; | |
vkCmdPipelineBarrier(m_commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, | |
0, nullptr, | |
1, &barrier, | |
0, nullptr); | |
VkBufferCopy copy = { | |
.size = BUFFER_SIZE, | |
}; | |
vkCmdCopyBuffer(m_commandBuffer, m_deviceBuffer, m_hostBuffer, 1, ©); | |
barrier = { | |
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | |
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | |
.dstAccessMask = VK_ACCESS_HOST_READ_BIT, | |
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.buffer = m_hostBuffer, | |
}; | |
vkCmdPipelineBarrier(m_commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, | |
0, nullptr, | |
1, &barrier, | |
0, nullptr); | |
vkEndCommandBuffer(m_commandBuffer); | |
// Submit work | |
vkResetFences(m_device, 1, &m_waitFence); | |
VkPipelineStageFlags waitFlags = VK_PIPELINE_STAGE_TRANSFER_BIT; | |
VkSubmitInfo submitI = { | |
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
.pWaitDstStageMask = &waitFlags, | |
.commandBufferCount = 1, | |
.pCommandBuffers = &m_commandBuffer, | |
}; | |
vkQueueSubmit(m_computeQueue, 1, &submitI, m_waitFence); | |
vkWaitForFences(m_device, 1, &m_waitFence, true, UINT64_MAX); | |
} | |
void OutputData() | |
{ | |
vkQueueWaitIdle(m_computeQueue); | |
void *mapped; | |
vkMapMemory(m_device, m_hostMemory, 0, BUFFER_SIZE, 0, &mapped); | |
memcpy(m_outputArray, mapped, BUFFER_SIZE); | |
vkUnmapMemory(m_device, m_hostMemory); | |
std::cout << "Input: " << ArrayToString(m_inputArray, BUFFER_ELEMENTS); | |
std::cout << "Output: " << ArrayToString(m_outputArray, BUFFER_ELEMENTS); | |
} | |
void Cleanup() | |
{ | |
vkDestroyFence(m_device, m_waitFence, nullptr); | |
vkDestroyPipeline(m_device, m_pipeline, nullptr); | |
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); | |
vkDestroyPipelineCache(m_device, m_pipelineCache, nullptr); | |
vkDestroyShaderModule(m_device, m_shader, nullptr); | |
vkDestroyDescriptorPool(m_device, m_descriptorPool, nullptr); | |
vkDestroyDescriptorSetLayout(m_device, m_descriptorSetLayout, nullptr); | |
vkFreeMemory(m_device, m_deviceMemory, nullptr); | |
vkDestroyBuffer(m_device, m_deviceBuffer, nullptr); | |
vkFreeMemory(m_device, m_hostMemory, nullptr); | |
vkDestroyBuffer(m_device, m_hostBuffer, nullptr); | |
vkFreeCommandBuffers(m_device, m_commandPool, 1, &m_commandBuffer); | |
vkDestroyCommandPool(m_device, m_commandPool, nullptr); | |
vkDestroyDevice(m_device, nullptr); | |
vkDestroyDebugUtilsMessengerEXT(m_instance, m_messenger, nullptr); | |
vkDestroyInstance(m_instance, nullptr); | |
} | |
}; | |
int main() | |
{ | |
VulkanDummy dummy; | |
dummy.Run(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment