From 36c07aa4d17ec26a8611c8311d8b86db8d31dcab Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Fri, 21 Oct 2022 13:58:59 +0100 Subject: [PATCH] Add support for window resizing with Vulkan --- CMakeLists.txt | 2 + gfx_device_vulkan (2).cpp | 1094 ------------------------------------- include/gfx_device.hpp | 8 +- src/engine.cpp | 4 +- src/gfx_device_vulkan.cpp | 162 +++--- src/resources/shader.cpp | 2 +- src/resources/texture.cpp | 2 +- 7 files changed, 89 insertions(+), 1185 deletions(-) delete mode 100644 gfx_device_vulkan (2).cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 72b10d4..2c42ec8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,8 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) if (MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /W3) target_compile_options(${PROJECT_NAME} PRIVATE /MP) + + target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) endif() target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/gfx_device_vulkan (2).cpp b/gfx_device_vulkan (2).cpp deleted file mode 100644 index 4886cb5..0000000 --- a/gfx_device_vulkan (2).cpp +++ /dev/null @@ -1,1094 +0,0 @@ -#if 0 - -// The implementation of the graphics layer using Vulkan 1.3 - -#ifdef ENGINE_BUILD_VULKAN - -#include "gfx_device.hpp" - -#include "util.hpp" - -#include "config.h" -#include "log.hpp" - -#define VOLK_IMPLEMENTATION -#include - -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 -#define VMA_VULKAN_VERSION 1003000 -#define VMA_IMPLEMENTATION -#include - -#include - -#include - -#include -#include -#include -#include - -namespace engine { - - static std::vector getRequiredVulkanExtensions(SDL_Window* window) - { - SDL_bool res; - - unsigned int sdlExtensionCount = 0; - res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, nullptr); - assert(res == SDL_TRUE); - std::vector requiredExtensions(sdlExtensionCount); - res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, requiredExtensions.data()); - assert(res == SDL_TRUE); - - return requiredExtensions; - } - - static VkSurfaceKHR createSurface(SDL_Window* window, VkInstance instance) - { - VkSurfaceKHR surface; - - if (SDL_Vulkan_CreateSurface(window, instance, &surface) == false) { - throw std::runtime_error("Unable to create window surface"); - } - - return surface; - } - - static uint32_t getMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) - { - VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); - for (uint32_t i = 0; i < memProps.memoryTypeCount; i++) { - if (typeFilter & (1 << i)) { - return i; - } - } - - throw std::runtime_error("Failed to find a suitable memory type"); - } - - class GFXDevice::Impl { - - public: - Impl(const char* appName, const char* appVersion, SDL_Window* window) - { -#ifdef NDEBUG - // release mode: don't use validation layer - LayerInfo layerInfo(false); -#else - // debug mode: use validation layer - LayerInfo layerInfo(true); -#endif - auto instance = std::make_shared(appName, appVersion, layerInfo, getRequiredVulkanExtensions(window)); - - volkLoadInstanceOnly(instance->getHandle()); - - m_debugMessenger = std::make_unique(instance); // owns the instance - auto surface = std::make_shared(window, instance); // owns the instance - - auto device = std::make_shared(surface); // owns the surface - auto allocator = std::make_shared(device); // owns the device - - m_swapchain = std::make_unique(device, allocator); // owns the device, allocator - - } - - private: - - struct LayerInfo { - - LayerInfo(bool useValidation) - { - VkResult res; - - uint32_t layerCount; - res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - assert(res == VK_SUCCESS); - layersAvailable.resize(layerCount); - res = vkEnumerateInstanceLayerProperties(&layerCount, layersAvailable.data()); - assert(res == VK_SUCCESS); - - if (useValidation == true) { - // find validation layer and print all layers to log - for (auto it = layersAvailable.begin(); it != layersAvailable.end(); it++) { - if (strncmp(it->layerName, LayerInfo::VALIDATION_LAYER_NAME, 256) == 0) { - validationLayer = it; - } - } - if (validationLayer.has_value() == false) { - throw std::runtime_error("The validation layer was not found. Quitting."); - } - } - } - - static constexpr const char* VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; - - std::vector layersAvailable{}; - std::optional::iterator> validationLayer; - - }; - - class Instance { - - public: - Instance(const char* appName, const char* appVersion, const LayerInfo& layerInfo, const std::vector& windowExtensions) - { - VkResult res; - - int appVersionMajor = 0, appVersionMinor = 0, appVersionPatch = 0; - assert(versionFromCharArray(appVersion, &appVersionMajor, &appVersionMinor, &appVersionPatch)); - int engineVersionMajor = 0, engineVersionMinor = 0, engineVersionPatch = 0; - assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch)); - - VkApplicationInfo applicationInfo{ - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .pApplicationName = appName, - .applicationVersion = VK_MAKE_VERSION(appVersionMajor, appVersionMinor, appVersionPatch), - .pEngineName = "engine", - .engineVersion = VK_MAKE_VERSION(engineVersionMajor, engineVersionMinor, engineVersionPatch), - .apiVersion = VK_API_VERSION_1_3, - }; - - // make a list of all extensions to use - std::vector extensions{}; - extensions.insert(extensions.end(), windowExtensions.begin(), windowExtensions.end()); - - // also use debug utils extension - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - - std::vector layers{}; - - if (layerInfo.validationLayer.has_value()) { - layers.push_back(layerInfo.validationLayer.value()->layerName); - } - - VkInstanceCreateInfo instanceInfo{ - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .pApplicationInfo = &applicationInfo, - .enabledLayerCount = (uint32_t)layers.size(), - .ppEnabledLayerNames = layers.data(), - .enabledExtensionCount = (uint32_t)extensions.size(), - .ppEnabledExtensionNames = extensions.data(), - }; - - VkDebugUtilsMessengerCreateInfoEXT debugMessengerCreateInfo = DebugMessenger::getCreateInfo(); - - if (layerInfo.validationLayer.has_value()) { - instanceInfo.pNext = &debugMessengerCreateInfo; - } - -#ifndef NDEBUG - for (const char* ext : extensions) { - TRACE("Using Vulkan instance extension: {}", ext); - } -#endif - - res = vkCreateInstance(&instanceInfo, nullptr, &m_handle); - if (res == VK_ERROR_INCOMPATIBLE_DRIVER) { - throw std::runtime_error("The graphics driver is incompatible with vulkan"); - } - assert(res == VK_SUCCESS); - - } - - Instance(const Instance&) = delete; - Instance& operator=(const Instance&) = delete; - ~Instance() - { - TRACE("Destroying instance..."); - vkDestroyInstance(m_handle, nullptr); - } - - VkInstance getHandle() const - { - return m_handle; - } - - private: - VkInstance m_handle; - - }; - - class DebugMessenger { - - public: - DebugMessenger(std::shared_ptr instance) : m_instance(instance) - { - VkDebugUtilsMessengerCreateInfoEXT createInfo = getCreateInfo(); - - VkResult res = vkCreateDebugUtilsMessengerEXT(m_instance->getHandle(), &createInfo, nullptr, &m_messengerHandle); - assert(res == VK_SUCCESS); - } - - DebugMessenger(const DebugMessenger&) = delete; - DebugMessenger& operator=(const DebugMessenger&) = delete; - ~DebugMessenger() - { - TRACE("Destroying debug messenger..."); - vkDestroyDebugUtilsMessengerEXT(m_instance->getHandle(), m_messengerHandle, nullptr); - } - - static VkDebugUtilsMessengerCreateInfoEXT getCreateInfo() - { - VkDebugUtilsMessengerCreateInfoEXT createInfo{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .pNext = nullptr, - .flags = 0, - .messageSeverity = 0, - .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, - .pfnUserCallback = messengerCallback, - .pUserData = nullptr, - }; - - switch (MESSAGE_LEVEL) { - case Severity::VERBOSE: - createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; - // fall-through - case Severity::INFO: - createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - // fall-through - case Severity::WARNING: - createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - // fall-through - case Severity::ERROR: - createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - // fall-through - default: - break; - } - - return createInfo; - } - - private: - std::shared_ptr m_instance; - VkDebugUtilsMessengerEXT m_messengerHandle; - - enum class Severity { - VERBOSE, - INFO, - WARNING, - ERROR - }; - static constexpr Severity MESSAGE_LEVEL = Severity::WARNING; - - static VkBool32 messengerCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) - { - - std::string msgType{}; - - if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) - msgType += " (GENERAL)"; - if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) - msgType += " (PERF.)"; - if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) - msgType += " (VALID.)"; - - switch (messageSeverity) { - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - TRACE("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - INFO("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - WARN("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - ERROR("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); - break; - default: - break; - } - return VK_FALSE; - } - - }; - - class Surface { - - public: - Surface(SDL_Window* window, std::shared_ptr instance) : m_instance(instance), m_window(window) - { - m_handle = createSurface(m_window, instance->getHandle()); - } - Surface(const Surface&) = delete; - Surface& operator=(const Surface&) = delete; - - ~Surface() - { - TRACE("Destroying surface..."); - vkDestroySurfaceKHR(m_instance->getHandle(), m_handle, nullptr); - } - - VkSurfaceKHR getHandle() const - { - return m_handle; - } - - SDL_Window* getWindow() const - { - return m_window; - } - - VkInstance getInstance() const - { - return m_instance->getHandle(); - } - - private: - std::shared_ptr m_instance; - VkSurfaceKHR m_handle; - SDL_Window* m_window; - - }; - - class Device { - - public: - Device(std::shared_ptr surface) : m_surface(surface) - { - // enumerate physical devices - uint32_t physDeviceCount = 0; - VkResult res; - res = vkEnumeratePhysicalDevices(m_surface->getInstance(), &physDeviceCount, nullptr); - assert(res == VK_SUCCESS); - if (physDeviceCount == 0) { - throw std::runtime_error("No GPU found with vulkan support!"); - } - std::vector physicalDevices(physDeviceCount); - res = vkEnumeratePhysicalDevices(m_surface->getInstance(), &physDeviceCount, physicalDevices.data()); - assert(res == VK_SUCCESS); - - // find suitable device: - - const std::vector requiredDeviceExtensions{ - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; - - for (const auto& dev : physicalDevices) { - - // first, check extension support - uint32_t extensionCount; - res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, nullptr); - assert(res == VK_SUCCESS); - std::vector availableExtensions(extensionCount); - res = vkEnumerateDeviceExtensionProperties(dev, nullptr, &extensionCount, availableExtensions.data()); - assert(res == VK_SUCCESS); - - for (const auto& extToFind : requiredDeviceExtensions) { - bool extFound = false; - for (const auto& ext : availableExtensions) { - if (strcmp(extToFind, ext.extensionName) == 0) { - extFound = true; - } - } - if (!extFound) { - continue; - } - } - - - - // get swapchain support details: - - // get surface capabilities - res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, m_surface->getHandle(), &m_swapchainSupportDetails.caps); - assert (res == VK_SUCCESS); - - // check there is at least one supported surface format - uint32_t surfaceFormatCount = 0; - res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, m_surface->getHandle(), &surfaceFormatCount, nullptr); - assert(res == VK_SUCCESS); - if (surfaceFormatCount == 0) { - continue; - } - m_swapchainSupportDetails.formats.resize(surfaceFormatCount); - res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, m_surface->getHandle(), &surfaceFormatCount, m_swapchainSupportDetails.formats.data()); - assert(res == VK_SUCCESS); - - // check there is at least one supported present mode - uint32_t surfacePresentModeCount = 0; - res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, m_surface->getHandle(), &surfacePresentModeCount, nullptr); - assert(res == VK_SUCCESS); - if (surfacePresentModeCount == 0) { - continue; - } - m_swapchainSupportDetails.presentModes.resize(surfacePresentModeCount); - res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, m_surface->getHandle(), &surfacePresentModeCount, m_swapchainSupportDetails.presentModes.data()); - assert(res == VK_SUCCESS); - - - - // check physical device properties - VkPhysicalDeviceProperties devProps; - vkGetPhysicalDeviceProperties(dev, &devProps); - - // check that the device supports vulkan 1.3 - if (devProps.apiVersion < VK_API_VERSION_1_3) { - continue; - } - - m_physicalDevice = dev; - break; - - } // end for() - - if (m_physicalDevice == VK_NULL_HANDLE) { - throw std::runtime_error("No suitable Vulkan physical device found"); - } - - VkPhysicalDeviceProperties devProps; - vkGetPhysicalDeviceProperties(m_physicalDevice, &devProps); - INFO("Selected physical device: {}", devProps.deviceName); - - TRACE("Supported present modes:"); - for (const auto& presMode : m_swapchainSupportDetails.presentModes) { - switch (presMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - TRACE("\tVK_PRESENT_MODE_IMMEDIATE_KHR"); - break; - case VK_PRESENT_MODE_MAILBOX_KHR: - TRACE("\tVK_PRESENT_MODE_MAILBOX_KHR"); - break; - case VK_PRESENT_MODE_FIFO_KHR: - TRACE("\tVK_PRESENT_MODE_FIFO_KHR"); - break; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - TRACE("\tVK_PRESENT_MODE_FIFO_RELAXED_KHR"); - break; - case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: - TRACE("\tVK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR"); - break; - case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: - TRACE("\tVK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR"); - break; - default: - TRACE("\tUNKNOWN DISPLAY MODE"); - break; - } - } - - - - // Get the queue families and find ones that support graphics, transfer, and compute - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr); - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies.data()); - - std::optional graphicsFamilyIndex; - std::optional transferFamilyIndex; - std::optional computeFamilyIndex; - - for (uint32_t i = 0; i < queueFamilyCount; i++) { - VkQueueFamilyProperties family = queueFamilies[i]; - if (family.queueCount > 0) { - if (graphicsFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - TRACE("GRAPHICS:"); - graphicsFamilyIndex = i; - } - if (transferFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_TRANSFER_BIT) { - TRACE("TRANSFER:"); - transferFamilyIndex = i; - } - if (computeFamilyIndex.has_value() == false && family.queueFlags & VK_QUEUE_COMPUTE_BIT) { - TRACE("COMPUTE:"); - computeFamilyIndex = i; - } - TRACE("\t\ti = {}\t\tcount = {}", i, family.queueCount); - } - } - if ( graphicsFamilyIndex.has_value() == false || - transferFamilyIndex.has_value() == false) { - throw std::runtime_error("Unable to find queues with the GRAPHICS or TRANSFER family flags"); - } - - // there is no guaranteed support for compute queues - - std::vector queueCreateInfos{}; - - // use a set to filter out duplicate indices - std::unordered_set uniqueQueueFamilies{}; - if (graphicsFamilyIndex.has_value()) uniqueQueueFamilies.insert(graphicsFamilyIndex.value()); - if (transferFamilyIndex.has_value()) uniqueQueueFamilies.insert(transferFamilyIndex.value()); - if (computeFamilyIndex.has_value()) uniqueQueueFamilies.insert(computeFamilyIndex.value()); - - float queuePriority = 1.0f; - - for (uint32_t family : uniqueQueueFamilies) { - // create a queue for each unique type to ensure that there are queues available for graphics, transfer, and compute - - Queue newQueue{}; - newQueue.familyIndex = family; - newQueue.queueIndex = 0; - if (graphicsFamilyIndex == family) newQueue.supportsGraphics = true; - if (transferFamilyIndex == family) newQueue.supportsTransfer = true; - if (computeFamilyIndex == family) newQueue.supportsCompute = true; - - TRACE("Creating queue from family {}", family); - VkDeviceQueueCreateInfo queueCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueFamilyIndex = family, - .queueCount = 1, - .pQueuePriorities = &queuePriority, - }; - queueCreateInfos.push_back(queueCreateInfo); - m_queues.push_back(newQueue); - } - - // check the physical device is compatible with the surface - VkBool32 graphicsQueueCanPresent; - res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, graphicsFamilyIndex.value(), m_surface->getHandle(), &graphicsQueueCanPresent); - assert(res == VK_SUCCESS); - if (graphicsQueueCanPresent != VK_TRUE) { - throw std::runtime_error("The selected queue family does not support this surface"); - } - - VkDeviceCreateInfo deviceCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .queueCreateInfoCount = (uint32_t)queueCreateInfos.size(), - .pQueueCreateInfos = queueCreateInfos.data(), - // IGNORED: .enabledLayerCount - // IGNORED: .ppEnabledLayerNames - .enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(), - .ppEnabledExtensionNames = requiredDeviceExtensions.data(), - .pEnabledFeatures = nullptr, - }; - - res = vkCreateDevice(m_physicalDevice, &deviceCreateInfo, nullptr, &m_handle); - if (res != VK_SUCCESS) { - throw std::runtime_error("Unable to create Vulkan logical device, error code: " + std::to_string(res)); - } - - volkLoadDevice(m_handle); - - for (auto& q : m_queues) { - vkGetDeviceQueue(m_handle, q.familyIndex, q.queueIndex, &q.handle); - } - - Queue gfxQueue = getGraphicsQueue(); - - VkCommandPoolCreateInfo gfxCmdPoolInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = gfxQueue.familyIndex, - }; - - res = vkCreateCommandPool(m_handle, &gfxCmdPoolInfo, nullptr, &m_gfxCommandPool); - assert(res == VK_SUCCESS); - - VkCommandBufferAllocateInfo gfxCmdBufInfo{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = m_gfxCommandPool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1 - }; - - res = vkAllocateCommandBuffers(m_handle, &gfxCmdBufInfo, &m_gfxCommandBuffer); - assert(res == VK_SUCCESS); - - } - Device(const Device&) = delete; - Device& operator=(const Device&) = delete; - - ~Device() - { - TRACE("Destroying device..."); - vkDestroyCommandPool(m_handle, m_gfxCommandPool, nullptr); - vkDestroyDevice(m_handle, nullptr); - } - - VkDevice getHandle() const - { - return m_handle; - } - - VkPhysicalDevice getPhysicalDevice() const - { - return m_physicalDevice; - } - - VkInstance getInstance() const - { - return m_surface->getInstance(); - } - - struct SwapchainSupportDetails { - VkSurfaceCapabilitiesKHR caps{}; - std::vector formats{}; - std::vector presentModes{}; - }; - - SwapchainSupportDetails getSupportDetails() - { - return m_swapchainSupportDetails; - } - - struct Queue { - uint32_t familyIndex; - uint32_t queueIndex; - bool supportsGraphics = false; - bool supportsTransfer = false; - bool supportsCompute = false; - - VkQueue handle; - }; - - VkCommandBuffer getGraphicsCommandBuffer() - { - return m_gfxCommandBuffer; - } - - std::shared_ptr getSurface() - { - return m_surface; - } - - Queue getGraphicsQueue() - { - for (const auto& queue : m_queues) { - if (queue.supportsGraphics) return queue; - } - throw std::runtime_error("Unable to find graphics queue"); - } - - Queue getTransferQueue() - { - for (const auto& queue : m_queues) { - if (queue.supportsTransfer) return queue; - } - throw std::runtime_error("Unable to find transfer queue"); - } - - /*Queue getComputeQueue() - { - for (const auto& queue : m_queues) { - if (queue.supportsCompute) return queue; - } - throw std::runtime_error("Unable to find compute queue"); - }*/ - - private: - std::shared_ptr m_surface; - - SwapchainSupportDetails m_swapchainSupportDetails{}; - - VkDevice m_handle = VK_NULL_HANDLE; - - VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; - - std::vector m_queues{}; - - VkCommandPool m_gfxCommandPool = VK_NULL_HANDLE; - VkCommandBuffer m_gfxCommandBuffer = VK_NULL_HANDLE; - - }; - - class GPUAllocator { - public: - GPUAllocator(std::shared_ptr device) : m_device(device) - { - VmaVulkanFunctions functions{ - .vkGetInstanceProcAddr = nullptr, - .vkGetDeviceProcAddr = nullptr, - .vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties, - .vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties, - .vkAllocateMemory = vkAllocateMemory, - .vkFreeMemory = vkFreeMemory, - .vkMapMemory = vkMapMemory, - .vkUnmapMemory = vkUnmapMemory, - .vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges, - .vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges, - .vkBindBufferMemory = vkBindBufferMemory, - .vkBindImageMemory = vkBindImageMemory, - .vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements, - .vkGetImageMemoryRequirements = vkGetImageMemoryRequirements, - .vkCreateBuffer = vkCreateBuffer, - .vkDestroyBuffer = vkDestroyBuffer, - .vkCreateImage = vkCreateImage, - .vkDestroyImage = vkDestroyImage, - .vkCmdCopyBuffer = vkCmdCopyBuffer, - .vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2, - .vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2, - .vkBindBufferMemory2KHR = vkBindBufferMemory2, - .vkBindImageMemory2KHR = vkBindImageMemory2, - .vkGetPhysicalDeviceMemoryProperties2KHR = vkGetPhysicalDeviceMemoryProperties2, - .vkGetDeviceBufferMemoryRequirements = vkGetDeviceBufferMemoryRequirements, - .vkGetDeviceImageMemoryRequirements = vkGetDeviceImageMemoryRequirements, - }; - - VmaAllocatorCreateInfo createInfo{ - .flags = 0, - .physicalDevice = m_device->getPhysicalDevice(), - .device = m_device->getHandle(), - .preferredLargeHeapBlockSize = 0, - .pAllocationCallbacks = nullptr, - .pDeviceMemoryCallbacks = nullptr, - .pHeapSizeLimit = nullptr, - .pVulkanFunctions = &functions, - .instance = m_device->getInstance(), - .vulkanApiVersion = VK_API_VERSION_1_3, - .pTypeExternalMemoryHandleTypes = nullptr - }; - - VkResult res = vmaCreateAllocator(&createInfo, &m_handle); - assert(res == VK_SUCCESS); - - } - GPUAllocator(const GPUAllocator&) = delete; - GPUAllocator& operator=(const GPUAllocator&) = delete; - ~GPUAllocator() - { - TRACE("Destroying allocator..."); - vmaDestroyAllocator(m_handle); - } - - VmaAllocator getHandle() const - { - return m_handle; - } - - private: - std::shared_ptr m_device; - VmaAllocator m_handle = nullptr; - }; - - class Swapchain { - - public: - Swapchain(std::shared_ptr device, std::shared_ptr allocator) : m_device(device), m_allocator(allocator) - { - VkResult res; - - auto supportDetails = m_device->getSupportDetails(); - - VkSurfaceFormatKHR chosenSurfaceFormat = supportDetails.formats[0]; - - for (const auto& format : supportDetails.formats) { - if ( format.format == VK_FORMAT_B8G8R8A8_SRGB && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ) { - chosenSurfaceFormat = format; // prefer using srgb non linear colors - } - } - - VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR; - - for (const auto& presMode : supportDetails.presentModes) { - if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) { - chosenPresentMode = presMode; // this mode allows uncapped FPS while also avoiding screen tearing - } - } - - VkExtent2D chosenSwapExtent{}; - - if (supportDetails.caps.currentExtent.width != std::numeric_limits::max()) { - chosenSwapExtent = supportDetails.caps.currentExtent; - } else { - // if fb size isn't already found, get it from SDL - int width, height; - SDL_Vulkan_GetDrawableSize(m_device->getSurface()->getWindow(), &width, &height); - - chosenSwapExtent.width = static_cast(width); - chosenSwapExtent.height = static_cast(height); - - chosenSwapExtent.width = std::clamp( - chosenSwapExtent.width, - supportDetails.caps.minImageExtent.width, supportDetails.caps.maxImageExtent.width); - chosenSwapExtent.height = std::clamp( - chosenSwapExtent.height, - supportDetails.caps.minImageExtent.height, supportDetails.caps.maxImageExtent.height); - } - - uint32_t imageCount = supportDetails.caps.minImageCount + 1; - if (supportDetails.caps.maxImageCount > 0 && imageCount > supportDetails.caps.maxImageCount) { - imageCount = supportDetails.caps.maxImageCount; - } - - VkSwapchainCreateInfoKHR createInfo{ - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .surface = m_device->getSurface()->getHandle(), - .minImageCount = imageCount, - .imageFormat = chosenSurfaceFormat.format, - .imageColorSpace = chosenSurfaceFormat.colorSpace, - .imageExtent = chosenSwapExtent, - .imageArrayLayers = 1, - .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr, - .preTransform = supportDetails.caps.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = chosenPresentMode, - .clipped = VK_TRUE, - .oldSwapchain = VK_NULL_HANDLE, - - }; - - std::array queueFamilyIndices{ - m_device->getGraphicsQueue().familyIndex, - m_device->getTransferQueue().familyIndex - }; - - // if graphics and transfer queues aren't in the same family - if (queueFamilyIndices[0] != queueFamilyIndices[1]) { - createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - createInfo.queueFamilyIndexCount = queueFamilyIndices.size(); - createInfo.pQueueFamilyIndices = queueFamilyIndices.data(); - } - - res = vkCreateSwapchainKHR(m_device->getHandle(), &createInfo, nullptr, &m_handle); - assert(res == VK_SUCCESS); - - // get all the image handles - uint32_t swapchainImageCount = 0; - res = vkGetSwapchainImagesKHR(m_device->getHandle(), m_handle, &swapchainImageCount, nullptr); - assert(res == VK_SUCCESS); - m_images.resize(swapchainImageCount); - res = vkGetSwapchainImagesKHR(m_device->getHandle(), m_handle, &swapchainImageCount, m_images.data()); - assert(res == VK_SUCCESS); - - m_currentFormat = chosenSurfaceFormat.format; - m_currentExtent = chosenSwapExtent; - - // create image views - m_imageViews.clear(); - for (VkImage image : m_images) { - - VkImageViewCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.pNext = nullptr; - createInfo.image = image; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = m_currentFormat; - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - VkImageView imageView; - res = vkCreateImageView(m_device->getHandle(), &createInfo, nullptr, &imageView); - assert (res == VK_SUCCESS); - - m_imageViews.push_back(imageView); - - } - - // create depth buffer - - m_depthBuffer = std::make_unique(m_currentExtent, m_device.get(), m_allocator.get()); - - } - Swapchain(const Swapchain&) = delete; - Swapchain& operator=(const Swapchain&) = delete; - - ~Swapchain() - { - TRACE("Destroying swapchain..."); - for (VkImageView view : m_imageViews) { - vkDestroyImageView(m_device->getHandle(), view, nullptr); - } - vkDestroySwapchainKHR(m_device->getHandle(), m_handle, nullptr); - } - - private: - std::shared_ptr m_device; - std::shared_ptr m_allocator; - - VkSwapchainKHR m_handle = VK_NULL_HANDLE; - - std::vector m_images; - std::vector m_imageViews; - - VkFormat m_currentFormat{}; - VkExtent2D m_currentExtent{}; - - class DepthStencil { - public: - DepthStencil(VkExtent2D bufferExtent, Device* device, GPUAllocator* allocator) : m_device(device), m_allocator(allocator) - { - - // find a suitable format - - const std::vector formatCandidates{ - VK_FORMAT_D24_UNORM_S8_UINT, - VK_FORMAT_D32_SFLOAT_S8_UINT, - }; - - const VkFormatFeatureFlags formatFeatures = - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; - - std::optional chosenFormat; - - for (VkFormat format : formatCandidates) { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(m_device->getPhysicalDevice(), format, &props); - - if ((props.optimalTilingFeatures & formatFeatures) == formatFeatures) { - chosenFormat = format; - break; - } - } - - if (chosenFormat.has_value() == false) { - throw std::runtime_error("Unable to find a suitable depth-stencil format"); - } - - m_format = chosenFormat.value(); - - switch (m_format) { - case VK_FORMAT_D24_UNORM_S8_UINT: - INFO("VK_FORMAT_D24_UNORM_S8_UINT"); - break; - case VK_FORMAT_D32_SFLOAT_S8_UINT: - INFO("VK_FORMAT_D32_SFLOAT_S8_UINT"); - break; - default: - break; - } - - VkImageCreateInfo imageCreateInfo{ - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = m_format, - .extent = { - .width = bufferExtent.width, - .height = bufferExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 1, - .pQueueFamilyIndices = nullptr, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }; - - VmaAllocationCreateInfo allocInfo{}; - allocInfo.usage = VMA_MEMORY_USAGE_AUTO; - - VkResult res; - - res = vmaCreateImage(m_allocator->getHandle(), &imageCreateInfo, &allocInfo, &m_image, &m_allocation, nullptr); - assert(res == VK_SUCCESS); - - VkImageViewCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.pNext = nullptr; - createInfo.image = m_image; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = m_format; - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - res = vkCreateImageView(m_device->getHandle(), &createInfo, nullptr, &m_imageView); - assert (res == VK_SUCCESS); - - } - DepthStencil(const DepthStencil&) = delete; - DepthStencil& operator=(const DepthStencil&) = delete; - ~DepthStencil() - { - TRACE("Destroying DepthStencil..."); - vkDestroyImageView(m_device->getHandle(), m_imageView, nullptr); - // destroy allocation - vmaDestroyImage(m_allocator->getHandle(), m_image, m_allocation); - } - - private: - - VkFormat m_format; - - Device* m_device; - GPUAllocator* m_allocator; - - VkImage m_image = VK_NULL_HANDLE; - VmaAllocation m_allocation; - VkImageView m_imageView = VK_NULL_HANDLE; - - }; - - std::unique_ptr m_depthBuffer; - - }; - - std::unique_ptr m_debugMessenger; // uses instance - - std::unique_ptr m_swapchain; - - }; - - GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window) - { - VkResult res; - res = volkInitialize(); - if (res == VK_ERROR_INITIALIZATION_FAILED) { - throw std::runtime_error("Unable to load vulkan, is it installed?"); - } - assert(res == VK_SUCCESS); - - uint32_t vulkanVersion = volkGetInstanceVersion(); - if (vulkanVersion < VK_MAKE_VERSION(1, 3, 0)) { - throw std::runtime_error("The loaded Vulkan version must be at least 1.3"); - } - - m_pimpl = std::make_unique(appName, appVersion, window); - - } - - GFXDevice::~GFXDevice() - { - TRACE("Destroying GFXDevice..."); - } - - void GFXDevice::draw() - { - - } - - bool GFXDevice::createBuffer(const gfx::BufferDesc& desc, const void* data, gfx::BufferHandle* out) - { - return false; - } - -} - -#endif - -#endif \ No newline at end of file diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index ee959b8..9f1c021 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -42,14 +42,16 @@ namespace engine { GFXDevice& operator=(const GFXDevice&) = delete; ~GFXDevice(); - // submit command lists and draw to the screen + // Call once per frame. Executes all queued draw calls and renders to the screen. void draw(); - + + // creates the equivalent of an OpenGL shader program & vertex attrib configuration void createPipeline(const char* vertShaderPath, const char* fragShaderPath); + // creates a vertex array for holding mesh data bool createBuffer(const gfx::BufferDesc& desc, const void* data, gfx::BufferHandle* out); - // waits for the gpu to stop doing stuff to allow for a safe cleanup + // wait until all the active GPU queues have finished working void waitIdle(); private: diff --git a/src/engine.cpp b/src/engine.cpp index b96943c..c1d9c0f 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -8,7 +8,7 @@ namespace engine { Application::Application(const char* appName, const char* appVersion) { - m_win = std::make_unique(appName, false); + m_win = std::make_unique(appName, true); m_gfx = std::make_unique(appName, appVersion, m_win->getHandle()); engine::ResourceManager resMan{}; @@ -35,7 +35,7 @@ namespace engine { lastTick = m_win->getLastFrameStamp(); // do tick stuff here - m_win->setTitle("frame time: " + std::to_string(m_win->dt() * 1000.0f) + " ms"); + m_win->setTitle("frame time: " + std::to_string(m_win->dt() * 1000.0f) + " ms, " + std::to_string(m_win->getFPS()) + " fps"); } diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 7571d1d..7a9b7df 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -35,12 +35,6 @@ namespace engine { std::optional::iterator> validationLayer; }; - struct SwapchainSupportDetails { - VkSurfaceCapabilitiesKHR caps{}; - std::vector formats{}; - std::vector presentModes{}; - }; - struct Queue { uint32_t familyIndex; uint32_t queueIndex; @@ -73,6 +67,11 @@ namespace engine { VkPipeline handle = VK_NULL_HANDLE; }; + struct AllocatedBuffer { + VkBuffer buffer = VK_NULL_HANDLE; + VmaAllocation allocation = nullptr; + }; + enum class QueueFlags : uint32_t { GRAPHICS = (1 << 0), TRANSFER = (1 << 1), @@ -255,12 +254,47 @@ namespace engine { } // This is called not just on initialisation, but also when the window is resized. - static void createSwapchain(VkDevice device, const std::vector queues, SDL_Window* window, VkSurfaceKHR surface, const SwapchainSupportDetails& supportDetails, Swapchain* swapchain) + static void createSwapchain(VkDevice device, VkPhysicalDevice physicalDevice, const std::vector queues, SDL_Window* window, VkSurfaceKHR surface, Swapchain* swapchain) { VkResult res; - swapchain->surfaceFormat = supportDetails.formats[0]; - for (const auto& format : supportDetails.formats) { + // get surface capabilities + VkSurfaceCapabilitiesKHR caps; + res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &caps); + assert(res == VK_SUCCESS); + + // check there is at least one supported surface format + uint32_t surfaceFormatCount = 0; + std::vector formats{}; + res = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, nullptr); + assert(res == VK_SUCCESS); + formats.resize(surfaceFormatCount); + res = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, formats.data()); + assert(res == VK_SUCCESS); + + // check there is at least one supported present mode + uint32_t surfacePresentModeCount = 0; + std::vector presentModes{}; + res = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &surfacePresentModeCount, nullptr); + assert(res == VK_SUCCESS); + presentModes.resize(surfacePresentModeCount); + res = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &surfacePresentModeCount, presentModes.data()); + assert(res == VK_SUCCESS); + + + + // delete old framebuffers + for (VkFramebuffer fb : swapchain->framebuffers) { + vkDestroyFramebuffer(device, fb, nullptr); + } + + // delete old image views + for (VkImageView view : swapchain->imageViews) { + vkDestroyImageView(device, view, nullptr); + } + + swapchain->surfaceFormat = formats[0]; + for (const auto& format : formats) { if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { swapchain->surfaceFormat = format; // prefer using srgb non linear colors @@ -269,14 +303,14 @@ namespace engine { swapchain->presentMode = VK_PRESENT_MODE_FIFO_KHR; // This mode is always available - for (const auto& presMode : supportDetails.presentModes) { + for (const auto& presMode : presentModes) { if (presMode == VK_PRESENT_MODE_MAILBOX_KHR) { //swapchain->presentMode = presMode; // this mode allows uncapped FPS while also avoiding screen tearing } } - if (supportDetails.caps.currentExtent.width != std::numeric_limits::max()) { - swapchain->extent = supportDetails.caps.currentExtent; + if (caps.currentExtent.width != std::numeric_limits::max()) { + swapchain->extent = caps.currentExtent; } else { // if fb size isn't already found, get it from SDL @@ -288,15 +322,15 @@ namespace engine { swapchain->extent.width = std::clamp( swapchain->extent.width, - supportDetails.caps.minImageExtent.width, supportDetails.caps.maxImageExtent.width); + caps.minImageExtent.width, caps.maxImageExtent.width); swapchain->extent.height = std::clamp( swapchain->extent.height, - supportDetails.caps.minImageExtent.height, supportDetails.caps.maxImageExtent.height); + caps.minImageExtent.height, caps.maxImageExtent.height); } - uint32_t imageCount = supportDetails.caps.minImageCount + 1; - if (supportDetails.caps.maxImageCount > 0 && imageCount > supportDetails.caps.maxImageCount) { - imageCount = supportDetails.caps.maxImageCount; + uint32_t imageCount = caps.minImageCount + 1; + if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) { + imageCount = caps.maxImageCount; } VkSwapchainCreateInfoKHR createInfo{ @@ -313,7 +347,7 @@ namespace engine { .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - .preTransform = supportDetails.caps.currentTransform, + .preTransform = caps.currentTransform, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, .presentMode = swapchain->presentMode, .clipped = VK_TRUE, @@ -348,7 +382,7 @@ namespace engine { assert(res == VK_SUCCESS); // create the render pass - { + if (swapchain->renderpass == VK_NULL_HANDLE) { VkAttachmentDescription colorAttachment{}; colorAttachment.format = swapchain->surfaceFormat.format; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; @@ -394,6 +428,7 @@ namespace engine { } // create image views and framebuffers + swapchain->imageViews.resize(swapchain->images.size()); swapchain->framebuffers.resize(swapchain->images.size()); for (int i = 0; i < swapchain->images.size(); i++) { @@ -429,9 +464,6 @@ namespace engine { framebufferInfo.height = swapchain->extent.height; framebufferInfo.layers = 1; - if (swapchain->framebuffers[i] != VK_NULL_HANDLE) { - vkDestroyFramebuffer(device, swapchain->framebuffers[i], nullptr); - } res = vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapchain->framebuffers[i]); assert(res == VK_SUCCESS); @@ -474,9 +506,10 @@ namespace engine { VkInstance instance = VK_NULL_HANDLE; VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + + SDL_Window* window = nullptr; VkSurfaceKHR surface = VK_NULL_HANDLE; - SwapchainSupportDetails swapchainSupportDetails{}; // available capabilities, formats, and present modes VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; @@ -502,6 +535,8 @@ namespace engine { VkResult res; + pimpl->window = window; + // initialise vulkan res = volkInitialize(); @@ -665,36 +700,6 @@ namespace engine { - // get swapchain support details: - - // get surface capabilities - res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, pimpl->surface, &pimpl->swapchainSupportDetails.caps); - assert(res == VK_SUCCESS); - - // check there is at least one supported surface format - uint32_t surfaceFormatCount = 0; - res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, pimpl->surface, &surfaceFormatCount, nullptr); - assert(res == VK_SUCCESS); - if (surfaceFormatCount == 0) { - continue; - } - pimpl->swapchainSupportDetails.formats.resize(surfaceFormatCount); - res = vkGetPhysicalDeviceSurfaceFormatsKHR(dev, pimpl->surface, &surfaceFormatCount, pimpl->swapchainSupportDetails.formats.data()); - assert(res == VK_SUCCESS); - - // check there is at least one supported present mode - uint32_t surfacePresentModeCount = 0; - res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, pimpl->surface, &surfacePresentModeCount, nullptr); - assert(res == VK_SUCCESS); - if (surfacePresentModeCount == 0) { - continue; - } - pimpl->swapchainSupportDetails.presentModes.resize(surfacePresentModeCount); - res = vkGetPhysicalDeviceSurfacePresentModesKHR(dev, pimpl->surface, &surfacePresentModeCount, pimpl->swapchainSupportDetails.presentModes.data()); - assert(res == VK_SUCCESS); - - - // check physical device properties VkPhysicalDeviceProperties devProps; vkGetPhysicalDeviceProperties(dev, &devProps); @@ -717,33 +722,6 @@ namespace engine { vkGetPhysicalDeviceProperties(pimpl->physicalDevice, &devProps); INFO("Selected physical device: {}", devProps.deviceName); - TRACE("Supported present modes:"); - for (const auto& presMode : pimpl->swapchainSupportDetails.presentModes) { - switch (presMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - TRACE("\tVK_PRESENT_MODE_IMMEDIATE_KHR"); - break; - case VK_PRESENT_MODE_MAILBOX_KHR: - TRACE("\tVK_PRESENT_MODE_MAILBOX_KHR"); - break; - case VK_PRESENT_MODE_FIFO_KHR: - TRACE("\tVK_PRESENT_MODE_FIFO_KHR"); - break; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - TRACE("\tVK_PRESENT_MODE_FIFO_RELAXED_KHR"); - break; - case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR: - TRACE("\tVK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR"); - break; - case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR: - TRACE("\tVK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR"); - break; - default: - TRACE("\tUNKNOWN DISPLAY MODE"); - break; - } - } - // Get the queue families and find ones that support graphics, transfer, and compute @@ -923,7 +901,7 @@ namespace engine { // Now make the swapchain - createSwapchain(pimpl->device, pimpl->queues, window, pimpl->surface, pimpl->swapchainSupportDetails, &pimpl->swapchain); + createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->queues, window, pimpl->surface, &pimpl->swapchain); @@ -977,9 +955,18 @@ namespace engine { assert(res == VK_SUCCESS); uint32_t imageIndex; - vkAcquireNextImageKHR(pimpl->device, pimpl->swapchain.swapchain, UINT64_MAX, pimpl->swapchain.acquireSemaphore, VK_NULL_HANDLE, &imageIndex); + res = vkAcquireNextImageKHR(pimpl->device, pimpl->swapchain.swapchain, UINT64_MAX, pimpl->swapchain.acquireSemaphore, VK_NULL_HANDLE, &imageIndex); + if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { + // recreate swapchain + waitIdle(); + createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->queues, pimpl->window, pimpl->surface, &pimpl->swapchain); + } + else { + assert(res == VK_SUCCESS); + } - vkResetCommandBuffer(pimpl->commandBuffer, 0); + res = vkResetCommandBuffer(pimpl->commandBuffer, 0); + assert(res == VK_SUCCESS); // now record command buffer { @@ -1049,7 +1036,14 @@ namespace engine { presentInfo.pResults = nullptr; res = vkQueuePresentKHR(pimpl->gfxQueue.handle, &presentInfo); - assert(res == VK_SUCCESS); + if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { + // recreate swapchain + waitIdle(); + createSwapchain(pimpl->device, pimpl->physicalDevice, pimpl->queues, pimpl->window, pimpl->surface, &pimpl->swapchain); + } + else { + assert(res == VK_SUCCESS); + } } void GFXDevice::createPipeline(const char* vertShaderPath, const char* fragShaderPath) diff --git a/src/resources/shader.cpp b/src/resources/shader.cpp index 85dec72..993badf 100644 --- a/src/resources/shader.cpp +++ b/src/resources/shader.cpp @@ -30,7 +30,7 @@ static GLuint compile(const char *path, GLenum type) // compile shader GLuint handle = glCreateShader(type); - GLint size = src->size(); + GLint size = (GLint)src->size(); GLchar *data = src->data(); glShaderSource(handle, 1, &data, &size); glCompileShader(handle); diff --git a/src/resources/texture.cpp b/src/resources/texture.cpp index 9bc9119..fab9af1 100644 --- a/src/resources/texture.cpp +++ b/src/resources/texture.cpp @@ -62,7 +62,7 @@ static bool readGLRaw(const std::string& path, std::vector& texbuf, int uint64_t end = ftell(fp); texbuf.resize(end); - fseek(fp, tex_data_offset, SEEK_SET); + fseek(fp, (long)tex_data_offset, SEEK_SET); fread(texbuf.data(), 1, end, fp); fclose(fp);