diff --git a/00_Introduction.md b/00_Introduction.md index d507ce21..c043dc89 100644 --- a/00_Introduction.md +++ b/00_Introduction.md @@ -46,6 +46,14 @@ linear algebra library and you will be on your own in terms of code structuring. We will use C++ features like classes and RAII to organize logic and resource lifetimes. +## E-book + +If you prefer to read this tutorial as an e-book, then you can download an EPUB +or PDF version here: + +* [EPUB](https://raw.githubusercontent.com/Overv/VulkanTutorial/master/ebook/Vulkan%20Tutorial.epub) +* [PDF](https://raw.githubusercontent.com/Overv/VulkanTutorial/master/ebook/Vulkan%20Tutorial.pdf) + ## Tutorial structure We'll start with an overview of how Vulkan works and the work we'll have to do diff --git a/03_Drawing_a_triangle/00_Setup/00_Base_code.md b/03_Drawing_a_triangle/00_Setup/00_Base_code.md index c5e6d59f..840e3b06 100644 --- a/03_Drawing_a_triangle/00_Setup/00_Base_code.md +++ b/03_Drawing_a_triangle/00_Setup/00_Base_code.md @@ -16,6 +16,7 @@ public: void run() { initVulkan(); mainLoop(); + cleanup(); } private: @@ -26,6 +27,10 @@ private: void mainLoop() { } + + void cleanup() { + + } }; int main() { @@ -52,6 +57,8 @@ as private class members and add functions to initiate each of them, which will be called from the `initVulkan` function. Once everything has been prepared, we enter the main loop to start rendering frames. We'll fill in the `mainLoop` function to include a loop that iterates until the window is closed in a moment. +Once the window is closed and `mainLoop` returns, we'll make sure to deallocate +the resources we've used in the `cleanup` function. If any kind of fatal error occurs during execution then we'll throw a `std::runtime_error` exception with a descriptive message, which will propagate @@ -61,157 +68,33 @@ extension is not supported. Roughly every chapter that follows after this one will add one new function that will be called from `initVulkan` and one or more new Vulkan objects to the -private class members. +private class members that need to be freed at the end in `cleanup`. ## Resource management -You may have noticed that there's no cleanup function anywhere to be seen and -that is intentional. Every Vulkan object needs to be destroyed with a function -call when it's no longer needed, just like each chunk of memory allocated with -`malloc` requires a call to `free`. Doing that manually is a lot of work and is -very error-prone, but we can completely avoid that by taking advantage of the -C++ [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) -principle. To do that, we're going to create a class that wraps Vulkan objects -and automatically cleans them up when it goes out of scope, for example because -the application was closed. - -First consider the interface we want from this `VDeleter` wrapper class. -Let's say we want to store a `VkInstance` object that should be destroyed with -`vkDestroyInstance` at some point. Then we would add the following class member: - -```c++ -VDeleter instance{vkDestroyInstance}; -``` - -The template argument specifies the type of Vulkan object we want to wrap and -the constructor argument specifies the function to use to clean up the object -when it goes out of scope. - -To assign an object to the wrapper, we would simply want to pass its pointer to -the creation function as if it was a normal `VkInstance` variable: - -```c++ -vkCreateInstance(&instanceCreateInfo, nullptr, &instance); -``` - -Unfortunately, taking the address of the handle in the wrapper doesn't -necessarily mean that we want to overwrite its existing value. A common pattern -is to simply use `&instance` as short-hand for an array of instances with 1 -item. If we intend to write a new handle, then the wrapper should clean up any -previous object to not leak memory. Therefore it would be better to have the `&` -operator return a constant pointer and have an explicit function to state that -we wish to replace the handle. The `replace` function calls clean up for any -existing handle and then gives you a non-const pointer to overwrite the handle: - -```c++ -vkCreateInstance(&instanceCreateInfo, nullptr, instance.replace()); -``` - -Just like that we can now use the `instance` variable wherever a `VkInstance` -would normally be accepted. We no longer have to worry about cleaning up -anymore, because that will automatically happen once the `instance` variable -becomes unreachable! That's pretty easy, right? - -The implementation of such a wrapper class is fairly straightforward. It just -requires a bit of lambda magic to shorten the syntax for specifying the cleanup -functions. - -```c++ -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; - } -}; -``` - -The three non-default constructors allow you to specify all three types of -deletion functions used in Vulkan: - -* `vkDestroyXXX(object, callbacks)`: Only the object itself needs to be passed -to the cleanup function, so we can simply construct a `VDeleter` with just the -function as argument. -* `vkDestroyXXX(instance, object, callbacks)`: A `VkInstance` also -needs to be passed to the cleanup function, so we use the `VDeleter` constructor -that takes the `VkInstance` reference and cleanup function as parameters. -* `vkDestroyXXX(device, object, callbacks)`: Similar to the previous case, but a -`VkDevice` must be passed instead of a `VkInstance`. - -The `callbacks` parameter is optional and we always pass `nullptr` to it, as you -can see in the `VDeleter` definition. - -All of the constructors initialize the object handle with the equivalent of -`nullptr` in Vulkan: `VK_NULL_HANDLE`. Any extra arguments that are needed for -the deleter functions must also be passed, usually the parent object. It -overloads the address-of, assignment, comparison and casting operators to make -the wrapper as transparent as possible. When the wrapped object goes out of -scope, the destructor is invoked, which in turn calls the cleanup function we -specified. - -The address-of operator returns a constant pointer to make sure that the object -within the wrapper is not unexpectedly changed. If you want to replace the -handle within the wrapper through a pointer, then you should use the `replace()` -function instead. It will invoke the cleanup function for the existing handle so -that you can safely overwrite it afterwards. - -There is also a default constructor with a dummy deleter function that can be -used to initialize it later, which will be useful for lists of deleters. - -I've added the class code between the headers and the `HelloTriangleApplication` -class definition. You can also choose to put it in a separate header file. We'll -use it for the first time in the next chapter where we'll create the very first -Vulkan object! +Just like each chunk of memory allocated with `malloc` requires a call to +`free`, every Vulkan object that we create needs to be explicitly destroyed when +we no longer need it. In modern C++ code it is possible to do automatic resource +management through the utilities in the `` header, but I've chosen to be +explicit about allocation and deallocation of Vulkan objects in this tutorial. +After all, Vulkan's niche is to be explicit about every operation to avoid +mistakes, so it's good to be explicit about the lifetime of objects to learn how +the API works. + +After following this tutorial, you could implement automatic resource management +by overloading `std::shared_ptr` for example. Using [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) +to your advantage is the recommended approach for larger Vulkan programs, but +for learning purposes it's always good to know what's going on behind the +scenes. + +Vulkan objects are either created directly with functions like `vkCreateXXX`, or +allocated through another object with functions like `vkAllocateXXX`. After +making sure that an object is no longer used anywhere, you need to destroy it +with the counterparts `vkDestroyXXX` and `vkFreeXXX`. The parameters for these +functions generally vary for different types of objects, but there is one +parameter that they all share: `pAllocator`. This is an optional parameter that +allows you to specify callbacks for a custom memory allocator. We will ignore +this parameter in the tutorial and always pass `nullptr` as argument. ## Integrating GLFW @@ -234,6 +117,7 @@ void run() { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: @@ -305,19 +189,24 @@ void mainLoop() { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } +} +``` +This code should be fairly self-explanatory. It loops and checks for events like +pressing the X button until the window has been closed by the user. This is also +the loop where we'll later call a function to render a single frame. + +Once the window is closed, we need to clean up resources by destroying it and +terminating GLFW itself. This will be our first `cleanup` code: + +```c++ +void cleanup() { glfwDestroyWindow(window); glfwTerminate(); } ``` -This code should be fairly self-explanatory. It loops and checks for events like -pressing the X button until the window has been closed by the user. This is also -the loop where we'll later call a function to render a single frame. Once the -window is closed, we need to clean up resources by destroying it and GLFW] -itself. - When you run the program now you should see a window titled `Vulkan` show up until the application is terminated by closing the window. Now that we have the skeleton for the Vulkan application, let's [create the first Vulkan object](!Drawing_a_triangle/Setup/Instance)! diff --git a/03_Drawing_a_triangle/00_Setup/01_Instance.md b/03_Drawing_a_triangle/00_Setup/01_Instance.md index 19c8a7e5..6c87e1c3 100644 --- a/03_Drawing_a_triangle/00_Setup/01_Instance.md +++ b/03_Drawing_a_triangle/00_Setup/01_Instance.md @@ -14,20 +14,13 @@ void initVulkan() { } ``` -Additionally add a class member to hold the handle to the instance, like we saw -in the resource management section of the previous chapter. +Additionally add a class member to hold the handle to the instance: ```c++ private: -VDeleter instance {vkDestroyInstance}; +VkInstance instance; ``` -The `vkDestroyInstance` function, as you might imagine, will clean up the -instance that we'll create in a moment. The second parameter is optional and -allows you to specify callbacks for a custom allocator. You'll see that most of -the creation and destroy functions have such a callback parameter and we'll -always pass a `nullptr` as argument, as seen in the `VDeleter` definition. - Now, to create an instance we'll first have to fill in a struct with some information about our application. This data is technically optional, but it may provide some useful information to the driver to optimize for our specific @@ -90,7 +83,7 @@ We've now specified everything Vulkan needs to create an instance and we can finally issue the `vkCreateInstance` call: ```c++ -VkResult result = vkCreateInstance(&createInfo, nullptr, instance.replace()); +VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); ``` As you'll see, the general pattern that object creation function parameters in @@ -101,12 +94,12 @@ Vulkan follow is: * Pointer to the variable that stores the handle to the new object If everything went well then the handle to the instance was stored in the -wrapped `VkInstance` class member. Nearly all Vulkan functions return a value of -type `VkResult` that is either `VK_SUCCESS` or an error code. To check if the +`VkInstance` class member. Nearly all Vulkan functions return a value of type +`VkResult` that is either `VK_SUCCESS` or an error code. To check if the instance was created successfully, simply add a check for the success value: ```c++ -if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { +if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } ``` @@ -167,6 +160,27 @@ that checks if all of the extensions returned by `glfwGetRequiredInstanceExtensions` are included in the supported extensions list. +## Cleaning up + +The `VkInstance` should be only destroyed right before the program exits. It can +be destroyed in `cleanup` with the `vkDestroyInstance` function: + +```c++ +void cleanup() { + vkDestroyInstance(instance, nullptr); + + glfwDestroyWindow(window); + + glfwTerminate(); +} +``` + +The parameters for the `vkDestroyInstance` function are straightforward. As +mentioned in the previous chapter, the allocation and deallocation functions +in Vulkan have an optional allocator callback that we'll ignore by passing +`nullptr` to it. All of the other Vulkan resources that we'll create in the +following chapters should be cleaned up before the instance is destroyed. + Before continuing with the more complex steps after instance creation, it's time to evaluate our debugging options by checking out [validation layers](!Drawing_a_triangle/Setup/Validation_layers). diff --git a/03_Drawing_a_triangle/00_Setup/02_Validation_layers.md b/03_Drawing_a_triangle/00_Setup/02_Validation_layers.md index 5a9fa21f..ad95a808 100644 --- a/03_Drawing_a_triangle/00_Setup/02_Validation_layers.md +++ b/03_Drawing_a_triangle/00_Setup/02_Validation_layers.md @@ -155,7 +155,7 @@ validation layer names if they are enabled: ```c++ if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; @@ -205,7 +205,7 @@ We can now use this function in `createInstance`: ```c++ auto extensions = getRequiredExtensions(); -createInfo.enabledExtensionCount = extensions.size(); +createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); ``` @@ -297,7 +297,7 @@ create the `VkDebugReportCallbackEXT` object. Unfortunately, because this function is an extension function, it is not automatically loaded. We have to look up its address ourselves using `vkGetInstanceProcAddr`. We're going to create our own proxy function that handles this in the background. I've added it -right above the `VDeleter` definition. +right above the `HelloTriangleApplication` class definition. ```c++ VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) { @@ -320,18 +320,21 @@ if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != V } ``` -Let's see if it works... Run the program and close the window once you're fed up -with staring at the blank window. You'll see that the following message is -printed to the command prompt: +The second to last parameter is again the optional allocator callback that we +set to `nullptr`, other than that the parameters are fairly straightforward. +Since the debug callback is specific to our Vulkan instance and its layers, it +needs to be explicitly specified as first argument. You will also see this +pattern with other *child* objects later on. Let's see if it works... Run the +program and close the window once you're fed up with staring at the blank +window. You'll see that the following message is printed to the command prompt: ![](/images/validation_layer_test.png) Oops, it has already spotted a bug in our program! The `VkDebugReportCallbackEXT` object needs to be cleaned up with a call to -`vkDestroyDebugReportCallbackEXT`. Change the `callback` variable to use our -deleter wrapper. Similarly to `vkCreateDebugReportCallbackEXT` the function -needs to be explicitly loaded. Create another proxy function right below -`CreateDebugReportCallbackEXT`: +`vkDestroyDebugReportCallbackEXT`. Similarly to `vkCreateDebugReportCallbackEXT` +the function needs to be explicitly loaded. Create another proxy function right +below `CreateDebugReportCallbackEXT`: ```c++ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { @@ -343,20 +346,20 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT ``` Make sure that this function is either a static class function or a function -outside the class. We can then specify it as cleanup function: +outside the class. We can then call it in the `cleanup` function: ```c++ -VDeleter callback{instance, DestroyDebugReportCallbackEXT}; -``` +void cleanup() { + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroyInstance(instance, nullptr); -Make sure to change the line that creates the debug report callback to use the -`replace()` method of the wrapper: + glfwDestroyWindow(window); -```c++ -if (CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, callback.replace()) != VK_SUCCESS) { + glfwTerminate(); +} ``` -When you run the program again you'll see that the error message has +When you run the program again you'll see that the error message has disappeared. If you want to see which call triggered a message, you can add a breakpoint to the message callback and look at the stack trace. diff --git a/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.md b/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.md index 4f090b7f..0eadf032 100644 --- a/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.md +++ b/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.md @@ -22,8 +22,8 @@ void pickPhysicalDevice() { The graphics card that we'll end up selecting will be stored in a VkPhysicalDevice handle that is added as a new class member. This object will be -implicitly destroyed when the VkInstance is destroyed, so we don't need to add a -delete wrapper. +implicitly destroyed when the VkInstance is destroyed, so we won't need to do +anything new in the `cleanup` function. ```c++ VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; diff --git a/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.md b/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.md index 9bfd17c7..8e587973 100644 --- a/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.md +++ b/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.md @@ -7,13 +7,10 @@ need to specify which queues to create now that we've queried which queue families are available. You can even create multiple logical devices from the same physical device if you have varying requirements. -Start by adding a new class member to store the logical device handle in. Make -sure to place the declaration below the `VkInstance` member, because it needs to -be cleaned up before the instance is cleaned up. See [C++ destruction order](https://msdn.microsoft.com/en-us/library/6t4fe76c.aspx). -Logical devices are cleaned up with the `vkDestroyDevice` function. +Start by adding a new class member to store the logical device handle in. ```c++ -VDeleter device{vkDestroyDevice}; +VkDevice device; ``` Next, add a `createLogicalDevice` function that is called from `initVulkan`. @@ -111,7 +108,7 @@ device specific extensions for now. createInfo.enabledExtensionCount = 0; if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; @@ -122,7 +119,7 @@ That's it, we're now ready to instantiate the logical device with a call to the appropriately named `vkCreateDevice` function. ```c++ -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!"); } ``` @@ -133,6 +130,18 @@ to a variable to store the logical device handle in. Similarly to the instance creation function, this call can return errors based on enabling non-existent extensions or specifying the desired usage of unsupported features. +The device should be destroyed in `cleanup` with the `vkDestroyDevice` function: + +```c++ +void cleanup() { + vkDestroyDevice(device, nullptr); + ... +} +``` + +Logical devices don't interact directly with instances, which is why it's not +included as a parameter. + ## Retrieving queue handles The queues are automatically created along with the logical device, but we don't @@ -144,7 +153,7 @@ VkQueue graphicsQueue; ``` Device queues are implicitly cleaned up when the device is destroyed, so we -don't need to wrap it in a deleter object. +don't need to do anything in `cleanup`. We can use the `vkGetDeviceQueue` function to retrieve queue handles for each queue family. The parameters are the logical device, queue family, queue index diff --git a/03_Drawing_a_triangle/01_Presentation/00_Window_surface.md b/03_Drawing_a_triangle/01_Presentation/00_Window_surface.md index b0480c57..fda6fe5c 100644 --- a/03_Drawing_a_triangle/01_Presentation/00_Window_surface.md +++ b/03_Drawing_a_triangle/01_Presentation/00_Window_surface.md @@ -23,10 +23,9 @@ allows you to do that without hacks like creating an invisible window ## Window surface creation Start by adding a `surface` class member right below the debug callback. -Surfaces are destroyed using the `vkDestroySurfaceKHR` call. ```c++ -VDeleter surface{instance, vkDestroySurfaceKHR}; +VkSurfaceKHR surface; ``` Although the `VkSurfaceKHR` object and its usage is platform agnostic, its @@ -67,8 +66,7 @@ allocators and the variable for the surface handle to be stored in. ```c++ auto CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); -if (!CreateWin32SurfaceKHR || CreateWin32SurfaceKHR(instance, &createInfo, - nullptr, surface.replace()) != VK_SUCCESS) { +if (!CreateWin32SurfaceKHR || CreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) { throw std::runtime_error("failed to create window surface!"); } ``` @@ -101,7 +99,7 @@ implementation of the function very straightforward: ```c++ 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!"); } } @@ -109,7 +107,19 @@ void createSurface() { The parameters are the `VkInstance`, GLFW window pointer, custom allocators and pointer to `VkSurfaceKHR` variable. It simply passes through the `VkResult` from -the relevant platform call. +the relevant platform call. GLFW doesn't offer a special function for destroying +a surface, but that can easily be done through the original API: + +```c++ +void cleanup() { + ... + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); + ... + } +``` + +Make sure that the surface is destroyed before the instance. ## Querying for presentation support @@ -200,8 +210,8 @@ for (int queueFamily : uniqueQueueFamilies) { And modify `VkDeviceCreateInfo` to point to the vector: ```c++ +createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); -createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); ``` If the queue families are the same, then we only need to pass its index once. diff --git a/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md b/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md index 67675070..fe448b29 100644 --- a/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md +++ b/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md @@ -85,7 +85,7 @@ Enabling the extension just requires a small change to the logical device creation structure: ```c++ -createInfo.enabledExtensionCount = deviceExtensions.size(); +createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); ``` @@ -531,26 +531,32 @@ be specified in this field. This is a complex topic that we'll learn more about in [a future chapter](!Drawing_a_triangle/Swap_chain_recreation). For now we'll assume that we'll only ever create one swap chain. -Now add a class member to store the `VkSwapchainKHR` object with a proper -deleter. Make sure to add it after `device` so that it gets cleaned up before -the logical device is. +Now add a class member to store the `VkSwapchainKHR` object: ```c++ -VDeleter swapChain{device, vkDestroySwapchainKHR}; +VkSwapchainKHR swapChain; ``` -Now creating the swap chain is as simple as calling `vkCreateSwapchainKHR`: +Creating the swap chain is now as simple as calling `vkCreateSwapchainKHR`: ```c++ -if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { +if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } ``` The parameters are the logical device, swap chain creation info, optional custom allocators and a pointer to the variable to store the handle in. No surprises -there. Now run the application to ensure that the swap chain is created -successfully! +there. It should be cleaned up using `vkDestroySwapchainKHR` before the device: + +```c++ +void cleanup() { + vkDestroySwapchainKHR(device, swapChain, nullptr); + ... +} +``` + +Now run the application to ensure that the swap chain is created successfully! Try removing the `createInfo.imageExtent = extent;` line with validation layers enabled. You'll see that one of the validation layers immediately catches the @@ -570,7 +576,7 @@ std::vector swapChainImages; The images were created by the implementation for the swap chain and they will be automatically cleaned up once the swap chain has been destroyed, therefore we -don't need a deleter here. +don't need to add any cleanup code. I'm adding the code to retrieve the handles to the end of the `createSwapChain` function, right after the `vkCreateSwapchainKHR` call. Retrieving them is very @@ -593,7 +599,7 @@ One last thing, store the format and extent we've chosen for the swap chain images in member variables. We'll need them in future chapters. ```c++ -VDeleter swapChain{device, vkDestroySwapchainKHR}; +VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; @@ -605,7 +611,8 @@ swapChainExtent = extent; ``` We now have a set of images that can be drawn onto and can be presented to the -window. The next two chapters will cover how we can set up the images as render -targets and then we start looking into the actual drawing commands! +window. The next chapter will begin to cover how we can set up the images as +render targets and then we start looking into the actual graphics pipeline and +drawing commands! [C++ code](/code/swap_chain_creation.cpp) diff --git a/03_Drawing_a_triangle/01_Presentation/02_Image_views.md b/03_Drawing_a_triangle/01_Presentation/02_Image_views.md index ede9da42..c44aa8a9 100644 --- a/03_Drawing_a_triangle/01_Presentation/02_Image_views.md +++ b/03_Drawing_a_triangle/01_Presentation/02_Image_views.md @@ -8,12 +8,10 @@ In this chapter we'll write a `createImageViews` function that creates a basic image view for every image in the swap chain so that we can use them as color targets later on. -First add a class member to store the image views in. Unlike the `VkImage`s, the -`VkImageView` objects are created by us so we need to clean them up ourselves -later. +First add a class member to store the image views in: ```c++ -std::vector> swapChainImageViews; +std::vector swapChainImageViews; ``` Create the `createImageViews` function and call it right after swap chain @@ -36,21 +34,19 @@ void createImageViews() { ``` The first thing we need to do is resize the list to fit all of the image views -we'll be creating. This is also the place where we'll actually define the -deleter function. +we'll be creating: ```c++ void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); } ``` -The `resize` function initializes all of the list items with the right deleter. Next, set up the loop that iterates over all of the swap chain images. ```c++ -for (uint32_t i = 0; i < swapChainImages.size(); i++) { +for (size_t i = 0; i < swapChainImages.size(); i++) { } ``` @@ -105,14 +101,23 @@ different layers. Creating the image view is now a matter of calling `vkCreateImageView`: ```c++ -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!"); } ``` -That's it, now run the program to verify that the image views are created -properly and destroyed properly. Checking the latter requires enabling the -validation layers, or putting a print statement in the deleter function. +Unlike images, the image views were explicitly created by us, so we need to add +a similar loop to destroy them again at the end of the program: + +```c++ +void cleanup() { + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + ... +} +``` An image view is sufficient to start using an image as a texture, but it's not quite ready to be used as a render target just yet. That requires one more step diff --git a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.md b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.md index 66440e6d..1266ae4f 100644 --- a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.md +++ b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.md @@ -350,15 +350,13 @@ Before we can pass the code to the pipeline, we have to wrap it in a do that. ```c++ -void createShaderModule(const std::vector& code, VDeleter& shaderModule) { +VkShaderModule createShaderModule(const std::vector& code) { } ``` The function will take a buffer with the bytecode as parameter and create a -`VkShaderModule` from it. Instead of returning this handle directly, it's -written to the variable specified for the second parameter, which makes it -easier to wrap it in a deleter variable when calling `createShaderModule`. +`VkShaderModule` from it. Creating a shader module is simple, we only need to specify a pointer to the buffer with the bytecode and the length of it. This information is specified in @@ -380,7 +378,8 @@ createInfo.pCode = codeAligned.data(); The `VkShaderModule` can then be created with a call to `vkCreateShaderModule`: ```c++ -if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { +VkShaderModule shaderModule; +if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } ``` @@ -395,17 +394,26 @@ process, so instead of declaring them as class members, we'll make them local variables in the `createGraphicsPipeline` function: ```c++ -VDeleter vertShaderModule{device, vkDestroyShaderModule}; -VDeleter fragShaderModule{device, vkDestroyShaderModule}; +VkShaderModule vertShaderModule; +VkShaderModule fragShaderModule; ``` -They will be automatically cleaned up when the graphics pipeline has been -created and `createGraphicsPipeline` returns. Now just call the helper function -we created and we're done: +Call the helper function we created to load the shader modules: ```c++ -createShaderModule(vertShaderCode, vertShaderModule); -createShaderModule(fragShaderCode, fragShaderModule); +vertShaderModule = createShaderModule(vertShaderCode); +fragShaderModule = createShaderModule(fragShaderCode); +``` + +They should be cleaned up when the graphics pipeline has been created and +`createGraphicsPipeline` returns, so make sure that they are deleted at the end +of the function: + +```c++ + ... + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); +} ``` ## Shader stage creation diff --git a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md index f5df4293..2f4a361e 100644 --- a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md +++ b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md @@ -213,7 +213,7 @@ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisampling.minSampleShading = 1.0f; // Optional -multisampling.pSampleMask = nullptr; /// Optional +multisampling.pSampleMask = nullptr; // Optional multisampling.alphaToCoverageEnable = VK_FALSE; // Optional multisampling.alphaToOneEnable = VK_FALSE; // Optional ``` @@ -301,7 +301,7 @@ You can find all of the possible operations in the `VkBlendFactor` and The second structure references the array of structures for all of the framebuffers and allows you to set blend constants that you can use as blend -factors in the aforementioned calculations. +factors in the aforementioned calculations. ```c++ VkPipelineColorBlendStateCreateInfo colorBlending = {}; @@ -365,7 +365,7 @@ Create a class member to hold this object, because we'll refer to it from other functions at a later point in time: ```c++ -VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; +VkPipelineLayout pipelineLayout; ``` And then create the object in the `createGraphicsPipeline` function: @@ -378,14 +378,22 @@ pipelineLayoutInfo.pSetLayouts = nullptr; // Optional pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional pipelineLayoutInfo.pPushConstantRanges = 0; // Optional -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!"); } ``` The structure also specifies *push constants*, which are another way of passing -dynamic values to shaders that we'll get into later. +dynamic values to shaders that we may get into in a future chapter. The pipeline +layout is may be referenced throughout the program's lifetime, so it should be +destroyed at the end: + +```c++ +void cleanup() { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + ... +} +``` ## Conclusion @@ -400,4 +408,4 @@ graphics pipeline and that is a [render pass](!Drawing_a_triangle/Graphics_pipel [C++ code](/code/fixed_functions.cpp) / [Vertex shader](/code/shader_base.vert) / -[Fragment shader](/code/shader_base.frag) \ No newline at end of file +[Fragment shader](/code/shader_base.frag) diff --git a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Render_passes.md b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Render_passes.md index 91506657..4ff24b0f 100644 --- a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Render_passes.md +++ b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Render_passes.md @@ -41,8 +41,9 @@ void createRenderPass() { } ``` -The `format` of the color attachment should match the one of the swap chain -images and we're not doing anything with multisampling, so we stick to 1 sample. +The `format` of the color attachment should match the format of the swap chain +images, and we're not doing anything with multisampling, so we'll stick to 1 +sample. ```c++ colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -173,7 +174,8 @@ we can create the render pass itself. Create a new class member variable to hold the `VkRenderPass` object right above the `pipelineLayout` variable: ```c++ -VDeleter renderPass{device, vkDestroyRenderPass}; +VkRenderPass renderPass; +VkPipelineLayout pipelineLayout; ``` The render pass object can then be created by filling in the @@ -189,14 +191,25 @@ renderPassInfo.pAttachments = &colorAttachment; renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; -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!"); } ``` +Just like the pipeline layout, the render pass will be referenced throughout the +program, so it should only be cleaned up at the end: + +```c++ +void cleanup() { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + ... +} +``` + That was a lot of work, but in the next chapter it all comes together to finally create the graphics pipeline object! [C++ code](/code/render_passes.cpp) / [Vertex shader](/code/shader_base.vert) / -[Fragment shader](/code/shader_base.frag) \ No newline at end of file +[Fragment shader](/code/shader_base.frag) diff --git a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.md b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.md index 6ff4db9c..d77e1e8d 100644 --- a/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.md +++ b/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.md @@ -73,13 +73,13 @@ Now prepare for the final step by creating a class member to hold the `VkPipeline` object: ```c++ -VDeleter graphicsPipeline{device, vkDestroyPipeline}; +VkPipeline graphicsPipeline; ``` And finally create the graphics pipeline: ```c++ -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!"); } ``` @@ -96,6 +96,17 @@ store and reuse data relevant to pipeline creation across multiple calls to stored to a file. This makes it possible to significantly speed up pipeline creation at a later time. We'll get into this in the pipeline cache chapter. +The graphics pipeline is required for all common drawing operations, so it +should also only be destroyed at the end of the program: + +```c++ +void cleanup() { + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + ... +} +``` + Now run your program to confirm that all this hard work has resulted in a successful pipeline creation! We are already getting quite close to seeing something pop up on the screen. In the next couple of chapters we'll set up the diff --git a/03_Drawing_a_triangle/03_Drawing/00_Framebuffers.md b/03_Drawing_a_triangle/03_Drawing/00_Framebuffers.md index cbf65363..2fe9262d 100644 --- a/03_Drawing_a_triangle/03_Drawing/00_Framebuffers.md +++ b/03_Drawing_a_triangle/03_Drawing/00_Framebuffers.md @@ -14,7 +14,7 @@ at drawing time. To that end, create another `std::vector` class member to hold the framebuffers: ```c++ -std::vector> swapChainFramebuffers; +std::vector swapChainFramebuffers; ``` We'll create the objects for this array in a new function `createFramebuffers` @@ -45,7 +45,7 @@ Start by resizing the container to hold all of the framebuffers: ```c++ void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); } ``` @@ -66,7 +66,7 @@ for (size_t i = 0; i < swapChainImageViews.size(); i++) { 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!"); } } @@ -85,6 +85,19 @@ The `width` and `height` parameters are self-explanatory and `layers` refers to the number of layers in image arrays. Our swap chain images are single images, so the number of layers is `1`. +We should delete the framebuffers before the image views and render pass that +they are based on, but only after we've finished rendering: + +```c++ +void cleanup() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + ... +} +``` + We've now reached the milestone where we have all of the objects that are required for rendering. In the next chapter we're going to write the first actual drawing commands. diff --git a/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.md b/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.md index 740495b2..7cbe7b43 100644 --- a/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.md +++ b/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.md @@ -12,7 +12,7 @@ pools manage the memory that is used to store the buffers and command buffers are allocated from them. Add a new class member to store a `VkCommandPool`: ```c++ -VDeleter commandPool{device, vkDestroyCommandPool}; +VkCommandPool commandPool; ``` Then create a new function `createCommandPool` and call it from `initVulkan` @@ -69,13 +69,23 @@ execute them many times in the main loop, so we're not going to use either of these flags. ```c++ -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!"); } ``` Finish creating the command pool using the `vkCreateCommandPool` function. It -doesn't have any special parameters. +doesn't have any special parameters. Commands will be used throughout the +program to draw things on the screen, so the pool should only be destroyed at +the end: + +```c++ +void cleanup() { + vkDestroyCommandPool(device, commandPool, nullptr); + + ... +} +``` ## Command buffer allocation @@ -84,7 +94,7 @@ them. Because one of the drawing commands involves binding the right `VkFramebuffer`, we'll actually have to record a command buffer for every image in the swap chain once again. To that end, create a list of `VkCommandBuffer` objects as class member. Command buffers will be automatically freed when their -command pool is destroyed, so we don't need a `VDeleter`. +command pool is destroyed, so we don't need an explicit cleanup. ```c++ std::vector commandBuffers; diff --git a/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.md b/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.md index 9252153e..87ee4063 100644 --- a/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.md +++ b/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.md @@ -55,8 +55,8 @@ presentation can happen. Create two class members to store these semaphore objects: ```c++ -VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; -VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; +VkSemaphore imageAvailableSemaphore; +VkSemaphore renderFinishedSemaphore; ``` To create the semaphores, we'll add the last `create` function for this part of @@ -102,13 +102,22 @@ Future versions of the Vulkan API or extensions may add functionality for the the semaphores follows the familiar pattern with `vkCreateSemaphore`: ```c++ -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!"); } ``` +The semaphores should be cleaned up at the end of the program, when all commands +have finished and no more synchronization is necessary: + +```c++ +void cleanup() { + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); +``` + ## Acquiring an image from the swap chain As mentioned before, the first thing we need to do in the `drawFrame` function @@ -310,8 +319,8 @@ something resembling the following when you run your program: ![](/images/triangle.png) Yay! Unfortunately, you'll see that when validation layers are enabled, the -program crashes as soon as you close it. The message printed to the terminal -from `debugCallback` tells us why: +program crashes as soon as you close it. The messages printed to the terminal +from `debugCallback` tell us why: ![](/images/semaphore_in_use.png) @@ -331,8 +340,6 @@ void mainLoop() { } vkDeviceWaitIdle(device); - - glfwDestroyWindow(window); } ``` diff --git a/03_Drawing_a_triangle/04_Swap_chain_recreation.md b/03_Drawing_a_triangle/04_Swap_chain_recreation.md index 322dc929..0b65374f 100644 --- a/03_Drawing_a_triangle/04_Swap_chain_recreation.md +++ b/03_Drawing_a_triangle/04_Swap_chain_recreation.md @@ -36,58 +36,82 @@ avoid this by using dynamic state for the viewports and scissor rectangles. Finally, the framebuffers and command buffers also directly depend on the swap chain images. -Because of our handy `VDeleter` construct, most of the functions will work fine -for recreation and will automatically clean up the old objects. However, the -`createSwapChain` and `createCommandBuffers` functions still need some -adjustments. +To make sure that the old versions of these objects are cleaned up before +recreating them, we should move some of the cleanup code to a separate function +that we can call from the `recreateSwapChain` function. Let's call it +`cleanupSwapChain`: ```c++ -VkSwapchainKHR oldSwapChain = swapChain; -createInfo.oldSwapchain = oldSwapChain; - -VkSwapchainKHR newSwapChain; -if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { - throw std::runtime_error("failed to create swap chain!"); +void cleanupSwapChain() { + } -swapChain = newSwapChain; +void recreateSwapChain() { + vkDeviceWaitIdle(device); + + cleanupSwapChain(); + + createSwapChain(); + createImageViews(); + createRenderPass(); + createGraphicsPipeline(); + createFramebuffers(); + createCommandBuffers(); +} ``` -We need to pass the previous swap chain object in the `oldSwapchain` parameter -of `VkSwapchainCreateInfoKHR` to indicate that we intend to replace it. The old -swap chain needs to stick around until after the new swap chain has been -created, which means that we can't directly write the new handle to `swapChain`. -The `VDeleter` would clear the old object before `vkCreateSwapchainKHR` has a -chance to execute. That's why we use the temporary `newSwapChain` variable. +we'll move the cleanup code of all objects that are recreated as part of a swap +chain refresh from `cleanup` to `cleanupSwapChain`: ```c++ -swapChain = newSwapChain; -``` - -This line will actually destroy the old swap chain and replace the handle with -the handle of the new swap chain. +void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } -The problem with `createCommandBuffers` is that it doesn't free the old command -buffers. There are two ways to solve this: + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); -* Call `createCommandPool` as well, which will automatically free the old -command buffers -* Extend `createCommandBuffers` to free any previous command buffers + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); -As there isn't really a need to recreate the command pool itself, I've chosen to -go for the second solution in this tutorial. + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } -```c++ -if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); + vkDestroySwapchainKHR(device, swapChain, nullptr); } -commandBuffers.resize(swapChainFramebuffers.size()); +void cleanup() { + cleanupSwapChain(); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); + + glfwDestroyWindow(window); + + glfwTerminate(); +} ``` -The `createCommandBuffers` function now first checks if the `commandBuffers` -vector already contains previous command buffers, and if so, frees them. That's -all it takes to recreate the swap chain! +We could recreate the command pool from scratch, but that is rather wasteful. +Instead I've opted to clean up the existing command buffers with the +`vkFreeCommandBuffers` function. This way we can reuse the existing pool to +allocate the new command buffers. + +That's all it takes to recreate the swap chain! However, the disadvantage of +this approach is that we need to stop all rendering before creating the new swap +chain. It is possible to create a new swap chain while drawing commands on an +image from the old swap chain are still in-flight. You need to pass the previous +swap chain to the `oldSwapChain` field in the `VkSwapchainCreateInfoKHR` struct +and destroy the old swap chain as soon as you've finished using it. ## Window resizing diff --git a/04_Vertex_buffers/00_Vertex_input_description.md b/04_Vertex_buffers/00_Vertex_input_description.md index a6c47c64..c52b6fa2 100644 --- a/04_Vertex_buffers/00_Vertex_input_description.md +++ b/04_Vertex_buffers/00_Vertex_input_description.md @@ -202,7 +202,7 @@ auto bindingDescription = Vertex::getBindingDescription(); auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; -vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); +vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); ``` diff --git a/04_Vertex_buffers/01_Vertex_buffer_creation.md b/04_Vertex_buffers/01_Vertex_buffer_creation.md index 2fcd41f2..4b498b32 100644 --- a/04_Vertex_buffers/01_Vertex_buffer_creation.md +++ b/04_Vertex_buffers/01_Vertex_buffer_creation.md @@ -74,7 +74,7 @@ We can now create the buffer with `vkCreateBuffer`. Define a class member to hold the buffer handle and call it `vertexBuffer`. ```c++ -VDeleter vertexBuffer{device, vkDestroyBuffer}; +VkBuffer vertexBuffer; ... @@ -85,12 +85,26 @@ void createVertexBuffer() { bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, vertexBuffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) { throw std::runtime_error("failed to create vertex buffer!"); } } ``` +The buffer should be available for use in rendering commands until the end of +the program and it does not depend on the swap chain, so we'll clean it up in +the original `cleanup` function: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + + ... +} +``` + ## Memory requirements The buffer has been created, but it doesn't actually have any memory assigned to @@ -199,20 +213,16 @@ desired property. Create a class member to store the handle to the memory and allocate it with `vkAllocateMemory`. ```c++ -VDeleter vertexBuffer{device, vkDestroyBuffer}; -VDeleter vertexBufferMemory{device, vkFreeMemory}; +VkBuffer vertexBuffer; +VkDeviceMemory vertexBufferMemory; ... -if (vkAllocateMemory(device, &allocInfo, nullptr, vertexBufferMemory.replace()) != VK_SUCCESS) { +if (vkAllocateMemory(device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate vertex buffer memory!"); } ``` -Note that specifying the `vertexBuffer` and `vertexBufferMemory` members in this -order will cause the memory to be freed before the buffer is destroyed, but -that's allowed as long as the buffer is no longer used. - If memory allocation was successful, then we can now associate this memory with the buffer using `vkBindBufferMemory`: @@ -225,6 +235,19 @@ offset within the region of memory. Since this memory is allocated specifically for this the vertex buffer, the offset is simply `0`. If the offset is non-zero, then it is required to be divisible by `memRequirements.alignment`. +Of course, just like dynamic memory allocation in C++, the memory should be +freed at some point. Memory that is bound to a buffer object may be freed once +the buffer is no longer used, so let's free it after the buffer has been +destroyed: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); +``` + ## Filling the vertex buffer It is now time to copy the vertex data to the buffer. This is done by [mapping @@ -279,7 +302,7 @@ VkBuffer vertexBuffers[] = {vertexBuffer}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets); -vkCmdDraw(commandBuffers[i], vertices.size(), 1, 0, 0); +vkCmdDraw(commandBuffers[i], static_cast(vertices.size()), 1, 0, 0); ``` The `vkCmdBindVertexBuffers` function is used to bind vertex buffers to diff --git a/04_Vertex_buffers/02_Staging_buffer.md b/04_Vertex_buffers/02_Staging_buffer.md index ea166480..7140d5c6 100644 --- a/04_Vertex_buffers/02_Staging_buffer.md +++ b/04_Vertex_buffers/02_Staging_buffer.md @@ -44,14 +44,14 @@ to move buffer creation to a helper function. Create a new function `createBuffer` and move the code in `createVertexBuffer` (except mapping) to it. ```c++ -void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { +void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -63,7 +63,7 @@ void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyF allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -101,8 +101,8 @@ as temporary buffer and use a device local one as actual vertex buffer. void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -229,6 +229,19 @@ createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERT copyBuffer(stagingBuffer, vertexBuffer, bufferSize); ``` +After copying the data from the staging buffer to the device buffer, we should +clean it up: + +```c++ + ... + + copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); +} +``` + Run your program to verify that you're seeing the familiar triangle again. It may not be visible, but its vertex data is now being loaded from high performance memory. This will matter when we're going to start rendering more diff --git a/04_Vertex_buffers/03_Index_buffer.md b/04_Vertex_buffers/03_Index_buffer.md index e0323de8..cd110dbb 100644 --- a/04_Vertex_buffers/03_Index_buffer.md +++ b/04_Vertex_buffers/03_Index_buffer.md @@ -54,10 +54,10 @@ the GPU to be able to access them. Define two new class members to hold the resources for the index buffer: ```c++ -VDeleter vertexBuffer{device, vkDestroyBuffer}; -VDeleter vertexBufferMemory{device, vkFreeMemory}; -VDeleter indexBuffer{device, vkDestroyBuffer}; -VDeleter indexBufferMemory{device, vkFreeMemory}; +VkBuffer vertexBuffer; +VkDeviceMemory vertexBufferMemory; +VkBuffer indexBuffer; +VkDeviceMemory indexBufferMemory; ``` The `createIndexBuffer` function that we'll add now is almost identical to @@ -74,8 +74,8 @@ void initVulkan() { void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -86,6 +86,9 @@ void createIndexBuffer() { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } ``` @@ -97,6 +100,23 @@ number of indices times the size of the index type, either `uint16_t` or process is exactly the same. We create a staging buffer to copy the contents of `indices` to and then copy it to the final device local index buffer. +The index buffer should be cleaned up at the end of the program, just like the +vertex buffer: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + ... +} +``` + ## Using an index buffer Using an index buffer for drawing involves two changes to @@ -122,7 +142,7 @@ the drawing command to tell Vulkan to use the index buffer. Remove the `vkCmdDraw` line and replace it with `vkCmdDrawIndexed`: ```c++ -vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); +vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); ``` A call to this function is very similar to `vkCmdDraw`. The first two parameters diff --git a/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md b/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md index eb275d5d..0a28bb10 100644 --- a/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md +++ b/05_Uniform_buffers/00_Descriptor_layout_and_buffer.md @@ -174,8 +174,8 @@ All of the descriptor bindings are combined into a single `pipelineLayout`: ```c++ -VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; -VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; +VkDescriptorSetLayout descriptorSetLayout; +VkPipelineLayout pipelineLayout; ``` We can then create it using `vkCreateDescriptorSetLayout`. This function accepts @@ -187,7 +187,7 @@ layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; -if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { +if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } ``` @@ -198,11 +198,10 @@ specified in the pipeline layout object. Modify the `VkPipelineLayoutCreateInfo` to reference the layout object: ```c++ -VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; -pipelineLayoutInfo.pSetLayouts = setLayouts; +pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; ``` You may be wondering why it's possible to specify multiple descriptor set @@ -210,28 +209,39 @@ layouts here, because a single one already includes all of the bindings. We'll get back to that in the next chapter, where we'll look into descriptor pools and descriptor sets. +The descriptor layout should stick around while we may create new graphics +pipelines i.e. until the program ends: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + + ... +} +``` + ## Uniform buffer In the next chapter we'll specify the buffer that contains the UBO data for the shader, but we need to create this buffer first. We're going to copy new data to -the uniform buffer every frame, so this time the staging buffer actually needs -to stick around. +the uniform buffer every frame, so it doesn't really make any sense to have a +staging buffer. It would just add extra overhead in this case and likely degrade +performance instead of improving it. -Add new class members for `uniformStagingBuffer`, `uniformStagingBufferMemory`, -`uniformBuffer`, and `uniformBufferMemory`: +Add new class members for `uniformBuffer`, and `uniformBufferMemory`: ```c++ -VDeleter indexBuffer{device, vkDestroyBuffer}; -VDeleter indexBufferMemory{device, vkFreeMemory}; +VkBuffer indexBuffer; +VkDeviceMemory indexBufferMemory; -VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; -VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; -VDeleter uniformBuffer{device, vkDestroyBuffer}; -VDeleter uniformBufferMemory{device, vkFreeMemory}; +VkBuffer uniformBuffer; +VkDeviceMemory uniformBufferMemory; ``` Similarly, create a new function `createUniformBuffer` that is called after -`createIndexBuffer` and allocates the buffers: +`createIndexBuffer` and allocates the buffer: ```c++ void initVulkan() { @@ -246,15 +256,31 @@ void initVulkan() { void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } ``` We're going to write a separate function that updates the uniform buffer with a -new transformation every frame, so there will be no `vkMapMemory` and -`copyBuffer` operations here. +new transformation every frame, so there will be no `vkMapMemory` here. The +uniform data will be used for all draw calls, so the buffer containing it should +only be destroyed at the end: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + ... +} +``` + +## Updating uniform data + +Create a new function `updateUniformBuffer` and add a call to it from the main +loop: ```c++ void mainLoop() { @@ -266,8 +292,6 @@ void mainLoop() { } vkDeviceWaitIdle(device); - - glfwDestroyWindow(window); } ... @@ -277,10 +301,7 @@ void updateUniformBuffer() { } ``` -## Updating uniform data - -Create a new function `updateUniformBuffer` and add a call to it from the main -loop. This function will generate a new transformation every frame to make the +This function will generate a new transformation every frame to make the geometry spin around. We need to include two new headers to implement this functionality: @@ -359,21 +380,18 @@ do this, then the image will be rendered upside down. All of the transformations are defined now, so we can copy the data in the uniform buffer object to the uniform buffer. This happens in exactly the same -way as we did for vertex buffers with a staging buffer: +way as we did for vertex buffers, except without a staging buffer: ```c++ void* data; -vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); +vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); -vkUnmapMemory(device, uniformStagingBufferMemory); - -copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); +vkUnmapMemory(device, uniformBufferMemory); ``` -Using a staging buffer and final buffer this way is not the most efficient way -to pass frequently changing values to the shader. A more efficient way to pass a -small buffer of data to shaders are *push constants*. We may look at these in a -future chapter. +Using a UBO this way is not the most efficient way to pass frequently changing +values to the shader. A more efficient way to pass a small buffer of data to +shaders are *push constants*. We may look at these in a future chapter. In the next chapter we'll look at descriptor sets, which will actually bind the `VkBuffer` to the uniform buffer descriptor so that the shader can access this @@ -381,4 +399,4 @@ transformation data. [C++ code](/code/descriptor_layout.cpp) / [Vertex shader](/code/shader_ubo.vert) / -[Fragment shader](/code/shader_ubo.frag) +[Fragment shader](/code/shader_ubo.frag) \ No newline at end of file diff --git a/05_Uniform_buffers/01_Descriptor_pool_and_sets.md b/05_Uniform_buffers/01_Descriptor_pool_and_sets.md index 119bd8f7..ee581dc9 100644 --- a/05_Uniform_buffers/01_Descriptor_pool_and_sets.md +++ b/05_Uniform_buffers/01_Descriptor_pool_and_sets.md @@ -60,17 +60,28 @@ the descriptor set after creating it, so we don't need this flag. You can leave `flags` to its default value of `0`. ```c++ -VDeleter descriptorPool{device, vkDestroyDescriptorPool}; +VkDescriptorPool descriptorPool; ... -if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { +if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } ``` Add a new class member to store the handle of the descriptor pool and call -`vkCreateDescriptorPool` to create it. +`vkCreateDescriptorPool` to create it. The descriptor pool should be destroyed +only at the end of the program, much like the other drawing related resources: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + ... +} +``` ## Descriptor set @@ -109,7 +120,7 @@ Add a class member to hold the descriptor set handle and allocate it with `vkAllocateDescriptorSets`: ```c++ -VDeleter descriptorPool{device, vkDestroyDescriptorPool}; +VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; ... @@ -119,7 +130,7 @@ if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) } ``` -You don't need to use a deleter for descriptor sets, because they will be +You don't need to explicitly clean up descriptor sets, because they will be automatically freed when the descriptor pool is destroyed. The call to `vkAllocateDescriptorSets` will allocate one descriptor set with one uniform buffer descriptor. @@ -182,8 +193,8 @@ vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); The updates are applied using `vkUpdateDescriptorSets`. It accepts two kinds of arrays as parameters: an array of `VkWriteDescriptorSet` and an array of -`VkCopyDescriptorSet`. The latter can be used to copy the configuration of -descriptors, as its name implies. +`VkCopyDescriptorSet`. The latter can be used to copy descriptors to each other, +as its name implies. ## Using a descriptor set @@ -208,7 +219,7 @@ visible. The problem is that because of the Y-flip we did in the projection matrix, the vertices are now being drawn in clockwise order instead of counter-clockwise order. This causes backface culling to kick in and prevents any geometry from being drawn. Go to the `createGraphicsPipeline` function and -modify the `cullFace` in `VkPipelineRasterizationStateCreateInfo` to correct +modify the `frontFace` in `VkPipelineRasterizationStateCreateInfo` to correct this: ```c++ diff --git a/06_Texture_mapping/00_Images.md b/06_Texture_mapping/00_Images.md index 84ab051d..e3151759 100644 --- a/06_Texture_mapping/00_Images.md +++ b/06_Texture_mapping/00_Images.md @@ -148,8 +148,8 @@ as texels and we'll use that name from this point on. Add the following two variables in the `createTextureImage` function: ```c++ -VDeleter stagingImage{device, vkDestroyImage}; -VDeleter stagingImageMemory{device, vkFreeMemory}; +VkImage stagingImage; +VkDeviceMemory stagingImageMemory; ``` The parameters for an image are specified in a `VkImageCreateInfo` struct: @@ -244,7 +244,7 @@ avoid allocating memory to store large volumes of "air" values. We won't be using it in this tutorial, so leave it to its default value of `0`. ```c++ -if (vkCreateImage(device, &imageInfo, nullptr, stagingImage.replace()) != VK_SUCCESS) { +if (vkCreateImage(device, &imageInfo, nullptr, &stagingImage) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } ``` @@ -266,7 +266,7 @@ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); -if (vkAllocateMemory(device, &allocInfo, nullptr, stagingImageMemory.replace()) != VK_SUCCESS) { +if (vkAllocateMemory(device, &allocInfo, nullptr, &stagingImageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -378,7 +378,7 @@ for buffers. Create the function and move the image object creation and memory allocation to it: ```c++ -void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { +void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -394,7 +394,7 @@ void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -406,7 +406,7 @@ void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -430,8 +430,8 @@ void createTextureImage() { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -465,10 +465,10 @@ The next step is to create the actual texture image. Define two new class members to hold the handle to the image and its memory: ```c++ -VDeleter commandPool{device, vkDestroyCommandPool}; -VDeleter textureImage{device, vkDestroyImage}; -VDeleter textureImageMemory{device, vkFreeMemory}; -VDeleter vertexBuffer{device, vkDestroyBuffer}; +VkCommandPool commandPool; +VkImage textureImage; +VkDeviceMemory textureImageMemory; +VkBuffer vertexBuffer; ``` The final texture image can now be created using the same function: @@ -787,6 +787,32 @@ it's also possible to use a buffer and copy pixels from it using performance on [some hardware](https://developer.nvidia.com/vulkan-memory-management) if you need to update the data in an image often. +## Cleanup + +Finish the `createTextureImage` function by cleaning up the staging image and +its memory at the end: + +```c++ + transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); +} +``` + +The main texture image is used until the end of the program: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + ... +} +``` + The image now contains the texture, but we still need a way to access it from the graphics pipeline. We'll work on that in the next chapter. diff --git a/06_Texture_mapping/01_Image_view_and_sampler.md b/06_Texture_mapping/01_Image_view_and_sampler.md index cf658e46..f40a96b5 100644 --- a/06_Texture_mapping/01_Image_view_and_sampler.md +++ b/06_Texture_mapping/01_Image_view_and_sampler.md @@ -13,7 +13,7 @@ Add a class member to hold a `VkImageView` for the texture image and create a new function `createTextureImageView` where we'll create it: ```c++ -VDeleter textureImageView{device, vkDestroyImageView}; +VkImageView textureImageView; ... @@ -53,7 +53,7 @@ I've left out the explicit `viewInfo.components` initialization, because image view by calling `vkCreateImageView`: ```c++ -if (vkCreateImageView(device, &viewInfo, nullptr, textureImageView.replace()) != VK_SUCCESS) { +if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } ``` @@ -62,7 +62,7 @@ Because so much of the logic is duplicated from `createImageViews`, you may wish to abstract it into a new `createImageView` function: ```c++ -void createImageView(VkImage image, VkFormat format, VDeleter& imageView) { +VkImageView createImageView(VkImage image, VkFormat format) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; @@ -74,9 +74,12 @@ void createImageView(VkImage image, VkFormat format, VDeleter& imag viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) { + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } + + return imageView; } ``` @@ -84,7 +87,7 @@ The `createTextureImageView` function can now be simplified to: ```c++ void createTextureImageView() { - createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, textureImageView); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM); } ``` @@ -92,14 +95,27 @@ And `createImageViews` can be simplified to: ```c++ void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); for (uint32_t i = 0; i < swapChainImages.size(); i++) { - createImageView(swapChainImages[i], swapChainImageFormat, swapChainImageViews[i]); + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); } } ``` +Make sure to destroy the image view at the end of the program, right before +destroying the image itself: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroyImageView(device, textureImageView, nullptr); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); +``` + ## Samplers It is possible for shaders to read texels directly from images, but that is not @@ -258,15 +274,15 @@ hold the handle of the sampler object and create the sampler with `vkCreateSampler`: ```c++ -VDeleter textureImageView{device, vkDestroyImageView}; -VDeleter textureSampler{device, vkDestroySampler}; +VkImageView textureImageView; +VkSampler textureSampler; ... void createTextureSampler() { ... - if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } @@ -278,6 +294,61 @@ can be applied to any image you want, whether it is 1D, 2D or 3D. This is different from many older APIs, which combined texture images and filtering into a single state. +Destroy the sampler at the end of the program when we'll no longer be accessing +the image: + +```c++ +void cleanup() { + cleanupSwapChain(); + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + + ... +} +``` + +## Anisotropy device feature + +If you run your program right now, you'll see a validation layer message like +this: + +![](/images/validation_layer_anisotropy.png) + +That's because anisotropic filtering is actually an optional device feature. We +need to update the `createLogicalDevice` function to request it: + +```c++ +VkPhysicalDeviceFeatures deviceFeatures = {}; +deviceFeatures.samplerAnisotropy = VK_TRUE; +``` + +And even though it is very unlikely that a modern graphics card will not support +it, we should update `isDeviceSuitable` to check if it is available: + +```c++ +bool isDeviceSuitable(VkPhysicalDevice device) { + ... + + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return indices.isComplete() && extensionsSupported && supportedFeatures.samplerAnisotropy; +} +``` + +The `vkGetPhysicalDeviceFeatures` repurposes the `VkPhysicalDeviceFeatures` +struct to indicate which features are supported rather than requested by setting +the boolean values. + +Instead of enforcing the availability of anisotropic filtering, it's also +possible to simply not use it by conditionally setting: + +```c++ +samplerInfo.anisotropyEnable = VK_FALSE; +samplerInfo.maxAnisotropy = 1; +``` + In the next chapter we will expose the image and sampler objects to the shaders to draw the texture onto the square. diff --git a/06_Texture_mapping/02_Combined_image_sampler.md b/06_Texture_mapping/02_Combined_image_sampler.md index 10138400..997117ee 100644 --- a/06_Texture_mapping/02_Combined_image_sampler.md +++ b/06_Texture_mapping/02_Combined_image_sampler.md @@ -28,7 +28,7 @@ samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; std::array bindings = {uboLayoutBinding, samplerLayoutBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; -layoutInfo.bindingCount = bindings.size(); +layoutInfo.bindingCount = static_cast(bindings.size()); layoutInfo.pBindings = bindings.data(); ``` @@ -53,7 +53,7 @@ poolSizes[1].descriptorCount = 1; VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; -poolInfo.poolSizeCount = poolSizes.size(); +poolInfo.poolSizeCount = static_cast(poolSizes.size()); poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 1; ``` @@ -92,7 +92,7 @@ descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrites[1].descriptorCount = 1; descriptorWrites[1].pImageInfo = &imageInfo; -vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); +vkUpdateDescriptorSets(device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); ``` The descriptor must be updated with this image info, just like the buffer. This diff --git a/07_Depth_buffering.md b/07_Depth_buffering.md index a4051350..7115847a 100644 --- a/07_Depth_buffering.md +++ b/07_Depth_buffering.md @@ -130,9 +130,9 @@ running at once. The depth image will again require the trifecta of resources: image, memory and image view. ```c++ -VDeleter depthImage{device, vkDestroyImage}; -VDeleter depthImageMemory{device, vkFreeMemory}; -VDeleter depthImageView{device, vkDestroyImageView}; +VkImage depthImage; +VkDeviceMemory depthImageMemory; +VkImageView depthImageView; ``` Create a new function `createDepthResources` to set up these resources: @@ -272,7 +272,7 @@ We now have all the required information to invoke our `createImage` and ```c++ createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); -createImageView(depthImage, depthFormat, depthImageView); +depthImageView = createImageView(depthImage, depthFormat); ``` However, the `createImageView` function currently assumes that the subresource @@ -280,7 +280,7 @@ is always the `VK_IMAGE_ASPECT_COLOR_BIT`, so we will need to turn that field into a parameter: ```c++ -void createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, VDeleter& imageView) { +VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) { ... viewInfo.subresourceRange.aspectMask = aspectFlags; ... @@ -290,11 +290,11 @@ void createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFl Update all calls to this function to use the right aspect: ```c++ -createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, swapChainImageViews[i]); +swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); ... -createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, depthImageView); +depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); ... -createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, textureImageView); +textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); ``` That's it for creating the depth image. We don't need to map it or copy another @@ -396,7 +396,7 @@ buffers. std::array attachments = {colorAttachment, depthAttachment}; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; -renderPassInfo.attachmentCount = attachments.size(); +renderPassInfo.attachmentCount = static_cast(attachments.size()); renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; @@ -422,7 +422,7 @@ std::array attachments = { VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; -framebufferInfo.attachmentCount = attachments.size(); +framebufferInfo.attachmentCount = static_cast(attachments.size()); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; @@ -456,7 +456,7 @@ std::array clearValues = {}; clearValues[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; clearValues[1].depthStencil = {1.0f, 0}; -renderPassInfo.clearValueCount = clearValues.size(); +renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); ``` @@ -548,6 +548,18 @@ void recreateSwapChain() { } ``` +The cleanup operations should happen in the swap chain cleanup function: + +```c++ +void cleanupSwapChain() { + vkDestroyImageView(device, depthImageView, nullptr); + vkDestroyImage(device, depthImage, nullptr); + vkFreeMemory(device, depthImageMemory, nullptr); + + ... +} +``` + Congratulations, your application is now finally ready to render arbitrary 3D geometry and have it look right. We're going to try this out in the next chapter by drawing a textured model! diff --git a/08_Loading_models.md b/08_Loading_models.md index 956bc068..67aa4129 100644 --- a/08_Loading_models.md +++ b/08_Loading_models.md @@ -88,8 +88,8 @@ non-const containers as class members: ```c++ std::vector vertices; std::vector indices; -VDeleter vertexBuffer{device, vkDestroyBuffer}; -VDeleter vertexBufferMemory{device, vkFreeMemory}; +VkBuffer vertexBuffer; +VkDeviceMemory vertexBufferMemory; ``` You should change the type of the indices from `uint16_t` to `uint32_t`, because @@ -249,14 +249,14 @@ Unfortunately we're not really taking advantage of the index buffer yet. The vertices are included in multiple triangles. We should keep only the unique vertices and use the index buffer to reuse them whenever they come up. A straightforward way to implement this is to use a `map` or `unordered_map` to -keep track of the unique vertices and their index: +keep track of the unique vertices and respective indices: ```c++ #include ... -std::unordered_map uniqueVertices = {}; +std::unordered_map uniqueVertices = {}; for (const auto& shape : shapes) { for (const auto& index : shape.mesh.indices) { @@ -265,7 +265,7 @@ for (const auto& shape : shapes) { ... if (uniqueVertices.count(vertex) == 0) { - uniqueVertices[vertex] = vertices.size(); + uniqueVertices[vertex] = static_cast(vertices.size()); vertices.push_back(vertex); } @@ -336,6 +336,7 @@ like: * Pipeline cache * Multi-threaded command buffer generation * Multiple subpasses +* Compute shaders The current program can be extended in many ways, like adding Blinn-Phong lighting, post-processing effects and shadow mapping. You should be able to diff --git a/README.md b/README.md index 7613a09f..54141df3 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,20 @@ have a problem with your code, then use the comments section in the related chapter to ask a question. Please provide your operating system, graphics card, driver version, source code, expected behaviour and actual behaviour. +E-book +------ + +This guide is now available in e-book formats as well: + +* [EPUB](https://raw.githubusercontent.com/Overv/VulkanTutorial/master/ebook/Vulkan%20Tutorial.epub) +* [PDF](https://raw.githubusercontent.com/Overv/VulkanTutorial/master/ebook/Vulkan%20Tutorial.pdf) + Changing code across chapters ----------------------------- It is sometimes necessary to change code that is reused across many chapters, -for example the `VDeleter` class or a function like `createBuffer`. If you make -such a change, then you should update the code files using the following steps: +for example a function like `createBuffer`. If you make such a change, then you +should update the code files using the following steps: * Update any chapters that reference the modified code. * Make a copy of the first file that uses it and modify the code there, e.g. diff --git a/code/base_code.cpp b/code/base_code.cpp index 8b5fe910..d6de426c 100644 --- a/code/base_code.cpp +++ b/code/base_code.cpp @@ -3,75 +3,17 @@ #include #include -#include const int WIDTH = 800; const int HEIGHT = 600; -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; - } -}; - class HelloTriangleApplication { public: void run() { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: @@ -94,7 +36,9 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + void cleanup() { glfwDestroyWindow(window); glfwTerminate(); diff --git a/code/command_buffers.cpp b/code/command_buffers.cpp index f1da66b0..12b5c983 100644 --- a/code/command_buffers.cpp +++ b/code/command_buffers.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,33 +63,34 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; std::vector commandBuffers; void initWindow() { @@ -179,6 +121,28 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyCommandPool(device, commandPool, nullptr); + + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -203,17 +167,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -226,13 +190,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -281,22 +245,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -345,10 +309,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -358,9 +322,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -376,7 +340,7 @@ class HelloTriangleApplication { 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!"); } } @@ -409,7 +373,7 @@ class HelloTriangleApplication { renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - 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!"); } } @@ -418,10 +382,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -501,7 +463,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -520,13 +482,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -542,7 +507,7 @@ class HelloTriangleApplication { 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!"); } } @@ -555,7 +520,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - 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!"); } } @@ -605,7 +570,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -615,9 +580,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -656,7 +624,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -826,4 +794,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/depth_buffering.cpp b/code/depth_buffering.cpp index 5aa24560..a0078d07 100644 --- a/code/depth_buffering.cpp +++ b/code/depth_buffering.cpp @@ -10,11 +10,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -53,64 +52,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -191,61 +132,60 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - - VDeleter swapChain{device, vkDestroySwapchainKHR}; + + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; - - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; - - VDeleter commandPool{device, vkDestroyCommandPool}; - - VDeleter depthImage{device, vkDestroyImage}; - VDeleter depthImageMemory{device, vkFreeMemory}; - VDeleter depthImageView{device, vkDestroyImageView}; - - VDeleter textureImage{device, vkDestroyImage}; - VDeleter textureImageMemory{device, vkFreeMemory}; - VDeleter textureImageView{device, vkDestroyImageView}; - VDeleter textureSampler{device, vkDestroySampler}; - - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; - - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; - - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; + + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; + + VkCommandPool commandPool; + + VkImage depthImage; + VkDeviceMemory depthImageMemory; + VkImageView depthImageView; + + VkImage textureImage; + VkDeviceMemory textureImageMemory; + VkImageView textureImageView; + VkSampler textureSampler; + + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; + + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; + + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -293,6 +233,60 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + vkDestroyImageView(device, depthImageView, nullptr); + vkDestroyImage(device, depthImage, nullptr); + vkFreeMemory(device, depthImageMemory, nullptr); + + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -308,6 +302,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -336,17 +332,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -359,13 +355,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -410,26 +406,27 @@ class HelloTriangleApplication { } VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -476,16 +473,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -495,10 +486,10 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); for (uint32_t i = 0; i < swapChainImages.size(); i++) { - createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, swapChainImageViews[i]); + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); } } @@ -548,14 +539,14 @@ class HelloTriangleApplication { std::array attachments = {colorAttachment, depthAttachment}; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = attachments.size(); + renderPassInfo.attachmentCount = static_cast(attachments.size()); renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; 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!"); } } @@ -578,10 +569,10 @@ class HelloTriangleApplication { std::array bindings = {uboLayoutBinding, samplerLayoutBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = bindings.size(); + layoutInfo.bindingCount = static_cast(bindings.size()); layoutInfo.pBindings = bindings.data(); - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -590,10 +581,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -616,7 +605,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -681,14 +670,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -708,13 +696,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { std::array attachments = { @@ -725,13 +716,13 @@ class HelloTriangleApplication { VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = attachments.size(); + framebufferInfo.attachmentCount = static_cast(attachments.size()); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; 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!"); } } @@ -744,7 +735,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -753,7 +744,7 @@ class HelloTriangleApplication { VkFormat depthFormat = findDepthFormat(); createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); - createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, depthImageView); + depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); transitionImageLayout(depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } @@ -794,8 +785,8 @@ class HelloTriangleApplication { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -830,10 +821,13 @@ class HelloTriangleApplication { copyImage(stagingImage, textureImage, texWidth, texHeight); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); } void createTextureImageView() { - createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, textureImageView); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); } void createTextureSampler() { @@ -852,12 +846,12 @@ class HelloTriangleApplication { samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } - void createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, VDeleter& imageView) { + VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; @@ -869,12 +863,15 @@ class HelloTriangleApplication { viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) { + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } + + return imageView; } - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -890,7 +887,7 @@ class HelloTriangleApplication { imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -902,7 +899,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -994,8 +991,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -1006,13 +1003,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -1023,13 +1023,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -1041,11 +1042,11 @@ class HelloTriangleApplication { VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.poolSizeCount = static_cast(poolSizes.size()); poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -1090,17 +1091,17 @@ class HelloTriangleApplication { descriptorWrites[1].descriptorCount = 1; descriptorWrites[1].pImageInfo = &imageInfo; - vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + vkUpdateDescriptorSets(device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -1112,7 +1113,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -1176,10 +1177,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -1210,7 +1207,7 @@ class HelloTriangleApplication { clearValues[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = clearValues.size(); + renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); @@ -1225,7 +1222,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -1239,8 +1236,8 @@ class HelloTriangleApplication { 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!"); } @@ -1259,11 +1256,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1318,7 +1313,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1328,9 +1323,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1368,7 +1366,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1412,7 +1413,10 @@ class HelloTriangleApplication { swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); } - return indices.isComplete() && extensionsSupported && swapChainAdequate; + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return indices.isComplete() && extensionsSupported && supportedFeatures.samplerAnisotropy; } bool checkDeviceExtensionSupport(VkPhysicalDevice device) { diff --git a/code/descriptor_layout.cpp b/code/descriptor_layout.cpp index 6b40847a..db7d2fdd 100644 --- a/code/descriptor_layout.cpp +++ b/code/descriptor_layout.cpp @@ -6,11 +6,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -49,64 +48,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -175,49 +116,48 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -259,6 +199,48 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -274,6 +256,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -301,17 +285,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -324,13 +308,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -379,22 +363,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -441,16 +425,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -460,9 +438,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -478,7 +456,7 @@ class HelloTriangleApplication { 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!"); } } @@ -521,7 +499,7 @@ class HelloTriangleApplication { 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!"); } } @@ -539,7 +517,7 @@ class HelloTriangleApplication { layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -548,10 +526,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -574,7 +550,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -631,14 +607,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -657,13 +632,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -679,7 +657,7 @@ class HelloTriangleApplication { 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!"); } } @@ -692,7 +670,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -700,8 +678,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -712,13 +690,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -729,23 +710,24 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -757,7 +739,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -811,10 +793,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -855,7 +833,7 @@ class HelloTriangleApplication { vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -869,8 +847,8 @@ class HelloTriangleApplication { 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!"); } @@ -889,11 +867,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -948,7 +924,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -958,9 +934,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -998,7 +977,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1172,4 +1154,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/descriptor_set.cpp b/code/descriptor_set.cpp index e66d8d90..80516e4d 100644 --- a/code/descriptor_set.cpp +++ b/code/descriptor_set.cpp @@ -6,11 +6,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -49,64 +48,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -175,52 +116,51 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -264,6 +204,50 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -279,6 +263,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -306,17 +292,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -329,13 +315,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -384,22 +370,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -446,16 +432,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -465,9 +445,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -483,7 +463,7 @@ class HelloTriangleApplication { 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!"); } } @@ -526,7 +506,7 @@ class HelloTriangleApplication { 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!"); } } @@ -544,7 +524,7 @@ class HelloTriangleApplication { layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -553,10 +533,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -579,7 +557,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -636,14 +614,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -662,13 +639,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -684,7 +664,7 @@ class HelloTriangleApplication { 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!"); } } @@ -697,7 +677,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -705,8 +685,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -717,13 +697,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -734,13 +717,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -754,7 +738,7 @@ class HelloTriangleApplication { poolInfo.pPoolSizes = &poolSize; poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -788,14 +772,14 @@ class HelloTriangleApplication { vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -807,7 +791,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -861,10 +845,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -907,7 +887,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -921,8 +901,8 @@ class HelloTriangleApplication { 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!"); } @@ -941,11 +921,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1000,7 +978,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1010,9 +988,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1050,7 +1031,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1224,4 +1208,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/fixed_functions.cpp b/code/fixed_functions.cpp index 364c39b5..74e433ed 100644 --- a/code/fixed_functions.cpp +++ b/code/fixed_functions.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,30 +63,29 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; + VkPipelineLayout pipelineLayout; void initWindow() { glfwInit(); @@ -171,6 +111,20 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -195,17 +149,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -218,13 +172,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -273,22 +227,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -337,10 +291,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -350,9 +304,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -368,7 +322,7 @@ class HelloTriangleApplication { 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!"); } } @@ -378,10 +332,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -461,12 +413,15 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -476,9 +431,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -517,7 +475,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -687,4 +645,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/framebuffers.cpp b/code/framebuffers.cpp index 598ccc92..d4671250 100644 --- a/code/framebuffers.cpp +++ b/code/framebuffers.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,31 +63,32 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; void initWindow() { glfwInit(); @@ -174,6 +116,26 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -198,17 +160,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -221,13 +183,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -276,22 +238,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -340,10 +302,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -353,9 +315,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -371,7 +333,7 @@ class HelloTriangleApplication { 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!"); } } @@ -404,7 +366,7 @@ class HelloTriangleApplication { renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - 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!"); } } @@ -413,10 +375,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -496,7 +456,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -515,13 +475,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -537,13 +500,13 @@ class HelloTriangleApplication { 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 createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -553,9 +516,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -594,7 +560,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -764,4 +730,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/graphics_pipeline.cpp b/code/graphics_pipeline.cpp index 34b1d80c..5c4f8b4e 100644 --- a/code/graphics_pipeline.cpp +++ b/code/graphics_pipeline.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include #include #include @@ -43,64 +41,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,26 +62,27 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - - VDeleter swapChain{device, vkDestroySwapchainKHR}; + + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; + std::vector swapChainImageViews; void initWindow() { glfwInit(); @@ -167,6 +108,18 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -191,17 +144,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -214,13 +167,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -269,22 +222,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -333,10 +286,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -346,9 +299,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -364,8 +317,8 @@ class HelloTriangleApplication { createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &createInfo, nullptr, swapChainImageViews[i].replace()) != VK_SUCCESS) { - throw std::runtime_error("failed to create image views"); + if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) { + throw std::runtime_error("failed to create image views!"); } } } @@ -410,7 +363,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -562,4 +515,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/graphics_pipeline_complete.cpp b/code/graphics_pipeline_complete.cpp index c22f9892..0a427406 100644 --- a/code/graphics_pipeline_complete.cpp +++ b/code/graphics_pipeline_complete.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,31 +63,31 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; void initWindow() { glfwInit(); @@ -173,6 +114,22 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -197,17 +154,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -220,13 +177,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -275,22 +232,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -339,10 +296,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -352,9 +309,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -370,7 +327,7 @@ class HelloTriangleApplication { 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!"); } } @@ -403,7 +360,7 @@ class HelloTriangleApplication { renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - 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!"); } } @@ -412,10 +369,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -495,7 +450,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -514,12 +469,15 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -529,9 +487,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -570,7 +531,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -740,4 +701,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/hello_triangle.cpp b/code/hello_triangle.cpp index d09876d5..2cd5a69a 100644 --- a/code/hello_triangle.cpp +++ b/code/hello_triangle.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,37 +63,38 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -186,6 +128,31 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanup() { + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -210,17 +177,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -233,13 +200,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -288,22 +255,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -352,7 +319,7 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } @@ -365,9 +332,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -383,7 +350,7 @@ class HelloTriangleApplication { 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!"); } } @@ -426,7 +393,7 @@ class HelloTriangleApplication { 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!"); } } @@ -435,10 +402,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -518,7 +483,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -537,13 +502,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -559,7 +527,7 @@ class HelloTriangleApplication { 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!"); } } @@ -572,7 +540,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - 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!"); } } @@ -626,8 +594,8 @@ class HelloTriangleApplication { 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!"); } @@ -672,7 +640,7 @@ class HelloTriangleApplication { vkQueuePresentKHR(presentQueue, &presentInfo); } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -682,9 +650,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -893,4 +864,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/image_views.cpp b/code/image_views.cpp index 7bd4a6ef..a370606a 100644 --- a/code/image_views.cpp +++ b/code/image_views.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -42,64 +41,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -121,26 +62,27 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; + std::vector swapChainImageViews; void initWindow() { glfwInit(); @@ -165,6 +107,18 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -189,17 +143,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -212,13 +166,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -267,22 +221,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -331,7 +285,7 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } @@ -344,9 +298,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -362,7 +316,7 @@ class HelloTriangleApplication { 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!"); } } diff --git a/code/index_buffer.cpp b/code/index_buffer.cpp index ad87d999..e7e81e10 100644 --- a/code/index_buffer.cpp +++ b/code/index_buffer.cpp @@ -4,9 +4,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -46,64 +45,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -166,43 +107,44 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -240,6 +182,44 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -255,6 +235,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -282,17 +264,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -305,13 +287,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -360,22 +342,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -422,16 +404,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -441,9 +417,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -459,7 +435,7 @@ class HelloTriangleApplication { 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!"); } } @@ -502,7 +478,7 @@ class HelloTriangleApplication { 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!"); } } @@ -511,10 +487,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -537,7 +511,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -600,7 +574,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -619,13 +593,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -641,7 +618,7 @@ class HelloTriangleApplication { 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!"); } } @@ -654,7 +631,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -662,8 +639,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -674,13 +651,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -691,16 +671,19 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -712,7 +695,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -766,10 +749,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -810,7 +789,7 @@ class HelloTriangleApplication { vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -824,8 +803,8 @@ class HelloTriangleApplication { 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!"); } @@ -883,7 +862,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -893,9 +872,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -933,7 +915,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1107,4 +1092,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/instance_creation.cpp b/code/instance_creation.cpp index 20c4a082..fa0bc6a4 100644 --- a/code/instance_creation.cpp +++ b/code/instance_creation.cpp @@ -3,81 +3,23 @@ #include #include -#include const int WIDTH = 800; const int HEIGHT = 600; -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; - } -}; - class HelloTriangleApplication { public: void run() { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; + VkInstance instance; void initWindow() { glfwInit(); @@ -96,6 +38,10 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -124,7 +70,7 @@ class HelloTriangleApplication { createInfo.enabledLayerCount = 0; - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } diff --git a/code/logical_device.cpp b/code/logical_device.cpp index 47f5e896..cdb41056 100644 --- a/code/logical_device.cpp +++ b/code/logical_device.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -36,64 +35,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -108,17 +49,17 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; @@ -142,6 +83,12 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -166,17 +113,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -189,7 +136,7 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } @@ -241,13 +188,13 @@ class HelloTriangleApplication { createInfo.enabledExtensionCount = 0; if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } diff --git a/code/model_loading.cpp b/code/model_loading.cpp index 67d625e5..097910e5 100644 --- a/code/model_loading.cpp +++ b/code/model_loading.cpp @@ -14,11 +14,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -61,64 +60,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -194,63 +135,62 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - - VDeleter swapChain{device, vkDestroySwapchainKHR}; + + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; - - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; - - VDeleter commandPool{device, vkDestroyCommandPool}; - - VDeleter depthImage{device, vkDestroyImage}; - VDeleter depthImageMemory{device, vkFreeMemory}; - VDeleter depthImageView{device, vkDestroyImageView}; - - VDeleter textureImage{device, vkDestroyImage}; - VDeleter textureImageMemory{device, vkFreeMemory}; - VDeleter textureImageView{device, vkDestroyImageView}; - VDeleter textureSampler{device, vkDestroySampler}; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; + + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; + + VkCommandPool commandPool; + + VkImage depthImage; + VkDeviceMemory depthImageMemory; + VkImageView depthImageView; + + VkImage textureImage; + VkDeviceMemory textureImageMemory; + VkImageView textureImageView; + VkSampler textureSampler; std::vector vertices; std::vector indices; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -299,6 +239,60 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + vkDestroyImageView(device, depthImageView, nullptr); + vkDestroyImage(device, depthImage, nullptr); + vkFreeMemory(device, depthImageMemory, nullptr); + + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -314,6 +308,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -342,17 +338,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -365,13 +361,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -416,26 +412,27 @@ class HelloTriangleApplication { } VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -482,16 +479,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -501,10 +492,10 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); for (uint32_t i = 0; i < swapChainImages.size(); i++) { - createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, swapChainImageViews[i]); + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT); } } @@ -554,14 +545,14 @@ class HelloTriangleApplication { std::array attachments = {colorAttachment, depthAttachment}; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = attachments.size(); + renderPassInfo.attachmentCount = static_cast(attachments.size()); renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; 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!"); } } @@ -584,10 +575,10 @@ class HelloTriangleApplication { std::array bindings = {uboLayoutBinding, samplerLayoutBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = bindings.size(); + layoutInfo.bindingCount = static_cast(bindings.size()); layoutInfo.pBindings = bindings.data(); - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -596,10 +587,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -622,7 +611,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -687,14 +676,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -714,13 +702,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { std::array attachments = { @@ -731,13 +722,13 @@ class HelloTriangleApplication { VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = attachments.size(); + framebufferInfo.attachmentCount = static_cast(attachments.size()); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; 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!"); } } @@ -750,7 +741,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -759,7 +750,7 @@ class HelloTriangleApplication { VkFormat depthFormat = findDepthFormat(); createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); - createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, depthImageView); + depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT); transitionImageLayout(depthImage, depthFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } @@ -800,8 +791,8 @@ class HelloTriangleApplication { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -836,10 +827,13 @@ class HelloTriangleApplication { copyImage(stagingImage, textureImage, texWidth, texHeight); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); } void createTextureImageView() { - createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, textureImageView); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT); } void createTextureSampler() { @@ -858,12 +852,12 @@ class HelloTriangleApplication { samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } - void createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, VDeleter& imageView) { + VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; @@ -875,12 +869,15 @@ class HelloTriangleApplication { viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) { + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } + + return imageView; } - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -896,7 +893,7 @@ class HelloTriangleApplication { imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -908,7 +905,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -1007,7 +1004,7 @@ class HelloTriangleApplication { throw std::runtime_error(err); } - std::unordered_map uniqueVertices = {}; + std::unordered_map uniqueVertices = {}; for (const auto& shape : shapes) { for (const auto& index : shape.mesh.indices) { @@ -1027,7 +1024,7 @@ class HelloTriangleApplication { vertex.color = {1.0f, 1.0f, 1.0f}; if (uniqueVertices.count(vertex) == 0) { - uniqueVertices[vertex] = vertices.size(); + uniqueVertices[vertex] = static_cast(vertices.size()); vertices.push_back(vertex); } @@ -1039,8 +1036,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -1051,13 +1048,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -1068,13 +1068,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -1086,11 +1087,11 @@ class HelloTriangleApplication { VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.poolSizeCount = static_cast(poolSizes.size()); poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -1135,17 +1136,17 @@ class HelloTriangleApplication { descriptorWrites[1].descriptorCount = 1; descriptorWrites[1].pImageInfo = &imageInfo; - vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + vkUpdateDescriptorSets(device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -1157,7 +1158,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -1221,10 +1222,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -1255,7 +1252,7 @@ class HelloTriangleApplication { clearValues[0].color = {0.0f, 0.0f, 0.0f, 1.0f}; clearValues[1].depthStencil = {1.0f, 0}; - renderPassInfo.clearValueCount = clearValues.size(); + renderPassInfo.clearValueCount = static_cast(clearValues.size()); renderPassInfo.pClearValues = clearValues.data(); vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); @@ -1270,7 +1267,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -1284,8 +1281,8 @@ class HelloTriangleApplication { 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!"); } @@ -1304,11 +1301,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1363,7 +1358,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1373,9 +1368,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1413,7 +1411,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1457,7 +1458,10 @@ class HelloTriangleApplication { swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); } - return indices.isComplete() && extensionsSupported && swapChainAdequate; + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return indices.isComplete() && extensionsSupported && supportedFeatures.samplerAnisotropy; } bool checkDeviceExtensionSupport(VkPhysicalDevice device) { diff --git a/code/physical_device_selection.cpp b/code/physical_device_selection.cpp index 5c1d657b..13fa20d6 100644 --- a/code/physical_device_selection.cpp +++ b/code/physical_device_selection.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -36,64 +35,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -108,14 +49,14 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; @@ -138,6 +79,11 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -162,17 +108,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -185,7 +131,7 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } diff --git a/code/render_passes.cpp b/code/render_passes.cpp index d239acdf..4703837d 100644 --- a/code/render_passes.cpp +++ b/code/render_passes.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,30 +63,30 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; void initWindow() { glfwInit(); @@ -172,6 +113,21 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -196,17 +152,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -219,13 +175,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -274,22 +230,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -338,10 +294,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -351,9 +307,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -369,7 +325,7 @@ class HelloTriangleApplication { 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!"); } } @@ -402,7 +358,7 @@ class HelloTriangleApplication { renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; - 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!"); } } @@ -411,10 +367,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -494,12 +448,15 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -509,9 +466,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -550,7 +510,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -720,4 +680,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/sampler.cpp b/code/sampler.cpp index e24a4fa8..aed51ecf 100644 --- a/code/sampler.cpp +++ b/code/sampler.cpp @@ -9,11 +9,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -52,64 +51,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -178,57 +119,56 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; + + VkImage textureImage; + VkDeviceMemory textureImageMemory; + VkImageView textureImageView; + VkSampler textureSampler; - VDeleter textureImage{device, vkDestroyImage}; - VDeleter textureImageMemory{device, vkFreeMemory}; - VDeleter textureImageView{device, vkDestroyImageView}; - VDeleter textureSampler{device, vkDestroySampler}; - - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; - - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; - - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; + + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; + + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -275,6 +215,56 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -290,6 +280,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -317,17 +309,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -340,13 +332,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -391,26 +383,27 @@ class HelloTriangleApplication { } VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -457,16 +450,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -476,10 +463,10 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { - createImageView(swapChainImages[i], swapChainImageFormat, swapChainImageViews[i]); + for (size_t i = 0; i < swapChainImages.size(); i++) { + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); } } @@ -520,7 +507,7 @@ class HelloTriangleApplication { 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!"); } } @@ -538,7 +525,7 @@ class HelloTriangleApplication { layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -547,10 +534,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -573,7 +558,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -630,14 +615,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -656,13 +640,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -678,7 +665,7 @@ class HelloTriangleApplication { 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!"); } } @@ -691,7 +678,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -705,8 +692,8 @@ class HelloTriangleApplication { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -741,10 +728,13 @@ class HelloTriangleApplication { copyImage(stagingImage, textureImage, texWidth, texHeight); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); } void createTextureImageView() { - createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, textureImageView); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM); } void createTextureSampler() { @@ -763,12 +753,12 @@ class HelloTriangleApplication { samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } - void createImageView(VkImage image, VkFormat format, VDeleter& imageView) { + VkImageView createImageView(VkImage image, VkFormat format) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; @@ -780,12 +770,15 @@ class HelloTriangleApplication { viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) { + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } + + return imageView; } - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -801,7 +794,7 @@ class HelloTriangleApplication { imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -813,7 +806,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -892,8 +885,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -904,13 +897,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -921,13 +917,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -941,7 +938,7 @@ class HelloTriangleApplication { poolInfo.pPoolSizes = &poolSize; poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -975,14 +972,14 @@ class HelloTriangleApplication { vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -994,7 +991,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -1058,10 +1055,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -1104,7 +1097,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -1118,8 +1111,8 @@ class HelloTriangleApplication { 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!"); } @@ -1138,11 +1131,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1197,7 +1188,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1207,9 +1198,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1247,7 +1241,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1291,7 +1288,10 @@ class HelloTriangleApplication { swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); } - return indices.isComplete() && extensionsSupported && swapChainAdequate; + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return indices.isComplete() && extensionsSupported && supportedFeatures.samplerAnisotropy; } bool checkDeviceExtensionSupport(VkPhysicalDevice device) { @@ -1421,4 +1421,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/shader_modules.cpp b/code/shader_modules.cpp index 982f1905..f426f5ab 100644 --- a/code/shader_modules.cpp +++ b/code/shader_modules.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,26 +63,27 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - - VDeleter swapChain{device, vkDestroySwapchainKHR}; + + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; + std::vector swapChainImageViews; void initWindow() { glfwInit(); @@ -167,6 +109,18 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -191,17 +145,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -214,13 +168,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -269,22 +223,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -333,10 +287,10 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -346,9 +300,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -364,7 +318,7 @@ class HelloTriangleApplication { 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!"); } } @@ -374,10 +328,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -392,9 +344,12 @@ class HelloTriangleApplication { fragShaderStageInfo.pName = "main"; VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -404,9 +359,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -445,7 +403,7 @@ class HelloTriangleApplication { actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); - + return actualExtent; } } @@ -615,4 +573,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/staging_buffer.cpp b/code/staging_buffer.cpp index 63ef25d5..097a433d 100644 --- a/code/staging_buffer.cpp +++ b/code/staging_buffer.cpp @@ -4,9 +4,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -46,64 +45,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -161,41 +102,42 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -232,6 +174,41 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -247,6 +224,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -274,17 +253,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -297,13 +276,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -352,22 +331,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -414,16 +393,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -433,9 +406,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -451,7 +424,7 @@ class HelloTriangleApplication { 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!"); } } @@ -494,7 +467,7 @@ class HelloTriangleApplication { 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!"); } } @@ -503,10 +476,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -529,7 +500,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -592,7 +563,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -611,13 +582,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -633,7 +607,7 @@ class HelloTriangleApplication { 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!"); } } @@ -646,7 +620,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -654,8 +628,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -666,16 +640,19 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -687,7 +664,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -741,10 +718,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -783,7 +756,7 @@ class HelloTriangleApplication { VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets); - vkCmdDraw(commandBuffers[i], vertices.size(), 1, 0, 0); + vkCmdDraw(commandBuffers[i], static_cast(vertices.size()), 1, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -797,8 +770,8 @@ class HelloTriangleApplication { 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!"); } @@ -856,7 +829,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -866,9 +839,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -906,7 +882,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1080,4 +1059,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/swap_chain_creation.cpp b/code/swap_chain_creation.cpp index 954e6584..aed817c9 100644 --- a/code/swap_chain_creation.cpp +++ b/code/swap_chain_creation.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -42,64 +41,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -121,22 +62,23 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; @@ -163,6 +105,14 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroySwapchainKHR(device, swapChain, nullptr); + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -187,17 +137,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -210,13 +160,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -265,22 +215,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -329,7 +279,7 @@ class HelloTriangleApplication { createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, swapChain.replace()) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } diff --git a/code/swap_chain_recreation.cpp b/code/swap_chain_recreation.cpp index 21f09e57..ef25dd7b 100644 --- a/code/swap_chain_recreation.cpp +++ b/code/swap_chain_recreation.cpp @@ -2,9 +2,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -43,64 +42,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -122,37 +63,38 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -188,6 +130,38 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -203,6 +177,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -230,17 +206,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -253,13 +229,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -308,22 +284,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -370,16 +346,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -389,9 +359,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -407,7 +377,7 @@ class HelloTriangleApplication { 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!"); } } @@ -450,7 +420,7 @@ class HelloTriangleApplication { 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!"); } } @@ -459,10 +429,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -542,7 +510,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -561,13 +529,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -583,7 +554,7 @@ class HelloTriangleApplication { 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!"); } } @@ -596,16 +567,12 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - 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 createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -654,8 +621,8 @@ class HelloTriangleApplication { 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!"); } @@ -713,7 +680,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -723,9 +690,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -763,7 +733,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -937,4 +910,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/texture_image.cpp b/code/texture_image.cpp index e1fdfff8..f226ca1b 100644 --- a/code/texture_image.cpp +++ b/code/texture_image.cpp @@ -9,11 +9,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -52,64 +51,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -178,55 +119,54 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; - - VDeleter textureImage{device, vkDestroyImage}; - VDeleter textureImageMemory{device, vkFreeMemory}; + VkCommandPool commandPool; + + VkImage textureImage; + VkDeviceMemory textureImageMemory; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -271,6 +211,53 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -286,6 +273,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -313,17 +302,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -336,13 +325,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -391,22 +380,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -453,16 +442,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -472,9 +455,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -490,7 +473,7 @@ class HelloTriangleApplication { 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!"); } } @@ -533,7 +516,7 @@ class HelloTriangleApplication { 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!"); } } @@ -551,7 +534,7 @@ class HelloTriangleApplication { layoutInfo.bindingCount = 1; layoutInfo.pBindings = &uboLayoutBinding; - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -560,10 +543,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -586,7 +567,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -643,14 +624,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -669,13 +649,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -691,7 +674,7 @@ class HelloTriangleApplication { 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!"); } } @@ -704,7 +687,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -718,8 +701,8 @@ class HelloTriangleApplication { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -754,9 +737,12 @@ class HelloTriangleApplication { copyImage(stagingImage, textureImage, texWidth, texHeight); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); } - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -772,7 +758,7 @@ class HelloTriangleApplication { imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -784,7 +770,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -863,8 +849,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -875,13 +861,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -892,13 +881,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -912,7 +902,7 @@ class HelloTriangleApplication { poolInfo.pPoolSizes = &poolSize; poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -946,14 +936,14 @@ class HelloTriangleApplication { vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -965,7 +955,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -1029,10 +1019,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -1075,7 +1061,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -1089,8 +1075,8 @@ class HelloTriangleApplication { 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!"); } @@ -1109,11 +1095,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1168,7 +1152,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1178,9 +1162,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1218,7 +1205,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1392,4 +1382,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/texture_mapping.cpp b/code/texture_mapping.cpp index 89ca8d41..6595b9e2 100644 --- a/code/texture_mapping.cpp +++ b/code/texture_mapping.cpp @@ -9,11 +9,10 @@ #include #include -#include -#include -#include #include +#include #include +#include #include #include #include @@ -52,64 +51,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -184,57 +125,56 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter descriptorSetLayout{device, vkDestroyDescriptorSetLayout}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; + + VkImage textureImage; + VkDeviceMemory textureImageMemory; + VkImageView textureImageView; + VkSampler textureSampler; - VDeleter textureImage{device, vkDestroyImage}; - VDeleter textureImageMemory{device, vkFreeMemory}; - VDeleter textureImageView{device, vkDestroyImageView}; - VDeleter textureSampler{device, vkDestroySampler}; - - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; - VDeleter indexBuffer{device, vkDestroyBuffer}; - VDeleter indexBufferMemory{device, vkFreeMemory}; - - VDeleter uniformStagingBuffer{device, vkDestroyBuffer}; - VDeleter uniformStagingBufferMemory{device, vkFreeMemory}; - VDeleter uniformBuffer{device, vkDestroyBuffer}; - VDeleter uniformBufferMemory{device, vkFreeMemory}; - - VDeleter descriptorPool{device, vkDestroyDescriptorPool}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; + VkBuffer indexBuffer; + VkDeviceMemory indexBufferMemory; + + VkBuffer uniformBuffer; + VkDeviceMemory uniformBufferMemory; + + VkDescriptorPool descriptorPool; VkDescriptorSet descriptorSet; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -281,6 +221,56 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySampler(device, textureSampler, nullptr); + vkDestroyImageView(device, textureImageView, nullptr); + + vkDestroyImage(device, textureImage, nullptr); + vkFreeMemory(device, textureImageMemory, nullptr); + + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyBuffer(device, uniformBuffer, nullptr); + vkFreeMemory(device, uniformBufferMemory, nullptr); + + vkDestroyBuffer(device, indexBuffer, nullptr); + vkFreeMemory(device, indexBufferMemory, nullptr); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -296,6 +286,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -323,17 +315,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -346,13 +338,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -397,26 +389,27 @@ class HelloTriangleApplication { } VkPhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -463,16 +456,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -482,10 +469,10 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { - createImageView(swapChainImages[i], swapChainImageFormat, swapChainImageViews[i]); + for (size_t i = 0; i < swapChainImages.size(); i++) { + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); } } @@ -526,7 +513,7 @@ class HelloTriangleApplication { 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!"); } } @@ -549,10 +536,10 @@ class HelloTriangleApplication { std::array bindings = {uboLayoutBinding, samplerLayoutBinding}; VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = bindings.size(); + layoutInfo.bindingCount = static_cast(bindings.size()); layoutInfo.pBindings = bindings.data(); - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); } } @@ -561,10 +548,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -587,7 +572,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -644,14 +629,13 @@ class HelloTriangleApplication { colorBlending.blendConstants[1] = 0.0f; colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - - VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = setLayouts; + pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; - 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!"); } @@ -670,13 +654,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -692,7 +679,7 @@ class HelloTriangleApplication { 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!"); } } @@ -705,7 +692,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - if (vkCreateCommandPool(device, &poolInfo, nullptr, commandPool.replace()) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { throw std::runtime_error("failed to create graphics command pool!"); } } @@ -719,8 +706,8 @@ class HelloTriangleApplication { throw std::runtime_error("failed to load texture image!"); } - VDeleter stagingImage{device, vkDestroyImage}; - VDeleter stagingImageMemory{device, vkFreeMemory}; + VkImage stagingImage; + VkDeviceMemory stagingImageMemory; createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingImage, stagingImageMemory); VkImageSubresource subresource = {}; @@ -755,10 +742,13 @@ class HelloTriangleApplication { copyImage(stagingImage, textureImage, texWidth, texHeight); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + vkDestroyImage(device, stagingImage, nullptr); + vkFreeMemory(device, stagingImageMemory, nullptr); } void createTextureImageView() { - createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM, textureImageView); + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_UNORM); } void createTextureSampler() { @@ -777,12 +767,12 @@ class HelloTriangleApplication { samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - if (vkCreateSampler(device, &samplerInfo, nullptr, textureSampler.replace()) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { throw std::runtime_error("failed to create texture sampler!"); } } - void createImageView(VkImage image, VkFormat format, VDeleter& imageView) { + VkImageView createImageView(VkImage image, VkFormat format) { VkImageViewCreateInfo viewInfo = {}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = image; @@ -794,12 +784,15 @@ class HelloTriangleApplication { viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, imageView.replace()) != VK_SUCCESS) { + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { throw std::runtime_error("failed to create texture image view!"); } + + return imageView; } - void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& image, VDeleter& imageMemory) { + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) { VkImageCreateInfo imageInfo = {}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -815,7 +808,7 @@ class HelloTriangleApplication { imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(device, &imageInfo, nullptr, image.replace()) != VK_SUCCESS) { + if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { throw std::runtime_error("failed to create image!"); } @@ -827,7 +820,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, imageMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate image memory!"); } @@ -906,8 +899,8 @@ class HelloTriangleApplication { void createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -918,13 +911,16 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createIndexBuffer() { VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - VDeleter stagingBuffer{device, vkDestroyBuffer}; - VDeleter stagingBufferMemory{device, vkFreeMemory}; + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory); void* data; @@ -935,13 +931,14 @@ class HelloTriangleApplication { createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); + + vkDestroyBuffer(device, stagingBuffer, nullptr); + vkFreeMemory(device, stagingBufferMemory, nullptr); } void createUniformBuffer() { VkDeviceSize bufferSize = sizeof(UniformBufferObject); - - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformStagingBuffer, uniformStagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, uniformBuffer, uniformBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory); } void createDescriptorPool() { @@ -953,11 +950,11 @@ class HelloTriangleApplication { VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = poolSizes.size(); + poolInfo.poolSizeCount = static_cast(poolSizes.size()); poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 1; - if (vkCreateDescriptorPool(device, &poolInfo, nullptr, descriptorPool.replace()) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor pool!"); } } @@ -1002,17 +999,17 @@ class HelloTriangleApplication { descriptorWrites[1].descriptorCount = 1; descriptorWrites[1].pImageInfo = &imageInfo; - vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + vkUpdateDescriptorSets(device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); } - void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VDeleter& buffer, VDeleter& bufferMemory) { + void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = usage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, buffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { throw std::runtime_error("failed to create buffer!"); } @@ -1024,7 +1021,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties); - if (vkAllocateMemory(device, &allocInfo, nullptr, bufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate buffer memory!"); } @@ -1088,10 +1085,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -1134,7 +1127,7 @@ class HelloTriangleApplication { vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - vkCmdDrawIndexed(commandBuffers[i], indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffers[i], static_cast(indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -1148,8 +1141,8 @@ class HelloTriangleApplication { 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!"); } @@ -1168,11 +1161,9 @@ class HelloTriangleApplication { ubo.proj[1][1] *= -1; void* data; - vkMapMemory(device, uniformStagingBufferMemory, 0, sizeof(ubo), 0, &data); + vkMapMemory(device, uniformBufferMemory, 0, sizeof(ubo), 0, &data); memcpy(data, &ubo, sizeof(ubo)); - vkUnmapMemory(device, uniformStagingBufferMemory); - - copyBuffer(uniformStagingBuffer, uniformBuffer, sizeof(ubo)); + vkUnmapMemory(device, uniformBufferMemory); } void drawFrame() { @@ -1227,7 +1218,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -1237,9 +1228,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -1277,7 +1271,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1321,7 +1318,10 @@ class HelloTriangleApplication { swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); } - return indices.isComplete() && extensionsSupported && swapChainAdequate; + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return indices.isComplete() && extensionsSupported && supportedFeatures.samplerAnisotropy; } bool checkDeviceExtensionSupport(VkPhysicalDevice device) { @@ -1451,4 +1451,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/validation_layers.cpp b/code/validation_layers.cpp index 0dd637ec..05c1019b 100644 --- a/code/validation_layers.cpp +++ b/code/validation_layers.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -36,77 +35,20 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; - } -}; - class HelloTriangleApplication { public: void run() { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; + VkInstance instance; + VkDebugReportCallbackEXT callback; void initWindow() { glfwInit(); @@ -126,6 +68,11 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -150,17 +97,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -173,7 +120,7 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } diff --git a/code/vertex_buffer.cpp b/code/vertex_buffer.cpp index b3253243..4647ce56 100644 --- a/code/vertex_buffer.cpp +++ b/code/vertex_buffer.cpp @@ -4,9 +4,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -46,64 +45,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -161,41 +102,42 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; - VDeleter vertexBuffer{device, vkDestroyBuffer}; - VDeleter vertexBufferMemory{device, vkFreeMemory}; + VkBuffer vertexBuffer; + VkDeviceMemory vertexBufferMemory; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -232,6 +174,41 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroyBuffer(device, vertexBuffer, nullptr); + vkFreeMemory(device, vertexBufferMemory, nullptr); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -247,6 +224,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -274,17 +253,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -297,13 +276,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -352,22 +331,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -414,16 +393,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -433,9 +406,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -451,7 +424,7 @@ class HelloTriangleApplication { 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!"); } } @@ -494,7 +467,7 @@ class HelloTriangleApplication { 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!"); } } @@ -503,10 +476,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -529,7 +500,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -592,7 +563,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -611,13 +582,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -633,7 +607,7 @@ class HelloTriangleApplication { 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!"); } } @@ -646,7 +620,7 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - 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!"); } } @@ -658,7 +632,7 @@ class HelloTriangleApplication { bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateBuffer(device, &bufferInfo, nullptr, vertexBuffer.replace()) != VK_SUCCESS) { + if (vkCreateBuffer(device, &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) { throw std::runtime_error("failed to create vertex buffer!"); } @@ -670,7 +644,7 @@ class HelloTriangleApplication { allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - if (vkAllocateMemory(device, &allocInfo, nullptr, vertexBufferMemory.replace()) != VK_SUCCESS) { + if (vkAllocateMemory(device, &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate vertex buffer memory!"); } @@ -696,10 +670,6 @@ class HelloTriangleApplication { } void createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -738,7 +708,7 @@ class HelloTriangleApplication { VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets); - vkCmdDraw(commandBuffers[i], vertices.size(), 1, 0, 0); + vkCmdDraw(commandBuffers[i], static_cast(vertices.size()), 1, 0, 0); vkCmdEndRenderPass(commandBuffers[i]); @@ -752,8 +722,8 @@ class HelloTriangleApplication { 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!"); } @@ -811,7 +781,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -821,9 +791,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -861,7 +834,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -1035,4 +1011,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/vertex_input.cpp b/code/vertex_input.cpp index c0725821..ecd661ad 100644 --- a/code/vertex_input.cpp +++ b/code/vertex_input.cpp @@ -4,9 +4,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -46,64 +45,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -161,37 +102,38 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; - VDeleter swapChain{device, vkDestroySwapchainKHR}; + VkSwapchainKHR swapChain; std::vector swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; - std::vector> swapChainImageViews; - std::vector> swapChainFramebuffers; + std::vector swapChainImageViews; + std::vector swapChainFramebuffers; - VDeleter renderPass{device, vkDestroyRenderPass}; - VDeleter pipelineLayout{device, vkDestroyPipelineLayout}; - VDeleter graphicsPipeline{device, vkDestroyPipeline}; + VkRenderPass renderPass; + VkPipelineLayout pipelineLayout; + VkPipeline graphicsPipeline; - VDeleter commandPool{device, vkDestroyCommandPool}; + VkCommandPool commandPool; std::vector commandBuffers; - VDeleter imageAvailableSemaphore{device, vkDestroySemaphore}; - VDeleter renderFinishedSemaphore{device, vkDestroySemaphore}; + VkSemaphore imageAvailableSemaphore; + VkSemaphore renderFinishedSemaphore; void initWindow() { glfwInit(); @@ -227,6 +169,38 @@ class HelloTriangleApplication { } vkDeviceWaitIdle(device); + } + + void cleanupSwapChain() { + for (size_t i = 0; i < swapChainFramebuffers.size(); i++) { + vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr); + } + + vkFreeCommandBuffers(device, commandPool, static_cast(commandBuffers.size()), commandBuffers.data()); + + vkDestroyPipeline(device, graphicsPipeline, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyRenderPass(device, renderPass, nullptr); + + for (size_t i = 0; i < swapChainImageViews.size(); i++) { + vkDestroyImageView(device, swapChainImageViews[i], nullptr); + } + + vkDestroySwapchainKHR(device, swapChain, nullptr); + } + + void cleanup() { + cleanupSwapChain(); + + vkDestroySemaphore(device, renderFinishedSemaphore, nullptr); + vkDestroySemaphore(device, imageAvailableSemaphore, nullptr); + + vkDestroyCommandPool(device, commandPool, nullptr); + + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -242,6 +216,8 @@ class HelloTriangleApplication { void recreateSwapChain() { vkDeviceWaitIdle(device); + + cleanupSwapChain(); createSwapChain(); createImageViews(); @@ -269,17 +245,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -292,13 +268,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -347,22 +323,22 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = deviceExtensions.size(); + createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } @@ -409,16 +385,10 @@ class HelloTriangleApplication { createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - VkSwapchainKHR oldSwapChain = swapChain; - createInfo.oldSwapchain = oldSwapChain; - - VkSwapchainKHR newSwapChain; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &newSwapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { throw std::runtime_error("failed to create swap chain!"); } - swapChain = newSwapChain; - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); @@ -428,9 +398,9 @@ class HelloTriangleApplication { } void createImageViews() { - swapChainImageViews.resize(swapChainImages.size(), VDeleter{device, vkDestroyImageView}); + swapChainImageViews.resize(swapChainImages.size()); - for (uint32_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages[i]; @@ -446,7 +416,7 @@ class HelloTriangleApplication { 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!"); } } @@ -489,7 +459,7 @@ class HelloTriangleApplication { 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!"); } } @@ -498,10 +468,8 @@ class HelloTriangleApplication { auto vertShaderCode = readFile("shaders/vert.spv"); auto fragShaderCode = readFile("shaders/frag.spv"); - VDeleter vertShaderModule{device, vkDestroyShaderModule}; - VDeleter fragShaderModule{device, vkDestroyShaderModule}; - createShaderModule(vertShaderCode, vertShaderModule); - createShaderModule(fragShaderCode, fragShaderModule); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -524,7 +492,7 @@ class HelloTriangleApplication { auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.vertexBindingDescriptionCount = 1; - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); @@ -587,7 +555,7 @@ class HelloTriangleApplication { pipelineLayoutInfo.setLayoutCount = 0; pipelineLayoutInfo.pushConstantRangeCount = 0; - 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!"); } @@ -606,13 +574,16 @@ class HelloTriangleApplication { pipelineInfo.subpass = 0; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; - 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!"); } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); } void createFramebuffers() { - swapChainFramebuffers.resize(swapChainImageViews.size(), VDeleter{device, vkDestroyFramebuffer}); + swapChainFramebuffers.resize(swapChainImageViews.size()); for (size_t i = 0; i < swapChainImageViews.size(); i++) { VkImageView attachments[] = { @@ -628,7 +599,7 @@ class HelloTriangleApplication { 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!"); } } @@ -641,16 +612,12 @@ class HelloTriangleApplication { poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; - 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 createCommandBuffers() { - if (commandBuffers.size() > 0) { - vkFreeCommandBuffers(device, commandPool, commandBuffers.size(), commandBuffers.data()); - } - commandBuffers.resize(swapChainFramebuffers.size()); VkCommandBufferAllocateInfo allocInfo = {}; @@ -699,8 +666,8 @@ class HelloTriangleApplication { 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!"); } @@ -758,7 +725,7 @@ class HelloTriangleApplication { } } - void createShaderModule(const std::vector& code, VDeleter& shaderModule) { + VkShaderModule createShaderModule(const std::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.size(); @@ -768,9 +735,12 @@ class HelloTriangleApplication { createInfo.pCode = codeAligned.data(); - if (vkCreateShaderModule(device, &createInfo, nullptr, shaderModule.replace()) != VK_SUCCESS) { + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { throw std::runtime_error("failed to create shader module!"); } + + return shaderModule; } VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats) { @@ -808,7 +778,10 @@ class HelloTriangleApplication { int width, height; glfwGetWindowSize(window, &width, &height); - VkExtent2D actualExtent = {width, height}; + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); @@ -982,4 +955,4 @@ int main() { } return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/code/window_surface.cpp b/code/window_surface.cpp index de4a36d4..fab2d876 100644 --- a/code/window_surface.cpp +++ b/code/window_surface.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -37,64 +36,6 @@ void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT } } -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; @@ -110,17 +51,18 @@ class HelloTriangleApplication { initWindow(); initVulkan(); mainLoop(); + cleanup(); } private: GLFWwindow* window; - VDeleter instance{vkDestroyInstance}; - VDeleter callback{instance, DestroyDebugReportCallbackEXT}; - VDeleter surface{instance, vkDestroySurfaceKHR}; + VkInstance instance; + VkDebugReportCallbackEXT callback; + VkSurfaceKHR surface; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VDeleter device{vkDestroyDevice}; + VkDevice device; VkQueue graphicsQueue; VkQueue presentQueue; @@ -146,6 +88,13 @@ class HelloTriangleApplication { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } + } + + void cleanup() { + vkDestroyDevice(device, nullptr); + DestroyDebugReportCallbackEXT(instance, callback, nullptr); + vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyInstance(instance, nullptr); glfwDestroyWindow(window); @@ -170,17 +119,17 @@ class HelloTriangleApplication { createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); - createInfo.enabledExtensionCount = extensions.size(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } - if (vkCreateInstance(&createInfo, nullptr, instance.replace()) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create instance!"); } } @@ -193,13 +142,13 @@ class HelloTriangleApplication { 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 set up debug callback!"); } } 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!"); } } @@ -248,21 +197,21 @@ class HelloTriangleApplication { VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); createInfo.pQueueCreateInfos = queueCreateInfos.data(); - createInfo.queueCreateInfoCount = (uint32_t) queueCreateInfos.size(); createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = 0; if (enableValidationLayers) { - createInfo.enabledLayerCount = validationLayers.size(); + createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { 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!"); } diff --git a/daux.patch b/daux.patch index 7571a6d3..8970b874 100644 --- a/daux.patch +++ b/daux.patch @@ -1,11 +1,11 @@ -From 40008c88788c97fd4b81e1117a5f029d9a457acd Mon Sep 17 00:00:00 2001 +From b3713faf02ab4ace5be4dbc57f9deb45510c57dd Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde -Date: Mon, 17 Apr 2017 20:02:04 +0200 +Date: Thu, 11 May 2017 15:48:53 +0200 Subject: [PATCH] Adjust theme for Vulkan tutorial --- daux/VulkanLinkProcessor.php | 69 ++++ - templates/content.php | 26 +- + templates/content.php | 25 +- templates/layout/00_layout.php | 2 +- templates/layout/05_page.php | 17 +- themes/daux/css/theme-blue.min.css | 2 +- @@ -20,7 +20,7 @@ Subject: [PATCH] Adjust theme for Vulkan tutorial themes/daux/less/structure.less | 27 +- themes/daux/less/theme-blue.less | 10 +- themes/daux_singlepage/css/main.min.css | 2 +- - 16 files changed, 924 insertions(+), 137 deletions(-) + 16 files changed, 923 insertions(+), 137 deletions(-) create mode 100644 daux/VulkanLinkProcessor.php diff --git a/daux/VulkanLinkProcessor.php b/daux/VulkanLinkProcessor.php @@ -99,7 +99,7 @@ index 0000000..4e4d456 + } +?> diff --git a/templates/content.php b/templates/content.php -index 2febe38..03017b7 100644 +index 2febe38..f1083bd 100644 --- a/templates/content.php +++ b/templates/content.php @@ -2,17 +2,14 @@ @@ -122,7 +122,7 @@ index 2febe38..03017b7 100644 -@@ -26,5 +23,24 @@ +@@ -26,5 +23,23 @@ @@ -131,8 +131,7 @@ index 2febe38..03017b7 100644 +