目录

  • Vulkan-Tutorial 学习相关资源整理
  • 开发环境搭建
  • Compile Shader
    • Shader
    • Compile
  • 素材
  • Vulkan 教程项目结构
    • 初始化 Vulkan 相关
    • 渲染循环相关
    • 销毁 Vulkan 实例
  • Code

Vulkan-Tutorial 学习相关资源整理

  • Vulkan-Tutorial PDF下载地址:https://vulkan-tutorial.com/
  • Vulkan SDK下载地址:https://vulkan.lunarg.com/
  • GLFW 下载地址:https://www.glfw.org/
  • GLM下载地址:https://github.com/g-truc/glm.git
  • stb_image.h下载地址:https://github.com/nothings/stb.git
  • tiny_obj_loader.h下载地址:https://github.com/tinyobjloader/tinyobjloader.git
  • 官方教程代码下载地址:https://github.com/Overv/VulkanTutorial.git

开发环境搭建

  1. 下载所有教程资源
  2. 安装Vulkan SDK,直接默认安装即可(记住安装路径)
  3. 编译GLM,用Cmake + VS编译
  4. 新建include目录和lib目录
  5. 将 glm 文件中的 glm 文件夹及其内所有文件复制到 include 文件夹中
  6. 将 stb 文件夹中 stb_image.h 复制到 include 文件夹中
  7. 将 tinyobjloader 文件夹中 tiny_obj_loader.h 复制到 include 文件夹中
  8. 将 glfw-3.3.4\include 中 GLFW 复制到 include 文件夹中
  9. 将 glfw-3.3.4\build\src\Release 中 glfw3.lib 复制到 lib 文件夹中
  10. VS工程中引入 include 和 lib 文件夹。并链接 glfw3.lib
  11. VS工程中引入 Vulkan SDK 的 Include 文件夹:VulkanSDK\1.2.176.1\Include
  12. VS工程中引入 Vulkan SDK 的 Lib 文件夹:VulkanSDK\1.2.176.1\Lib
  13. VS工程链接 vulkan-1.lib
  14. C++语言标准设置为:ISO C++17 标准 (/std:c++17)

Compile Shader

Shader

在工程根目录中新建 shaders 文件夹放入两个 shader 文件

shader.vert

 #version 450#version 450#extension GL_ARB_separate_shader_objects : enablelayout(binding = 0) uniform UniformBufferObject {mat4 model;mat4 view;mat4 proj;} ubo;layout(location = 0) in vec3 inPosition;layout(location = 1) in vec3 inColor;layout(location = 2) in vec2 inTexCoord;layout(location = 0) out vec3 fragColor;layout(location = 1) out vec2 fragTexCoord;void main() {gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);fragColor = inColor;fragTexCoord = inTexCoord;}

shader.frag

 #version 450#extension GL_ARB_separate_shader_objects : enablelayout(location = 0) in vec3 fragColor;layout(location = 1) in vec2 fragTexCoord;layout(location = 0) out vec4 outColor;layout(binding = 1) uniform sampler2D texSampler;void main() {outColor = texture(texSampler, fragTexCoord);}

Compile

在shaders文件夹新建 bat 文件放置下列命令

C:\VulkanSDK\1.2.176.1\Bin32\glslc.exe shader.vert -o shaders/vert.spv
C:\VulkanSDK\1.2.176.1\Bin32\glslc.exe shader.frag -o shaders/frag.spv
pause

素材

  • 在工程根目录中新建 models 文件夹,并放入 VulkanTutorial\resources 中的 viking_room.obj
  • 在工程根目录中新建 textures文件夹,并放入 VulkanTutorial\resources 中的 viking_room.png

Vulkan 教程项目结构

初始化 Vulkan 相关

(!!为每次渲染都需要创建的内容)

-- 创建 Vulkan 实例:。ValidationLayerSupport:验证层在Debug的时候开启,在release的时候关闭,用于捕获异常。(第一节)。RequiredInstanceExtensions:获取支持使用的全局扩展。(第一节)。vkCreateInstance: 创建实例
--  创建debug工具 setupDebugMessenger。(第一节)
-- 创建 Surface 这里指定的是 glfw 的 surface :glfwCreateWindowSurface
-- 选择显卡 。列出所有显卡:vkEnumeratePhysicalDevices。。isDeviceSuitable():选择合适的显卡。。获取选择显卡支持的多重采样的个数,为抗锯齿做准备
-- 创建逻辑驱动器 vkCreateDevice
!!-- 创建 SwapChain:vkCreateSwapchainKHR
!!-- 创建 ImageViews:    个数取决于逻辑驱动支持的最大数
!!-- 创建 RenderPass:  其中包含。colorAttachment。depthAttachment。colorAttachmentResolve 用于多重采样。subpass
-- 创建 DescriptorSetLayout 是着色器自由访问缓冲区和图像等资源的一种方式(第十一节)。uboLayoutBinding:UNIFORM_BUFFER。samplerLayoutBinding:IMAGE_SAMPLER。 vkCreateDescriptorSetLayout
!!-- 创建 GraphicsPipeline。createShaderModule: vkCreateShaderModule 读取shader字符串并编译shader。vertShaderStageInfo:顶点着色器配置。fragShaderStageInfo:片元着色器设置。vertexInputInfo : 包括 getBindingDescription 和 getAttributeDescriptions 即绑定模型数据。inputAssembly : 设置输入模型数据的属性。viewport 相关。RasterizationState:光栅化设置。Multisample:多重采样相关。DepthStencil:深度和模板设置相关。ColorBlend:颜色混合相关。vkCreatePipelineLayout。vkCreateGraphicsPipelines。创建完 Pipelin e后销毁 ShaderModule
-- 创建 CommandPool
!!-- 创建 ColorResources:包括 createImage 和 createImageView
!!-- 创建 DepthResources:包括 createImage 和 createImageView
!!-- 创建 Framebuffers:buffer的数量与 swapChainImageViews 相同
-- 创建 TextureImage:。createBuffer: 创建缓存区。vkMapMemory:将读取到内存的贴图数据映射到缓冲区。memcpy:将贴图数据拷贝到缓冲区。vkUnmapMemory:解除映射。createImage:创建 image。copyBufferToImage:将缓冲区贴图数据复制到Image中。vkDestroyBuffer:删除缓冲区。vkFreeMemory:释放内存。generateMipmaps:生成mipmap
-- 创建TextureImageView
-- 创建 TextureSampler
-- 加载模型
-- 创建VBO。createBuffer。vkMapMemory。memcpy。vkUnmapMemory。createBuffer。copyBuffer。vkDestroyBuffer。vkFreeMemory
-- 创建 IBO 同上
!!-- 创建 UniformBuffers:与 swapChainImages 数量相同
!!-- 创建 DescriptorPool:用于绑定 UNIFORM_BUFFER 和 IMAGE_SAMPLER
!!-- 创建 DescriptorSets:用于写入 UNIFORM_BUFFER 和 IMAGE_SAMPLER 所绑定的值
!!-- 创建 CommandBuffers:用于绑定所有用于渲染的资源。vkBeginCommandBuffer:遍历 commandBuffers 设置执行渲染的命令。vkCmdBeginRenderPass。vkCmdBindPipeline。vkCmdBindVertexBuffers。vkCmdBindIndexBuffer。vkCmdBindDescriptorSets。vkCmdDrawIndexed。vkCmdEndRenderPass
-- 创建 SyncObjects 用于同步或异步渲染资源管理(锁)。vkCreateSemaphore。vkCreateFence

