#ifndef _VK_MX_H__ #define _VK_MX_H__ #include "config.h" #ifndef WITH_MOLTEN #include "volk.h" #include <SDL_vulkan.h> #else #include <SDL_vulkan.h> #include <vulkan/vulkan.h> #endif #include "exception.hpp" #include "util.hpp" #include <algorithm> #include <array> #include <cmath> #include <cstdlib> #include <format> #include <fstream> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> #include <optional> #include <set> #include <stdexcept> #include <vector> #ifndef VK_CHECK_RESULT #define VK_CHECK_RESULT(f) \ { \ VkResult res = (f); \ if (res != VK_SUCCESS) { \ throw mx::Exception(std::format("Fatal : VkResult is \"{}\" in {} at line {}", static_cast<int>(res), __FILE__, __LINE__)); \ } \ } #endif namespace mx { struct Vertex { float pos[3]; float texCoord[2]; }; 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 UniformBufferObject { glm::vec2 iResolution; float time_f; float _pad0; glm::vec4 iMouse; }; class VKWindow { public: VKWindow() = default; VKWindow(const std::string &title, int width, int height); virtual ~VKWindow() {} void initWindow(const std::string &title, int width, int height); void initVulkan(); void createVertexBuffer(); void setPath(const std::string &path); void loop(); void proc(); void cleanup(); virtual void event(SDL_Event &e) = 0; void draw(); void createGraphicsPipeline(); VkShaderModule createShaderModule(const std::vector<char> &code); int w = 0, h = 0; mxUtil util; protected: VkInstance instance = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkDescriptorSetLayout descriptorSetLayout; VkSwapchainKHR swapChain = VK_NULL_HANDLE; std::vector<VkImage> swapChainImages; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; std::vector<VkImageView> swapChainImageViews; std::vector<VkBuffer> uniformBuffers; std::vector<VkDeviceMemory> uniformBuffersMemory; std::vector<void *> uniformBuffersMapped; VkRenderPass renderPass = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; VkPipeline graphicsPipeline = VK_NULL_HANDLE; VkPipelineLayout bgPipelineLayout = VK_NULL_HANDLE; VkPipeline bgPipeline = VK_NULL_HANDLE; std::vector<VkFramebuffer> swapChainFramebuffers; VkCommandPool commandPool = VK_NULL_HANDLE; std::vector<VkCommandBuffer> commandBuffers; VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE; VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE; VkBuffer vertexBuffer = VK_NULL_HANDLE; VkDeviceMemory vertexBufferMemory = VK_NULL_HANDLE; VkBuffer indexBuffer = VK_NULL_HANDLE; VkDeviceMemory indexBufferMemory = VK_NULL_HANDLE; uint32_t indexCount; VkImage textureImage = VK_NULL_HANDLE; VkDeviceMemory textureImageMemory = VK_NULL_HANDLE; VkImageView textureImageView = VK_NULL_HANDLE; VkSampler textureSampler = VK_NULL_HANDLE; // Background texture VkImage bgTextureImage = VK_NULL_HANDLE; VkDeviceMemory bgTextureImageMemory = VK_NULL_HANDLE; VkImageView bgTextureImageView = VK_NULL_HANDLE; VkSampler bgTextureSampler = VK_NULL_HANDLE; VkDescriptorPool descriptorPool = VK_NULL_HANDLE; std::vector<VkDescriptorSet> descriptorSets; std::vector<VkDescriptorSet> bgDescriptorSets; uint32_t width, height; void createDescriptorSetLayout(); SDL_Window *window = nullptr; void createInstance(); void createSurface(); void pickPhysicalDevice(); void createLogicalDevice(); void createUniformBuffers(); virtual void createSwapChain(); void createImageViews(); void createRenderPass(); void createFramebuffers(); void createCommandPool(); void createCommandBuffers(); void createSyncObjects(); virtual void cleanupSwapChain(); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR> &availableFormats); VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR> &availablePresentModes); VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities); bool isDeviceSuitable(VkPhysicalDevice device); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void createTextureImage(SDL_Surface *surface); void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); void createTextureImageView(); VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags); void createTextureSampler(); void createDescriptorPool(); void createDescriptorSets(); void updateDescriptorSets(); void createBackgroundDescriptorSets(); void recreateSwapChain(); void createBackgroundPipeline(); void createBackgroundTextureImage(SDL_Surface *surface); void createBackgroundTextureImageView(); void createBackgroundTextureSampler(); }; } // namespace mx #endif