diff --git a/src/main.cpp b/src/main.cpp index 576420e..f61c1d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,13 @@ constexpr i32 HEIGHT = 600; constexpr std::array validationLayers = { "VK_LAYER_KHRONOS_validation" }; +#ifdef __APPLE__ +constexpr std::array deviceExtensions = { vk::KHRSwapchainExtensionName, + vk::KHRPortabilitySubsetExtensionName }; +#else +constexpr std::array deviceExtensions = { vk::KHRSwapchainExtensionName }; +#endif + #ifdef NDEBUG constexpr bool enableValidationLayers = false; #else @@ -56,6 +63,12 @@ class VulkanApp { fn isComplete() -> bool { return graphics_family.has_value() && present_family.has_value(); } }; + struct SwapChainSupportDetails { + vk::SurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector present_modes; + }; + fn initWindow() -> void { mGLFWInstance = vkfw::initUnique(); @@ -92,9 +105,9 @@ class VulkanApp { // Retrieve extensions using custom function std::vector extensions = getRequiredExtensions(); +#ifdef __APPLE__ // Enable the portability extension and set flags extensions.emplace_back(vk::KHRPortabilityEnumerationExtensionName); -#ifdef __APPLE__ // Technically deprecated but vulkan complains if I don't include it for macOS // So instead of using the vk::KHRPortabilitySubsetExtensionName, I just use // the direct string. @@ -187,19 +200,11 @@ class VulkanApp { vk::PhysicalDeviceFeatures deviceFeatures; -#ifdef __APPLE__ vk::DeviceCreateInfo createInfo { .queueCreateInfoCount = static_cast(queueCreateInfos.size()), .pQueueCreateInfos = queueCreateInfos.data(), - .enabledExtensionCount = 1, - .ppEnabledExtensionNames = &vk::KHRPortabilitySubsetExtensionName, + .enabledExtensionCount = static_cast(deviceExtensions.size()), + .ppEnabledExtensionNames = deviceExtensions.data(), .pEnabledFeatures = &deviceFeatures }; -#else - vk::DeviceCreateInfo createInfo { .queueCreateInfoCount = static_cast(queueCreateInfos.size()), - .pQueueCreateInfos = queueCreateInfos.data(), - .enabledExtensionCount = 0, - .ppEnabledExtensionNames = nullptr, - .pEnabledFeatures = &deviceFeatures }; -#endif mDevice = mPhysicalDevice.createDeviceUnique(createInfo); @@ -210,7 +215,26 @@ class VulkanApp { fn isDeviceSuitable(vk::PhysicalDevice device) -> bool { QueueFamilyIndices indices = findQueueFamilies(device); - return indices.isComplete(); + bool extensionsSupported = checkDeviceExtensionSupport(device); + + bool swapChainAdequate = false; + + if (extensionsSupported) { + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device); + swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty(); + } + + return indices.isComplete() && extensionsSupported && swapChainAdequate; + } + + static fn checkDeviceExtensionSupport(vk::PhysicalDevice device) -> bool { + std::vector availableExtensions = device.enumerateDeviceExtensionProperties(); + + std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); + + for (const auto& extension : availableExtensions) requiredExtensions.erase(extension.extensionName); + + return requiredExtensions.empty(); } fn findQueueFamilies(vk::PhysicalDevice device) -> QueueFamilyIndices { @@ -234,6 +258,16 @@ class VulkanApp { return indices; } + fn querySwapChainSupport(vk::PhysicalDevice device) -> SwapChainSupportDetails { + SwapChainSupportDetails details; + + details.capabilities = device.getSurfaceCapabilitiesKHR(mSurface.get()); + details.formats = device.getSurfaceFormatsKHR(mSurface.get()); + details.present_modes = device.getSurfacePresentModesKHR(mSurface.get()); + + return details; + } + static fn getRequiredExtensions() -> std::vector { std::span extensionsSpan = vkfw::getRequiredInstanceExtensions();