渲染循环相关

-- vkWaitForFences:锁
-- vkAcquireNextImageKHR:获取渲染图片
-- recreateSwapChain:重置SwapChain。glfwGetFramebufferSize:重新设置渲染窗口大小。vkDeviceWaitIdle:锁。cleanupSwapChain:清理SwapChain相关资源- vkDestroyImageView:包括:深度和 Color ImageView- vkDestroyImage:包括:深度和 Color Image- vkFreeMemory:包括:深度和 Color ImageMemory- vkDestroyFramebuffer- vkFreeCommandBuffers- vkDestroyPipeline- vkDestroyPipelineLayout- vkDestroyRenderPass- vkDestroyImageView- vkDestroySwapchainKHR- vkDestroyBuffer:uniformBuffers- vkFreeMemory:uniformBuffersMemory- vkDestroyDescriptorPool。createSwapChain。createImageViews。createRenderPass。createGraphicsPipeline。createColorResources。createDepthResources。createFramebuffers。createUniformBuffers。createDescriptorPool。createDescriptorSets。createCommandBuffers
-- updateUniformBuffer
-- vkWaitForFences
-- vkResetFences
-- vkQueueSubmit

销毁 Vulkan 实例

-- cleanupSwapChain
-- vkDestroySampler
-- vkDestroyImageView
--  vkDestroyImage
-- vkFreeMemory
-- vkDestroyDescriptorSetLayout
-- vkDestroyBuffer
-- vkFreeMemory
-- vkDestroySemaphore
-- vkDestroyFence
-- vkDestroyCommandPool
-- vkDestroyDevice
-- DestroyDebugUtilsMessengerEXT
-- vkDestroySurfaceKHR
-- vkDestroyInstance

