diff --git a/src/main.cpp b/src/main.cpp index a123e5c..937c00c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -226,7 +226,16 @@ class VulkanApp { for (const char* extension : extensions) fmt::println("\t{}", extension); #endif - mInstance = vk::createInstanceUnique(createInfo).value; + vk::Result instanceResult = vk::Result::eSuccess; + vk::UniqueInstance instanceValue; + + std::tie(instanceResult, instanceValue) = vk::createInstanceUnique(createInfo).asTuple(); + + if (instanceResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create instance!"); + + mInstance = std::move(instanceValue); + VULKAN_HPP_DEFAULT_DISPATCHER.init(mInstance.get()); } @@ -244,22 +253,36 @@ class VulkanApp { .pfnUserCallback = debugCallback, }; - mDebugMessenger = mInstance->createDebugUtilsMessengerEXTUnique(messengerCreateInfo, nullptr).value; + vk::Result debugMessengerResult = vk::Result::eSuccess; + vk::UniqueDebugUtilsMessengerEXT debugMessengerValue; + + std::tie(debugMessengerResult, debugMessengerValue) = + mInstance->createDebugUtilsMessengerEXTUnique(messengerCreateInfo, nullptr).asTuple(); + + if (debugMessengerResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to set up debug messenger!"); + + mDebugMessenger = std::move(debugMessengerValue); } fn createSurface() -> void { mSurface = vkfw::createWindowSurfaceUnique(mInstance.get(), mWindow.get()); } fn pickPhysicalDevice() -> void { - std::vector devices = mInstance->enumeratePhysicalDevices().value; + vk::Result devicesResult = vk::Result::eSuccess; + std::vector devicesValue; + std::tie(devicesResult, devicesValue) = mInstance->enumeratePhysicalDevices(); - if (devices.empty()) + if (devicesResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to enumerate physical devices!"); + + if (devicesValue.empty()) throw std::runtime_error("Failed to find GPUs with Vulkan support!"); #ifndef NDEBUG fmt::println("Available devices:"); #endif - for (const auto& device : devices) { + for (const vk::PhysicalDevice& device : devicesValue) { #ifndef NDEBUG vk::PhysicalDeviceProperties properties = device.getProperties(); fmt::println("\t{}", properties.deviceName.data()); @@ -299,7 +322,16 @@ class VulkanApp { .ppEnabledExtensionNames = deviceExtensions.data(), .pEnabledFeatures = &deviceFeatures }; - mDevice = mPhysicalDevice.createDeviceUnique(createInfo).value; + vk::Result createDeviceResult = vk::Result::eSuccess; + vk::UniqueDevice createDeviceValue; + + std::tie(createDeviceResult, createDeviceValue) = + mPhysicalDevice.createDeviceUnique(createInfo).asTuple(); + + if (createDeviceResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create logical device!"); + + mDevice = std::move(createDeviceValue); mGraphicsQueue = mDevice->getQueue(indices.graphics_family.value(), 0); mPresentQueue = mDevice->getQueue(indices.present_family.value(), 0); @@ -342,9 +374,24 @@ class VulkanApp { .oldSwapchain = nullptr, }; - mSwapChain = mDevice->createSwapchainKHRUnique(createInfo).value; + vk::Result swapChainResult = vk::Result::eSuccess; + vk::UniqueSwapchainKHR swapChainValue; - mSwapChainImages = mDevice->getSwapchainImagesKHR(mSwapChain.get()).value; + std::tie(swapChainResult, swapChainValue) = mDevice->createSwapchainKHRUnique(createInfo).asTuple(); + + if (swapChainResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create swap chain!"); + + mSwapChain = std::move(swapChainValue); + + vk::Result swapChainImagesResult = vk::Result::eSuccess; + std::vector mSwapChainImagesValue; + std::tie(swapChainImagesResult, mSwapChainImagesValue) = mDevice->getSwapchainImagesKHR(mSwapChain.get()); + + if (swapChainImagesResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to get swap chain images!"); + + mSwapChainImages = std::move(mSwapChainImagesValue); mSwapChainImageFormat = surfaceFormat.format; mSwapChainExtent = extent; } @@ -370,7 +417,15 @@ class VulkanApp { // clang-format on }; - mSwapChainImageViews[i] = mDevice->createImageViewUnique(createInfo).value; + vk::Result createImageViewResult = vk::Result::eSuccess; + vk::UniqueImageView imageViewValue; + + std::tie(createImageViewResult, imageViewValue) = mDevice->createImageViewUnique(createInfo).asTuple(); + + if (createImageViewResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create image views!"); + + mSwapChainImageViews[i] = std::move(imageViewValue); } } @@ -404,7 +459,15 @@ class VulkanApp { .pSubpasses = &subpass, }; - mRenderPass = mDevice->createRenderPassUnique(renderPassInfo).value; + vk::Result renderPassResult = vk::Result::eSuccess; + vk::UniqueRenderPass renderPassValue; + + std::tie(renderPassResult, renderPassValue) = mDevice->createRenderPassUnique(renderPassInfo).asTuple(); + + if (renderPassResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create render pass!"); + + mRenderPass = std::move(renderPassValue); } fn createGraphicsPipeline() -> void { @@ -486,7 +549,16 @@ class VulkanApp { .pushConstantRangeCount = 0, }; - mPipelineLayout = mDevice->createPipelineLayoutUnique(pipelineLayoutInfo).value; + vk::Result pipelineLayoutResult = vk::Result::eSuccess; + vk::UniquePipelineLayout pipelineLayoutValue; + + std::tie(pipelineLayoutResult, pipelineLayoutValue) = + mDevice->createPipelineLayoutUnique(pipelineLayoutInfo).asTuple(); + + if (pipelineLayoutResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create pipeline layout!"); + + mPipelineLayout = std::move(pipelineLayoutValue); vk::GraphicsPipelineCreateInfo pipelineInfo { .stageCount = static_cast(shaderStages.size()), @@ -503,7 +575,16 @@ class VulkanApp { .subpass = 0, }; - mGraphicsPipeline = mDevice->createGraphicsPipelineUnique(nullptr, pipelineInfo).value; + vk::Result graphicsPipelineResult = vk::Result::eSuccess; + vk::UniquePipeline graphicsPipelineValue; + + std::tie(graphicsPipelineResult, graphicsPipelineValue) = + mDevice->createGraphicsPipelineUnique(nullptr, pipelineInfo).asTuple(); + + if (graphicsPipelineResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create graphics pipeline!"); + + mGraphicsPipeline = std::move(graphicsPipelineValue); } fn createFramebuffers() -> void { @@ -519,7 +600,16 @@ class VulkanApp { .layers = 1, }; - mSwapChainFramebuffers[i] = mDevice->createFramebufferUnique(framebufferInfo).value; + vk::Result framebufferResult = vk::Result::eSuccess; + vk::UniqueFramebuffer framebufferValue; + + std::tie(framebufferResult, framebufferValue) = + mDevice->createFramebufferUnique(framebufferInfo).asTuple(); + + if (framebufferResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create framebuffer!"); + + mSwapChainFramebuffers[i] = std::move(framebufferValue); } } @@ -531,7 +621,15 @@ class VulkanApp { .queueFamilyIndex = queueFamilyIndices.graphics_family.value(), }; - mCommandPool = mDevice->createCommandPoolUnique(poolInfo).value; + vk::Result commandPoolResult = vk::Result::eSuccess; + vk::UniqueCommandPool commandPoolValue; + + std::tie(commandPoolResult, commandPoolValue) = mDevice->createCommandPoolUnique(poolInfo).asTuple(); + + if (commandPoolResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create command pool!"); + + mCommandPool = std::move(commandPoolValue); } fn createCommandBuffers() -> void { @@ -542,7 +640,16 @@ class VulkanApp { .commandBufferCount = static_cast(mCommandBuffers.size()) }; - mCommandBuffers = mDevice->allocateCommandBuffersUnique(allocInfo).value; + vk::Result commandBufferResult = vk::Result::eSuccess; + std::vector commandBufferValue; + + std::tie(commandBufferResult, commandBufferValue) = + mDevice->allocateCommandBuffersUnique(allocInfo).asTuple(); + + if (commandBufferResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to allocate command buffers!"); + + mCommandBuffers = std::move(commandBufferValue); } fn recordCommandBuffer(vk::CommandBuffer commandBuffer, u32 imageIndex) -> void { @@ -601,9 +708,37 @@ class VulkanApp { vk::FenceCreateInfo fenceInfo { .flags = vk::FenceCreateFlagBits::eSignaled }; for (usize idx = 0; idx < MAX_FRAMES_IN_FLIGHT; idx++) { - mImageAvailableSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo).value; - mRenderFinishedSemaphores[idx] = mDevice->createSemaphoreUnique(semaphoreInfo).value; - mInFlightFences[idx] = mDevice->createFenceUnique(fenceInfo).value; + vk::Result imageAvailableSemaphoreResult = vk::Result::eSuccess; + vk::UniqueSemaphore imageAvailableSemaphoreValue; + + std::tie(imageAvailableSemaphoreResult, imageAvailableSemaphoreValue) = + mDevice->createSemaphoreUnique(semaphoreInfo).asTuple(); + + if (imageAvailableSemaphoreResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create semaphores!"); + + mImageAvailableSemaphores[idx] = std::move(imageAvailableSemaphoreValue); + + vk::Result renderFinishedSemaphoreResult = vk::Result::eSuccess; + vk::UniqueSemaphore renderFinishedSemaphoreValue; + + std::tie(renderFinishedSemaphoreResult, renderFinishedSemaphoreValue) = + mDevice->createSemaphoreUnique(semaphoreInfo).asTuple(); + + if (imageAvailableSemaphoreResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create semaphores!"); + + mRenderFinishedSemaphores[idx] = std::move(renderFinishedSemaphoreValue); + + vk::Result fenceResult = vk::Result::eSuccess; + vk::UniqueFence fenceValue; + + std::tie(fenceResult, fenceValue) = mDevice->createFenceUnique(fenceInfo).asTuple(); + + if (fenceResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create fences!"); + + mInFlightFences[idx] = std::move(fenceValue); } } @@ -614,22 +749,25 @@ class VulkanApp { if (result != vk::Result::eSuccess) throw std::runtime_error("Failed to wait for fences!"); - vk::ResultValue imageIndex = mDevice->acquireNextImageKHR( + vk::Result imageIndexResult = vk::Result::eSuccess; + u32 imageIndexValue = 0; + + std::tie(imageIndexResult, imageIndexValue) = mDevice->acquireNextImageKHR( mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame].get(), nullptr ); - if (imageIndex.result == vk::Result::eErrorOutOfDateKHR) { + if (imageIndexResult == vk::Result::eErrorOutOfDateKHR) { recreateSwapChain(); return; } - if (imageIndex.result != vk::Result::eSuccess && imageIndex.result != vk::Result::eSuboptimalKHR) + if (imageIndexResult != vk::Result::eSuccess && imageIndexResult != vk::Result::eSuboptimalKHR) throw std::runtime_error("Failed to acquire swap chain image!"); mDevice->resetFences(mInFlightFences[mCurrentFrame].get()); mCommandBuffers[mCurrentFrame]->reset(vk::CommandBufferResetFlagBits::eReleaseResources); - recordCommandBuffer(mCommandBuffers[mCurrentFrame].get(), imageIndex.value); + recordCommandBuffer(mCommandBuffers[mCurrentFrame].get(), imageIndexValue); std::array waitStages = { vk::PipelineStageFlagBits::eColorAttachmentOutput }; @@ -653,7 +791,7 @@ class VulkanApp { .pWaitSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(), .swapchainCount = 1, .pSwapchains = &mSwapChain.get(), - .pImageIndices = &imageIndex.value, + .pImageIndices = &imageIndexValue, }; vk::Result presentResult = mPresentQueue.presentKHR(presentInfo); @@ -673,7 +811,15 @@ class VulkanApp { vk::ShaderModuleCreateInfo createInfo { .codeSize = code.size(), .pCode = std::bit_cast(code.data()) }; - return mDevice->createShaderModuleUnique(createInfo).value; + vk::Result shaderModuleResult = vk::Result::eSuccess; + vk::UniqueShaderModule shaderModuleValue; + + std::tie(shaderModuleResult, shaderModuleValue) = mDevice->createShaderModuleUnique(createInfo).asTuple(); + + if (shaderModuleResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to create shader module!"); + + return shaderModuleValue; } static fn chooseSwapSurfaceFormat(const std::vector& availableFormats @@ -715,9 +861,36 @@ class VulkanApp { fn querySwapChainSupport(vk::PhysicalDevice device) -> SwapChainSupportDetails { SwapChainSupportDetails details; - details.capabilities = device.getSurfaceCapabilitiesKHR(mSurface.get()).value; - details.formats = device.getSurfaceFormatsKHR(mSurface.get()).value; - details.present_modes = device.getSurfacePresentModesKHR(mSurface.get()).value; + vk::Result surfaceCapabilitiesResult = vk::Result::eSuccess; + vk::SurfaceCapabilitiesKHR surfaceCapabilitiesValue; + + std::tie(surfaceCapabilitiesResult, surfaceCapabilitiesValue) = + device.getSurfaceCapabilitiesKHR(mSurface.get()); + + if (surfaceCapabilitiesResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to get surface capabilities!"); + + details.capabilities = surfaceCapabilitiesValue; + + vk::Result surfaceFormatsResult = vk::Result::eSuccess; + std::vector surfaceFormatsValue; + + std::tie(surfaceFormatsResult, surfaceFormatsValue) = device.getSurfaceFormatsKHR(mSurface.get()); + + if (surfaceFormatsResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to get surface formats!"); + + details.formats = surfaceFormatsValue; + + vk::Result presentModesResult = vk::Result::eSuccess; + std::vector presentModesValue; + + std::tie(presentModesResult, presentModesValue) = device.getSurfacePresentModesKHR(mSurface.get()); + + if (presentModesResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to get surface present modes!"); + + details.present_modes = presentModesValue; return details; } @@ -738,12 +911,19 @@ class VulkanApp { } static fn checkDeviceExtensionSupport(vk::PhysicalDevice device) -> bool { - std::vector availableExtensions = - device.enumerateDeviceExtensionProperties().value; + vk::Result availableExtensionsResult = vk::Result::eSuccess; + std::vector availableExtensionsValue; + + std::tie(availableExtensionsResult, availableExtensionsValue) = + device.enumerateDeviceExtensionProperties(); + + if (availableExtensionsResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to enumerate device extensions!"); std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - for (const auto& extension : availableExtensions) requiredExtensions.erase(extension.extensionName); + for (const vk::ExtensionProperties& extension : availableExtensionsValue) + requiredExtensions.erase(extension.extensionName); return requiredExtensions.empty(); } @@ -757,9 +937,16 @@ class VulkanApp { if (queueFamilies[i].queueFlags & vk::QueueFlagBits::eGraphics) indices.graphics_family = i; - vk::Bool32 presentSupport = device.getSurfaceSupportKHR(i, mSurface.get()).value; + vk::Result queuePresentSupportResult = vk::Result::eSuccess; + vk::Bool32 queuePresentSupportValue = 0; - if (presentSupport) + std::tie(queuePresentSupportResult, queuePresentSupportValue) = + device.getSurfaceSupportKHR(i, mSurface.get()); + + if (queuePresentSupportResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to get surface support!"); + + if (queuePresentSupportValue) indices.present_family = i; if (indices.isComplete()) @@ -781,12 +968,17 @@ class VulkanApp { } static fn checkValidationLayerSupport() -> bool { - std::vector availableLayers = vk::enumerateInstanceLayerProperties().value; + vk::Result availableLayersResult = vk::Result::eSuccess; + std::vector availableLayersValue; + std::tie(availableLayersResult, availableLayersValue) = vk::enumerateInstanceLayerProperties(); + + if (availableLayersResult != vk::Result::eSuccess) + throw std::runtime_error("Failed to enumerate validation layers!"); for (const char* layerName : validationLayers) { bool layerFound = false; - for (const auto& layerProperties : availableLayers) + for (const vk::LayerProperties& layerProperties : availableLayersValue) if (strcmp(layerName, layerProperties.layerName) == 0) { layerFound = true; break;