diff --git a/thirdparty/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h b/thirdparty/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h index 7b04e54..39f9d9d 100644 --- a/thirdparty/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h +++ b/thirdparty/ZVulkan/include/zvulkan/vk_mem_alloc/vk_mem_alloc.h @@ -123,6 +123,7 @@ See documentation chapter: \ref statistics. #ifdef __cplusplus +#include extern "C" { #endif diff --git a/thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h b/thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h index 104d9ce..5f5a02f 100644 --- a/thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h +++ b/thirdparty/ZVulkan/include/zvulkan/vulkanbuilders.h @@ -144,7 +144,7 @@ public: ImageViewBuilder(); ImageViewBuilder& Type(VkImageViewType type); - ImageViewBuilder& Image(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT); + ImageViewBuilder& Image(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int mipLevel = 0, int arrayLayer = 0, int levelCount = 0, int layerCount = 0); ImageViewBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); @@ -492,8 +492,8 @@ public: PipelineBarrier& AddMemory(VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddBuffer(VulkanBuffer *buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); - PipelineBarrier& AddImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); - PipelineBarrier& AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); + PipelineBarrier& AddImage(VulkanImage *image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); + PipelineBarrier& AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1, int baseArrayLayer = 0, int layerCount = 1); PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanBuffer *buffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); PipelineBarrier& AddQueueTransfer(int srcFamily, int dstFamily, VulkanImage *image, VkImageLayout layout, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, int baseMipLevel = 0, int levelCount = 1); @@ -546,3 +546,24 @@ private: std::vector writes; std::vector> writeExtras; }; + +class BufferTransfer +{ +public: + BufferTransfer& AddBuffer(VulkanBuffer* buffer, size_t offset, const void* data, size_t size); + BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data, size_t size); + BufferTransfer& AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1); + std::unique_ptr Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer); + +private: + struct BufferCopy + { + VulkanBuffer* buffer; + size_t offset; + const void* data0; + size_t size0; + const void* data1; + size_t size1; + }; + std::vector bufferCopies; +}; diff --git a/thirdparty/ZVulkan/src/glslang/glslang/Include/Common.h b/thirdparty/ZVulkan/src/glslang/glslang/Include/Common.h index 1e47239..4f888ae 100644 --- a/thirdparty/ZVulkan/src/glslang/glslang/Include/Common.h +++ b/thirdparty/ZVulkan/src/glslang/glslang/Include/Common.h @@ -94,6 +94,7 @@ std::string to_string(const T& val) { #endif #if defined(_MSC_VER) +#undef strdup #define strdup _strdup #endif diff --git a/thirdparty/ZVulkan/src/volk/volk.c b/thirdparty/ZVulkan/src/volk/volk.c index 7a6969b..33255c0 100644 --- a/thirdparty/ZVulkan/src/volk/volk.c +++ b/thirdparty/ZVulkan/src/volk/volk.c @@ -5,7 +5,11 @@ #define VK_USE_PLATFORM_MACOS_MVK #define VK_USE_PLATFORM_METAL_EXT #else +#if defined(VULKAN_USE_XLIB) #define VK_USE_PLATFORM_XLIB_KHR +#elif defined(VULKAN_USE_WAYLAND) +#define VK_USE_PLATFORM_WAYLAND_KHR +#endif #endif /* This file is part of volk library; see volk.h for version/license details */ diff --git a/thirdparty/ZVulkan/src/vulkanbuilders.cpp b/thirdparty/ZVulkan/src/vulkanbuilders.cpp index 5a0db35..90527f7 100644 --- a/thirdparty/ZVulkan/src/vulkanbuilders.cpp +++ b/thirdparty/ZVulkan/src/vulkanbuilders.cpp @@ -1,4 +1,3 @@ - #include "vulkanbuilders.h" #include "vulkansurface.h" #include "vulkancompatibledevice.h" @@ -281,7 +280,7 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules, includer); if (!compileSuccess) { - throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog()); + VulkanError((std::string("Shader compile failed: ") + shader.getInfoLog()).c_str()); } glslang::TProgram program; @@ -289,13 +288,13 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk bool linkSuccess = program.link(EShMsgDefault); if (!linkSuccess) { - throw std::runtime_error(std::string("Shader link failed: ") + program.getInfoLog()); + VulkanError((std::string("Shader link failed: ") + program.getInfoLog()).c_str()); } glslang::TIntermediate *intermediate = program.getIntermediate(stage); if (!intermediate) { - throw std::runtime_error("Internal shader compiler error"); + VulkanError("Internal shader compiler error"); } glslang::SpvOptions spvOptions; @@ -315,7 +314,7 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk VkShaderModule shaderModule; VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule); if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan shader module"); + VulkanError("Could not create vulkan shader module"); auto obj = std::make_unique(device, shaderModule); if (debugName) @@ -505,13 +504,15 @@ ImageViewBuilder& ImageViewBuilder::Type(VkImageViewType type) return *this; } -ImageViewBuilder& ImageViewBuilder::Image(VulkanImage* image, VkFormat format, VkImageAspectFlags aspectMask) +ImageViewBuilder& ImageViewBuilder::Image(VulkanImage* image, VkFormat format, VkImageAspectFlags aspectMask, int mipLevel, int arrayLayer, int levelCount, int layerCount) { viewInfo.image = image->image; viewInfo.format = format; - viewInfo.subresourceRange.levelCount = image->mipLevels; + viewInfo.subresourceRange.levelCount = levelCount == 0 ? image->mipLevels : levelCount; viewInfo.subresourceRange.aspectMask = aspectMask; - viewInfo.subresourceRange.layerCount = image->layerCount; + viewInfo.subresourceRange.layerCount = layerCount == 0 ? image->layerCount : layerCount; + viewInfo.subresourceRange.baseMipLevel = mipLevel; + viewInfo.subresourceRange.baseArrayLayer = arrayLayer; return *this; } @@ -704,7 +705,7 @@ std::unique_ptr AccelerationStructureBuilder::Creat VkAccelerationStructureKHR hande = {}; VkResult result = vkCreateAccelerationStructureKHR(device->device, &createInfo, nullptr, &hande); if (result != VK_SUCCESS) - throw std::runtime_error("vkCreateAccelerationStructureKHR failed"); + VulkanError("vkCreateAccelerationStructureKHR failed"); auto obj = std::make_unique(device, hande); if (debugName) obj->SetDebugName(debugName); @@ -1459,12 +1460,12 @@ PipelineBarrier& PipelineBarrier::AddBuffer(VulkanBuffer* buffer, VkDeviceSize o return *this; } -PipelineBarrier& PipelineBarrier::AddImage(VulkanImage* image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) +PipelineBarrier& PipelineBarrier::AddImage(VulkanImage* image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount, int baseArrayLayer, int layerCount) { - return AddImage(image->image, oldLayout, newLayout, srcAccessMask, dstAccessMask, aspectMask, baseMipLevel, levelCount); + return AddImage(image->image, oldLayout, newLayout, srcAccessMask, dstAccessMask, aspectMask, baseMipLevel, levelCount, baseArrayLayer, layerCount); } -PipelineBarrier& PipelineBarrier::AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount) +PipelineBarrier& PipelineBarrier::AddImage(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, int baseMipLevel, int levelCount, int baseArrayLayer, int layerCount) { VkImageMemoryBarrier barrier = { }; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -1478,8 +1479,8 @@ PipelineBarrier& PipelineBarrier::AddImage(VkImage image, VkImageLayout oldLayou barrier.subresourceRange.aspectMask = aspectMask; barrier.subresourceRange.baseMipLevel = baseMipLevel; barrier.subresourceRange.levelCount = levelCount; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.baseArrayLayer = baseArrayLayer; + barrier.subresourceRange.layerCount = layerCount; imageMemoryBarriers.push_back(barrier); return *this; } @@ -1823,7 +1824,8 @@ std::vector VulkanDeviceBuilder::FindDevices(const std:: // Check if all required features are there if (info.Features.Features.samplerAnisotropy != VK_TRUE || - info.Features.Features.fragmentStoresAndAtomics != VK_TRUE) + info.Features.Features.fragmentStoresAndAtomics != VK_TRUE || + info.Features.Features.multiDrawIndirect != VK_TRUE) continue; VulkanCompatibleDevice dev; @@ -1846,6 +1848,7 @@ std::vector VulkanDeviceBuilder::FindDevices(const std:: enabledFeatures.Features.fragmentStoresAndAtomics = deviceFeatures.Features.fragmentStoresAndAtomics; enabledFeatures.Features.depthClamp = deviceFeatures.Features.depthClamp; enabledFeatures.Features.shaderClipDistance = deviceFeatures.Features.shaderClipDistance; + enabledFeatures.Features.multiDrawIndirect = deviceFeatures.Features.multiDrawIndirect; enabledFeatures.BufferDeviceAddress.bufferDeviceAddress = deviceFeatures.BufferDeviceAddress.bufferDeviceAddress; enabledFeatures.AccelerationStructure.accelerationStructure = deviceFeatures.AccelerationStructure.accelerationStructure; enabledFeatures.RayQuery.rayQuery = deviceFeatures.RayQuery.rayQuery; @@ -1853,6 +1856,7 @@ std::vector VulkanDeviceBuilder::FindDevices(const std:: enabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound = deviceFeatures.DescriptorIndexing.descriptorBindingPartiallyBound; enabledFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind = deviceFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind; enabledFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount = deviceFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount; + enabledFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing = deviceFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing; // Figure out which queue can present if (surface) @@ -1936,3 +1940,64 @@ std::shared_ptr VulkanSwapChainBuilder::Create(VulkanDevice* de { return std::make_shared(device); } + +///////////////////////////////////////////////////////////////////////////// + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, size_t offset, const void* data, size_t size) +{ + bufferCopies.push_back({ buffer, offset, data, size, nullptr, 0 }); + return *this; +} + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data, size_t size) +{ + bufferCopies.push_back({ buffer, 0, data, size, nullptr, 0 }); + return *this; +} + +BufferTransfer& BufferTransfer::AddBuffer(VulkanBuffer* buffer, const void* data0, size_t size0, const void* data1, size_t size1) +{ + bufferCopies.push_back({ buffer, 0, data0, size0, data1, size1 }); + return *this; +} + +std::unique_ptr BufferTransfer::Execute(VulkanDevice* device, VulkanCommandBuffer* cmdbuffer) +{ + size_t transferbuffersize = 0; + for (const auto& copy : bufferCopies) + transferbuffersize += copy.size0 + copy.size1; + + if (transferbuffersize == 0) + return nullptr; + + auto transferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(transferbuffersize) + .DebugName("BufferTransfer.transferBuffer") + .Create(device); + + uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); + size_t pos = 0; + for (const auto& copy : bufferCopies) + { + memcpy(data + pos, copy.data0, copy.size0); + pos += copy.size0; + memcpy(data + pos, copy.data1, copy.size1); + pos += copy.size1; + } + transferBuffer->Unmap(); + + pos = 0; + for (const auto& copy : bufferCopies) + { + if (copy.size0 > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, copy.offset, copy.size0); + pos += copy.size0; + + if (copy.size1 > 0) + cmdbuffer->copyBuffer(transferBuffer.get(), copy.buffer, pos, copy.offset + copy.size0, copy.size1); + pos += copy.size1; + } + + return transferBuffer; +} diff --git a/thirdparty/ZVulkan/src/vulkanswapchain.cpp b/thirdparty/ZVulkan/src/vulkanswapchain.cpp index 495c684..12e0987 100644 --- a/thirdparty/ZVulkan/src/vulkanswapchain.cpp +++ b/thirdparty/ZVulkan/src/vulkanswapchain.cpp @@ -34,13 +34,13 @@ void VulkanSwapChain::Create(int width, int height, int imageCount, bool vsync, uint32_t imageCount; VkResult result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, nullptr); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetSwapchainImagesKHR failed"); + VulkanError("vkGetSwapchainImagesKHR failed"); std::vector swapchainImages; swapchainImages.resize(imageCount); result = vkGetSwapchainImagesKHR(device->device, swapchain, &imageCount, swapchainImages.data()); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)"); + VulkanError("vkGetSwapchainImagesKHR failed (2)"); for (VkImage vkimage : swapchainImages) { @@ -103,7 +103,7 @@ bool VulkanSwapChain::CreateSwapchain(int width, int height, int imageCount, boo } if (caps.PresentModes.empty()) - throw std::runtime_error("No surface present modes supported"); + VulkanError("No surface present modes supported"); bool supportsFifoRelaxed = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != caps.PresentModes.end(); bool supportsMailbox = std::find(caps.PresentModes.begin(), caps.PresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != caps.PresentModes.end(); @@ -241,7 +241,8 @@ int VulkanSwapChain::AcquireImage(VulkanSemaphore* semaphore, VulkanFence* fence } else { - throw std::runtime_error("Failed to acquire next image!"); + VulkanError("Failed to acquire next image!"); + return -1; } } @@ -270,15 +271,15 @@ void VulkanSwapChain::QueuePresent(int imageIndex, VulkanSemaphore* semaphore) // The spec says we can recover from this. // However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem. - throw std::runtime_error("vkQueuePresentKHR failed: out of memory"); + VulkanError("vkQueuePresentKHR failed: out of memory"); } else if (result == VK_ERROR_DEVICE_LOST) { - throw std::runtime_error("vkQueuePresentKHR failed: device lost"); + VulkanError("vkQueuePresentKHR failed: device lost"); } else { - throw std::runtime_error("vkQueuePresentKHR failed"); + VulkanError("vkQueuePresentKHR failed"); } } @@ -332,7 +333,7 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive VkResult result = vkGetPhysicalDeviceSurfaceCapabilities2KHR(device->PhysicalDevice.Device, &surfaceInfo, &caps2); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilities2KHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceCapabilities2KHR failed"); caps.Capabilites = caps2.surfaceCapabilities; } @@ -340,7 +341,7 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive { VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &caps.Capabilites); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); } #ifdef WIN32 @@ -351,14 +352,14 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive uint32_t presentModeCount = 0; VkResult result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, nullptr); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); + VulkanError("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); if (presentModeCount > 0) { caps.PresentModes.resize(presentModeCount); result = vkGetPhysicalDeviceSurfacePresentModes2EXT(device->PhysicalDevice.Device, &surfaceInfo, &presentModeCount, caps.PresentModes.data()); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); + VulkanError("vkGetPhysicalDeviceSurfacePresentModes2EXT failed"); } } else @@ -367,14 +368,14 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive uint32_t presentModeCount = 0; VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, nullptr); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + VulkanError("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); if (presentModeCount > 0) { caps.PresentModes.resize(presentModeCount); result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->Surface->Surface, &presentModeCount, caps.PresentModes.data()); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + VulkanError("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); } } @@ -383,14 +384,14 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive uint32_t surfaceFormatCount = 0; VkResult result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, nullptr); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); if (surfaceFormatCount > 0) { std::vector formats(surfaceFormatCount, { VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR }); result = vkGetPhysicalDeviceSurfaceFormats2KHR(device->PhysicalDevice.Device, &surfaceInfo, &surfaceFormatCount, formats.data()); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceFormats2KHR failed"); for (VkSurfaceFormat2KHR& fmt : formats) caps.Formats.push_back(fmt.surfaceFormat); @@ -401,14 +402,14 @@ VulkanSurfaceCapabilities VulkanSwapChain::GetSurfaceCapabilities(bool exclusive uint32_t surfaceFormatCount = 0; VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, nullptr); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); if (surfaceFormatCount > 0) { caps.Formats.resize(surfaceFormatCount); result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->Surface->Surface, &surfaceFormatCount, caps.Formats.data()); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + VulkanError("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); } }