Code

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/hash.hpp>#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny_obj_loader.h>#include <iostream>
#include <fstream>
#include <stdexcept>
#include <algorithm>
#include <chrono>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <cstdint>
#include <array>
#include <optional>
#include <set>
#include <unordered_map>const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;const std::string MODEL_PATH = "models/viking_room.obj";
const std::string TEXTURE_PATH = "textures/viking_room.png";const int MAX_FRAMES_IN_FLIGHT = 2;const std::vector<const char*> validationLayers = {"VK_LAYER_KHRONOS_validation"
};const std::vector<const char*> deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME
};#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endifVkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");if (func != nullptr) {return func(instance, pCreateInfo, pAllocator, pDebugMessenger);}else {return VK_ERROR_EXTENSION_NOT_PRESENT;}
}void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator) {auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");if (func != nullptr) {func(instance, debugMessenger, pAllocator);}
}struct QueueFamilyIndices {std::optional<uint32_t> graphicsFamily;std::optional<uint32_t> presentFamily;bool isComplete() {return graphicsFamily.has_value() && presentFamily.has_value();}
};struct SwapChainSupportDetails {VkSurfaceCapabilitiesKHR capabilities;std::vector<VkSurfaceFormatKHR> formats;std::vector<VkPresentModeKHR> presentModes;
};struct Vertex {glm::vec3 pos;glm::vec3 color;glm::vec2 texCoord;static VkVertexInputBindingDescription getBindingDescription() {VkVertexInputBindingDescription bindingDescription{};bindingDescription.binding = 0;bindingDescription.stride = sizeof(Vertex);bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;return bindingDescription;}static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};attributeDescriptions[0].binding = 0;attributeDescriptions[0].location = 0;attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;attributeDescriptions[0].offset = offsetof(Vertex, pos);attributeDescriptions[1].binding = 0;attributeDescriptions[1].location = 1;attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;attributeDescriptions[1].offset = offsetof(Vertex, color);attributeDescriptions[2].binding = 0;attributeDescriptions[2].location = 2;attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;attributeDescriptions[2].offset = offsetof(Vertex, texCoord);return attributeDescriptions;}bool operator==(const Vertex& other) const {return pos == other.pos && color == other.color && texCoord == other.texCoord;}
};namespace std {template<> struct hash<Vertex> {size_t operator()(Vertex const& vertex) const {return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^ (hash<glm::vec2>()(vertex.texCoord) << 1);}};
}struct UniformBufferObject {alignas(16) glm::mat4 model;alignas(16) glm::mat4 view;alignas(16) glm::mat4 proj;
};class HelloTriangleApplication {public:void run() {initWindow();initVulkan();mainLoop();cleanup();}private:GLFWwindow* window;VkInstance instance;VkDebugUtilsMessengerEXT debugMessenger;VkSurfaceKHR surface;VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;VkDevice device;VkQueue graphicsQueue;VkQueue presentQueue;VkSwapchainKHR swapChain;std::vector<VkImage> swapChainImages;VkFormat swapChainImageFormat;VkExtent2D swapChainExtent;std::vector<VkImageView> swapChainImageViews;std::vector<VkFramebuffer> swapChainFramebuffers;VkRenderPass renderPass;VkDescriptorSetLayout descriptorSetLayout;VkPipelineLayout pipelineLayout;VkPipeline graphicsPipeline;VkCommandPool commandPool;VkImage colorImage;VkDeviceMemory colorImageMemory;VkImageView colorImageView;VkImage depthImage;VkDeviceMemory depthImageMemory;VkImageView depthImageView;uint32_t mipLevels;VkImage textureImage;VkDeviceMemory textureImageMemory;VkImageView textureImageView;VkSampler textureSampler;std::vector<Vertex> vertices;std::vector<uint32_t> indices;VkBuffer vertexBuffer;VkDeviceMemory vertexBufferMemory;VkBuffer indexBuffer;VkDeviceMemory indexBufferMemory;std::vector<VkBuffer> uniformBuffers;std::vector<VkDeviceMemory> uniformBuffersMemory;VkDescriptorPool descriptorPool;std::vector<VkDescriptorSet> descriptorSets;std::vector<VkCommandBuffer> commandBuffers;std::vector<VkSemaphore> imageAvailableSemaphores;std::vector<VkSemaphore> renderFinishedSemaphores;std::vector<VkFence> inFlightFences;std::vector<VkFence> imagesInFlight;size_t currentFrame = 0;bool framebufferResized = false;void initWindow() {glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);glfwSetWindowUserPointer(window, this);glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);}static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));app->framebufferResized = true;}void initVulkan() {createInstance();setupDebugMessenger();createSurface();pickPhysicalDevice();createLogicalDevice();createSwapChain();createImageViews();createRenderPass();createDescriptorSetLayout();createGraphicsPipeline();createCommandPool();createColorResources();createDepthResources();createFramebuffers();createTextureImage();createTextureImageView();createTextureSampler();loadModel();createVertexBuffer();createIndexBuffer();createUniformBuffers();createDescriptorPool();createDescriptorSets();createCommandBuffers();createSyncObjects();}void mainLoop() {while (!glfwWindowShouldClose(window)) {glfwPollEvents();drawFrame();}vkDeviceWaitIdle(device);}void cleanupSwapChain() {vkDestroyImageView(device, depthImageView, nullptr);vkDestroyImage(device, depthImage, nullptr);vkFreeMemory(device, depthImageMemory, nullptr);vkDestroyImageView(device, colorImageView, nullptr);vkDestroyImage(device, colorImage, nullptr);vkFreeMemory(device, colorImageMemory, nullptr);for (auto framebuffer : swapChainFramebuffers) {vkDestroyFramebuffer(device, framebuffer, nullptr);}vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());vkDestroyPipeline(device, graphicsPipeline, nullptr);vkDestroyPipelineLayout(device, pipelineLayout, nullptr);vkDestroyRenderPass(device, renderPass, nullptr);for (auto imageView : swapChainImageViews) {vkDestroyImageView(device, imageView, nullptr);}vkDestroySwapchainKHR(device, swapChain, nullptr);for (size_t i = 0; i < swapChainImages.size(); i++) {vkDestroyBuffer(device, uniformBuffers[i], nullptr);vkFreeMemory(device, uniformBuffersMemory[i], nullptr);}vkDestroyDescriptorPool(device, descriptorPool, nullptr);}void cleanup() {cleanupSwapChain();vkDestroySampler(device, textureSampler, nullptr);vkDestroyImageView(device, textureImageView, nullptr);vkDestroyImage(device, textureImage, nullptr);vkFreeMemory(device, textureImageMemory, nullptr);vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);vkDestroyBuffer(device, indexBuffer, nullptr);vkFreeMemory(device, indexBufferMemory, nullptr);vkDestroyBuffer(device, vertexBuffer, nullptr);vkFreeMemory(device, vertexBufferMemory, nullptr);for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);vkDestroyFence(device, inFlightFences[i], nullptr);}vkDestroyCommandPool(device, commandPool, nullptr);vkDestroyDevice(device, nullptr);if (enableValidationLayers) {DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);}vkDestroySurfaceKHR(instance, surface, nullptr);vkDestroyInstance(instance, nullptr);glfwDestroyWindow(window);glfwTerminate();}void recreateSwapChain() {int width = 0, height = 0;glfwGetFramebufferSize(window, &width, &height);while (width == 0 || height == 0) {glfwGetFramebufferSize(window, &width, &height);glfwWaitEvents();}vkDeviceWaitIdle(device);cleanupSwapChain();createSwapChain();createImageViews();createRenderPass();createGraphicsPipeline();createColorResources();createDepthResources();createFramebuffers();createUniformBuffers();createDescriptorPool();createDescriptorSets();createCommandBuffers();imagesInFlight.resize(swapChainImages.size(), VK_NULL_HANDLE);}void createInstance() {if (enableValidationLayers && !checkValidationLayerSupport()) {throw std::runtime_error("validation layers requested, but not available!");}VkApplicationInfo appInfo{};appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pApplicationName = "Hello Triangle";appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.pEngineName = "No Engine";appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);appInfo.apiVersion = VK_API_VERSION_1_0;VkInstanceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;createInfo.pApplicationInfo = &appInfo;auto extensions = getRequiredExtensions();createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());createInfo.ppEnabledExtensionNames = extensions.data();VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};if (enableValidationLayers) {createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());createInfo.ppEnabledLayerNames = validationLayers.data();populateDebugMessengerCreateInfo(debugCreateInfo);createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;}else {createInfo.enabledLayerCount = 0;createInfo.pNext = nullptr;}if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {throw std::runtime_error("failed to create instance!");}}void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {createInfo = {};createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;createInfo.pfnUserCallback = debugCallback;}void setupDebugMessenger() {if (!enableValidationLayers) return;VkDebugUtilsMessengerCreateInfoEXT createInfo;populateDebugMessengerCreateInfo(createInfo);if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {throw std::runtime_error("failed to set up debug messenger!");}}void createSurface() {if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {throw std::runtime_error("failed to create window surface!");}}void pickPhysicalDevice() {uint32_t deviceCount = 0;vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);if (deviceCount == 0) {throw std::runtime_error("failed to find GPUs with Vulkan support!");}std::vector<VkPhysicalDevice> devices(deviceCount);vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());for (const auto& device : devices) {if (isDeviceSuitable(device)) {physicalDevice = device;msaaSamples = getMaxUsableSampleCount();break;}}if (physicalDevice == VK_NULL_HANDLE) {throw std::runtime_error("failed to find a suitable GPU!");}}void createLogicalDevice() {QueueFamilyIndices indices = findQueueFamilies(physicalDevice);std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };float queuePriority = 1.0f;for (uint32_t queueFamily : uniqueQueueFamilies) {VkDeviceQueueCreateInfo queueCreateInfo{};queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;queueCreateInfo.queueFamilyIndex = queueFamily;queueCreateInfo.queueCount = 1;queueCreateInfo.pQueuePriorities = &queuePriority;queueCreateInfos.push_back(queueCreateInfo);}VkPhysicalDeviceFeatures deviceFeatures{};deviceFeatures.samplerAnisotropy = VK_TRUE;VkDeviceCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());createInfo.pQueueCreateInfos = queueCreateInfos.data();createInfo.pEnabledFeatures = &deviceFeatures;createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());createInfo.ppEnabledExtensionNames = deviceExtensions.data();if (enableValidationLayers) {createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());createInfo.ppEnabledLayerNames = validationLayers.data();}else {createInfo.enabledLayerCount = 0;}if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {throw std::runtime_error("failed to create logical device!");}vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);}void createSwapChain() {SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {imageCount = swapChainSupport.capabilities.maxImageCount;}VkSwapchainCreateInfoKHR createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;createInfo.surface = surface;createInfo.minImageCount = imageCount;createInfo.imageFormat = surfaceFormat.format;createInfo.imageColorSpace = surfaceFormat.colorSpace;createInfo.imageExtent = extent;createInfo.imageArrayLayers = 1;createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;QueueFamilyIndices indices = findQueueFamilies(physicalDevice);uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };if (indices.graphicsFamily != indices.presentFamily) {createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;createInfo.queueFamilyIndexCount = 2;createInfo.pQueueFamilyIndices = queueFamilyIndices;}else {createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;}createInfo.preTransform = swapChainSupport.capabilities.currentTransform;createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;createInfo.presentMode = presentMode;createInfo.clipped = VK_TRUE;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());swapChainImageFormat = surfaceFormat.format;swapChainExtent = extent;}void createImageViews() {swapChainImageViews.resize(swapChainImages.size());for (uint32_t i = 0; i < swapChainImages.size(); i++) {swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);}}void createRenderPass() {VkAttachmentDescription colorAttachment{};colorAttachment.format = swapChainImageFormat;colorAttachment.samples = msaaSamples;colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;VkAttachmentDescription depthAttachment{};depthAttachment.format = findDepthFormat();depthAttachment.samples = msaaSamples;depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;VkAttachmentDescription colorAttachmentResolve{};colorAttachmentResolve.format = swapChainImageFormat;colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;VkAttachmentReference colorAttachmentRef{};colorAttachmentRef.attachment = 0;colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;VkAttachmentReference depthAttachmentRef{};depthAttachmentRef.attachment = 1;depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;VkAttachmentReference colorAttachmentResolveRef{};colorAttachmentResolveRef.attachment = 2;colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;VkSubpassDescription subpass{};subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;subpass.colorAttachmentCount = 1;subpass.pColorAttachments = &colorAttachmentRef;subpass.pDepthStencilAttachment = &depthAttachmentRef;subpass.pResolveAttachments = &colorAttachmentResolveRef;VkSubpassDependency dependency{};dependency.srcSubpass = VK_SUBPASS_EXTERNAL;dependency.dstSubpass = 0;dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;dependency.srcAccessMask = 0;dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;std::array<VkAttachmentDescription, 3> attachments = { colorAttachment, depthAttachment, colorAttachmentResolve };VkRenderPassCreateInfo renderPassInfo{};renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());renderPassInfo.pAttachments = attachments.data();renderPassInfo.subpassCount = 1;renderPassInfo.pSubpasses = &subpass;renderPassInfo.dependencyCount = 1;renderPassInfo.pDependencies = &dependency;if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {throw std::runtime_error("failed to create render pass!");}}void createDescriptorSetLayout() {VkDescriptorSetLayoutBinding uboLayoutBinding{};uboLayoutBinding.binding = 0;uboLayoutBinding.descriptorCount = 1;uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;uboLayoutBinding.pImmutableSamplers = nullptr;uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;VkDescriptorSetLayoutBinding samplerLayoutBinding{};samplerLayoutBinding.binding = 1;samplerLayoutBinding.descriptorCount = 1;samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;samplerLayoutBinding.pImmutableSamplers = nullptr;samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;std::array<VkDescriptorSetLayoutBinding, 2> bindings = { uboLayoutBinding, samplerLayoutBinding };VkDescriptorSetLayoutCreateInfo layoutInfo{};layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());layoutInfo.pBindings = bindings.data();if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {throw std::runtime_error("failed to create descriptor set layout!");}}void createGraphicsPipeline() {auto vertShaderCode = readFile("shaders/vert.spv");auto fragShaderCode = readFile("shaders/frag.spv");VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);VkPipelineShaderStageCreateInfo vertShaderStageInfo{};vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;vertShaderStageInfo.module = vertShaderModule;vertShaderStageInfo.pName = "main";VkPipelineShaderStageCreateInfo fragShaderStageInfo{};fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;fragShaderStageInfo.module = fragShaderModule;fragShaderStageInfo.pName = "main";VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };VkPipelineVertexInputStateCreateInfo vertexInputInfo{};vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;auto bindingDescription = Vertex::getBindingDescription();auto attributeDescriptions = Vertex::getAttributeDescriptions();vertexInputInfo.vertexBindingDescriptionCount = 1;vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();VkPipelineInputAssemblyStateCreateInfo inputAssembly{};inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;inputAssembly.primitiveRestartEnable = VK_FALSE;VkViewport viewport{};viewport.x = 0.0f;viewport.y = 0.0f;viewport.width = (float)swapChainExtent.width;viewport.height = (float)swapChainExtent.height;viewport.minDepth = 0.0f;viewport.maxDepth = 1.0f;VkRect2D scissor{};scissor.offset = { 0, 0 };scissor.extent = swapChainExtent;VkPipelineViewportStateCreateInfo viewportState{};viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;viewportState.viewportCount = 1;viewportState.pViewports = &viewport;viewportState.scissorCount = 1;viewportState.pScissors = &scissor;VkPipelineRasterizationStateCreateInfo rasterizer{};rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;rasterizer.depthClampEnable = VK_FALSE;rasterizer.rasterizerDiscardEnable = VK_FALSE;rasterizer.polygonMode = VK_POLYGON_MODE_FILL;rasterizer.lineWidth = 1.0f;rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;rasterizer.depthBiasEnable = VK_FALSE;VkPipelineMultisampleStateCreateInfo multisampling{};multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;multisampling.sampleShadingEnable = VK_FALSE;multisampling.rasterizationSamples = msaaSamples;VkPipelineDepthStencilStateCreateInfo depthStencil{};depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;depthStencil.depthTestEnable = VK_TRUE;depthStencil.depthWriteEnable = VK_TRUE;depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;depthStencil.depthBoundsTestEnable = VK_FALSE;depthStencil.stencilTestEnable = VK_FALSE;VkPipelineColorBlendAttachmentState colorBlendAttachment{};colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;colorBlendAttachment.blendEnable = VK_FALSE;VkPipelineColorBlendStateCreateInfo colorBlending{};colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;colorBlending.logicOpEnable = VK_FALSE;colorBlending.logicOp = VK_LOGIC_OP_COPY;colorBlending.attachmentCount = 1;colorBlending.pAttachments = &colorBlendAttachment;colorBlending.blendConstants[0] = 0.0f;colorBlending.blendConstants[1] = 0.0f;colorBlending.blendConstants[2] = 0.0f;colorBlending.blendConstants[3] = 0.0f;VkPipelineLayoutCreateInfo pipelineLayoutInfo{};pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;pipelineLayoutInfo.setLayoutCount = 1;pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {throw std::runtime_error("failed to create pipeline layout!");}VkGraphicsPipelineCreateInfo pipelineInfo{};pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;pipelineInfo.stageCount = 2;pipelineInfo.pStages = shaderStages;pipelineInfo.pVertexInputState = &vertexInputInfo;pipelineInfo.pInputAssemblyState = &inputAssembly;pipelineInfo.pViewportState = &viewportState;pipelineInfo.pRasterizationState = &rasterizer;pipelineInfo.pMultisampleState = &multisampling;pipelineInfo.pDepthStencilState = &depthStencil;pipelineInfo.pColorBlendState = &colorBlending;pipelineInfo.layout = pipelineLayout;pipelineInfo.renderPass = renderPass;pipelineInfo.subpass = 0;pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;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());for (size_t i = 0; i < swapChainImageViews.size(); i++) {std::array<VkImageView, 3> attachments = {colorImageView,depthImageView,swapChainImageViews[i]};VkFramebufferCreateInfo framebufferInfo{};framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;framebufferInfo.renderPass = renderPass;framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());framebufferInfo.pAttachments = attachments.data();framebufferInfo.width = swapChainExtent.width;framebufferInfo.height = swapChainExtent.height;framebufferInfo.layers = 1;if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {throw std::runtime_error("failed to create framebuffer!");}}}void createCommandPool() {QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);VkCommandPoolCreateInfo poolInfo{};poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {throw std::runtime_error("failed to create graphics command pool!");}}void createColorResources() {VkFormat colorFormat = swapChainImageFormat;createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage, colorImageMemory);colorImageView = createImageView(colorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);}void createDepthResources() {VkFormat depthFormat = findDepthFormat();createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory);depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);}VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {for (VkFormat format : candidates) {VkFormatProperties props;vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {return format;}else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {return format;}}throw std::runtime_error("failed to find supported format!");}VkFormat findDepthFormat() {return findSupportedFormat({ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },VK_IMAGE_TILING_OPTIMAL,VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);}bool hasStencilComponent(VkFormat format) {return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;}void createTextureImage() {int texWidth, texHeight, texChannels;stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);VkDeviceSize imageSize = texWidth * texHeight * 4;mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;if (!pixels) {throw std::runtime_error("failed to load texture image!");}VkBuffer stagingBuffer;VkDeviceMemory stagingBufferMemory;createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);void* data;vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);memcpy(data, pixels, static_cast<size_t>(imageSize));vkUnmapMemory(device, stagingBufferMemory);stbi_image_free(pixels);createImage(texWidth, texHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));//transitioned to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL while generating mipmapsvkDestroyBuffer(device, stagingBuffer, nullptr);vkFreeMemory(device, stagingBufferMemory, nullptr);generateMipmaps(textureImage, VK_FORMAT_R8G8B8A8_SRGB, texWidth, texHeight, mipLevels);}void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels) {// Check if image format supports linear blittingVkFormatProperties formatProperties;vkGetPhysicalDeviceFormatProperties(physicalDevice, imageFormat, &formatProperties);if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {throw std::runtime_error("texture image format does not support linear blitting!");}VkCommandBuffer commandBuffer = beginSingleTimeCommands();VkImageMemoryBarrier barrier{};barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;barrier.image = image;barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;barrier.subresourceRange.baseArrayLayer = 0;barrier.subresourceRange.layerCount = 1;barrier.subresourceRange.levelCount = 1;int32_t mipWidth = texWidth;int32_t mipHeight = texHeight;for (uint32_t i = 1; i < mipLevels; i++) {barrier.subresourceRange.baseMipLevel = i - 1;barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;vkCmdPipelineBarrier(commandBuffer,VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,0, nullptr,0, nullptr,1, &barrier);VkImageBlit blit{};blit.srcOffsets[0] = { 0, 0, 0 };blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;blit.srcSubresource.mipLevel = i - 1;blit.srcSubresource.baseArrayLayer = 0;blit.srcSubresource.layerCount = 1;blit.dstOffsets[0] = { 0, 0, 0 };blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;blit.dstSubresource.mipLevel = i;blit.dstSubresource.baseArrayLayer = 0;blit.dstSubresource.layerCount = 1;vkCmdBlitImage(commandBuffer,image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1, &blit,VK_FILTER_LINEAR);barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;vkCmdPipelineBarrier(commandBuffer,VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,0, nullptr,0, nullptr,1, &barrier);if (mipWidth > 1) mipWidth /= 2;if (mipHeight > 1) mipHeight /= 2;}barrier.subresourceRange.baseMipLevel = mipLevels - 1;barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;vkCmdPipelineBarrier(commandBuffer,VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,0, nullptr,0, nullptr,1, &barrier);endSingleTimeCommands(commandBuffer);}VkSampleCountFlagBits getMaxUsableSampleCount() {VkPhysicalDeviceProperties physicalDeviceProperties;vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;if (counts & VK_SAMPLE_COUNT_64_BIT) { return VK_SAMPLE_COUNT_64_BIT; }if (counts & VK_SAMPLE_COUNT_32_BIT) { return VK_SAMPLE_COUNT_32_BIT; }if (counts & VK_SAMPLE_COUNT_16_BIT) { return VK_SAMPLE_COUNT_16_BIT; }if (counts & VK_SAMPLE_COUNT_8_BIT) { return VK_SAMPLE_COUNT_8_BIT; }if (counts & VK_SAMPLE_COUNT_4_BIT) { return VK_SAMPLE_COUNT_4_BIT; }if (counts & VK_SAMPLE_COUNT_2_BIT) { return VK_SAMPLE_COUNT_2_BIT; }return VK_SAMPLE_COUNT_1_BIT;}void createTextureImageView() {textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, mipLevels);}void createTextureSampler() {VkPhysicalDeviceProperties properties{};vkGetPhysicalDeviceProperties(physicalDevice, &properties);VkSamplerCreateInfo samplerInfo{};samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;samplerInfo.magFilter = VK_FILTER_LINEAR;samplerInfo.minFilter = VK_FILTER_LINEAR;samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;samplerInfo.anisotropyEnable = VK_TRUE;samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;samplerInfo.unnormalizedCoordinates = VK_FALSE;samplerInfo.compareEnable = VK_FALSE;samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;samplerInfo.minLod = 0.0f;samplerInfo.maxLod = static_cast<float>(mipLevels);samplerInfo.mipLodBias = 0.0f;if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {throw std::runtime_error("failed to create texture sampler!");}}VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels) {VkImageViewCreateInfo viewInfo{};viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;viewInfo.image = image;viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;viewInfo.format = format;viewInfo.subresourceRange.aspectMask = aspectFlags;viewInfo.subresourceRange.baseMipLevel = 0;viewInfo.subresourceRange.levelCount = mipLevels;viewInfo.subresourceRange.baseArrayLayer = 0;viewInfo.subresourceRange.layerCount = 1;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, uint32_t mipLevels, VkSampleCountFlagBits numSamples, 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;imageInfo.extent.width = width;imageInfo.extent.height = height;imageInfo.extent.depth = 1;imageInfo.mipLevels = mipLevels;imageInfo.arrayLayers = 1;imageInfo.format = format;imageInfo.tiling = tiling;imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;imageInfo.usage = usage;imageInfo.samples = numSamples;imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) {throw std::runtime_error("failed to create image!");}VkMemoryRequirements memRequirements;vkGetImageMemoryRequirements(device, image, &memRequirements);VkMemoryAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {throw std::runtime_error("failed to allocate image memory!");}vkBindImageMemory(device, image, imageMemory, 0);}void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) {VkCommandBuffer commandBuffer = beginSingleTimeCommands();VkImageMemoryBarrier barrier{};barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;barrier.oldLayout = oldLayout;barrier.newLayout = newLayout;barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;barrier.image = image;barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;barrier.subresourceRange.baseMipLevel = 0;barrier.subresourceRange.levelCount = mipLevels;barrier.subresourceRange.baseArrayLayer = 0;barrier.subresourceRange.layerCount = 1;VkPipelineStageFlags sourceStage;VkPipelineStageFlags destinationStage;if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {barrier.srcAccessMask = 0;barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;}else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;}else {throw std::invalid_argument("unsupported layout transition!");}vkCmdPipelineBarrier(commandBuffer,sourceStage, destinationStage,0,0, nullptr,0, nullptr,1, &barrier);endSingleTimeCommands(commandBuffer);}void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {VkCommandBuffer commandBuffer = beginSingleTimeCommands();VkBufferImageCopy region{};region.bufferOffset = 0;region.bufferRowLength = 0;region.bufferImageHeight = 0;region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;region.imageSubresource.mipLevel = 0;region.imageSubresource.baseArrayLayer = 0;region.imageSubresource.layerCount = 1;region.imageOffset = { 0, 0, 0 };region.imageExtent = {width,height,1};vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);endSingleTimeCommands(commandBuffer);}void loadModel() {tinyobj::attrib_t attrib;std::vector<tinyobj::shape_t> shapes;std::vector<tinyobj::material_t> materials;std::string warn, err;if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) {throw std::runtime_error(warn + err);}std::unordered_map<Vertex, uint32_t> uniqueVertices{};for (const auto& shape : shapes) {for (const auto& index : shape.mesh.indices) {Vertex vertex{};vertex.pos = {attrib.vertices[3 * index.vertex_index + 0],attrib.vertices[3 * index.vertex_index + 1],attrib.vertices[3 * index.vertex_index + 2]};vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0],1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};vertex.color = { 1.0f, 1.0f, 1.0f };if (uniqueVertices.count(vertex) == 0) {uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());vertices.push_back(vertex);}indices.push_back(uniqueVertices[vertex]);}}}void createVertexBuffer() {VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();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;vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);memcpy(data, vertices.data(), (size_t)bufferSize);vkUnmapMemory(device, stagingBufferMemory);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();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;vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);memcpy(data, indices.data(), (size_t)bufferSize);vkUnmapMemory(device, stagingBufferMemory);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 createUniformBuffers() {VkDeviceSize bufferSize = sizeof(UniformBufferObject);uniformBuffers.resize(swapChainImages.size());uniformBuffersMemory.resize(swapChainImages.size());for (size_t i = 0; i < swapChainImages.size(); i++) {createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);}}void createDescriptorPool() {std::array<VkDescriptorPoolSize, 2> poolSizes{};poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;poolSizes[0].descriptorCount = static_cast<uint32_t>(swapChainImages.size());poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;poolSizes[1].descriptorCount = static_cast<uint32_t>(swapChainImages.size());VkDescriptorPoolCreateInfo poolInfo{};poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());poolInfo.pPoolSizes = poolSizes.data();poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {throw std::runtime_error("failed to create descriptor pool!");}}void createDescriptorSets() {std::vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);VkDescriptorSetAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;allocInfo.descriptorPool = descriptorPool;allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());allocInfo.pSetLayouts = layouts.data();descriptorSets.resize(swapChainImages.size());if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {throw std::runtime_error("failed to allocate descriptor sets!");}for (size_t i = 0; i < swapChainImages.size(); i++) {VkDescriptorBufferInfo bufferInfo{};bufferInfo.buffer = uniformBuffers[i];bufferInfo.offset = 0;bufferInfo.range = sizeof(UniformBufferObject);VkDescriptorImageInfo imageInfo{};imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;imageInfo.imageView = textureImageView;imageInfo.sampler = textureSampler;std::array<VkWriteDescriptorSet, 2> descriptorWrites{};descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;descriptorWrites[0].dstSet = descriptorSets[i];descriptorWrites[0].dstBinding = 0;descriptorWrites[0].dstArrayElement = 0;descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;descriptorWrites[0].descriptorCount = 1;descriptorWrites[0].pBufferInfo = &bufferInfo;descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;descriptorWrites[1].dstSet = descriptorSets[i];descriptorWrites[1].dstBinding = 1;descriptorWrites[1].dstArrayElement = 0;descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;descriptorWrites[1].descriptorCount = 1;descriptorWrites[1].pImageInfo = &imageInfo;vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);}}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) != VK_SUCCESS) {throw std::runtime_error("failed to create buffer!");}VkMemoryRequirements memRequirements;vkGetBufferMemoryRequirements(device, buffer, &memRequirements);VkMemoryAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;allocInfo.allocationSize = memRequirements.size;allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {throw std::runtime_error("failed to allocate buffer memory!");}vkBindBufferMemory(device, buffer, bufferMemory, 0);}VkCommandBuffer beginSingleTimeCommands() {VkCommandBufferAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandPool = commandPool;allocInfo.commandBufferCount = 1;VkCommandBuffer commandBuffer;vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);VkCommandBufferBeginInfo beginInfo{};beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;vkBeginCommandBuffer(commandBuffer, &beginInfo);return commandBuffer;}void endSingleTimeCommands(VkCommandBuffer commandBuffer) {vkEndCommandBuffer(commandBuffer);VkSubmitInfo submitInfo{};submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &commandBuffer;vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);vkQueueWaitIdle(graphicsQueue);vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);}void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {VkCommandBuffer commandBuffer = beginSingleTimeCommands();VkBufferCopy copyRegion{};copyRegion.size = size;vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);endSingleTimeCommands(commandBuffer);}uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {VkPhysicalDeviceMemoryProperties memProperties;vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {return i;}}throw std::runtime_error("failed to find suitable memory type!");}void createCommandBuffers() {commandBuffers.resize(swapChainFramebuffers.size());VkCommandBufferAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;allocInfo.commandPool = commandPool;allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {throw std::runtime_error("failed to allocate command buffers!");}for (size_t i = 0; i < commandBuffers.size(); i++) {VkCommandBufferBeginInfo beginInfo{};beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {throw std::runtime_error("failed to begin recording command buffer!");}VkRenderPassBeginInfo renderPassInfo{};renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;renderPassInfo.renderPass = renderPass;renderPassInfo.framebuffer = swapChainFramebuffers[i];renderPassInfo.renderArea.offset = { 0, 0 };renderPassInfo.renderArea.extent = swapChainExtent;std::array<VkClearValue, 2> clearValues{};clearValues[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };clearValues[1].depthStencil = { 1.0f, 0 };renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());renderPassInfo.pClearValues = clearValues.data();vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);VkBuffer vertexBuffers[] = { vertexBuffer };VkDeviceSize offsets[] = { 0 };vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT32);vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);vkCmdEndRenderPass(commandBuffers[i]);if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {throw std::runtime_error("failed to record command buffer!");}}}void createSyncObjects() {imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);imagesInFlight.resize(swapChainImages.size(), VK_NULL_HANDLE);VkSemaphoreCreateInfo semaphoreInfo{};semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;VkFenceCreateInfo fenceInfo{};fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {throw std::runtime_error("failed to create synchronization objects for a frame!");}}}void updateUniformBuffer(uint32_t currentImage) {static auto startTime = std::chrono::high_resolution_clock::now();auto currentTime = std::chrono::high_resolution_clock::now();float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();UniformBufferObject ubo{};ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);ubo.proj[1][1] *= -1;void* data;vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);memcpy(data, &ubo, sizeof(ubo));vkUnmapMemory(device, uniformBuffersMemory[currentImage]);}void drawFrame() {vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);uint32_t imageIndex;VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);if (result == VK_ERROR_OUT_OF_DATE_KHR) {recreateSwapChain();return;}else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {throw std::runtime_error("failed to acquire swap chain image!");}updateUniformBuffer(imageIndex);if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);}imagesInFlight[imageIndex] = inFlightFences[currentFrame];VkSubmitInfo submitInfo{};submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };submitInfo.waitSemaphoreCount = 1;submitInfo.pWaitSemaphores = waitSemaphores;submitInfo.pWaitDstStageMask = waitStages;submitInfo.commandBufferCount = 1;submitInfo.pCommandBuffers = &commandBuffers[imageIndex];VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };submitInfo.signalSemaphoreCount = 1;submitInfo.pSignalSemaphores = signalSemaphores;vkResetFences(device, 1, &inFlightFences[currentFrame]);if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {throw std::runtime_error("failed to submit draw command buffer!");}VkPresentInfoKHR presentInfo{};presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;presentInfo.waitSemaphoreCount = 1;presentInfo.pWaitSemaphores = signalSemaphores;VkSwapchainKHR swapChains[] = { swapChain };presentInfo.swapchainCount = 1;presentInfo.pSwapchains = swapChains;presentInfo.pImageIndices = &imageIndex;result = vkQueuePresentKHR(presentQueue, &presentInfo);if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {framebufferResized = false;recreateSwapChain();}else if (result != VK_SUCCESS) {throw std::runtime_error("failed to present swap chain image!");}currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;}VkShaderModule createShaderModule(const std::vector<char>& code) {VkShaderModuleCreateInfo createInfo{};createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;createInfo.codeSize = code.size();createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());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<VkSurfaceFormatKHR>& availableFormats) {for (const auto& availableFormat : availableFormats) {if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {return availableFormat;}}return availableFormats[0];}VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {for (const auto& availablePresentMode : availablePresentModes) {if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {return availablePresentMode;}}return VK_PRESENT_MODE_FIFO_KHR;}VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {if (capabilities.currentExtent.width != UINT32_MAX) {return capabilities.currentExtent;}else {int width, height;glfwGetFramebufferSize(window, &width, &height);VkExtent2D actualExtent = {static_cast<uint32_t>(width),static_cast<uint32_t>(height)};actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);return actualExtent;}}SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {SwapChainSupportDetails details;vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);uint32_t formatCount;vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);if (formatCount != 0) {details.formats.resize(formatCount);vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());}uint32_t presentModeCount;vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);if (presentModeCount != 0) {details.presentModes.resize(presentModeCount);vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());}return details;}bool isDeviceSuitable(VkPhysicalDevice device) {QueueFamilyIndices indices = findQueueFamilies(device);bool extensionsSupported = checkDeviceExtensionSupport(device);bool swapChainAdequate = false;if (extensionsSupported) {SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();}VkPhysicalDeviceFeatures supportedFeatures;vkGetPhysicalDeviceFeatures(device, &supportedFeatures);return indices.isComplete() && extensionsSupported && swapChainAdequate && supportedFeatures.samplerAnisotropy;}bool checkDeviceExtensionSupport(VkPhysicalDevice device) {uint32_t extensionCount;vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);std::vector<VkExtensionProperties> availableExtensions(extensionCount);vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());for (const auto& extension : availableExtensions) {requiredExtensions.erase(extension.extensionName);}return requiredExtensions.empty();}QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {QueueFamilyIndices indices;uint32_t queueFamilyCount = 0;vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());int i = 0;for (const auto& queueFamily : queueFamilies) {if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {indices.graphicsFamily = i;}VkBool32 presentSupport = false;vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);if (presentSupport) {indices.presentFamily = i;}if (indices.isComplete()) {break;}i++;}return indices;}std::vector<const char*> getRequiredExtensions() {uint32_t glfwExtensionCount = 0;const char** glfwExtensions;glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);if (enableValidationLayers) {extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);}return extensions;}bool checkValidationLayerSupport() {uint32_t layerCount;vkEnumerateInstanceLayerProperties(&layerCount, nullptr);std::vector<VkLayerProperties> availableLayers(layerCount);vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());for (const char* layerName : validationLayers) {bool layerFound = false;for (const auto& layerProperties : availableLayers) {if (strcmp(layerName, layerProperties.layerName) == 0) {layerFound = true;break;}}if (!layerFound) {return false;}}return true;}static std::vector<char> readFile(const std::string& filename) {std::ifstream file(filename, std::ios::ate | std::ios::binary);if (!file.is_open()) {throw std::runtime_error("failed to open file!");}size_t fileSize = (size_t)file.tellg();std::vector<char> buffer(fileSize);file.seekg(0);file.read(buffer.data(), fileSize);file.close();return buffer;}static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;return VK_FALSE;}
};int main() {HelloTriangleApplication app;try {app.run();}catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

Vulkan学习(十五): 总结相关推荐

  1. OpenCV与图像处理学习十五——LBP纹理特征(含代码)

    OpenCV与图像处理学习十五--LBP纹理特征(含代码) 一.LBP介绍 二.LBP原理 三.代码应用 一.LBP介绍 LBP(Local Binary Pattern, 局部二值模式) , 是一种 ...

  2. PyTorch框架学习十五——可视化工具TensorBoard

    PyTorch框架学习十五--可视化工具TensorBoard 一.TensorBoard简介 二.TensorBoard安装及测试 三.TensorBoard的使用 1.add_scalar() 2 ...

  3. C++学习 十五、类继承(1)基类,派生类,访问权限,protected

    C++学习 十五.类继承(1)基类,派生类 前言 类继承 类的关系与继承 基类, 派生类 基类 派生类 构造函数,析构函数 文件位置 访问权限 protected 后记 前言 本篇开始学习C++类的继 ...

  4. OpenGL入门学习(十五)

    OpenGL入门学习[十五] 这次讲的所有内容都装在一个立方体中,呵呵. 呵呵,绘制一个立方体,简单呀,我们学了第一课第二课,早就会了. 先别着急,立方体是很简单,但是这里只是拿立方体做一个例子,来说 ...

  5. Linux学习十五 DNS基础服务

    Linux学习十五 DNS基础服务 DNS服务基础 BIND 伯利克Internet 域名服务 主要执行程序:/usr/sbin/named 系统服务:named 默认端口: TCP/UDP 53 主 ...

  6. 强化学习(十五) A3C

    在强化学习(十四) Actor-Critic中,我们讨论了Actor-Critic的算法流程,但是由于普通的Actor-Critic算法难以收敛,需要一些其他的优化.而Asynchronous Adv ...

  7. 推荐系统遇上深度学习(十五)--强化学习在京东推荐中的探索

    强化学习在各个公司的推荐系统中已经有过探索,包括阿里.京东等.之前在美团做过的一个引导语推荐项目,背后也是基于强化学习算法.本文,我们先来看一下强化学习是如何在京东推荐中进行探索的. 本文来自于pap ...

  8. 智能车学习(十五)——K60野火2013版例程

    一.中断函数注册方法: 1.格式: 配置某个功能的中断 注册中断函数 开启中断 2.一个例子 pit_init_ms(PIT0,5);//定时中断初始化 set_vector_handler(PIT0 ...

  9. JAVA基础学习(十五)--集合二--TreeSet和泛型

    一.TreeSet 1.1.TreeSet Set:hashSet:数据结构是哈希表.线程是非同步的. 保证元素唯一性的原理:判断元素的HashCode值是否相同. 如果相同,还会判断元素的equal ...

  10. detectron2训练自己的数据集_TensorFlow2学习十五、使用VGG16模型训练自己的数据集...

    一.说明 VGG16在2014年ImageNet比赛中获胜.ImageNet数据集中有1000个图像属于1000个不同的类别. VGG模型的权重是免费的,可以在您自己的模型和应用程序中加载和使用.这使 ...

最新文章

  1. Win7封装无损廋身清单
  2. Exchange 2003允许部分用户发送邮件到部分外网服务器
  3. RedHat Linux乱码解决方案(转)
  4. 关于simplemodal的动态加载
  5. 3dmax2014:打开3dmax2014软件时,出现许可证检出失败 错误20
  6. ASM上的备份集如何转移到文件系统中
  7. QT自定义MainWindow
  8. fckeditor配置
  9. sql join中能否使用case when_SQL(五)——多表查询
  10. c语言c程序由函数构成 每个函数完成相对独立的功能,17秋学期(1709)《C语言程序设计》在线作业  满分...
  11. Ubuntu开启或重启ssh服务
  12. JavaScript的DOM编程--01--js代码的写入位置
  13. Python学习之路_day_08(函数介绍)
  14. 传统研发团队的敏捷转型实践之路
  15. Hook淘宝X-SIGN
  16. Web网页如何实现QQ好友,QQ空间,微博分享
  17. bootstrap 表单验证
  18. persona chat
  19. LEA指令和OFFSET指令
  20. 求任意整数模3的余数

热门文章

  1. 【码上实战】【立体匹配系列】经典AD-Census: (1)框架
  2. strtok函数及其实现
  3. WNMP环境搭建(Win10+Nginx+MySQL+PHP)
  4. ARM GICv3 GIC代码分析
  5. 白帽子黑帽子_6种白帽子seo技术可实现在线预期业务
  6. VS发生RC1107错误的原因
  7. (十九)VMware Harbor 详细介绍
  8. 详解tf.variable_scope函数
  9. 计算机网络复试面试题
  10. NoteExpress引用文献出现ADDIN NE.Ref.