#pragma once #include #include #include #include #include #include const std::vector validationLayers = { "VK_LAYER_KHRONOS_validation" }; const std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; const int MAX_FRAMES_IN_FLIGHT = 2; #ifdef NDEBUG const bool enableValidationLayers = false; #else const bool enableValidationLayers = true; #endif VkResult CreateDebugUtilsMessengerEXT(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugUtilsMessengerEXT*); void DestroyDebugUtilsMessengerEXT(VkInstance, VkDebugUtilsMessengerEXT, const VkAllocationCallbacks*); struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; bool complete() { return graphicsFamily.has_value() && presentFamily.has_value(); } }; struct SwapChainSupportDetails { VkSurfaceCapabilitiesKHR capabilities; std::vector formats; std::vector presentModes; }; class VulkanApp { public: VulkanApp(const uint32_t& _w, const uint32_t& _h) : mWin(nullptr), mWidth(_w), mHeight(_h) {} void init(); void loop(); void cleanup(); private: // SDL2 SDL_Window *mWin; SDL_Event mEvent; // Not tied to library uint32_t mWidth; uint32_t mHeight; bool mActive = false; bool mResized = false; bool mMinimized = false; // Vulkan VkInstance mInstance; VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE; VkDevice mLogicalDevice; VkSurfaceKHR mSurface; VkSwapchainKHR mSwapChain; std::vector mSwapChainImages; std::vector mSwapChainImageViews; VkFormat mSwapChainImageFormat; VkExtent2D mSwapChainExtent; std::vector mSwapChainFramebuffers; VkRenderPass mRenderPass; VkPipelineLayout mPipelineLayout; VkPipeline mGraphicsPipeline; VkCommandPool mCommandPool; std::vector mCommandBuffers; VkQueue mGraphicsQueue; VkQueue mPresentQueue; std::vector mImageAvailableSemaphores; std::vector mRenderFinishedSemaphores; std::vector mInFlightFences; VkDebugUtilsMessengerEXT mDebugMessenger; void createInstance(); void selectPhysicalDevice(); void createLogicalDevice(); void createSwapChain(); void recreateSwapChain(); void cleanupSwapChain(); void createImageViews(); void createRenderPass(); void createGraphicsPipeline(); void createFramebuffers(); void createCommandPool(); void createCommandBuffer(); void createSyncObjects(); void recordCommandBuffer(VkCommandBuffer, uint32_t); void drawFrame(); QueueFamilyIndices findQueueFamilies(VkPhysicalDevice); bool isDeviceSuitable(VkPhysicalDevice); bool checkDeviceExtensionSupport(VkPhysicalDevice); VkShaderModule createShaderModule(const std::vector&); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice); VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector&); VkPresentModeKHR chooseSwapPresentMode(const std::vector&); VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR&); // Validation layer stuff void setupDebugMessenger(); bool checkValidationLayerSupport(); static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { (void)pUserData; if(messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { fprintf(stderr, "Validation Layer [Error/Warning]: %s \n", pCallbackData->pMessage); } else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { fprintf(stderr, "Validation Layer [General]: %s \n", pCallbackData->pMessage); } else { fprintf(stderr, "Validation Layer: %s \n", pCallbackData->pMessage); } return VK_FALSE; } };