diff --git a/VulkanTutorial.vcxproj b/VulkanTutorial.vcxproj
index ba8a931..ecc4e22 100644
--- a/VulkanTutorial.vcxproj
+++ b/VulkanTutorial.vcxproj
@@ -61,8 +61,12 @@
- D:\Code\GLFW3\include;C:\VulkanSDK\1.0.46.0\Include;$(IncludePath)
- C:\VulkanSDK\1.0.46.0\Lib;D:\Code\GLFW3\win64\lib-vc2015;$(LibraryPath)
+ D:\Code\GLFW3\include;C:\VulkanSDK\1.1.70.1\Include;$(IncludePath)
+ C:\VulkanSDK\1.1.70.1\Lib;D:\Code\GLFW3\win64\lib-vc2015;$(LibraryPath)
+
+
+ D:\Code\GLFW3\include;C:\VulkanSDK\1.1.70.1\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);
+ C:\VulkanSDK\1.1.70.1\Lib;D:\Code\GLFW3\win64\lib-vc2015;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64
diff --git a/main.cpp b/main.cpp
index 136eb3c..be1a971 100644
--- a/main.cpp
+++ b/main.cpp
@@ -61,26 +61,26 @@ public:
private:
// Instance variables:
GLFWwindow* window;
- VDeleter instance {vkDestroyInstance};
- VDeleter callback {instance, DestroyDebugReportCallbackEXT};
+ VkInstance instance;
+ VkDebugReportCallbackEXT callback;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkQueue graphicsQueue;
- VDeleter device {vkDestroyDevice};
- VDeleter surface {instance, vkDestroySurfaceKHR};
+ VkDevice device;
+ VkSurfaceKHR surface;
VkQueue presentQueue;
- VDeleter swapChain {device, vkDestroySwapchainKHR};
+ VkSwapchainKHR swapChain;
std::vector swapChainImages;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;
- std::vector> swapChainImageViews;
- VDeleter renderPass {device, vkDestroyRenderPass};
- VDeleter pipelineLayout {device, vkDestroyPipelineLayout};
- VDeleter graphicsPipeline {device, vkDestroyPipeline};
- std::vector> swapChainFramebuffers;
- VDeleter commandPool {device, vkDestroyCommandPool};
+ std::vector swapChainImageViews;
+ VkRenderPass renderPass;
+ VkPipelineLayout pipelineLayout;
+ VkPipeline graphicsPipeline;
+ std::vector swapChainFramebuffers;
+ VkCommandPool commandPool;
std::vector commandBuffers;
- VDeleter imageAvailableSemaphore {device, vkDestroySemaphore};
- VDeleter renderFinishedSemaphore {device, vkDestroySemaphore};
+ VkSemaphore imageAvailableSemaphore;
+ VkSemaphore renderFinishedSemaphore;
// Initialize our GLFW window.
@@ -175,7 +175,7 @@ private:
createInfo.enabledExtensionCount = reqExtensions.size();
createInfo.ppEnabledExtensionNames = reqExtensions.data();
- if(vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) {
+ if(vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create Vulkan instance!");
}
@@ -192,6 +192,10 @@ private:
}
}
+ void destroyInstance() {
+ vkDestroyInstance(instance, nullptr);
+ }
+
// Check if the validation layers are supported.s
bool checkValidationLayerSupport() {
uint32_t layerCount;
@@ -227,11 +231,17 @@ private:
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
createInfo.pfnCallback = debugCallback;
- if(CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, callback.replace()) != VK_SUCCESS) {
+ if(CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) {
throw std::runtime_error("failed to setup debug callback!");
}
}
+ void cleanupDebugCallback() {
+ if (!enableValidationLayers) return;
+
+ DestroyDebugReportCallbackEXT(instance, callback, nullptr);
+ }
+
// Pick the first suitable physical device, using isDeviceSuitable(VkPhysicalDevice)
void pickPhysicalDevice() {
uint32_t deviceCount = 0;
@@ -368,7 +378,7 @@ private:
createInfo.enabledLayerCount = 0;
}
- if(vkCreateDevice(physicalDevice, &createInfo, nullptr, device.replace()) != VK_SUCCESS) {
+ if(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device!");
}
@@ -376,14 +386,22 @@ private:
vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);
}
+ void destroyLogicalDevice() {
+ vkDestroyDevice(device, nullptr);
+ }
+
// Have GLFW create a surface for us, this lets us not be concerned with the platform-specifics
// involved in surfaces.
void createSurface() {
- if(glfwCreateWindowSurface(instance, window, nullptr, surface.replace()) != VK_SUCCESS) {
+ if(glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!");
}
}
+ void destroySurface() {
+ vkDestroySurfaceKHR(instance, surface, nullptr);
+ }
+
// Find out what formats and present modes the physical device supports.
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
SwapChainSupportDetails details;
@@ -457,7 +475,7 @@ private:
// Create the swap chain that will be used to submit completed frames to
void createSwapChain() {
- SwapChainSupportDetails swapChainSupport= querySwapChainSupport(physicalDevice);
+ SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
@@ -532,8 +550,12 @@ private:
swapChainExtent = extent;
}
+ void destroySwapChain() {
+ vkDestroySwapchainKHR(device, swapChain, nullptr);
+ }
+
void createImageViews() {
- swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView});
+ swapChainImageViews.resize(swapChainImages.size(), VkImageView{});
// For each image in the swap chain create a VkImageView
for(uint32_t i = 0; i < swapChainImages.size(); i++) {
@@ -556,22 +578,28 @@ private:
createInfo.subresourceRange.baseArrayLayer = 0;
createInfo.subresourceRange.layerCount = 1;
- if(vkCreateImageView(device, &createInfo, nullptr, swapChainImageViews[i].replace()) != VK_SUCCESS) {
+ if(vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
throw std::runtime_error("failed to create image views!");
}
}
}
+ void destroyImageViews() {
+ for (uint32_t i = 0; i < swapChainImages.size(); i++) {
+ vkDestroyImageView(device, swapChainImageViews[i], nullptr);
+ }
+ }
+
void createGraphicsPipeline() {
auto vertShaderCode = readFile("shaders/vert.spv");
auto fragShaderCode = readFile("shaders/frag.spv");
- VDeleter vertShaderModule{device, vkDestroyShaderModule};
- VDeleter fragShaderModule{device, vkDestroyShaderModule};
+ VkShaderModule vertShaderModule;
+ VkShaderModule fragShaderModule;
- createShaderModule(vertShaderCode, vertShaderModule);
- createShaderModule(fragShaderCode, fragShaderModule);
+ createShaderModule(vertShaderCode, &vertShaderModule);
+ createShaderModule(fragShaderCode, &fragShaderModule);
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -670,7 +698,7 @@ private:
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.pSetLayouts = nullptr;
- if(vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, pipelineLayout.replace()) != VK_SUCCESS) {
+ if(vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("failed to create pipeline layout!");
}
@@ -696,11 +724,16 @@ private:
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
- if(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, graphicsPipeline.replace()) != VK_SUCCESS) {
+ if(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
}
+ void destroyGraphicsPipeline() {
+ vkDestroyPipeline(device, graphicsPipeline, nullptr);
+ vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
+ }
+
static std::vector readFile(const std::string& filename) {
// Start reading at end of the file, as binary.
std::ifstream file(filename, std::ios::ate | std::ios::binary);
@@ -718,13 +751,13 @@ private:
return buffer;
}
- void createShaderModule(const std::vector& code, VDeleter& shaderModule) {
+ void createShaderModule(const std::vector& code, VkShaderModule* shaderModule) {
VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = (uint32_t*) code.data();
- if(vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) {
+ if(vkCreateShaderModule(device, &createInfo, nullptr, shaderModule) != VK_SUCCESS) {
throw std::runtime_error("failed to create shader module!");
}
}
@@ -770,13 +803,17 @@ private:
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
- if(vkCreateRenderPass(device, &renderPassInfo, nullptr, renderPass.replace()) != VK_SUCCESS) {
+ if(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
throw std::runtime_error("failed to create render pass!");
}
}
+
+ void destroyRenderPass() {
+ vkDestroyRenderPass(device, renderPass, nullptr);
+ }
void createFramebuffers() {
- swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter {device, vkDestroyFramebuffer});
+ swapChainFramebuffers.resize(swapChainImageViews.size(), VkFramebuffer{});
for(size_t i = 0; i < swapChainImageViews.size(); i++) {
VkImageView attachments[] = { swapChainImageViews[i] };
@@ -790,13 +827,19 @@ private:
framebufferInfo.height = swapChainExtent.height;
framebufferInfo.layers = 1;
- if(vkCreateFramebuffer(device, &framebufferInfo, nullptr, swapChainFramebuffers[i].replace()) != VK_SUCCESS) {
+ if(vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
throw std::runtime_error("failed to create framebuffer!");
}
}
}
+ void destroyFramebuffers() {
+ for (size_t i = 0; i < swapChainImageViews.size(); i++) {
+ vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr);
+ }
+ }
+
void createCommandPool() {
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
@@ -805,11 +848,15 @@ private:
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
poolInfo.flags = 0;
- if(vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) {
+ if(vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
throw std::runtime_error("failed to create command pool!");
}
}
+ void destroyCommandPool() {
+ vkDestroyCommandPool(device, commandPool, nullptr);
+ }
+
void createCommandBuffers() {
if(commandBuffers.size() > 0) {
vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data());
@@ -859,17 +906,28 @@ private:
}
}
}
+
+ void destroyCommandBuffers() {
+ if (commandBuffers.size() > 0) {
+ vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data());
+ }
+ }
void createSemaphores() {
VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- if(vkCreateSemaphore(device, &semaphoreInfo, nullptr, imageAvailableSemaphore.replace()) != VK_SUCCESS ||
- vkCreateSemaphore(device, &semaphoreInfo, nullptr, renderFinishedSemaphore.replace()) != VK_SUCCESS) {
+ if(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS ||
+ vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS) {
throw std::runtime_error("failed to create semaphores!");
}
}
+ void destroySemaphores() {
+ vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
+ vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
+ }
+
void mainLoop() {
// While we shouldn't close, have glfw poll for events
while(!glfwWindowShouldClose(window)) {
@@ -878,6 +936,22 @@ private:
}
vkDeviceWaitIdle(device);
+ cleanup();
+ }
+
+ void cleanup() {
+ destroySemaphores();
+ destroyCommandBuffers();
+ destroyCommandPool();
+ destroyFramebuffers();
+ destroyGraphicsPipeline();
+ destroyRenderPass();
+ destroyImageViews();
+ destroySwapChain();
+ destroyLogicalDevice();
+ destroySurface();
+ cleanupDebugCallback();
+ destroyInstance();
}
void drawFrame() {
diff --git a/main.h b/main.h
index 9cc1fd1..89467da 100644
--- a/main.h
+++ b/main.h
@@ -16,65 +16,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT
}
}
-// VDeleter utility class that automatically destroys objects when they fall out of scope.
-template
-class VDeleter {
-public:
- VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {}
-
- VDeleter(std::function deletef) {
- this->deleter = [=](T obj) { deletef(obj, nullptr); };
- }
-
- VDeleter(const VDeleter& instance, std::function deletef) {
- this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); };
- }
-
- VDeleter(const VDeleter& device, std::function deletef) {
- this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); };
- }
-
- ~VDeleter() {
- cleanup();
- }
-
- const T* operator &() const {
- return &object;
- }
-
- T* replace() {
- cleanup();
- return &object;
- }
-
- operator T() const {
- return object;
- }
-
- void operator=(T rhs) {
- if (rhs != object) {
- cleanup();
- object = rhs;
- }
- }
-
- template
- bool operator==(V rhs) {
- return object == T(rhs);
- }
-
-private:
- T object{VK_NULL_HANDLE};
- std::function deleter;
-
- void cleanup() {
- if (object != VK_NULL_HANDLE) {
- deleter(object);
- }
- object = VK_NULL_HANDLE;
- }
-};
-
struct QueueFamilyIndices {
int graphicsFamily = -1;
int presentFamily = -1;