mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-28 14:41:57 +00:00
Update the vulkan support classes and enable runtime detection for falling back to non-rayquery rendering if the device does not support it
This commit is contained in:
parent
0c6954a767
commit
1e62255b28
15 changed files with 1109 additions and 931 deletions
|
@ -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
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "framework/templates.h"
|
||||
#include "framework/halffloat.h"
|
||||
#include "vulkanbuilders.h"
|
||||
#include "vulkancompatibledevice.h"
|
||||
#include "stacktrace.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
@ -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<VulkanDevice>(0, VKDebug);
|
||||
useRayQuery = !NoRtx;// && device->physicalDevice.rayQueryProperties.supportsRayQuery;
|
||||
auto instance = std::make_shared<VulkanInstance>(VKDebug);
|
||||
device = std::make_unique<VulkanDevice>(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<VulkanFence>(device.get());
|
||||
cmdpool = std::make_unique<VulkanCommandPool>(device.get(), device->graphicsFamily);
|
||||
cmdpool = std::make_unique<VulkanCommandPool>(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<uint64_t>::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<CollisionNode> GPURaytracer::CreateCollisionNodes()
|
|||
|
||||
void GPURaytracer::PrintVulkanInfo()
|
||||
{
|
||||
const auto& props = device->physicalDevice.properties;
|
||||
const auto& props = device->PhysicalDevice.Properties;
|
||||
|
||||
std::string deviceType;
|
||||
switch (props.deviceType)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -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<VulkanShader> 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<VulkanShader> 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<VulkanShader> 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<VulkanShader> 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<VulkanShader>(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<VulkanImage> 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<VulkanImageView> 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<VulkanImageView>(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<VulkanSampler> 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<VulkanSampler>(device, sampler);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -511,8 +480,7 @@ std::unique_ptr<VulkanBuffer> 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<VulkanBuffer>(device, buffer, allocation, bufferInfo.size);
|
||||
if (debugName)
|
||||
|
@ -562,131 +530,6 @@ std::unique_ptr<VulkanAccelerationStructure> 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<VulkanPipeline> 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<uint8_t> 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<VulkanPipeline>(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<VulkanPipeline> 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<VulkanDescriptorSetLayout> 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<VulkanDescriptorSetLayout>(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<VulkanDescriptorPool> 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<VulkanDescriptorPool>(device, descriptorPool);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -811,8 +671,7 @@ std::unique_ptr<VulkanQueryPool> 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<VulkanQueryPool>(device, queryPool);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -862,8 +721,7 @@ std::unique_ptr<VulkanFramebuffer> 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<VulkanFramebuffer>(device, framebuffer);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -1179,8 +1037,7 @@ std::unique_ptr<VulkanPipeline> 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<VulkanPipeline>(device, pipeline);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -1218,8 +1075,7 @@ std::unique_ptr<VulkanPipelineLayout> 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<VulkanPipelineLayout>(device, pipelineLayout);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -1323,8 +1179,7 @@ std::unique_ptr<VulkanRenderPass> 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<VulkanRenderPass>(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<WriteExtra>();
|
||||
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<WriteExtra>();
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "vulkanobjects.h"
|
||||
#include "framework/zstring.h"
|
||||
#include <cassert>
|
||||
|
||||
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<VulkanShader> 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<VulkanPipeline> Create(VulkanDevice* device);
|
||||
|
||||
private:
|
||||
VkRayTracingPipelineCreateInfoKHR pipelineInfo = {};
|
||||
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> 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<VulkanDescriptorSetLayout> Create(VulkanDevice *device);
|
||||
|
||||
private:
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
|
||||
TArray<VkDescriptorSetLayoutBinding> 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<VkDescriptorSetLayoutBinding> bindings;
|
||||
std::vector<VkDescriptorBindingFlags> 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);
|
||||
|
||||
|
|
145
src/lightmap/vulkancompatibledevice.cpp
Normal file
145
src/lightmap/vulkancompatibledevice.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
|
||||
#include "vulkancompatibledevice.h"
|
||||
#include "vulkansurface.h"
|
||||
|
||||
std::vector<VulkanCompatibleDevice> VulkanCompatibleDevice::FindDevices(const std::shared_ptr<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& surface)
|
||||
{
|
||||
std::vector<std::string> RequiredDeviceExtensions =
|
||||
{
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
|
||||
std::vector<std::string> 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<VulkanCompatibleDevice> 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<std::string> 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<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& 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<VulkanCompatibleDevice> 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];
|
||||
}
|
22
src/lightmap/vulkancompatibledevice.h
Normal file
22
src/lightmap/vulkancompatibledevice.h
Normal file
|
@ -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<std::string> EnabledDeviceExtensions;
|
||||
VulkanDeviceFeatures EnabledFeatures;
|
||||
|
||||
static std::vector<VulkanCompatibleDevice> FindDevices(const std::shared_ptr<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& surface);
|
||||
static VulkanCompatibleDevice SelectDevice(const std::shared_ptr<VulkanInstance>& instance, const std::shared_ptr<VulkanSurface>& surface, int vk_device);
|
||||
};
|
|
@ -1,194 +1,69 @@
|
|||
|
||||
#include "vulkandevice.h"
|
||||
#include "vulkanobjects.h"
|
||||
#include "stacktrace.h"
|
||||
#include "vulkancompatibledevice.h"
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
VulkanDevice::VulkanDevice(int vk_device, bool vk_debug) : vk_device(vk_device), vk_debug(vk_debug)
|
||||
VulkanDevice::VulkanDevice(std::shared_ptr<VulkanInstance> instance, std::shared_ptr<VulkanSurface> 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<std::string> 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<bool>(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<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
|
||||
std::set<int> 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<const char*> 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<void**>(&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<std::string> seenMessages;
|
||||
static int totalMessages;
|
||||
|
||||
std::unique_lock<std::mutex> 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<VkLayerProperties> VulkanDevice::getAvailableLayers()
|
||||
{
|
||||
uint32_t layerCount;
|
||||
VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
return availableLayers;
|
||||
}
|
||||
|
||||
std::vector<VkExtensionProperties> VulkanDevice::getExtensions()
|
||||
{
|
||||
uint32_t extensionCount = 0;
|
||||
VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> extensions(extensionCount);
|
||||
result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::vector<VulkanPhysicalDevice> 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<VkPhysicalDevice> devices(deviceCount);
|
||||
result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("vkEnumeratePhysicalDevices failed (2)");
|
||||
|
||||
std::vector<VulkanPhysicalDevice> 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<const char *> VulkanDevice::getPlatformExtensions()
|
||||
{
|
||||
return
|
||||
{
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
}
|
||||
#else
|
||||
std::vector<const char *> 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);
|
||||
}
|
||||
|
|
|
@ -1,136 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "vulkaninstance.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#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 <mutex>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
class VulkanSwapChain;
|
||||
class VulkanSemaphore;
|
||||
class VulkanFence;
|
||||
|
||||
class VulkanPhysicalDevice
|
||||
{
|
||||
public:
|
||||
VkPhysicalDevice device = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<VkExtensionProperties> extensions;
|
||||
std::vector<VkQueueFamilyProperties> 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<VulkanInstance> instance, std::shared_ptr<VulkanSurface> surface, const VulkanCompatibleDevice& selectedDevice);
|
||||
~VulkanDevice();
|
||||
|
||||
void setDebugObjectName(const char *name, uint64_t handle, VkObjectType type)
|
||||
{
|
||||
if (!debugLayerActive) return;
|
||||
std::vector<std::string> 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<VulkanInstance> Instance;
|
||||
std::shared_ptr<VulkanSurface> Surface;
|
||||
|
||||
// Instance setup
|
||||
std::vector<VkLayerProperties> availableLayers;
|
||||
std::vector<VkExtensionProperties> extensions;
|
||||
std::vector<const char *> enabledExtensions;
|
||||
std::vector<const char *> optionalExtensions = { };
|
||||
std::vector<const char*> enabledValidationLayers;
|
||||
|
||||
// Device setup
|
||||
VkPhysicalDeviceFeatures enabledDeviceFeatures = {};
|
||||
std::vector<const char *> 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<const char *> 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<VulkanPhysicalDevice> availableDevices;
|
||||
std::vector<VulkanCompatibleDevice> 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<VkLayerProperties> getAvailableLayers();
|
||||
static std::vector<VkExtensionProperties> getExtensions();
|
||||
static std::vector<const char *> getPlatformExtensions();
|
||||
static std::vector<VulkanPhysicalDevice> getPhysicalDevices(VkInstance instance);
|
||||
void CreateDevice();
|
||||
void CreateAllocator();
|
||||
void ReleaseResources();
|
||||
};
|
||||
|
|
378
src/lightmap/vulkaninstance.cpp
Normal file
378
src/lightmap/vulkaninstance.cpp
Normal file
|
@ -0,0 +1,378 @@
|
|||
|
||||
#include "vulkaninstance.h"
|
||||
#include "vulkanbuilders.h"
|
||||
#include <mutex>
|
||||
|
||||
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<VulkanPhysicalDevice> 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<VkPhysicalDevice> devices(deviceCount);
|
||||
result = vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
CheckVulkanError(result, "vkEnumeratePhysicalDevices failed (2)");
|
||||
|
||||
std::vector<VulkanPhysicalDevice> 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<void**>(&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<VkLayerProperties> VulkanInstance::GetAvailableLayers()
|
||||
{
|
||||
uint32_t layerCount;
|
||||
VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
return availableLayers;
|
||||
}
|
||||
|
||||
std::vector<VkExtensionProperties> VulkanInstance::GetExtensions()
|
||||
{
|
||||
uint32_t extensionCount = 0;
|
||||
VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> 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<std::string> seenMessages;
|
||||
static int totalMessages;
|
||||
|
||||
std::unique_lock<std::mutex> 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 += "<noname>";
|
||||
}
|
||||
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<std::string> VulkanInstance::SplitString(const std::string& s, const std::string& seperator)
|
||||
{
|
||||
std::vector<std::string> 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);
|
||||
}
|
106
src/lightmap/vulkaninstance.h
Normal file
106
src/lightmap/vulkaninstance.h
Normal file
|
@ -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 <functional>
|
||||
#include <memory>
|
||||
|
||||
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<VkExtensionProperties> Extensions;
|
||||
std::vector<VkQueueFamilyProperties> QueueFamilies;
|
||||
VkPhysicalDeviceProperties Properties = {};
|
||||
VkPhysicalDeviceMemoryProperties MemoryProperties = {};
|
||||
VulkanDeviceFeatures Features;
|
||||
};
|
||||
|
||||
class VulkanInstance
|
||||
{
|
||||
public:
|
||||
VulkanInstance(bool wantDebugLayer);
|
||||
~VulkanInstance();
|
||||
|
||||
std::vector<const char*> 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<const char*> 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<uint32_t> ApiVersionsToTry = { VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0 };
|
||||
|
||||
std::vector<VkLayerProperties> AvailableLayers;
|
||||
std::vector<VkExtensionProperties> AvailableExtensions;
|
||||
|
||||
std::vector<const char*> EnabledValidationLayers;
|
||||
std::vector<const char*> EnabledExtensions;
|
||||
|
||||
std::vector<VulkanPhysicalDevice> 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<VkLayerProperties> GetAvailableLayers();
|
||||
static std::vector<VkExtensionProperties> GetExtensions();
|
||||
static std::vector<VulkanPhysicalDevice> 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<std::string> 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());
|
||||
}
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
#include "vulkandevice.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
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<VulkanDescriptorSet> tryAllocate(VulkanDescriptorSetLayout *layout);
|
||||
std::unique_ptr<VulkanDescriptorSet> tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount);
|
||||
std::unique_ptr<VulkanDescriptorSet> allocate(VulkanDescriptorSetLayout *layout);
|
||||
std::unique_ptr<VulkanDescriptorSet> allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount);
|
||||
|
||||
VulkanDevice *device;
|
||||
VkDescriptorPool pool;
|
||||
|
||||
private:
|
||||
enum class AllocType { TryAllocate, AlwaysAllocate };
|
||||
std::unique_ptr<VulkanDescriptorSet> allocate(VulkanDescriptorSetLayout* layout, AllocType allocType);
|
||||
std::unique_ptr<VulkanDescriptorSet> 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<uint8_t> 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<uint8_t> 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<VulkanCommandBuffer> 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<VulkanDescriptorSet> VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout)
|
||||
inline std::unique_ptr<VulkanDescriptorSet> 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<VulkanDescriptorSet>(device, this, descriptorSet);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<VulkanDescriptorSet> 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<VulkanDescriptorSet>(device, this, descriptorSet);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<VulkanDescriptorSet> VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout *layout)
|
||||
{
|
||||
return allocate(layout, AllocType::TryAllocate);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<VulkanDescriptorSet> VulkanDescriptorPool::allocate(VulkanDescriptorSetLayout *layout)
|
||||
{
|
||||
return allocate(layout, AllocType::AlwaysAllocate);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<VulkanDescriptorSet> VulkanDescriptorPool::tryAllocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount)
|
||||
{
|
||||
return allocate(layout, bindlessCount, AllocType::TryAllocate);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<VulkanDescriptorSet> 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<uint8_t> shaderGroupHandles) : device(device), pipeline(pipeline), shaderGroupHandles(shaderGroupHandles)
|
||||
inline VulkanPipeline::VulkanPipeline(VulkanDevice *device, VkPipeline pipeline) : device(device), pipeline(pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
53
src/lightmap/vulkansurface.cpp
Normal file
53
src/lightmap/vulkansurface.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
|
||||
#include "vulkansurface.h"
|
||||
#include "vulkaninstance.h"
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
|
||||
VulkanSurface::VulkanSurface(std::shared_ptr<VulkanInstance> 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<VulkanInstance> 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<VulkanInstance> instance) : Instance(std::move(instance))
|
||||
{
|
||||
VulkanError("VulkanSurface not implemented on this platform");
|
||||
}
|
||||
|
||||
VulkanSurface::~VulkanSurface()
|
||||
{
|
||||
vkDestroySurfaceKHR(Instance->Instance, Surface, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
46
src/lightmap/vulkansurface.h
Normal file
46
src/lightmap/vulkansurface.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "VulkanInstance.h"
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
|
||||
class VulkanSurface
|
||||
{
|
||||
public:
|
||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance, HWND window);
|
||||
~VulkanSurface();
|
||||
|
||||
std::shared_ptr<VulkanInstance> Instance;
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
HWND Window = 0;
|
||||
};
|
||||
|
||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
class VulkanSurface
|
||||
{
|
||||
public:
|
||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance, Display* disp, Window wind);
|
||||
~VulkanSurface();
|
||||
|
||||
std::shared_ptr<VulkanInstance> Instance;
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
Display* disp = nullptr;
|
||||
Window wind;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class VulkanSurface
|
||||
{
|
||||
public:
|
||||
VulkanSurface(std::shared_ptr<VulkanInstance> instance);
|
||||
~VulkanSurface();
|
||||
|
||||
std::shared_ptr<VulkanInstance> Instance;
|
||||
VkSurfaceKHR Surface = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
#endif
|
10
thirdparty/volk/volk.c
vendored
10
thirdparty/volk/volk.c
vendored
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue