From 1e62255b28c977a8bac1aba6dab2ac61d5226c87 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 1 Sep 2022 01:04:17 +0200 Subject: [PATCH] Update the vulkan support classes and enable runtime detection for falling back to non-rayquery rendering if the device does not support it --- CMakeLists.txt | 6 + src/lightmap/gpuraytracer.cpp | 36 +- src/lightmap/stacktrace.cpp | 18 +- src/lightmap/vulkanbuilders.cpp | 304 +++---------- src/lightmap/vulkanbuilders.h | 52 +-- src/lightmap/vulkancompatibledevice.cpp | 145 ++++++ src/lightmap/vulkancompatibledevice.h | 22 + src/lightmap/vulkandevice.cpp | 573 ++++-------------------- src/lightmap/vulkandevice.h | 136 ++---- src/lightmap/vulkaninstance.cpp | 378 ++++++++++++++++ src/lightmap/vulkaninstance.h | 106 +++++ src/lightmap/vulkanobjects.h | 155 +++++-- src/lightmap/vulkansurface.cpp | 53 +++ src/lightmap/vulkansurface.h | 46 ++ thirdparty/volk/volk.c | 10 + 15 files changed, 1109 insertions(+), 931 deletions(-) create mode 100644 src/lightmap/vulkancompatibledevice.cpp create mode 100644 src/lightmap/vulkancompatibledevice.h create mode 100644 src/lightmap/vulkaninstance.cpp create mode 100644 src/lightmap/vulkaninstance.h create mode 100644 src/lightmap/vulkansurface.cpp create mode 100644 src/lightmap/vulkansurface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5212511..5bfc20a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,6 +180,12 @@ set( SOURCES src/lightmap/vulkanobjects.h src/lightmap/vulkanbuilders.cpp src/lightmap/vulkanbuilders.h + src/lightmap/vulkancompatibledevice.cpp + src/lightmap/vulkancompatibledevice.h + src/lightmap/vulkaninstance.cpp + src/lightmap/vulkaninstance.h + src/lightmap/vulkansurface.cpp + src/lightmap/vulkansurface.h src/lightmap/stacktrace.cpp src/lightmap/stacktrace.h src/lightmap/surfaceclip.cpp diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 7030204..fb6a0c5 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -7,6 +7,8 @@ #include "framework/templates.h" #include "framework/halffloat.h" #include "vulkanbuilders.h" +#include "vulkancompatibledevice.h" +#include "stacktrace.h" #include #include #include @@ -21,10 +23,22 @@ extern bool VKDebug; extern bool NoRtx; +void VulkanPrintLog(const char* typestr, const std::string& msg) +{ + printf("[%s] %s\n", typestr, msg.c_str()); + printf("%s\n", CaptureStackTraceText(2).c_str()); +} + +void VulkanError(const char* text) +{ + throw std::runtime_error(text); +} + GPURaytracer::GPURaytracer() { - device = std::make_unique(0, VKDebug); - useRayQuery = !NoRtx;// && device->physicalDevice.rayQueryProperties.supportsRayQuery; + auto instance = std::make_shared(VKDebug); + device = std::make_unique(instance, nullptr, VulkanCompatibleDevice::SelectDevice(instance, nullptr, 0)); + useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery; PrintVulkanInfo(); } @@ -38,9 +52,6 @@ void GPURaytracer::Raytrace(LevelMesh* level) printf("Building Vulkan acceleration structures\n"); - if (device->renderdoc) - device->renderdoc->StartFrameCapture(0, 0); - CreateVulkanObjects(); printf("Ray tracing in progress...\n"); @@ -79,9 +90,6 @@ void GPURaytracer::Raytrace(LevelMesh* level) DownloadAtlasImage(pageIndex); } - if (device->renderdoc) - device->renderdoc->EndFrameCapture(0, 0); - printf("Ray trace complete\n"); } @@ -332,7 +340,7 @@ vec2 GPURaytracer::ToUV(const vec3& vert, const Surface* targetSurface) void GPURaytracer::CreateVulkanObjects() { submitFence = std::make_unique(device.get()); - cmdpool = std::make_unique(device.get(), device->graphicsFamily); + cmdpool = std::make_unique(device.get(), device->GraphicsFamily); BeginCommands(); @@ -402,7 +410,7 @@ void GPURaytracer::FinishCommands() QueueSubmit() .AddCommandBuffer(cmdbuffer.get()) - .Execute(device.get(), device->graphicsQueue, submitFence.get()); + .Execute(device.get(), device->GraphicsQueue, submitFence.get()); VkResult result = vkWaitForFences(device->device, 1, &submitFence->fence, VK_TRUE, std::numeric_limits::max()); if (result != VK_SUCCESS) @@ -623,8 +631,8 @@ void GPURaytracer::CreateTopLevelAccelerationStructure() void GPURaytracer::CreateShaders() { - FString prefix = "#version 460\r\n#line 1\r\n"; - FString traceprefix = "#version 460\r\n"; + std::string prefix = "#version 460\r\n#line 1\r\n"; + std::string traceprefix = "#version 460\r\n"; if (useRayQuery) { traceprefix += "#extension GL_EXT_ray_query : require\r\n"; @@ -878,7 +886,7 @@ LightmapImage GPURaytracer::CreateImage(int width, int height) void GPURaytracer::CreateUniformBuffer() { - VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment; + VkDeviceSize align = device->PhysicalDevice.Properties.limits.minUniformBufferOffsetAlignment; uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align; uniformBuffer = BufferBuilder() @@ -932,7 +940,7 @@ std::vector GPURaytracer::CreateCollisionNodes() void GPURaytracer::PrintVulkanInfo() { - const auto& props = device->physicalDevice.properties; + const auto& props = device->PhysicalDevice.Properties; std::string deviceType; switch (props.deviceType) diff --git a/src/lightmap/stacktrace.cpp b/src/lightmap/stacktrace.cpp index 09c38d9..37f4383 100644 --- a/src/lightmap/stacktrace.cpp +++ b/src/lightmap/stacktrace.cpp @@ -4,6 +4,7 @@ #ifdef WIN32 #include #include +#include #else #include #include @@ -17,8 +18,16 @@ class NativeSymbolResolver { public: - NativeSymbolResolver() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); } - ~NativeSymbolResolver() { SymCleanup(GetCurrentProcess()); } + NativeSymbolResolver() + { + SymInitialize(GetCurrentProcess(), nullptr, TRUE); + GetModuleInformation(GetCurrentProcess(), GetModuleHandle(0), &moduleInfo, sizeof(MODULEINFO)); + } + + ~NativeSymbolResolver() + { + SymCleanup(GetCurrentProcess()); + } std::string GetName(void* frame) { @@ -34,6 +43,9 @@ public: BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64); if (result) { + if ((DWORD64)frame < (DWORD64)moduleInfo.lpBaseOfDll || (DWORD64)frame >= ((DWORD64)moduleInfo.lpBaseOfDll + moduleInfo.SizeOfImage)) + return s; // Ignore anything not from the exe itself + IMAGEHLP_LINE64 line64; DWORD displacement = 0; memset(&line64, 0, sizeof(IMAGEHLP_LINE64)); @@ -51,6 +63,8 @@ public: return s; } + + MODULEINFO moduleInfo = {}; }; #else class NativeSymbolResolver diff --git a/src/lightmap/vulkanbuilders.cpp b/src/lightmap/vulkanbuilders.cpp index 5c1710d..1146dc3 100644 --- a/src/lightmap/vulkanbuilders.cpp +++ b/src/lightmap/vulkanbuilders.cpp @@ -109,77 +109,45 @@ static const TBuiltInResource DefaultTBuiltInResource = { } }; +void ShaderBuilder::Init() +{ + ShInitialize(); +} + +void ShaderBuilder::Deinit() +{ + ShFinalize(); +} + ShaderBuilder::ShaderBuilder() { } -ShaderBuilder& ShaderBuilder::VertexShader(const FString &c) +ShaderBuilder& ShaderBuilder::VertexShader(const std::string& c) { code = c; stage = EShLanguage::EShLangVertex; return *this; } -ShaderBuilder& ShaderBuilder::FragmentShader(const FString &c) +ShaderBuilder& ShaderBuilder::FragmentShader(const std::string& c) { code = c; stage = EShLanguage::EShLangFragment; return *this; } -ShaderBuilder& ShaderBuilder::RayGenShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangRayGen; - return *this; -} - -ShaderBuilder& ShaderBuilder::IntersectShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangIntersect; - return *this; -} - -ShaderBuilder& ShaderBuilder::AnyHitShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangAnyHit; - return *this; -} - -ShaderBuilder& ShaderBuilder::ClosestHitShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangClosestHit; - return *this; -} - -ShaderBuilder& ShaderBuilder::MissShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangMiss; - return *this; -} - -ShaderBuilder& ShaderBuilder::CallableShader(const FString& c) -{ - code = c; - stage = EShLanguage::EShLangCallable; - return *this; -} - std::unique_ptr ShaderBuilder::Create(const char *shadername, VulkanDevice *device) { EShLanguage stage = (EShLanguage)this->stage; - const char *sources[] = { code.GetChars() }; + const char *sources[] = { code.c_str() }; TBuiltInResource resources = DefaultTBuiltInResource; glslang::TShader shader(stage); shader.setStrings(sources, 1); shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100); - if (device->ApiVersion >= VK_API_VERSION_1_2) + if (device->Instance->ApiVersion >= VK_API_VERSION_1_2) { shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); @@ -192,7 +160,7 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules); if (!compileSuccess) { - throw std::runtime_error(std::string("Could not compile shader ") + shadername + ": " + shader.getInfoLog()); + throw std::runtime_error(std::string("Shader compile failed: ") + shader.getInfoLog()); } glslang::TProgram program; @@ -200,13 +168,13 @@ std::unique_ptr ShaderBuilder::Create(const char *shadername, Vulk bool linkSuccess = program.link(EShMsgDefault); if (!linkSuccess) { - throw std::runtime_error(std::string("Could not link shader ") + shadername + ": " + program.getInfoLog()); + throw std::runtime_error(std::string("Shader link failed: ") + program.getInfoLog()); } glslang::TIntermediate *intermediate = program.getIntermediate(stage); if (!intermediate) { - throw std::runtime_error(std::string("Internal shader compile error while processing: ") + shadername); + throw std::runtime_error("Internal shader compiler error"); } glslang::SpvOptions spvOptions; @@ -226,9 +194,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"); - } auto obj = std::make_unique(device, shaderModule); if (debugName) @@ -297,7 +263,7 @@ ImageBuilder& ImageBuilder::MemoryType(VkMemoryPropertyFlags requiredFlags, VkMe bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags bufferFeatures) { VkImageFormatProperties properties = { }; - VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->physicalDevice.device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties); + VkResult result = vkGetPhysicalDeviceImageFormatProperties(device->PhysicalDevice.Device, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &properties); if (result != VK_SUCCESS) return false; if (imageInfo.extent.width > properties.maxExtent.width) return false; if (imageInfo.extent.height > properties.maxExtent.height) return false; @@ -308,7 +274,7 @@ bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags if (bufferFeatures != 0) { VkFormatProperties formatProperties = { }; - vkGetPhysicalDeviceFormatProperties(device->physicalDevice.device, imageInfo.format, &formatProperties); + vkGetPhysicalDeviceFormatProperties(device->PhysicalDevice.Device, imageInfo.format, &formatProperties); if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures) return false; } @@ -321,8 +287,7 @@ std::unique_ptr ImageBuilder::Create(VulkanDevice* device, VkDevice VmaAllocation allocation; VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan image"); + CheckVulkanError(result, "Could not create vulkan image"); if (allocatedBytes != nullptr) { @@ -385,8 +350,7 @@ std::unique_ptr ImageViewBuilder::Create(VulkanDevice* device) { VkImageView view; VkResult result = vkCreateImageView(device->device, &viewInfo, nullptr, &view); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create texture image view"); + CheckVulkanError(result, "Could not create texture image view"); auto obj = std::make_unique(device, view); if (debugName) @@ -457,6 +421,12 @@ SamplerBuilder& SamplerBuilder::Anisotropy(float maxAnisotropy) return *this; } +SamplerBuilder& SamplerBuilder::MipLodBias(float bias) +{ + samplerInfo.mipLodBias = bias; + return *this; +} + SamplerBuilder& SamplerBuilder::MaxLod(float value) { samplerInfo.maxLod = value; @@ -467,8 +437,7 @@ std::unique_ptr SamplerBuilder::Create(VulkanDevice* device) { VkSampler sampler; VkResult result = vkCreateSampler(device->device, &samplerInfo, nullptr, &sampler); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create texture sampler"); + CheckVulkanError(result, "Could not create texture sampler"); auto obj = std::make_unique(device, sampler); if (debugName) obj->SetDebugName(debugName); @@ -511,8 +480,7 @@ std::unique_ptr BufferBuilder::Create(VulkanDevice* device) VmaAllocation allocation; VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not allocate memory for vulkan buffer"); + CheckVulkanError(result, "Could not allocate memory for vulkan buffer"); auto obj = std::make_unique(device, buffer, allocation, bufferInfo.size); if (debugName) @@ -562,131 +530,6 @@ std::unique_ptr AccelerationStructureBuilder::Creat ///////////////////////////////////////////////////////////////////////////// -RayTracingPipelineBuilder::RayTracingPipelineBuilder() -{ - pipelineInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::Layout(VulkanPipelineLayout* layout) -{ - pipelineInfo.layout = layout->layout; - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::MaxPipelineRayRecursionDepth(int depth) -{ - pipelineInfo.maxPipelineRayRecursionDepth = depth; - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::AddShader(VkShaderStageFlagBits stage, VulkanShader* shader) -{ - VkPipelineShaderStageCreateInfo stageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; - stageInfo.stage = stage; - stageInfo.module = shader->module; - stageInfo.pName = "main"; - stages.push_back(stageInfo); - - pipelineInfo.pStages = stages.data(); - pipelineInfo.stageCount = (uint32_t)stages.size(); - - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::AddRayGenGroup(int rayGenShader) -{ - VkRayTracingShaderGroupCreateInfoKHR group = {}; - group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = rayGenShader; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - groups.push_back(group); - - pipelineInfo.pGroups = groups.data(); - pipelineInfo.groupCount = (uint32_t)groups.size(); - - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::AddMissGroup(int missShader) -{ - VkRayTracingShaderGroupCreateInfoKHR group = {}; - group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group.generalShader = missShader; - group.closestHitShader = VK_SHADER_UNUSED_KHR; - group.anyHitShader = VK_SHADER_UNUSED_KHR; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - groups.push_back(group); - - pipelineInfo.pGroups = groups.data(); - pipelineInfo.groupCount = (uint32_t)groups.size(); - - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::AddTrianglesHitGroup(int closestHitShader, int anyHitShader) -{ - VkRayTracingShaderGroupCreateInfoKHR group = {}; - group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = closestHitShader; - group.anyHitShader = anyHitShader; - group.intersectionShader = VK_SHADER_UNUSED_KHR; - groups.push_back(group); - - pipelineInfo.pGroups = groups.data(); - pipelineInfo.groupCount = (uint32_t)groups.size(); - - return *this; -} - -RayTracingPipelineBuilder& RayTracingPipelineBuilder::AddProceduralHitGroup(int intersectionShader, int closestHitShader, int anyHitShader) -{ - VkRayTracingShaderGroupCreateInfoKHR group = {}; - group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - group.generalShader = VK_SHADER_UNUSED_KHR; - group.closestHitShader = closestHitShader; - group.anyHitShader = anyHitShader; - group.intersectionShader = intersectionShader; - groups.push_back(group); - - pipelineInfo.pGroups = groups.data(); - pipelineInfo.groupCount = (uint32_t)groups.size(); - - return *this; -} - -std::unique_ptr RayTracingPipelineBuilder::Create(VulkanDevice* device) -{ - VkPipeline pipeline; - VkResult result = vkCreateRayTracingPipelinesKHR(device->device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); - if (result != VK_SUCCESS) - throw std::runtime_error("vkCreateRayTracingPipelinesKHR failed"); - - std::vector shaderGroupHandles(device->physicalDevice.rayTracingProperties.shaderGroupHandleSize * groups.size()); - if (!groups.empty()) - { - result = vkGetRayTracingShaderGroupHandlesKHR(device->device, pipeline, 0, (uint32_t)groups.size(), shaderGroupHandles.size(), shaderGroupHandles.data()); - if (result != VK_SUCCESS) - { - vkDestroyPipeline(device->device, pipeline, nullptr); - throw std::runtime_error("vkGetRayTracingShaderGroupHandlesKHR failed"); - } - } - - auto obj = std::make_unique(device, pipeline, shaderGroupHandles); - if (debugName) - obj->SetDebugName(debugName); - return obj; -} - -///////////////////////////////////////////////////////////////////////////// - ComputePipelineBuilder::ComputePipelineBuilder() { pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; @@ -723,10 +566,15 @@ std::unique_ptr ComputePipelineBuilder::Create(VulkanDevice* dev DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() { - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; } -DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::AddBinding(int index, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags) +DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::Flags(VkDescriptorSetLayoutCreateFlags flags) +{ + layoutInfo.flags = flags; + return *this; +} + +DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::AddBinding(int index, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags, VkDescriptorBindingFlags flags) { VkDescriptorSetLayoutBinding binding = { }; binding.binding = index; @@ -734,10 +582,18 @@ DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::AddBinding(int index, Vk binding.descriptorCount = arrayCount; binding.stageFlags = stageFlags; binding.pImmutableSamplers = nullptr; - bindings.Push(binding); + bindings.push_back(binding); + bindingFlags.push_back(flags); + + layoutInfo.bindingCount = (uint32_t)bindings.size(); + layoutInfo.pBindings = bindings.data(); + + bindingFlagsInfo.bindingCount = (uint32_t)bindings.size(); + bindingFlagsInfo.pBindingFlags = bindingFlags.data(); + + if (flags != 0) + layoutInfo.pNext = &bindingFlagsInfo; - layoutInfo.bindingCount = (uint32_t)bindings.Size(); - layoutInfo.pBindings = &bindings[0]; return *this; } @@ -745,8 +601,7 @@ std::unique_ptr DescriptorSetLayoutBuilder::Create(Vu { VkDescriptorSetLayout layout; VkResult result = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &layout); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create descriptor set layout"); + CheckVulkanError(result, "Could not create descriptor set layout"); auto obj = std::make_unique(device, layout); if (debugName) obj->SetDebugName(debugName); @@ -762,6 +617,12 @@ DescriptorPoolBuilder::DescriptorPoolBuilder() poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; } +DescriptorPoolBuilder& DescriptorPoolBuilder::Flags(VkDescriptorPoolCreateFlags flags) +{ + poolInfo.flags = flags | VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + return *this; +} + DescriptorPoolBuilder& DescriptorPoolBuilder::MaxSets(int value) { poolInfo.maxSets = value; @@ -784,8 +645,7 @@ std::unique_ptr DescriptorPoolBuilder::Create(VulkanDevice { VkDescriptorPool descriptorPool; VkResult result = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create descriptor pool"); + CheckVulkanError(result, "Could not create descriptor pool"); auto obj = std::make_unique(device, descriptorPool); if (debugName) obj->SetDebugName(debugName); @@ -811,8 +671,7 @@ std::unique_ptr QueryPoolBuilder::Create(VulkanDevice* device) { VkQueryPool queryPool; VkResult result = vkCreateQueryPool(device->device, &poolInfo, nullptr, &queryPool); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create query pool"); + CheckVulkanError(result, "Could not create query pool"); auto obj = std::make_unique(device, queryPool); if (debugName) obj->SetDebugName(debugName); @@ -862,8 +721,7 @@ std::unique_ptr FramebufferBuilder::Create(VulkanDevice* devi { VkFramebuffer framebuffer = 0; VkResult result = vkCreateFramebuffer(device->device, &framebufferInfo, nullptr, &framebuffer); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create framebuffer"); + CheckVulkanError(result, "Could not create framebuffer"); auto obj = std::make_unique(device, framebuffer); if (debugName) obj->SetDebugName(debugName); @@ -1179,8 +1037,7 @@ std::unique_ptr GraphicsPipelineBuilder::Create(VulkanDevice* de { VkPipeline pipeline = 0; VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create graphics pipeline"); + CheckVulkanError(result, "Could not create graphics pipeline"); auto obj = std::make_unique(device, pipeline); if (debugName) obj->SetDebugName(debugName); @@ -1218,8 +1075,7 @@ std::unique_ptr PipelineLayoutBuilder::Create(VulkanDevice { VkPipelineLayout pipelineLayout; VkResult result = vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, nullptr, &pipelineLayout); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create pipeline layout"); + CheckVulkanError(result, "Could not create pipeline layout"); auto obj = std::make_unique(device, pipelineLayout); if (debugName) obj->SetDebugName(debugName); @@ -1323,8 +1179,7 @@ std::unique_ptr RenderPassBuilder::Create(VulkanDevice* device { VkRenderPass renderPass = 0; VkResult result = vkCreateRenderPass(device->device, &renderPassInfo, nullptr, &renderPass); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create render pass"); + CheckVulkanError(result, "Could not create render pass"); auto obj = std::make_unique(device, renderPass); if (debugName) obj->SetDebugName(debugName); @@ -1466,9 +1321,8 @@ QueueSubmit& QueueSubmit::AddSignal(VulkanSemaphore* semaphore) void QueueSubmit::Execute(VulkanDevice* device, VkQueue queue, VulkanFence* fence) { - VkResult result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not submit command buffer"); + VkResult result = vkQueueSubmit(device->GraphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE); + CheckVulkanError(result, "Could not submit command buffer"); } ///////////////////////////////////////////////////////////////////////////// @@ -1501,28 +1355,6 @@ WriteDescriptors& WriteDescriptors::AddBuffer(VulkanDescriptorSet* descriptorSet return *this; } -WriteDescriptors& WriteDescriptors::AddSampledImage(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VkImageLayout imageLayout) -{ - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageView = view->view; - imageInfo.imageLayout = imageLayout; - - auto extra = std::make_unique(); - extra->imageInfo = imageInfo; - - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet->set; - descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pImageInfo = &extra->imageInfo; - writes.push_back(descriptorWrite); - writeExtras.push_back(std::move(extra)); - return *this; -} - WriteDescriptors& WriteDescriptors::AddStorageImage(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VkImageLayout imageLayout) { VkDescriptorImageInfo imageInfo = {}; @@ -1546,10 +1378,15 @@ WriteDescriptors& WriteDescriptors::AddStorageImage(VulkanDescriptorSet* descrip } WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout) +{ + return AddCombinedImageSampler(descriptorSet, binding, 0, view, sampler, imageLayout); +} + +WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, int arrayIndex, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout) { VkDescriptorImageInfo imageInfo = {}; imageInfo.imageView = view->view; - imageInfo.sampler = sampler ? sampler->sampler : nullptr; + imageInfo.sampler = sampler->sampler; imageInfo.imageLayout = imageLayout; auto extra = std::make_unique(); @@ -1559,7 +1396,7 @@ WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.dstSet = descriptorSet->set; descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; + descriptorWrite.dstArrayElement = arrayIndex; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrite.descriptorCount = 1; descriptorWrite.pImageInfo = &extra->imageInfo; @@ -1591,5 +1428,6 @@ WriteDescriptors& WriteDescriptors::AddAccelerationStructure(VulkanDescriptorSet void WriteDescriptors::Execute(VulkanDevice* device) { - vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr); + if (!writes.empty()) + vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr); } diff --git a/src/lightmap/vulkanbuilders.h b/src/lightmap/vulkanbuilders.h index aa6dee1..e607ece 100644 --- a/src/lightmap/vulkanbuilders.h +++ b/src/lightmap/vulkanbuilders.h @@ -1,7 +1,6 @@ #pragma once #include "vulkanobjects.h" -#include "framework/zstring.h" #include class ImageBuilder @@ -55,6 +54,7 @@ public: SamplerBuilder& MagFilter(VkFilter magFilter); SamplerBuilder& MipmapMode(VkSamplerMipmapMode mode); SamplerBuilder& Anisotropy(float maxAnisotropy); + SamplerBuilder& MipLodBias(float bias); SamplerBuilder& MaxLod(float value); SamplerBuilder& DebugName(const char* name) { debugName = name; return *this; } @@ -88,20 +88,17 @@ class ShaderBuilder public: ShaderBuilder(); - ShaderBuilder& VertexShader(const FString &code); - ShaderBuilder& FragmentShader(const FString &code); - ShaderBuilder& RayGenShader(const FString& code); - ShaderBuilder& IntersectShader(const FString& code); - ShaderBuilder& AnyHitShader(const FString& code); - ShaderBuilder& ClosestHitShader(const FString& code); - ShaderBuilder& MissShader(const FString& code); - ShaderBuilder& CallableShader(const FString& code); + static void Init(); + static void Deinit(); + + ShaderBuilder& VertexShader(const std::string &code); + ShaderBuilder& FragmentShader(const std::string&code); ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(const char *shadername, VulkanDevice *device); private: - FString code; + std::string code; int stage = 0; const char* debugName = nullptr; }; @@ -123,29 +120,6 @@ private: const char* debugName = nullptr; }; -class RayTracingPipelineBuilder -{ -public: - RayTracingPipelineBuilder(); - - RayTracingPipelineBuilder& Layout(VulkanPipelineLayout* layout); - RayTracingPipelineBuilder& MaxPipelineRayRecursionDepth(int depth); - RayTracingPipelineBuilder& AddShader(VkShaderStageFlagBits stage, VulkanShader* shader); - RayTracingPipelineBuilder& AddRayGenGroup(int rayGenShader); - RayTracingPipelineBuilder& AddMissGroup(int missShader); - RayTracingPipelineBuilder& AddTrianglesHitGroup(int closestHitShader, int anyHitShader = VK_SHADER_UNUSED_KHR); - RayTracingPipelineBuilder& AddProceduralHitGroup(int intersectionShader, int closestHitShader, int anyHitShader); - RayTracingPipelineBuilder& DebugName(const char* name) { debugName = name; return *this; } - - std::unique_ptr Create(VulkanDevice* device); - -private: - VkRayTracingPipelineCreateInfoKHR pipelineInfo = {}; - std::vector stages; - std::vector groups; - const char* debugName = nullptr; -}; - class ComputePipelineBuilder { public: @@ -168,14 +142,17 @@ class DescriptorSetLayoutBuilder public: DescriptorSetLayoutBuilder(); - DescriptorSetLayoutBuilder& AddBinding(int binding, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags); + DescriptorSetLayoutBuilder& Flags(VkDescriptorSetLayoutCreateFlags flags); + DescriptorSetLayoutBuilder& AddBinding(int binding, VkDescriptorType type, int arrayCount, VkShaderStageFlags stageFlags, VkDescriptorBindingFlags flags = 0); DescriptorSetLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; } std::unique_ptr Create(VulkanDevice *device); private: - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - TArray bindings; + VkDescriptorSetLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT }; + std::vector bindings; + std::vector bindingFlags; const char* debugName = nullptr; }; @@ -184,6 +161,7 @@ class DescriptorPoolBuilder public: DescriptorPoolBuilder(); + DescriptorPoolBuilder& Flags(VkDescriptorPoolCreateFlags flags); DescriptorPoolBuilder& MaxSets(int value); DescriptorPoolBuilder& AddPoolSize(VkDescriptorType type, int count); DescriptorPoolBuilder& DebugName(const char* name) { debugName = name; return *this; } @@ -388,9 +366,9 @@ class WriteDescriptors public: WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer); WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range); - WriteDescriptors& AddSampledImage(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VkImageLayout imageLayout); WriteDescriptors& AddStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout); WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout); + WriteDescriptors& AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, int arrayIndex, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout); WriteDescriptors& AddAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct); void Execute(VulkanDevice *device); diff --git a/src/lightmap/vulkancompatibledevice.cpp b/src/lightmap/vulkancompatibledevice.cpp new file mode 100644 index 0000000..e05188a --- /dev/null +++ b/src/lightmap/vulkancompatibledevice.cpp @@ -0,0 +1,145 @@ + +#include "vulkancompatibledevice.h" +#include "vulkansurface.h" + +std::vector VulkanCompatibleDevice::FindDevices(const std::shared_ptr& instance, const std::shared_ptr& surface) +{ + std::vector RequiredDeviceExtensions = + { + VK_KHR_SWAPCHAIN_EXTENSION_NAME + }; + + std::vector OptionalDeviceExtensions = + { + VK_EXT_HDR_METADATA_EXTENSION_NAME, + VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, + VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, + VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, + VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, + VK_KHR_RAY_QUERY_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, +#if defined(VK_USE_PLATFORM_WIN32_KHR) + VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME +#endif + }; + + std::vector supportedDevices; + + for (size_t idx = 0; idx < instance->PhysicalDevices.size(); idx++) + { + const auto& info = instance->PhysicalDevices[idx]; + + // Check if all required extensions are there + std::set requiredExtensionSearch(RequiredDeviceExtensions.begin(), RequiredDeviceExtensions.end()); + for (const auto& ext : info.Extensions) + requiredExtensionSearch.erase(ext.extensionName); + if (!requiredExtensionSearch.empty()) + continue; + + // Check if all required features are there + if (info.Features.Features.samplerAnisotropy != VK_TRUE || + info.Features.Features.fragmentStoresAndAtomics != VK_TRUE) + continue; + + VulkanCompatibleDevice dev; + dev.Device = &instance->PhysicalDevices[idx]; + dev.EnabledDeviceExtensions = RequiredDeviceExtensions; + + // Enable optional extensions we are interested in, if they are available on this device + for (const auto& ext : dev.Device->Extensions) + { + for (const auto& opt : OptionalDeviceExtensions) + { + if (ext.extensionName == opt) + { + dev.EnabledDeviceExtensions.push_back(opt); + } + } + } + + // Enable optional features we are interested in, if they are available on this device + auto& enabledFeatures = dev.EnabledFeatures; + auto& deviceFeatures = dev.Device->Features; + enabledFeatures.Features.samplerAnisotropy = deviceFeatures.Features.samplerAnisotropy; + enabledFeatures.Features.fragmentStoresAndAtomics = deviceFeatures.Features.fragmentStoresAndAtomics; + enabledFeatures.Features.depthClamp = deviceFeatures.Features.depthClamp; + enabledFeatures.Features.shaderClipDistance = deviceFeatures.Features.shaderClipDistance; + enabledFeatures.BufferDeviceAddress.bufferDeviceAddress = deviceFeatures.BufferDeviceAddress.bufferDeviceAddress; + enabledFeatures.AccelerationStructure.accelerationStructure = deviceFeatures.AccelerationStructure.accelerationStructure; + enabledFeatures.RayQuery.rayQuery = deviceFeatures.RayQuery.rayQuery; + enabledFeatures.DescriptorIndexing.runtimeDescriptorArray = deviceFeatures.DescriptorIndexing.runtimeDescriptorArray; + enabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound = deviceFeatures.DescriptorIndexing.descriptorBindingPartiallyBound; + enabledFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind = deviceFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind; + enabledFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount = deviceFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount; + + // Figure out which queue can present + if (surface) + { + for (int i = 0; i < (int)info.QueueFamilies.size(); i++) + { + VkBool32 presentSupport = false; + VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.Device, i, surface->Surface, &presentSupport); + if (result == VK_SUCCESS && info.QueueFamilies[i].queueCount > 0 && presentSupport) + { + dev.PresentFamily = i; + break; + } + } + } + + // The vulkan spec states that graphics and compute queues can always do transfer. + // Furthermore the spec states that graphics queues always can do compute. + // Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer. + // + // In short: pick the first graphics queue family for everything. + for (int i = 0; i < (int)info.QueueFamilies.size(); i++) + { + const auto& queueFamily = info.QueueFamilies[i]; + if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) + { + dev.GraphicsFamily = i; + dev.GraphicsTimeQueries = queueFamily.timestampValidBits != 0; + break; + } + } + + // Only use device if we found the required graphics and present queues + if (dev.GraphicsFamily != -1 && (!surface || dev.PresentFamily != -1)) + { + supportedDevices.push_back(dev); + } + } + + // The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other + std::stable_sort(supportedDevices.begin(), supportedDevices.end(), [&](const auto& a, const auto b) { + + // Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0 + static const int typeSort[] = { 4, 1, 0, 2, 3 }; + int sortA = a.Device->Properties.deviceType < 5 ? typeSort[a.Device->Properties.deviceType] : (int)a.Device->Properties.deviceType; + int sortB = b.Device->Properties.deviceType < 5 ? typeSort[b.Device->Properties.deviceType] : (int)b.Device->Properties.deviceType; + if (sortA != sortB) + return sortA < sortB; + + // Then sort by the device's unique ID so that vk_device uses a consistent order + int sortUUID = memcmp(a.Device->Properties.pipelineCacheUUID, b.Device->Properties.pipelineCacheUUID, VK_UUID_SIZE); + return sortUUID < 0; + }); + + return supportedDevices; +} + +VulkanCompatibleDevice VulkanCompatibleDevice::SelectDevice(const std::shared_ptr& instance, const std::shared_ptr& surface, int vk_device) +{ + if (instance->PhysicalDevices.empty()) + VulkanError("No Vulkan devices found. The graphics card may have no vulkan support or the driver may be too old."); + + std::vector supportedDevices = FindDevices(instance, surface); + if (supportedDevices.empty()) + VulkanError("No Vulkan device found supports the minimum requirements of this application"); + + size_t selected = vk_device; + if (selected >= supportedDevices.size()) + selected = 0; + return supportedDevices[selected]; +} diff --git a/src/lightmap/vulkancompatibledevice.h b/src/lightmap/vulkancompatibledevice.h new file mode 100644 index 0000000..e070a81 --- /dev/null +++ b/src/lightmap/vulkancompatibledevice.h @@ -0,0 +1,22 @@ +#pragma once + +#include "VulkanInstance.h" + +class VulkanSurface; + +class VulkanCompatibleDevice +{ +public: + VulkanPhysicalDevice* Device = nullptr; + + int GraphicsFamily = -1; + int PresentFamily = -1; + + bool GraphicsTimeQueries = false; + + std::vector EnabledDeviceExtensions; + VulkanDeviceFeatures EnabledFeatures; + + static std::vector FindDevices(const std::shared_ptr& instance, const std::shared_ptr& surface); + static VulkanCompatibleDevice SelectDevice(const std::shared_ptr& instance, const std::shared_ptr& surface, int vk_device); +}; diff --git a/src/lightmap/vulkandevice.cpp b/src/lightmap/vulkandevice.cpp index 904ba2f..81085d1 100644 --- a/src/lightmap/vulkandevice.cpp +++ b/src/lightmap/vulkandevice.cpp @@ -1,194 +1,69 @@ #include "vulkandevice.h" #include "vulkanobjects.h" -#include "stacktrace.h" +#include "vulkancompatibledevice.h" #include #include #include -#include -VulkanDevice::VulkanDevice(int vk_device, bool vk_debug) : vk_device(vk_device), vk_debug(vk_debug) +VulkanDevice::VulkanDevice(std::shared_ptr instance, std::shared_ptr surface, const VulkanCompatibleDevice& selectedDevice) : Instance(instance), Surface(surface) { - #ifdef WIN32 - if (HMODULE mod = GetModuleHandle(TEXT("renderdoc.dll"))) - { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_4_2, (void**)&renderdoc); - if (ret != 1) - renderdoc = nullptr; - } - #endif + PhysicalDevice = *selectedDevice.Device; + EnabledDeviceExtensions = selectedDevice.EnabledDeviceExtensions; + EnabledFeatures = selectedDevice.EnabledFeatures; + + GraphicsFamily = selectedDevice.GraphicsFamily; + PresentFamily = selectedDevice.PresentFamily; + GraphicsTimeQueries = selectedDevice.GraphicsTimeQueries; try { - ShInitialize(); - initVolk(); - createInstance(); - selectPhysicalDevice(); - selectFeatures(); - createDevice(); - createAllocator(); + CreateDevice(); + CreateAllocator(); } catch (...) { - releaseResources(); + ReleaseResources(); throw; } } VulkanDevice::~VulkanDevice() { - releaseResources(); + ReleaseResources(); } -void VulkanDevice::selectFeatures() +bool VulkanDevice::SupportsDeviceExtension(const char* ext) const { - enabledDeviceFeatures.samplerAnisotropy = physicalDevice.features.samplerAnisotropy; - enabledDeviceFeatures.fragmentStoresAndAtomics = physicalDevice.features.fragmentStoresAndAtomics; - enabledDeviceFeatures.depthClamp = physicalDevice.features.depthClamp; - enabledDeviceFeatures.shaderClipDistance = physicalDevice.features.shaderClipDistance; + return std::find(EnabledDeviceExtensions.begin(), EnabledDeviceExtensions.end(), ext) != EnabledDeviceExtensions.end(); } -bool VulkanDevice::checkRequiredFeatures(const VkPhysicalDeviceFeatures &f) -{ - return - f.samplerAnisotropy == VK_TRUE && - f.fragmentStoresAndAtomics == VK_TRUE && - f.depthClamp == VK_TRUE; -} - -void VulkanDevice::selectPhysicalDevice() -{ - availableDevices = getPhysicalDevices(instance); - if (availableDevices.empty()) - throw std::runtime_error("No Vulkan devices found. Either the graphics card has no vulkan support or the driver is too old."); - - // createSurface(); - - supportedDevices.clear(); - - for (size_t idx = 0; idx < availableDevices.size(); idx++) - { - const auto &info = availableDevices[idx]; - - if (!checkRequiredFeatures(info.features)) - continue; - - std::set requiredExtensionSearch(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end()); - for (const auto &ext : info.extensions) - requiredExtensionSearch.erase(ext.extensionName); - if (!requiredExtensionSearch.empty()) - continue; - - VulkanCompatibleDevice dev; - dev.device = &availableDevices[idx]; - - bool window = false; // static_cast(createSurfaceWindow); - - // Figure out what can present - if (window) - { - for (int i = 0; i < (int)info.queueFamilies.size(); i++) - { - VkBool32 presentSupport = false; - VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(info.device, i, surface, &presentSupport); - if (result == VK_SUCCESS && info.queueFamilies[i].queueCount > 0 && presentSupport) - { - dev.presentFamily = i; - break; - } - } - } - - // The vulkan spec states that graphics and compute queues can always do transfer. - // Furthermore the spec states that graphics queues always can do compute. - // Last, the spec makes it OPTIONAL whether the VK_QUEUE_TRANSFER_BIT is set for such queues, but they MUST support transfer. - // - // In short: pick the first graphics queue family for everything. - for (int i = 0; i < (int)info.queueFamilies.size(); i++) - { - const auto &queueFamily = info.queueFamilies[i]; - if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) - { - dev.graphicsFamily = i; - break; - } - } - - if (dev.graphicsFamily != -1 && (!window || dev.presentFamily != -1)) - { - supportedDevices.push_back(dev); - } - } - - if (supportedDevices.empty()) - throw std::runtime_error("No Vulkan device supports the minimum requirements of this application"); - - // The device order returned by Vulkan can be anything. Prefer discrete > integrated > virtual gpu > cpu > other - std::stable_sort(supportedDevices.begin(), supportedDevices.end(), [&](const auto &a, const auto b) { - - // Sort by GPU type first. This will ensure the "best" device is most likely to map to vk_device 0 - static const int typeSort[] = { 4, 1, 0, 2, 3 }; - int sortA = a.device->properties.deviceType < 5 ? typeSort[a.device->properties.deviceType] : (int)a.device->properties.deviceType; - int sortB = b.device->properties.deviceType < 5 ? typeSort[b.device->properties.deviceType] : (int)b.device->properties.deviceType; - if (sortA != sortB) - return sortA < sortB; - - // Then sort by the device's unique ID so that vk_device uses a consistent order - int sortUUID = memcmp(a.device->properties.pipelineCacheUUID, b.device->properties.pipelineCacheUUID, VK_UUID_SIZE); - return sortUUID < 0; - }); - - size_t selected = vk_device; - if (selected >= supportedDevices.size()) - selected = 0; - - // Enable optional extensions we are interested in, if they are available on this device - for (const auto &ext : supportedDevices[selected].device->extensions) - { - for (const auto &opt : optionalDeviceExtensions) - { - if (strcmp(ext.extensionName, opt) == 0) - { - enabledDeviceExtensions.push_back(opt); - } - } - } - - physicalDevice = *supportedDevices[selected].device; - graphicsFamily = supportedDevices[selected].graphicsFamily; - presentFamily = supportedDevices[selected].presentFamily; -} - -bool VulkanDevice::supportsDeviceExtension(const char *ext) const -{ - return std::find(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), ext) != enabledDeviceExtensions.end(); -} - -void VulkanDevice::createAllocator() +void VulkanDevice::CreateAllocator() { VmaAllocatorCreateInfo allocinfo = {}; - allocinfo.vulkanApiVersion = ApiVersion; - if (supportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && supportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) - allocinfo.flags = VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; - allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; - allocinfo.physicalDevice = physicalDevice.device; + allocinfo.vulkanApiVersion = Instance->ApiVersion; + if (SupportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && SupportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) + allocinfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT; + if (SupportsDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; + allocinfo.physicalDevice = PhysicalDevice.Device; allocinfo.device = device; + allocinfo.instance = Instance->Instance; allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024; - allocinfo.instance = instance; if (vmaCreateAllocator(&allocinfo, &allocator) != VK_SUCCESS) - throw std::runtime_error("Unable to create allocator"); + VulkanError("Unable to create allocator"); } -void VulkanDevice::createDevice() +void VulkanDevice::CreateDevice() { float queuePriority = 1.0f; std::vector queueCreateInfos; std::set neededFamilies; - neededFamilies.insert(graphicsFamily); - if (presentFamily != -1) - neededFamilies.insert(presentFamily); + if (GraphicsFamily != -1) + neededFamilies.insert(GraphicsFamily); + if (PresentFamily != -1) + neededFamilies.insert(PresentFamily); for (int index : neededFamilies) { @@ -200,359 +75,85 @@ void VulkanDevice::createDevice() queueCreateInfos.push_back(queueCreateInfo); } - VkPhysicalDeviceRayQueryFeaturesKHR rayqueryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR }; - rayqueryFeatures.rayQuery = true; + std::vector extensionNames; + extensionNames.reserve(EnabledDeviceExtensions.size()); + for (const auto& name : EnabledDeviceExtensions) + extensionNames.push_back(name.c_str()); - VkPhysicalDeviceRayTracingPipelineFeaturesKHR raytracingFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR }; - raytracingFeatures.rayTracingPipeline = true; - raytracingFeatures.rayTraversalPrimitiveCulling = true; - raytracingFeatures.pNext = &rayqueryFeatures; - - VkPhysicalDeviceAccelerationStructureFeaturesKHR deviceAccelFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR }; - deviceAccelFeatures.accelerationStructure = true; - deviceAccelFeatures.pNext = &raytracingFeatures; - - VkPhysicalDeviceBufferDeviceAddressFeatures deviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES }; - deviceAddressFeatures.bufferDeviceAddress = true; - deviceAddressFeatures.pNext = &deviceAccelFeatures; - - VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; - deviceFeatures2.features = enabledDeviceFeatures; - deviceFeatures2.pNext = &deviceAddressFeatures; - - VkDeviceCreateInfo deviceCreateInfo = {}; - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.pNext = &deviceFeatures2; + VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); - //deviceCreateInfo.pEnabledFeatures = &enabledDeviceFeatures; - deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size(); - deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data(); + deviceCreateInfo.enabledExtensionCount = (uint32_t)extensionNames.size(); + deviceCreateInfo.ppEnabledExtensionNames = extensionNames.data(); deviceCreateInfo.enabledLayerCount = 0; - VkResult result = vkCreateDevice(physicalDevice.device, &deviceCreateInfo, nullptr, &device); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan device"); + VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + deviceFeatures2.features = EnabledFeatures.Features; + + void** next = const_cast(&deviceCreateInfo.pNext); + if (SupportsDeviceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + { + *next = &deviceFeatures2; + next = &deviceFeatures2.pNext; + } + else // vulkan 1.0 specified features in a different way + { + deviceCreateInfo.pEnabledFeatures = &deviceFeatures2.features; + } + + if (SupportsDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + { + *next = &EnabledFeatures.BufferDeviceAddress; + next = &EnabledFeatures.BufferDeviceAddress.pNext; + } + if (SupportsDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) + { + *next = &EnabledFeatures.AccelerationStructure; + next = &EnabledFeatures.AccelerationStructure.pNext; + } + if (SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + { + *next = &EnabledFeatures.RayQuery; + next = &EnabledFeatures.RayQuery.pNext; + } + if (SupportsDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) + { + *next = &EnabledFeatures.DescriptorIndexing; + next = &EnabledFeatures.DescriptorIndexing.pNext; + } + + VkResult result = vkCreateDevice(PhysicalDevice.Device, &deviceCreateInfo, nullptr, &device); + CheckVulkanError(result, "Could not create vulkan device"); volkLoadDevice(device); - vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue); - if (presentFamily != -1) - vkGetDeviceQueue(device, presentFamily, 0, &presentQueue); + if (GraphicsFamily != -1) + vkGetDeviceQueue(device, GraphicsFamily, 0, &GraphicsQueue); + if (PresentFamily != -1) + vkGetDeviceQueue(device, PresentFamily, 0, &PresentQueue); } -/* -#ifdef WIN32 -void VulkanDevice::createSurface() -{ - VkWin32SurfaceCreateInfoKHR windowCreateInfo = {}; - windowCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - windowCreateInfo.hwnd = window; - windowCreateInfo.hinstance = GetModuleHandle(nullptr); - - VkResult result = vkCreateWin32SurfaceKHR(instance, &windowCreateInfo, nullptr, &surface); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan surface"); -} -#else -void VulkanDevice::createSurface() -{ - for (const auto &info : availableDevices) - { - for (uint32_t i = 0; i < (uint32_t)info.queueFamilies.size(); i++) - { - const auto &queueFamily = info.queueFamilies[i]; - if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)) - { - uint32_t graphicsFamily = i; - auto handles = createSurfaceWindow(info.device, graphicsFamily); - - VkXlibSurfaceCreateInfoKHR windowCreateInfo = {}; - windowCreateInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - windowCreateInfo.dpy = handles.first; - windowCreateInfo.window = handles.second; - - VkResult result = vkCreateXlibSurfaceKHR(instance, &windowCreateInfo, nullptr, &surface); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan surface"); - - return; - } - } - } - throw std::runtime_error("No vulkan device supports graphics!"); -} -#endif -*/ - -void VulkanDevice::createInstance() -{ - availableLayers = getAvailableLayers(); - extensions = getExtensions(); - enabledExtensions = getPlatformExtensions(); - - std::string debugLayer = "VK_LAYER_KHRONOS_validation"; - bool wantDebugLayer = vk_debug; - bool debugLayerFound = false; - if (wantDebugLayer) - { - for (const VkLayerProperties& layer : availableLayers) - { - if (layer.layerName == debugLayer) - { - enabledValidationLayers.push_back(layer.layerName); - enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - debugLayerFound = true; - break; - } - } - } - - // Enable optional instance extensions we are interested in - for (const auto &ext : extensions) - { - for (const auto &opt : optionalExtensions) - { - if (strcmp(ext.extensionName, opt) == 0) - { - enabledExtensions.push_back(opt); - } - } - } - - VkApplicationInfo appInfo = {}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "ZDRay"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "ZDRay"; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = ApiVersion; - - VkInstanceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - createInfo.enabledExtensionCount = (uint32_t)enabledExtensions.size(); - createInfo.enabledLayerCount = (uint32_t)enabledValidationLayers.size(); - createInfo.ppEnabledLayerNames = enabledValidationLayers.data(); - createInfo.ppEnabledExtensionNames = enabledExtensions.data(); - - VkResult result = vkCreateInstance(&createInfo, nullptr, &instance); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create vulkan instance"); - - volkLoadInstance(instance); - - if (debugLayerFound) - { - VkDebugUtilsMessengerCreateInfoEXT createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - createInfo.messageSeverity = - //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - //VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - createInfo.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; - createInfo.pfnUserCallback = debugCallback; - createInfo.pUserData = this; - result = vkCreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger); - if (result != VK_SUCCESS) - throw std::runtime_error("vkCreateDebugUtilsMessengerEXT failed"); - - debugLayerActive = true; - } -} - -VkBool32 VulkanDevice::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) -{ - VulkanDevice *device = (VulkanDevice*)userData; - - static std::mutex mtx; - static std::set seenMessages; - static int totalMessages; - - std::unique_lock lock(mtx); - - std::string msg = callbackData->pMessage; - - bool found = seenMessages.find(msg) != seenMessages.end(); - if (!found) - { - if (totalMessages < 20) - { - totalMessages++; - seenMessages.insert(msg); - - const char *typestr; - if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) - { - typestr = "vulkan error"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) - { - typestr = "vulkan warning"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) - { - typestr = "vulkan info"; - } - else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) - { - typestr = "vulkan verbose"; - } - else - { - typestr = "vulkan"; - } - - printf("\n[%s] %s\n", typestr, msg.c_str()); - - std::string callstack = CaptureStackTraceText(0); - if (!callstack.empty()) - printf("%s\n", callstack.c_str()); - } - } - - return VK_FALSE; -} - -std::vector VulkanDevice::getAvailableLayers() -{ - uint32_t layerCount; - VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); - - std::vector availableLayers(layerCount); - result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - return availableLayers; -} - -std::vector VulkanDevice::getExtensions() -{ - uint32_t extensionCount = 0; - VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); - - std::vector extensions(extensionCount); - result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); - return extensions; -} - -std::vector VulkanDevice::getPhysicalDevices(VkInstance instance) -{ - uint32_t deviceCount = 0; - VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - if (result == VK_ERROR_INITIALIZATION_FAILED) // Some drivers return this when a card does not support vulkan - return {}; - if (result != VK_SUCCESS) - throw std::runtime_error("vkEnumeratePhysicalDevices failed"); - if (deviceCount == 0) - return {}; - - std::vector devices(deviceCount); - result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); - if (result != VK_SUCCESS) - throw std::runtime_error("vkEnumeratePhysicalDevices failed (2)"); - - std::vector devinfo(deviceCount); - for (size_t i = 0; i < devices.size(); i++) - { - auto &dev = devinfo[i]; - dev.device = devices[i]; - - VkPhysicalDeviceProperties2 props = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 }; - VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayprops = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR }; - props.pNext = &rayprops; - vkGetPhysicalDeviceProperties2(dev.device, &props); - dev.properties = props.properties; - dev.rayTracingProperties = rayprops; - dev.rayTracingProperties.pNext = nullptr; - - vkGetPhysicalDeviceMemoryProperties(dev.device, &dev.memoryProperties); - vkGetPhysicalDeviceFeatures(dev.device, &dev.features); - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(dev.device, &queueFamilyCount, nullptr); - dev.queueFamilies.resize(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(dev.device, &queueFamilyCount, dev.queueFamilies.data()); - - uint32_t deviceExtensionCount = 0; - vkEnumerateDeviceExtensionProperties(dev.device, nullptr, &deviceExtensionCount, nullptr); - dev.extensions.resize(deviceExtensionCount); - vkEnumerateDeviceExtensionProperties(dev.device, nullptr, &deviceExtensionCount, dev.extensions.data()); - } - return devinfo; -} - -#ifdef WIN32 -std::vector VulkanDevice::getPlatformExtensions() -{ - return - { - VK_KHR_SURFACE_EXTENSION_NAME, - VK_KHR_WIN32_SURFACE_EXTENSION_NAME - }; -} -#else -std::vector VulkanDevice::getPlatformExtensions() -{ - return - { - VK_KHR_SURFACE_EXTENSION_NAME/*, - VK_KHR_XLIB_SURFACE_EXTENSION_NAME*/ - }; -} -#endif - -void VulkanDevice::initVolk() -{ - static bool volkInited = false; - if (!volkInited && volkInitialize() != VK_SUCCESS) - { - throw std::runtime_error("Unable to find Vulkan"); - } - volkInited = true; - auto iver = volkGetInstanceVersion(); - if (iver == 0) - { - throw std::runtime_error("Vulkan not supported"); - } -} - -void VulkanDevice::releaseResources() +void VulkanDevice::ReleaseResources() { if (device) vkDeviceWaitIdle(device); if (allocator) vmaDestroyAllocator(allocator); - allocator = VK_NULL_HANDLE; if (device) vkDestroyDevice(device, nullptr); - device = VK_NULL_HANDLE; - - if (surface) - vkDestroySurfaceKHR(instance, surface, nullptr); - surface = VK_NULL_HANDLE; - - if (debugMessenger) - vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); - - if (instance) - vkDestroyInstance(instance, nullptr); - instance = VK_NULL_HANDLE; - - ShFinalize(); + device = nullptr; } -uint32_t VulkanDevice::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) +void VulkanDevice::SetObjectName(const char* name, uint64_t handle, VkObjectType type) { - for (uint32_t i = 0; i < physicalDevice.memoryProperties.memoryTypeCount; i++) - { - if ((typeFilter & (1 << i)) && (physicalDevice.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) - return i; - } + if (!DebugLayerActive) return; - throw std::runtime_error("failed to find suitable memory type!"); + VkDebugUtilsObjectNameInfoEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + info.objectHandle = handle; + info.objectType = type; + info.pObjectName = name; + vkSetDebugUtilsObjectNameEXT(device, &info); } diff --git a/src/lightmap/vulkandevice.h b/src/lightmap/vulkandevice.h index 2cba352..918bc28 100644 --- a/src/lightmap/vulkandevice.h +++ b/src/lightmap/vulkandevice.h @@ -1,136 +1,52 @@ #pragma once +#include "vulkaninstance.h" + #include - -#ifdef WIN32 -#define VK_USE_PLATFORM_WIN32_KHR -#endif - -#include "volk/volk.h" -#include "vk_mem_alloc/vk_mem_alloc.h" -#include "renderdoc_app.h" - -#ifdef WIN32 -#undef min -#undef max -#endif - -#include "ShaderCompiler/glslang/Public/ShaderLang.h" -#include "ShaderCompiler/spirv/GlslangToSpv.h" +#include +#include +#include +#include class VulkanSwapChain; class VulkanSemaphore; class VulkanFence; - -class VulkanPhysicalDevice -{ -public: - VkPhysicalDevice device = VK_NULL_HANDLE; - - std::vector extensions; - std::vector queueFamilies; - VkPhysicalDeviceProperties properties = {}; - VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingProperties = {}; - VkPhysicalDeviceFeatures features = {}; - VkPhysicalDeviceMemoryProperties memoryProperties = {}; -}; - -class VulkanCompatibleDevice -{ -public: - VulkanPhysicalDevice *device = nullptr; - int graphicsFamily = -1; - int presentFamily = -1; -}; +class VulkanPhysicalDevice; +class VulkanSurface; +class VulkanCompatibleDevice; class VulkanDevice { public: - VulkanDevice(int vk_device = 0, bool vk_debug = false); + VulkanDevice(std::shared_ptr instance, std::shared_ptr surface, const VulkanCompatibleDevice& selectedDevice); ~VulkanDevice(); - void setDebugObjectName(const char *name, uint64_t handle, VkObjectType type) - { - if (!debugLayerActive) return; + std::vector EnabledDeviceExtensions; + VulkanDeviceFeatures EnabledFeatures; - VkDebugUtilsObjectNameInfoEXT info = {}; - info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - info.objectHandle = handle; - info.objectType = type; - info.pObjectName = name; - vkSetDebugUtilsObjectNameEXT(device, &info); - } + VulkanPhysicalDevice PhysicalDevice; - uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + std::shared_ptr Instance; + std::shared_ptr Surface; - // Instance setup - std::vector availableLayers; - std::vector extensions; - std::vector enabledExtensions; - std::vector optionalExtensions = { }; - std::vector enabledValidationLayers; - - // Device setup - VkPhysicalDeviceFeatures enabledDeviceFeatures = {}; - std::vector enabledDeviceExtensions = { - //VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_KHR_RAY_QUERY_EXTENSION_NAME, - VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, - VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, - VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME - }; - std::vector optionalDeviceExtensions = { - //VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, - //VK_EXT_HDR_METADATA_EXTENSION_NAME, - VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, - VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME - }; - VulkanPhysicalDevice physicalDevice; - bool debugLayerActive = false; - - VkInstance instance = VK_NULL_HANDLE; - VkSurfaceKHR surface = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE; VmaAllocator allocator = VK_NULL_HANDLE; - VkQueue graphicsQueue = VK_NULL_HANDLE; - VkQueue presentQueue = VK_NULL_HANDLE; + VkQueue GraphicsQueue = VK_NULL_HANDLE; + VkQueue PresentQueue = VK_NULL_HANDLE; - int graphicsFamily = -1; - int presentFamily = -1; + int GraphicsFamily = -1; + int PresentFamily = -1; + bool GraphicsTimeQueries = false; - // Physical device info - std::vector availableDevices; - std::vector supportedDevices; + bool SupportsDeviceExtension(const char* ext) const; - uint32_t ApiVersion = VK_API_VERSION_1_2; - - RENDERDOC_API_1_4_2* renderdoc = nullptr; - - static void initVolk(); + void SetObjectName(const char* name, uint64_t handle, VkObjectType type); private: - int vk_device; - bool vk_debug; + bool DebugLayerActive = false; - void createInstance(); - //void createSurface(); - void selectPhysicalDevice(); - void selectFeatures(); - void createDevice(); - void createAllocator(); - void releaseResources(); - - bool supportsDeviceExtension(const char *ext) const; - - static bool checkRequiredFeatures(const VkPhysicalDeviceFeatures &f); - - VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; - - static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); - - static std::vector getAvailableLayers(); - static std::vector getExtensions(); - static std::vector getPlatformExtensions(); - static std::vector getPhysicalDevices(VkInstance instance); + void CreateDevice(); + void CreateAllocator(); + void ReleaseResources(); }; diff --git a/src/lightmap/vulkaninstance.cpp b/src/lightmap/vulkaninstance.cpp new file mode 100644 index 0000000..2db1f4a --- /dev/null +++ b/src/lightmap/vulkaninstance.cpp @@ -0,0 +1,378 @@ + +#include "vulkaninstance.h" +#include "vulkanbuilders.h" +#include + +VulkanInstance::VulkanInstance(bool wantDebugLayer) : WantDebugLayer(wantDebugLayer) +{ + try + { + ShaderBuilder::Init(); + InitVolk(); + CreateInstance(); + } + catch (...) + { + ReleaseResources(); + throw; + } +} + +VulkanInstance::~VulkanInstance() +{ + ReleaseResources(); +} + +void VulkanInstance::ReleaseResources() +{ + if (debugMessenger) + vkDestroyDebugUtilsMessengerEXT(Instance, debugMessenger, nullptr); + debugMessenger = VK_NULL_HANDLE; + + if (Instance) + vkDestroyInstance(Instance, nullptr); + Instance = nullptr; +} + +void VulkanInstance::InitVolk() +{ + if (volkInitialize() != VK_SUCCESS) + { + VulkanError("Unable to find Vulkan"); + } + auto iver = volkGetInstanceVersion(); + if (iver == 0) + { + VulkanError("Vulkan not supported"); + } +} + +void VulkanInstance::CreateInstance() +{ + AvailableLayers = GetAvailableLayers(); + AvailableExtensions = GetExtensions(); + EnabledExtensions = RequiredExtensions; + + std::string debugLayer = "VK_LAYER_KHRONOS_validation"; + bool debugLayerFound = false; + if (WantDebugLayer) + { + for (const VkLayerProperties& layer : AvailableLayers) + { + if (layer.layerName == debugLayer) + { + EnabledValidationLayers.push_back(layer.layerName); + EnabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + debugLayerFound = true; + break; + } + } + } + + // Enable optional instance extensions we are interested in + for (const auto& ext : AvailableExtensions) + { + for (const auto& opt : OptionalExtensions) + { + if (strcmp(ext.extensionName, opt) == 0) + { + EnabledExtensions.push_back(opt); + } + } + } + + // Try get the highest vulkan version we can get + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + for (uint32_t apiVersion : ApiVersionsToTry) + { + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "VulkanDrv"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "VulkanDrv"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = apiVersion; + + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.enabledExtensionCount = (uint32_t)EnabledExtensions.size(); + createInfo.enabledLayerCount = (uint32_t)EnabledValidationLayers.size(); + createInfo.ppEnabledLayerNames = EnabledValidationLayers.data(); + createInfo.ppEnabledExtensionNames = EnabledExtensions.data(); + + result = vkCreateInstance(&createInfo, nullptr, &Instance); + if (result >= VK_SUCCESS) + { + ApiVersion = apiVersion; + break; + } + } + CheckVulkanError(result, "Could not create vulkan instance"); + + volkLoadInstance(Instance); + + if (debugLayerFound) + { + VkDebugUtilsMessengerCreateInfoEXT dbgCreateInfo = {}; + dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + dbgCreateInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + dbgCreateInfo.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; + dbgCreateInfo.pfnUserCallback = DebugCallback; + dbgCreateInfo.pUserData = this; + result = vkCreateDebugUtilsMessengerEXT(Instance, &dbgCreateInfo, nullptr, &debugMessenger); + CheckVulkanError(result, "vkCreateDebugUtilsMessengerEXT failed"); + + DebugLayerActive = true; + } + + PhysicalDevices = GetPhysicalDevices(Instance, ApiVersion); +} + +std::vector VulkanInstance::GetPhysicalDevices(VkInstance instance, uint32_t apiVersion) +{ + uint32_t deviceCount = 0; + VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + if (result == VK_ERROR_INITIALIZATION_FAILED) // Some drivers return this when a card does not support vulkan + return {}; + CheckVulkanError(result, "vkEnumeratePhysicalDevices failed"); + if (deviceCount == 0) + return {}; + + std::vector devices(deviceCount); + result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + CheckVulkanError(result, "vkEnumeratePhysicalDevices failed (2)"); + + std::vector devinfo(deviceCount); + for (size_t i = 0; i < devices.size(); i++) + { + auto& dev = devinfo[i]; + dev.Device = devices[i]; + + vkGetPhysicalDeviceMemoryProperties(dev.Device, &dev.MemoryProperties); + vkGetPhysicalDeviceProperties(dev.Device, &dev.Properties); + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, nullptr); + dev.QueueFamilies.resize(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(dev.Device, &queueFamilyCount, dev.QueueFamilies.data()); + + uint32_t deviceExtensionCount = 0; + vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, nullptr); + dev.Extensions.resize(deviceExtensionCount); + vkEnumerateDeviceExtensionProperties(dev.Device, nullptr, &deviceExtensionCount, dev.Extensions.data()); + + auto checkForExtension = [&](const char* name) + { + for (const auto& ext : dev.Extensions) + { + if (strcmp(ext.extensionName, name) == 0) + return true; + } + return false; + }; + + if (apiVersion != VK_API_VERSION_1_0) + { + VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; + + void** next = const_cast(&deviceFeatures2.pNext); + if (checkForExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + { + *next = &dev.Features.BufferDeviceAddress; + next = &dev.Features.BufferDeviceAddress.pNext; + } + if (checkForExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME)) + { + *next = &dev.Features.AccelerationStructure; + next = &dev.Features.AccelerationStructure.pNext; + } + if (checkForExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + { + *next = &dev.Features.RayQuery; + next = &dev.Features.RayQuery.pNext; + } + if (checkForExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) + { + *next = &dev.Features.DescriptorIndexing; + next = &dev.Features.DescriptorIndexing.pNext; + } + + vkGetPhysicalDeviceFeatures2(dev.Device, &deviceFeatures2); + dev.Features.Features = deviceFeatures2.features; + dev.Features.BufferDeviceAddress.pNext = nullptr; + dev.Features.AccelerationStructure.pNext = nullptr; + dev.Features.RayQuery.pNext = nullptr; + dev.Features.DescriptorIndexing.pNext = nullptr; + } + else + { + vkGetPhysicalDeviceFeatures(dev.Device, &dev.Features.Features); + } + } + return devinfo; +} + +std::vector VulkanInstance::GetAvailableLayers() +{ + uint32_t layerCount; + VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + + std::vector availableLayers(layerCount); + result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); + return availableLayers; +} + +std::vector VulkanInstance::GetExtensions() +{ + uint32_t extensionCount = 0; + VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); + + std::vector extensions(extensionCount); + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); + return extensions; +} + +VkBool32 VulkanInstance::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) +{ + VulkanInstance* instance = (VulkanInstance*)userData; + + static std::mutex mtx; + static std::set seenMessages; + static int totalMessages; + + std::unique_lock lock(mtx); + + std::string msg = callbackData->pMessage; + + // Attempt to parse the string because the default formatting is totally unreadable and half of what it writes is totally useless! + auto parts = SplitString(msg, " | "); + if (parts.size() == 3) + { + msg = parts[2]; + size_t pos = msg.find(" The Vulkan spec states:"); + if (pos != std::string::npos) + msg = msg.substr(0, pos); + + if (callbackData->objectCount > 0) + { + msg += " ("; + for (uint32_t i = 0; i < callbackData->objectCount; i++) + { + if (i > 0) + msg += ", "; + if (callbackData->pObjects[i].pObjectName) + msg += callbackData->pObjects[i].pObjectName; + else + msg += ""; + } + msg += ")"; + } + } + + bool found = seenMessages.find(msg) != seenMessages.end(); + if (!found) + { + if (totalMessages < 20) + { + totalMessages++; + seenMessages.insert(msg); + + const char* typestr; + bool showcallstack = false; + if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + { + typestr = "vulkan error"; + showcallstack = true; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + { + typestr = "vulkan warning"; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) + { + typestr = "vulkan info"; + } + else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) + { + typestr = "vulkan verbose"; + } + else + { + typestr = "vulkan"; + } + + VulkanPrintLog(typestr, msg); + } + } + + return VK_FALSE; +} + +std::vector VulkanInstance::SplitString(const std::string& s, const std::string& seperator) +{ + std::vector output; + std::string::size_type prev_pos = 0, pos = 0; + + while ((pos = s.find(seperator, pos)) != std::string::npos) + { + std::string substring(s.substr(prev_pos, pos - prev_pos)); + + output.push_back(substring); + + pos += seperator.length(); + prev_pos = pos; + } + + output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word + return output; +} + +std::string VkResultToString(VkResult result) +{ + switch (result) + { + case VK_SUCCESS: return "success"; + case VK_NOT_READY: return "not ready"; + case VK_TIMEOUT: return "timeout"; + case VK_EVENT_SET: return "event set"; + case VK_EVENT_RESET: return "event reset"; + case VK_INCOMPLETE: return "incomplete"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "out of host memory"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory"; + case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed"; + case VK_ERROR_DEVICE_LOST: return "device lost"; + case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed"; + case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver"; + case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported"; + case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool"; + case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalid external handle"; + case VK_ERROR_SURFACE_LOST_KHR: return "surface lost"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use"; + case VK_SUBOPTIMAL_KHR: return "suboptimal"; + case VK_ERROR_OUT_OF_DATE_KHR: return "out of date"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed"; + case VK_ERROR_INVALID_SHADER_NV: return "invalid shader"; + case VK_ERROR_FRAGMENTATION_EXT: return "fragmentation"; + case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "full screen exclusive mode lost"; + case VK_THREAD_IDLE_KHR: return "thread idle"; + case VK_THREAD_DONE_KHR: return "thread done"; + case VK_OPERATION_DEFERRED_KHR: return "operation deferred"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required"; + default: break; + } + return "vkResult " + std::to_string((int)result); +} diff --git a/src/lightmap/vulkaninstance.h b/src/lightmap/vulkaninstance.h new file mode 100644 index 0000000..2068984 --- /dev/null +++ b/src/lightmap/vulkaninstance.h @@ -0,0 +1,106 @@ +#pragma once + +#if defined(_WIN32) +#define VK_USE_PLATFORM_WIN32_KHR +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT +#else +#define VK_USE_PLATFORM_XLIB_KHR +#endif + +#include "volk/volk.h" +#include "vk_mem_alloc/vk_mem_alloc.h" +#undef min +#undef max +#include "ShaderCompiler/glslang/Public/ShaderLang.h" +#include "ShaderCompiler/spirv/GlslangToSpv.h" + +#include +#include + +class VulkanDeviceFeatures +{ +public: + VkPhysicalDeviceFeatures Features = {}; + VkPhysicalDeviceBufferDeviceAddressFeatures BufferDeviceAddress = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES }; + VkPhysicalDeviceAccelerationStructureFeaturesKHR AccelerationStructure = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR }; + VkPhysicalDeviceRayQueryFeaturesKHR RayQuery = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR }; + VkPhysicalDeviceDescriptorIndexingFeatures DescriptorIndexing = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT }; +}; + +class VulkanPhysicalDevice +{ +public: + VkPhysicalDevice Device = VK_NULL_HANDLE; + std::vector Extensions; + std::vector QueueFamilies; + VkPhysicalDeviceProperties Properties = {}; + VkPhysicalDeviceMemoryProperties MemoryProperties = {}; + VulkanDeviceFeatures Features; +}; + +class VulkanInstance +{ +public: + VulkanInstance(bool wantDebugLayer); + ~VulkanInstance(); + + std::vector RequiredExtensions = + { + VK_KHR_SURFACE_EXTENSION_NAME, +#if defined(VK_USE_PLATFORM_WIN32_KHR) + VK_KHR_WIN32_SURFACE_EXTENSION_NAME +#elif defined(VK_USE_PLATFORM_MACOS_MVK) + VK_MVK_MACOS_SURFACE_EXTENSION_NAME +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + VK_KHR_XLIB_SURFACE_EXTENSION_NAME +#endif + }; + std::vector OptionalExtensions = + { + VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, + VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME + }; + std::vector ApiVersionsToTry = { VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0 }; + + std::vector AvailableLayers; + std::vector AvailableExtensions; + + std::vector EnabledValidationLayers; + std::vector EnabledExtensions; + + std::vector PhysicalDevices; + + uint32_t ApiVersion = {}; + VkInstance Instance = VK_NULL_HANDLE; + + bool DebugLayerActive = false; + +private: + bool WantDebugLayer = false; + VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + + void CreateInstance(); + void ReleaseResources(); + + static void InitVolk(); + static std::vector GetAvailableLayers(); + static std::vector GetExtensions(); + static std::vector GetPhysicalDevices(VkInstance instance, uint32_t apiVersion); + + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); + static std::vector SplitString(const std::string& s, const std::string& seperator); +}; + +std::string VkResultToString(VkResult result); + +void VulkanPrintLog(const char* typestr, const std::string& msg); +void VulkanError(const char* text); + +inline void CheckVulkanError(VkResult result, const char* text) +{ + if (result >= VK_SUCCESS) return; + VulkanError((text + std::string(": ") + VkResultToString(result)).c_str()); +} diff --git a/src/lightmap/vulkanobjects.h b/src/lightmap/vulkanobjects.h index 9dbe60d..0b447ec 100644 --- a/src/lightmap/vulkanobjects.h +++ b/src/lightmap/vulkanobjects.h @@ -2,9 +2,6 @@ #include "vulkandevice.h" -#include -#include - class VulkanCommandPool; class VulkanDescriptorPool; class VulkanCommandBuffer; @@ -15,7 +12,7 @@ public: VulkanSemaphore(VulkanDevice *device); ~VulkanSemaphore(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)semaphore, VK_OBJECT_TYPE_SEMAPHORE); } VulkanDevice *device = nullptr; VkSemaphore semaphore = VK_NULL_HANDLE; @@ -31,7 +28,7 @@ public: VulkanFence(VulkanDevice *device); ~VulkanFence(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)fence, VK_OBJECT_TYPE_FENCE); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)fence, VK_OBJECT_TYPE_FENCE); } VulkanDevice *device = nullptr; VkFence fence = VK_NULL_HANDLE; @@ -54,7 +51,12 @@ public: return vkGetBufferDeviceAddress(device->device, &info); } - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_BUFFER); } +#endif VulkanDevice *device = nullptr; @@ -76,7 +78,7 @@ public: VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer); ~VulkanFramebuffer(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)framebuffer, VK_OBJECT_TYPE_FRAMEBUFFER); } VulkanDevice *device; VkFramebuffer framebuffer; @@ -92,7 +94,7 @@ public: VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount); ~VulkanImage(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)image, VK_OBJECT_TYPE_IMAGE); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)image, VK_OBJECT_TYPE_IMAGE); } VkImage image = VK_NULL_HANDLE; int width = 0; @@ -117,7 +119,7 @@ public: VulkanImageView(VulkanDevice *device, VkImageView view); ~VulkanImageView(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); } VkImageView view = VK_NULL_HANDLE; @@ -134,7 +136,7 @@ public: VulkanSampler(VulkanDevice *device, VkSampler sampler); ~VulkanSampler(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)sampler, VK_OBJECT_TYPE_SAMPLER); } VkSampler sampler = VK_NULL_HANDLE; @@ -151,7 +153,7 @@ public: VulkanShader(VulkanDevice *device, VkShaderModule module); ~VulkanShader(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)module, VK_OBJECT_TYPE_SHADER_MODULE); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)module, VK_OBJECT_TYPE_SHADER_MODULE); } VkShaderModule module = VK_NULL_HANDLE; @@ -168,7 +170,7 @@ public: VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout); ~VulkanDescriptorSetLayout(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT); } VulkanDevice *device; VkDescriptorSetLayout layout; @@ -184,7 +186,12 @@ public: VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set); ~VulkanDescriptorSet(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)set, VK_OBJECT_TYPE_DESCRIPTOR_SET); } +#endif VulkanDevice *device; VulkanDescriptorPool *pool; @@ -201,14 +208,26 @@ public: VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool); ~VulkanDescriptorPool(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } +#ifdef _DEBUG + void SetDebugName(const char* name) { debugName = name; device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } + std::string debugName; +#else + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_DESCRIPTOR_POOL); } +#endif + std::unique_ptr tryAllocate(VulkanDescriptorSetLayout *layout); + std::unique_ptr tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount); std::unique_ptr allocate(VulkanDescriptorSetLayout *layout); + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount); VulkanDevice *device; VkDescriptorPool pool; private: + enum class AllocType { TryAllocate, AlwaysAllocate }; + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, AllocType allocType); + std::unique_ptr allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount, AllocType allocType); + VulkanDescriptorPool(const VulkanDescriptorPool &) = delete; VulkanDescriptorPool &operator=(const VulkanDescriptorPool &) = delete; }; @@ -219,7 +238,7 @@ public: VulkanQueryPool(VulkanDevice *device, VkQueryPool pool); ~VulkanQueryPool(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_QUERY_POOL); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_QUERY_POOL); } bool getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags); @@ -244,7 +263,7 @@ public: return vkGetAccelerationStructureDeviceAddressKHR(device->device, &addressInfo); } - void SetDebugName(const char* name) { device->setDebugObjectName(name, (uint64_t)accelstruct, VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR); } + void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)accelstruct, VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR); } VulkanDevice* device; VkAccelerationStructureKHR accelstruct; @@ -257,14 +276,13 @@ private: class VulkanPipeline { public: - VulkanPipeline(VulkanDevice *device, VkPipeline pipeline, std::vector shaderGroupHandles = {}); + VulkanPipeline(VulkanDevice *device, VkPipeline pipeline); ~VulkanPipeline(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pipeline, VK_OBJECT_TYPE_PIPELINE); } VulkanDevice *device; VkPipeline pipeline; - std::vector shaderGroupHandles; private: VulkanPipeline(const VulkanPipeline &) = delete; @@ -277,7 +295,7 @@ public: VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout); ~VulkanPipelineLayout(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)layout, VK_OBJECT_TYPE_PIPELINE_LAYOUT); } VulkanDevice *device; VkPipelineLayout layout; @@ -293,7 +311,7 @@ public: VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass); ~VulkanRenderPass(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)renderPass, VK_OBJECT_TYPE_RENDER_PASS); } VulkanDevice *device; VkRenderPass renderPass; @@ -308,9 +326,9 @@ class RenderPassBegin public: RenderPassBegin(); - RenderPassBegin& RenderPass(VulkanRenderPass *renderpass); + RenderPassBegin& RenderPass(VulkanRenderPass* renderpass); RenderPassBegin& RenderArea(int x, int y, int width, int height); - RenderPassBegin& Framebuffer(VulkanFramebuffer *framebuffer); + RenderPassBegin& Framebuffer(VulkanFramebuffer* framebuffer); RenderPassBegin& AddClearColor(float r, float g, float b, float a); RenderPassBegin& AddClearDepth(float value); RenderPassBegin& AddClearStencil(int value); @@ -384,6 +402,7 @@ public: void copyQueryPoolResults(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); void pushConstants(VulkanPipelineLayout *layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); void pushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void* pValues); + void beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE); void beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents); void nextSubpass(VkSubpassContents contents); void endRenderPass(); @@ -410,7 +429,7 @@ public: VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex); ~VulkanCommandPool(); - void SetDebugName(const char *name) { device->setDebugObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_COMMAND_POOL); } + void SetDebugName(const char *name) { device->SetObjectName(name, (uint64_t)pool, VK_OBJECT_TYPE_COMMAND_POOL); } std::unique_ptr createBuffer(); @@ -432,8 +451,7 @@ inline VulkanSemaphore::VulkanSemaphore(VulkanDevice *device) : device(device) VkSemaphoreCreateInfo semaphoreInfo = {}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkResult result = vkCreateSemaphore(device->device, &semaphoreInfo, nullptr, &semaphore); - if (result != VK_SUCCESS) - throw std::runtime_error("Failed to create semaphore!"); + CheckVulkanError(result, "Could not create semaphore"); } inline VulkanSemaphore::~VulkanSemaphore() @@ -448,8 +466,7 @@ inline VulkanFence::VulkanFence(VulkanDevice *device) : device(device) VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; VkResult result = vkCreateFence(device->device, &fenceInfo, nullptr, &fence); - if (result != VK_SUCCESS) - throw std::runtime_error("Failed to create fence!"); + CheckVulkanError(result, "Could not create fence!"); } inline VulkanFence::~VulkanFence() @@ -490,8 +507,7 @@ inline VulkanCommandPool::VulkanCommandPool(VulkanDevice *device, int queueFamil poolInfo.flags = 0; VkResult result = vkCreateCommandPool(device->device, &poolInfo, nullptr, &pool); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create command pool"); + CheckVulkanError(result, "Could not create command pool"); } inline VulkanCommandPool::~VulkanCommandPool() @@ -511,7 +527,7 @@ inline RenderPassBegin::RenderPassBegin() renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; } -inline RenderPassBegin& RenderPassBegin::RenderPass(VulkanRenderPass *renderPass) +inline RenderPassBegin& RenderPassBegin::RenderPass(VulkanRenderPass* renderPass) { renderPassInfo.renderPass = renderPass->renderPass; return *this; @@ -526,7 +542,7 @@ inline RenderPassBegin& RenderPassBegin::RenderArea(int x, int y, int width, int return *this; } -inline RenderPassBegin& RenderPassBegin::Framebuffer(VulkanFramebuffer *framebuffer) +inline RenderPassBegin& RenderPassBegin::Framebuffer(VulkanFramebuffer* framebuffer) { renderPassInfo.framebuffer = framebuffer->framebuffer; return *this; @@ -593,8 +609,7 @@ inline VulkanCommandBuffer::VulkanCommandBuffer(VulkanCommandPool *pool) : pool( allocInfo.commandBufferCount = 1; VkResult result = vkAllocateCommandBuffers(pool->device->device, &allocInfo, &buffer); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create command buffer"); + CheckVulkanError(result, "Could not create command buffer"); } inline VulkanCommandBuffer::~VulkanCommandBuffer() @@ -606,19 +621,17 @@ inline void VulkanCommandBuffer::begin() { VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; beginInfo.pInheritanceInfo = nullptr; VkResult result = vkBeginCommandBuffer(buffer, &beginInfo); - if (result != VK_SUCCESS) - throw std::runtime_error("Failed to begin recording command buffer!"); + CheckVulkanError(result, "Could not begin recording command buffer"); } inline void VulkanCommandBuffer::end() { VkResult result = vkEndCommandBuffer(buffer); - if (result != VK_SUCCESS) - throw std::runtime_error("Failed to record command buffer!"); + CheckVulkanError(result, "Could not end command buffer recording"); } inline void VulkanCommandBuffer::debugFullPipelineBarrier() @@ -910,6 +923,11 @@ inline void VulkanCommandBuffer::pushConstants(VkPipelineLayout layout, VkShader vkCmdPushConstants(buffer, layout, stageFlags, offset, size, pValues); } +inline void VulkanCommandBuffer::beginRenderPass(const RenderPassBegin &renderPassBegin, VkSubpassContents contents) +{ + beginRenderPass(&renderPassBegin.renderPassInfo, contents); +} + inline void VulkanCommandBuffer::beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { vkCmdBeginRenderPass(buffer, pRenderPassBegin, contents); @@ -947,7 +965,7 @@ inline void VulkanCommandBuffer::writeAccelerationStructuresProperties(uint32_t inline void VulkanCommandBuffer::SetDebugName(const char *name) { - pool->device->setDebugObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_COMMAND_BUFFER); + pool->device->SetObjectName(name, (uint64_t)buffer, VK_OBJECT_TYPE_COMMAND_BUFFER); } ///////////////////////////////////////////////////////////////////////////// @@ -994,22 +1012,62 @@ inline VulkanDescriptorPool::~VulkanDescriptorPool() vkDestroyDescriptorPool(device->device, pool, nullptr); } -inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout) +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, AllocType allocType) { - VkDescriptorSetAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + VkDescriptorSetAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; allocInfo.descriptorPool = pool; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &layout->layout; VkDescriptorSet descriptorSet; VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not allocate descriptor sets"); - + if (allocType == AllocType::TryAllocate && result != VK_SUCCESS) + return nullptr; + else + CheckVulkanError(result, "Could not allocate descriptor sets"); return std::make_unique(device, this, descriptorSet); } +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount, AllocType allocType) +{ + VkDescriptorSetAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT countInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT }; + allocInfo.descriptorPool = pool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &layout->layout; + allocInfo.pNext = &countInfo; + countInfo.descriptorSetCount = 1; + countInfo.pDescriptorCounts = &bindlessCount; + + VkDescriptorSet descriptorSet; + VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet); + if (allocType == AllocType::TryAllocate && result != VK_SUCCESS) + return nullptr; + else + CheckVulkanError(result, "Could not allocate descriptor sets"); + return std::make_unique(device, this, descriptorSet); +} + +inline std::unique_ptr VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout *layout) +{ + return allocate(layout, AllocType::TryAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout) +{ + return allocate(layout, AllocType::AlwaysAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount) +{ + return allocate(layout, bindlessCount, AllocType::TryAllocate); +} + +inline std::unique_ptr VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount) +{ + return allocate(layout, bindlessCount, AllocType::AlwaysAllocate); +} + ///////////////////////////////////////////////////////////////////////////// inline VulkanQueryPool::VulkanQueryPool(VulkanDevice *device, VkQueryPool pool) : device(device), pool(pool) @@ -1024,8 +1082,7 @@ inline VulkanQueryPool::~VulkanQueryPool() inline bool VulkanQueryPool::getResults(uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *data, VkDeviceSize stride, VkQueryResultFlags flags) { VkResult result = vkGetQueryPoolResults(device->device, pool, firstQuery, queryCount, dataSize, data, stride, flags); - if (result != VK_SUCCESS && result != VK_NOT_READY) - throw std::runtime_error("vkGetQueryPoolResults failed"); + CheckVulkanError(result, "vkGetQueryPoolResults failed"); return result == VK_SUCCESS; } @@ -1099,7 +1156,7 @@ inline VulkanAccelerationStructure::~VulkanAccelerationStructure() ///////////////////////////////////////////////////////////////////////////// -inline VulkanPipeline::VulkanPipeline(VulkanDevice *device, VkPipeline pipeline, std::vector shaderGroupHandles) : device(device), pipeline(pipeline), shaderGroupHandles(shaderGroupHandles) +inline VulkanPipeline::VulkanPipeline(VulkanDevice *device, VkPipeline pipeline) : device(device), pipeline(pipeline) { } diff --git a/src/lightmap/vulkansurface.cpp b/src/lightmap/vulkansurface.cpp new file mode 100644 index 0000000..848cbcf --- /dev/null +++ b/src/lightmap/vulkansurface.cpp @@ -0,0 +1,53 @@ + +#include "vulkansurface.h" +#include "vulkaninstance.h" + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +VulkanSurface::VulkanSurface(std::shared_ptr instance, HWND window) : Instance(std::move(instance)), Window(window) +{ + VkWin32SurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; + createInfo.hwnd = window; + createInfo.hinstance = GetModuleHandle(nullptr); + + VkResult result = vkCreateWin32SurfaceKHR(Instance->Instance, &createInfo, nullptr, &Surface); + if (result != VK_SUCCESS) + VulkanError("Could not create vulkan surface"); +} + +VulkanSurface::~VulkanSurface() +{ + vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr); +} + +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + +VulkanSurface::VulkanSurface(std::shared_ptr instance, Display* disp, Window wind) : Instance(std::move(instance)), disp(disp), wind(wind) +{ + VkXlibSurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; + createInfo.dpy = disp; + createInfo.window = wind; + + VkResult result = vkCreateXlibSurfaceKHR(Instance->Instance, &createInfo, nullptr, &Surface); + if (result != VK_SUCCESS) + VulkanError("Could not create vulkan surface"); +} + +VulkanSurface::~VulkanSurface() +{ + vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr); +} + +#else + +VulkanSurface::VulkanSurface(std::shared_ptr instance) : Instance(std::move(instance)) +{ + VulkanError("VulkanSurface not implemented on this platform"); +} + +VulkanSurface::~VulkanSurface() +{ + vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr); +} + +#endif diff --git a/src/lightmap/vulkansurface.h b/src/lightmap/vulkansurface.h new file mode 100644 index 0000000..25aee76 --- /dev/null +++ b/src/lightmap/vulkansurface.h @@ -0,0 +1,46 @@ +#pragma once + +#include "VulkanInstance.h" + +#ifdef VK_USE_PLATFORM_WIN32_KHR + +class VulkanSurface +{ +public: + VulkanSurface(std::shared_ptr instance, HWND window); + ~VulkanSurface(); + + std::shared_ptr Instance; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + HWND Window = 0; +}; + +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + +#include + +class VulkanSurface +{ +public: + VulkanSurface(std::shared_ptr instance, Display* disp, Window wind); + ~VulkanSurface(); + + std::shared_ptr Instance; + VkSurfaceKHR Surface = VK_NULL_HANDLE; + Display* disp = nullptr; + Window wind; +}; + +#else + +class VulkanSurface +{ +public: + VulkanSurface(std::shared_ptr instance); + ~VulkanSurface(); + + std::shared_ptr Instance; + VkSurfaceKHR Surface = VK_NULL_HANDLE; +}; + +#endif diff --git a/thirdparty/volk/volk.c b/thirdparty/volk/volk.c index bb8b928..1e99c7d 100644 --- a/thirdparty/volk/volk.c +++ b/thirdparty/volk/volk.c @@ -1,3 +1,13 @@ + +#if defined(_WIN32) +#define VK_USE_PLATFORM_WIN32_KHR +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT +#else +#define VK_USE_PLATFORM_XLIB_KHR +#endif + /* This file is part of volk library; see volk.h for version/license details */ /* clang-format off */ #include "volk.h"