mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-10 06:41:37 +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/vulkanobjects.h
|
||||||
src/lightmap/vulkanbuilders.cpp
|
src/lightmap/vulkanbuilders.cpp
|
||||||
src/lightmap/vulkanbuilders.h
|
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.cpp
|
||||||
src/lightmap/stacktrace.h
|
src/lightmap/stacktrace.h
|
||||||
src/lightmap/surfaceclip.cpp
|
src/lightmap/surfaceclip.cpp
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "framework/templates.h"
|
#include "framework/templates.h"
|
||||||
#include "framework/halffloat.h"
|
#include "framework/halffloat.h"
|
||||||
#include "vulkanbuilders.h"
|
#include "vulkanbuilders.h"
|
||||||
|
#include "vulkancompatibledevice.h"
|
||||||
|
#include "stacktrace.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -21,10 +23,22 @@
|
||||||
extern bool VKDebug;
|
extern bool VKDebug;
|
||||||
extern bool NoRtx;
|
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()
|
GPURaytracer::GPURaytracer()
|
||||||
{
|
{
|
||||||
device = std::make_unique<VulkanDevice>(0, VKDebug);
|
auto instance = std::make_shared<VulkanInstance>(VKDebug);
|
||||||
useRayQuery = !NoRtx;// && device->physicalDevice.rayQueryProperties.supportsRayQuery;
|
device = std::make_unique<VulkanDevice>(instance, nullptr, VulkanCompatibleDevice::SelectDevice(instance, nullptr, 0));
|
||||||
|
useRayQuery = !NoRtx && device->PhysicalDevice.Features.RayQuery.rayQuery;
|
||||||
PrintVulkanInfo();
|
PrintVulkanInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +52,6 @@ void GPURaytracer::Raytrace(LevelMesh* level)
|
||||||
|
|
||||||
printf("Building Vulkan acceleration structures\n");
|
printf("Building Vulkan acceleration structures\n");
|
||||||
|
|
||||||
if (device->renderdoc)
|
|
||||||
device->renderdoc->StartFrameCapture(0, 0);
|
|
||||||
|
|
||||||
CreateVulkanObjects();
|
CreateVulkanObjects();
|
||||||
|
|
||||||
printf("Ray tracing in progress...\n");
|
printf("Ray tracing in progress...\n");
|
||||||
|
@ -79,9 +90,6 @@ void GPURaytracer::Raytrace(LevelMesh* level)
|
||||||
DownloadAtlasImage(pageIndex);
|
DownloadAtlasImage(pageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device->renderdoc)
|
|
||||||
device->renderdoc->EndFrameCapture(0, 0);
|
|
||||||
|
|
||||||
printf("Ray trace complete\n");
|
printf("Ray trace complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +340,7 @@ vec2 GPURaytracer::ToUV(const vec3& vert, const Surface* targetSurface)
|
||||||
void GPURaytracer::CreateVulkanObjects()
|
void GPURaytracer::CreateVulkanObjects()
|
||||||
{
|
{
|
||||||
submitFence = std::make_unique<VulkanFence>(device.get());
|
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();
|
BeginCommands();
|
||||||
|
|
||||||
|
@ -402,7 +410,7 @@ void GPURaytracer::FinishCommands()
|
||||||
|
|
||||||
QueueSubmit()
|
QueueSubmit()
|
||||||
.AddCommandBuffer(cmdbuffer.get())
|
.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());
|
VkResult result = vkWaitForFences(device->device, 1, &submitFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
|
@ -623,8 +631,8 @@ void GPURaytracer::CreateTopLevelAccelerationStructure()
|
||||||
|
|
||||||
void GPURaytracer::CreateShaders()
|
void GPURaytracer::CreateShaders()
|
||||||
{
|
{
|
||||||
FString prefix = "#version 460\r\n#line 1\r\n";
|
std::string prefix = "#version 460\r\n#line 1\r\n";
|
||||||
FString traceprefix = "#version 460\r\n";
|
std::string traceprefix = "#version 460\r\n";
|
||||||
if (useRayQuery)
|
if (useRayQuery)
|
||||||
{
|
{
|
||||||
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
|
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
|
||||||
|
@ -878,7 +886,7 @@ LightmapImage GPURaytracer::CreateImage(int width, int height)
|
||||||
|
|
||||||
void GPURaytracer::CreateUniformBuffer()
|
void GPURaytracer::CreateUniformBuffer()
|
||||||
{
|
{
|
||||||
VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment;
|
VkDeviceSize align = device->PhysicalDevice.Properties.limits.minUniformBufferOffsetAlignment;
|
||||||
uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align;
|
uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align;
|
||||||
|
|
||||||
uniformBuffer = BufferBuilder()
|
uniformBuffer = BufferBuilder()
|
||||||
|
@ -932,7 +940,7 @@ std::vector<CollisionNode> GPURaytracer::CreateCollisionNodes()
|
||||||
|
|
||||||
void GPURaytracer::PrintVulkanInfo()
|
void GPURaytracer::PrintVulkanInfo()
|
||||||
{
|
{
|
||||||
const auto& props = device->physicalDevice.properties;
|
const auto& props = device->PhysicalDevice.Properties;
|
||||||
|
|
||||||
std::string deviceType;
|
std::string deviceType;
|
||||||
switch (props.deviceType)
|
switch (props.deviceType)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <DbgHelp.h>
|
#include <DbgHelp.h>
|
||||||
|
#include <psapi.h>
|
||||||
#else
|
#else
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
|
@ -17,8 +18,16 @@
|
||||||
class NativeSymbolResolver
|
class NativeSymbolResolver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NativeSymbolResolver() { SymInitialize(GetCurrentProcess(), nullptr, TRUE); }
|
NativeSymbolResolver()
|
||||||
~NativeSymbolResolver() { SymCleanup(GetCurrentProcess()); }
|
{
|
||||||
|
SymInitialize(GetCurrentProcess(), nullptr, TRUE);
|
||||||
|
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(0), &moduleInfo, sizeof(MODULEINFO));
|
||||||
|
}
|
||||||
|
|
||||||
|
~NativeSymbolResolver()
|
||||||
|
{
|
||||||
|
SymCleanup(GetCurrentProcess());
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetName(void* frame)
|
std::string GetName(void* frame)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +43,9 @@ public:
|
||||||
BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64);
|
BOOL result = SymGetSymFromAddr64(GetCurrentProcess(), (DWORD64)frame, &displacement, symbol64);
|
||||||
if (result)
|
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;
|
IMAGEHLP_LINE64 line64;
|
||||||
DWORD displacement = 0;
|
DWORD displacement = 0;
|
||||||
memset(&line64, 0, sizeof(IMAGEHLP_LINE64));
|
memset(&line64, 0, sizeof(IMAGEHLP_LINE64));
|
||||||
|
@ -51,6 +63,8 @@ public:
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MODULEINFO moduleInfo = {};
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
class NativeSymbolResolver
|
class NativeSymbolResolver
|
||||||
|
|
|
@ -109,77 +109,45 @@ static const TBuiltInResource DefaultTBuiltInResource = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ShaderBuilder::Init()
|
||||||
|
{
|
||||||
|
ShInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderBuilder::Deinit()
|
||||||
|
{
|
||||||
|
ShFinalize();
|
||||||
|
}
|
||||||
|
|
||||||
ShaderBuilder::ShaderBuilder()
|
ShaderBuilder::ShaderBuilder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBuilder& ShaderBuilder::VertexShader(const FString &c)
|
ShaderBuilder& ShaderBuilder::VertexShader(const std::string& c)
|
||||||
{
|
{
|
||||||
code = c;
|
code = c;
|
||||||
stage = EShLanguage::EShLangVertex;
|
stage = EShLanguage::EShLangVertex;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBuilder& ShaderBuilder::FragmentShader(const FString &c)
|
ShaderBuilder& ShaderBuilder::FragmentShader(const std::string& c)
|
||||||
{
|
{
|
||||||
code = c;
|
code = c;
|
||||||
stage = EShLanguage::EShLangFragment;
|
stage = EShLanguage::EShLangFragment;
|
||||||
return *this;
|
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)
|
std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, VulkanDevice *device)
|
||||||
{
|
{
|
||||||
EShLanguage stage = (EShLanguage)this->stage;
|
EShLanguage stage = (EShLanguage)this->stage;
|
||||||
const char *sources[] = { code.GetChars() };
|
const char *sources[] = { code.c_str() };
|
||||||
|
|
||||||
TBuiltInResource resources = DefaultTBuiltInResource;
|
TBuiltInResource resources = DefaultTBuiltInResource;
|
||||||
|
|
||||||
glslang::TShader shader(stage);
|
glslang::TShader shader(stage);
|
||||||
shader.setStrings(sources, 1);
|
shader.setStrings(sources, 1);
|
||||||
shader.setEnvInput(glslang::EShSourceGlsl, stage, glslang::EShClientVulkan, 100);
|
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.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2);
|
||||||
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4);
|
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);
|
bool compileSuccess = shader.parse(&resources, 110, false, EShMsgVulkanRules);
|
||||||
if (!compileSuccess)
|
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;
|
glslang::TProgram program;
|
||||||
|
@ -200,13 +168,13 @@ std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, Vulk
|
||||||
bool linkSuccess = program.link(EShMsgDefault);
|
bool linkSuccess = program.link(EShMsgDefault);
|
||||||
if (!linkSuccess)
|
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);
|
glslang::TIntermediate *intermediate = program.getIntermediate(stage);
|
||||||
if (!intermediate)
|
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;
|
glslang::SpvOptions spvOptions;
|
||||||
|
@ -226,9 +194,7 @@ std::unique_ptr<VulkanShader> ShaderBuilder::Create(const char *shadername, Vulk
|
||||||
VkShaderModule shaderModule;
|
VkShaderModule shaderModule;
|
||||||
VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule);
|
VkResult result = vkCreateShaderModule(device->device, &createInfo, nullptr, &shaderModule);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
|
||||||
throw std::runtime_error("Could not create vulkan shader module");
|
throw std::runtime_error("Could not create vulkan shader module");
|
||||||
}
|
|
||||||
|
|
||||||
auto obj = std::make_unique<VulkanShader>(device, shaderModule);
|
auto obj = std::make_unique<VulkanShader>(device, shaderModule);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
|
@ -297,7 +263,7 @@ ImageBuilder& ImageBuilder::MemoryType(VkMemoryPropertyFlags requiredFlags, VkMe
|
||||||
bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags bufferFeatures)
|
bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags bufferFeatures)
|
||||||
{
|
{
|
||||||
VkImageFormatProperties properties = { };
|
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 (result != VK_SUCCESS) return false;
|
||||||
if (imageInfo.extent.width > properties.maxExtent.width) return false;
|
if (imageInfo.extent.width > properties.maxExtent.width) return false;
|
||||||
if (imageInfo.extent.height > properties.maxExtent.height) return false;
|
if (imageInfo.extent.height > properties.maxExtent.height) return false;
|
||||||
|
@ -308,7 +274,7 @@ bool ImageBuilder::IsFormatSupported(VulkanDevice* device, VkFormatFeatureFlags
|
||||||
if (bufferFeatures != 0)
|
if (bufferFeatures != 0)
|
||||||
{
|
{
|
||||||
VkFormatProperties formatProperties = { };
|
VkFormatProperties formatProperties = { };
|
||||||
vkGetPhysicalDeviceFormatProperties(device->physicalDevice.device, imageInfo.format, &formatProperties);
|
vkGetPhysicalDeviceFormatProperties(device->PhysicalDevice.Device, imageInfo.format, &formatProperties);
|
||||||
if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures)
|
if ((formatProperties.bufferFeatures & bufferFeatures) != bufferFeatures)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -321,8 +287,7 @@ std::unique_ptr<VulkanImage> ImageBuilder::Create(VulkanDevice* device, VkDevice
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
|
|
||||||
VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr);
|
VkResult result = vmaCreateImage(device->allocator, &imageInfo, &allocInfo, &image, &allocation, nullptr);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create vulkan image");
|
||||||
throw std::runtime_error("Could not create vulkan image");
|
|
||||||
|
|
||||||
if (allocatedBytes != nullptr)
|
if (allocatedBytes != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -385,8 +350,7 @@ std::unique_ptr<VulkanImageView> ImageViewBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
VkResult result = vkCreateImageView(device->device, &viewInfo, nullptr, &view);
|
VkResult result = vkCreateImageView(device->device, &viewInfo, nullptr, &view);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create texture image view");
|
||||||
throw std::runtime_error("Could not create texture image view");
|
|
||||||
|
|
||||||
auto obj = std::make_unique<VulkanImageView>(device, view);
|
auto obj = std::make_unique<VulkanImageView>(device, view);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
|
@ -457,6 +421,12 @@ SamplerBuilder& SamplerBuilder::Anisotropy(float maxAnisotropy)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SamplerBuilder& SamplerBuilder::MipLodBias(float bias)
|
||||||
|
{
|
||||||
|
samplerInfo.mipLodBias = bias;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SamplerBuilder& SamplerBuilder::MaxLod(float value)
|
SamplerBuilder& SamplerBuilder::MaxLod(float value)
|
||||||
{
|
{
|
||||||
samplerInfo.maxLod = value;
|
samplerInfo.maxLod = value;
|
||||||
|
@ -467,8 +437,7 @@ std::unique_ptr<VulkanSampler> SamplerBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
VkResult result = vkCreateSampler(device->device, &samplerInfo, nullptr, &sampler);
|
VkResult result = vkCreateSampler(device->device, &samplerInfo, nullptr, &sampler);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create texture sampler");
|
||||||
throw std::runtime_error("Could not create texture sampler");
|
|
||||||
auto obj = std::make_unique<VulkanSampler>(device, sampler);
|
auto obj = std::make_unique<VulkanSampler>(device, sampler);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -511,8 +480,7 @@ std::unique_ptr<VulkanBuffer> BufferBuilder::Create(VulkanDevice* device)
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
|
|
||||||
VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
VkResult result = vmaCreateBuffer(device->allocator, &bufferInfo, &allocInfo, &buffer, &allocation, nullptr);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not allocate memory for vulkan buffer");
|
||||||
throw std::runtime_error("Could not allocate memory for vulkan buffer");
|
|
||||||
|
|
||||||
auto obj = std::make_unique<VulkanBuffer>(device, buffer, allocation, bufferInfo.size);
|
auto obj = std::make_unique<VulkanBuffer>(device, buffer, allocation, bufferInfo.size);
|
||||||
if (debugName)
|
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()
|
ComputePipelineBuilder::ComputePipelineBuilder()
|
||||||
{
|
{
|
||||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||||
|
@ -723,10 +566,15 @@ std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* dev
|
||||||
|
|
||||||
DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder()
|
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 = { };
|
VkDescriptorSetLayoutBinding binding = { };
|
||||||
binding.binding = index;
|
binding.binding = index;
|
||||||
|
@ -734,10 +582,18 @@ DescriptorSetLayoutBuilder& DescriptorSetLayoutBuilder::AddBinding(int index, Vk
|
||||||
binding.descriptorCount = arrayCount;
|
binding.descriptorCount = arrayCount;
|
||||||
binding.stageFlags = stageFlags;
|
binding.stageFlags = stageFlags;
|
||||||
binding.pImmutableSamplers = nullptr;
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,8 +601,7 @@ std::unique_ptr<VulkanDescriptorSetLayout> DescriptorSetLayoutBuilder::Create(Vu
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayout layout;
|
VkDescriptorSetLayout layout;
|
||||||
VkResult result = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &layout);
|
VkResult result = vkCreateDescriptorSetLayout(device->device, &layoutInfo, nullptr, &layout);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create descriptor set layout");
|
||||||
throw std::runtime_error("Could not create descriptor set layout");
|
|
||||||
auto obj = std::make_unique<VulkanDescriptorSetLayout>(device, layout);
|
auto obj = std::make_unique<VulkanDescriptorSetLayout>(device, layout);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -762,6 +617,12 @@ DescriptorPoolBuilder::DescriptorPoolBuilder()
|
||||||
poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
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)
|
DescriptorPoolBuilder& DescriptorPoolBuilder::MaxSets(int value)
|
||||||
{
|
{
|
||||||
poolInfo.maxSets = value;
|
poolInfo.maxSets = value;
|
||||||
|
@ -784,8 +645,7 @@ std::unique_ptr<VulkanDescriptorPool> DescriptorPoolBuilder::Create(VulkanDevice
|
||||||
{
|
{
|
||||||
VkDescriptorPool descriptorPool;
|
VkDescriptorPool descriptorPool;
|
||||||
VkResult result = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool);
|
VkResult result = vkCreateDescriptorPool(device->device, &poolInfo, nullptr, &descriptorPool);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create descriptor pool");
|
||||||
throw std::runtime_error("Could not create descriptor pool");
|
|
||||||
auto obj = std::make_unique<VulkanDescriptorPool>(device, descriptorPool);
|
auto obj = std::make_unique<VulkanDescriptorPool>(device, descriptorPool);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -811,8 +671,7 @@ std::unique_ptr<VulkanQueryPool> QueryPoolBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkQueryPool queryPool;
|
VkQueryPool queryPool;
|
||||||
VkResult result = vkCreateQueryPool(device->device, &poolInfo, nullptr, &queryPool);
|
VkResult result = vkCreateQueryPool(device->device, &poolInfo, nullptr, &queryPool);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create query pool");
|
||||||
throw std::runtime_error("Could not create query pool");
|
|
||||||
auto obj = std::make_unique<VulkanQueryPool>(device, queryPool);
|
auto obj = std::make_unique<VulkanQueryPool>(device, queryPool);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -862,8 +721,7 @@ std::unique_ptr<VulkanFramebuffer> FramebufferBuilder::Create(VulkanDevice* devi
|
||||||
{
|
{
|
||||||
VkFramebuffer framebuffer = 0;
|
VkFramebuffer framebuffer = 0;
|
||||||
VkResult result = vkCreateFramebuffer(device->device, &framebufferInfo, nullptr, &framebuffer);
|
VkResult result = vkCreateFramebuffer(device->device, &framebufferInfo, nullptr, &framebuffer);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create framebuffer");
|
||||||
throw std::runtime_error("Could not create framebuffer");
|
|
||||||
auto obj = std::make_unique<VulkanFramebuffer>(device, framebuffer);
|
auto obj = std::make_unique<VulkanFramebuffer>(device, framebuffer);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -1179,8 +1037,7 @@ std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* de
|
||||||
{
|
{
|
||||||
VkPipeline pipeline = 0;
|
VkPipeline pipeline = 0;
|
||||||
VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create graphics pipeline");
|
||||||
throw std::runtime_error("Could not create graphics pipeline");
|
|
||||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -1218,8 +1075,7 @@ std::unique_ptr<VulkanPipelineLayout> PipelineLayoutBuilder::Create(VulkanDevice
|
||||||
{
|
{
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
VkResult result = vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
|
VkResult result = vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create pipeline layout");
|
||||||
throw std::runtime_error("Could not create pipeline layout");
|
|
||||||
auto obj = std::make_unique<VulkanPipelineLayout>(device, pipelineLayout);
|
auto obj = std::make_unique<VulkanPipelineLayout>(device, pipelineLayout);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -1323,8 +1179,7 @@ std::unique_ptr<VulkanRenderPass> RenderPassBuilder::Create(VulkanDevice* device
|
||||||
{
|
{
|
||||||
VkRenderPass renderPass = 0;
|
VkRenderPass renderPass = 0;
|
||||||
VkResult result = vkCreateRenderPass(device->device, &renderPassInfo, nullptr, &renderPass);
|
VkResult result = vkCreateRenderPass(device->device, &renderPassInfo, nullptr, &renderPass);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create render pass");
|
||||||
throw std::runtime_error("Could not create render pass");
|
|
||||||
auto obj = std::make_unique<VulkanRenderPass>(device, renderPass);
|
auto obj = std::make_unique<VulkanRenderPass>(device, renderPass);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -1466,9 +1321,8 @@ QueueSubmit& QueueSubmit::AddSignal(VulkanSemaphore* semaphore)
|
||||||
|
|
||||||
void QueueSubmit::Execute(VulkanDevice* device, VkQueue queue, VulkanFence* fence)
|
void QueueSubmit::Execute(VulkanDevice* device, VkQueue queue, VulkanFence* fence)
|
||||||
{
|
{
|
||||||
VkResult result = vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE);
|
VkResult result = vkQueueSubmit(device->GraphicsQueue, 1, &submitInfo, fence ? fence->fence : VK_NULL_HANDLE);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not submit command buffer");
|
||||||
throw std::runtime_error("Could not submit command buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1501,28 +1355,6 @@ WriteDescriptors& WriteDescriptors::AddBuffer(VulkanDescriptorSet* descriptorSet
|
||||||
return *this;
|
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)
|
WriteDescriptors& WriteDescriptors::AddStorageImage(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VkImageLayout imageLayout)
|
||||||
{
|
{
|
||||||
VkDescriptorImageInfo imageInfo = {};
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
|
@ -1546,10 +1378,15 @@ WriteDescriptors& WriteDescriptors::AddStorageImage(VulkanDescriptorSet* descrip
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet* descriptorSet, int binding, VulkanImageView* view, VulkanSampler* sampler, VkImageLayout imageLayout)
|
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 = {};
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
imageInfo.imageView = view->view;
|
imageInfo.imageView = view->view;
|
||||||
imageInfo.sampler = sampler ? sampler->sampler : nullptr;
|
imageInfo.sampler = sampler->sampler;
|
||||||
imageInfo.imageLayout = imageLayout;
|
imageInfo.imageLayout = imageLayout;
|
||||||
|
|
||||||
auto extra = std::make_unique<WriteExtra>();
|
auto extra = std::make_unique<WriteExtra>();
|
||||||
|
@ -1559,7 +1396,7 @@ WriteDescriptors& WriteDescriptors::AddCombinedImageSampler(VulkanDescriptorSet*
|
||||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptorWrite.dstSet = descriptorSet->set;
|
descriptorWrite.dstSet = descriptorSet->set;
|
||||||
descriptorWrite.dstBinding = binding;
|
descriptorWrite.dstBinding = binding;
|
||||||
descriptorWrite.dstArrayElement = 0;
|
descriptorWrite.dstArrayElement = arrayIndex;
|
||||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
descriptorWrite.descriptorCount = 1;
|
descriptorWrite.descriptorCount = 1;
|
||||||
descriptorWrite.pImageInfo = &extra->imageInfo;
|
descriptorWrite.pImageInfo = &extra->imageInfo;
|
||||||
|
@ -1591,5 +1428,6 @@ WriteDescriptors& WriteDescriptors::AddAccelerationStructure(VulkanDescriptorSet
|
||||||
|
|
||||||
void WriteDescriptors::Execute(VulkanDevice* device)
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "vulkanobjects.h"
|
#include "vulkanobjects.h"
|
||||||
#include "framework/zstring.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
class ImageBuilder
|
class ImageBuilder
|
||||||
|
@ -55,6 +54,7 @@ public:
|
||||||
SamplerBuilder& MagFilter(VkFilter magFilter);
|
SamplerBuilder& MagFilter(VkFilter magFilter);
|
||||||
SamplerBuilder& MipmapMode(VkSamplerMipmapMode mode);
|
SamplerBuilder& MipmapMode(VkSamplerMipmapMode mode);
|
||||||
SamplerBuilder& Anisotropy(float maxAnisotropy);
|
SamplerBuilder& Anisotropy(float maxAnisotropy);
|
||||||
|
SamplerBuilder& MipLodBias(float bias);
|
||||||
SamplerBuilder& MaxLod(float value);
|
SamplerBuilder& MaxLod(float value);
|
||||||
SamplerBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
SamplerBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
|
@ -88,20 +88,17 @@ class ShaderBuilder
|
||||||
public:
|
public:
|
||||||
ShaderBuilder();
|
ShaderBuilder();
|
||||||
|
|
||||||
ShaderBuilder& VertexShader(const FString &code);
|
static void Init();
|
||||||
ShaderBuilder& FragmentShader(const FString &code);
|
static void Deinit();
|
||||||
ShaderBuilder& RayGenShader(const FString& code);
|
|
||||||
ShaderBuilder& IntersectShader(const FString& code);
|
ShaderBuilder& VertexShader(const std::string &code);
|
||||||
ShaderBuilder& AnyHitShader(const FString& code);
|
ShaderBuilder& FragmentShader(const std::string&code);
|
||||||
ShaderBuilder& ClosestHitShader(const FString& code);
|
|
||||||
ShaderBuilder& MissShader(const FString& code);
|
|
||||||
ShaderBuilder& CallableShader(const FString& code);
|
|
||||||
ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
ShaderBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
std::unique_ptr<VulkanShader> Create(const char *shadername, VulkanDevice *device);
|
std::unique_ptr<VulkanShader> Create(const char *shadername, VulkanDevice *device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FString code;
|
std::string code;
|
||||||
int stage = 0;
|
int stage = 0;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -123,29 +120,6 @@ private:
|
||||||
const char* debugName = nullptr;
|
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
|
class ComputePipelineBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -168,14 +142,17 @@ class DescriptorSetLayoutBuilder
|
||||||
public:
|
public:
|
||||||
DescriptorSetLayoutBuilder();
|
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; }
|
DescriptorSetLayoutBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
|
||||||
std::unique_ptr<VulkanDescriptorSetLayout> Create(VulkanDevice *device);
|
std::unique_ptr<VulkanDescriptorSetLayout> Create(VulkanDevice *device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VkDescriptorSetLayoutCreateInfo layoutInfo = {};
|
VkDescriptorSetLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||||
TArray<VkDescriptorSetLayoutBinding> bindings;
|
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;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,6 +161,7 @@ class DescriptorPoolBuilder
|
||||||
public:
|
public:
|
||||||
DescriptorPoolBuilder();
|
DescriptorPoolBuilder();
|
||||||
|
|
||||||
|
DescriptorPoolBuilder& Flags(VkDescriptorPoolCreateFlags flags);
|
||||||
DescriptorPoolBuilder& MaxSets(int value);
|
DescriptorPoolBuilder& MaxSets(int value);
|
||||||
DescriptorPoolBuilder& AddPoolSize(VkDescriptorType type, int count);
|
DescriptorPoolBuilder& AddPoolSize(VkDescriptorType type, int count);
|
||||||
DescriptorPoolBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
DescriptorPoolBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
@ -388,9 +366,9 @@ class WriteDescriptors
|
||||||
public:
|
public:
|
||||||
WriteDescriptors& AddBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer);
|
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& 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& 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, 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);
|
WriteDescriptors& AddAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct);
|
||||||
void Execute(VulkanDevice *device);
|
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 "vulkandevice.h"
|
||||||
#include "vulkanobjects.h"
|
#include "vulkanobjects.h"
|
||||||
#include "stacktrace.h"
|
#include "vulkancompatibledevice.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#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
|
PhysicalDevice = *selectedDevice.Device;
|
||||||
if (HMODULE mod = GetModuleHandle(TEXT("renderdoc.dll")))
|
EnabledDeviceExtensions = selectedDevice.EnabledDeviceExtensions;
|
||||||
{
|
EnabledFeatures = selectedDevice.EnabledFeatures;
|
||||||
pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
|
|
||||||
int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_4_2, (void**)&renderdoc);
|
GraphicsFamily = selectedDevice.GraphicsFamily;
|
||||||
if (ret != 1)
|
PresentFamily = selectedDevice.PresentFamily;
|
||||||
renderdoc = nullptr;
|
GraphicsTimeQueries = selectedDevice.GraphicsTimeQueries;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ShInitialize();
|
CreateDevice();
|
||||||
initVolk();
|
CreateAllocator();
|
||||||
createInstance();
|
|
||||||
selectPhysicalDevice();
|
|
||||||
selectFeatures();
|
|
||||||
createDevice();
|
|
||||||
createAllocator();
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
releaseResources();
|
ReleaseResources();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanDevice::~VulkanDevice()
|
VulkanDevice::~VulkanDevice()
|
||||||
{
|
{
|
||||||
releaseResources();
|
ReleaseResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::selectFeatures()
|
bool VulkanDevice::SupportsDeviceExtension(const char* ext) const
|
||||||
{
|
{
|
||||||
enabledDeviceFeatures.samplerAnisotropy = physicalDevice.features.samplerAnisotropy;
|
return std::find(EnabledDeviceExtensions.begin(), EnabledDeviceExtensions.end(), ext) != EnabledDeviceExtensions.end();
|
||||||
enabledDeviceFeatures.fragmentStoresAndAtomics = physicalDevice.features.fragmentStoresAndAtomics;
|
|
||||||
enabledDeviceFeatures.depthClamp = physicalDevice.features.depthClamp;
|
|
||||||
enabledDeviceFeatures.shaderClipDistance = physicalDevice.features.shaderClipDistance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::checkRequiredFeatures(const VkPhysicalDeviceFeatures &f)
|
void VulkanDevice::CreateAllocator()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
VmaAllocatorCreateInfo allocinfo = {};
|
VmaAllocatorCreateInfo allocinfo = {};
|
||||||
allocinfo.vulkanApiVersion = ApiVersion;
|
allocinfo.vulkanApiVersion = Instance->ApiVersion;
|
||||||
if (supportsDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) && supportsDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME))
|
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_KHR_DEDICATED_ALLOCATION_BIT;
|
||||||
allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
if (SupportsDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
|
||||||
allocinfo.physicalDevice = physicalDevice.device;
|
allocinfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||||
|
allocinfo.physicalDevice = PhysicalDevice.Device;
|
||||||
allocinfo.device = device;
|
allocinfo.device = device;
|
||||||
|
allocinfo.instance = Instance->Instance;
|
||||||
allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024;
|
allocinfo.preferredLargeHeapBlockSize = 64 * 1024 * 1024;
|
||||||
allocinfo.instance = instance;
|
|
||||||
if (vmaCreateAllocator(&allocinfo, &allocator) != VK_SUCCESS)
|
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;
|
float queuePriority = 1.0f;
|
||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
|
||||||
std::set<int> neededFamilies;
|
std::set<int> neededFamilies;
|
||||||
neededFamilies.insert(graphicsFamily);
|
if (GraphicsFamily != -1)
|
||||||
if (presentFamily != -1)
|
neededFamilies.insert(GraphicsFamily);
|
||||||
neededFamilies.insert(presentFamily);
|
if (PresentFamily != -1)
|
||||||
|
neededFamilies.insert(PresentFamily);
|
||||||
|
|
||||||
for (int index : neededFamilies)
|
for (int index : neededFamilies)
|
||||||
{
|
{
|
||||||
|
@ -200,359 +75,85 @@ void VulkanDevice::createDevice()
|
||||||
queueCreateInfos.push_back(queueCreateInfo);
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPhysicalDeviceRayQueryFeaturesKHR rayqueryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR };
|
std::vector<const char*> extensionNames;
|
||||||
rayqueryFeatures.rayQuery = true;
|
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 };
|
VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
|
||||||
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;
|
|
||||||
deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();
|
deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();
|
||||||
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
//deviceCreateInfo.pEnabledFeatures = &enabledDeviceFeatures;
|
deviceCreateInfo.enabledExtensionCount = (uint32_t)extensionNames.size();
|
||||||
deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
|
deviceCreateInfo.ppEnabledExtensionNames = extensionNames.data();
|
||||||
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
|
|
||||||
deviceCreateInfo.enabledLayerCount = 0;
|
deviceCreateInfo.enabledLayerCount = 0;
|
||||||
|
|
||||||
VkResult result = vkCreateDevice(physicalDevice.device, &deviceCreateInfo, nullptr, &device);
|
VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
|
||||||
if (result != VK_SUCCESS)
|
deviceFeatures2.features = EnabledFeatures.Features;
|
||||||
throw std::runtime_error("Could not create vulkan device");
|
|
||||||
|
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);
|
volkLoadDevice(device);
|
||||||
|
|
||||||
vkGetDeviceQueue(device, graphicsFamily, 0, &graphicsQueue);
|
if (GraphicsFamily != -1)
|
||||||
if (presentFamily != -1)
|
vkGetDeviceQueue(device, GraphicsFamily, 0, &GraphicsQueue);
|
||||||
vkGetDeviceQueue(device, presentFamily, 0, &presentQueue);
|
if (PresentFamily != -1)
|
||||||
|
vkGetDeviceQueue(device, PresentFamily, 0, &PresentQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void VulkanDevice::ReleaseResources()
|
||||||
#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()
|
|
||||||
{
|
{
|
||||||
if (device)
|
if (device)
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
||||||
if (allocator)
|
if (allocator)
|
||||||
vmaDestroyAllocator(allocator);
|
vmaDestroyAllocator(allocator);
|
||||||
allocator = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
if (device)
|
if (device)
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
device = VK_NULL_HANDLE;
|
device = nullptr;
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (!DebugLayerActive) return;
|
||||||
{
|
|
||||||
if ((typeFilter & (1 << i)) && (physicalDevice.memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "vulkaninstance.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
#ifdef WIN32
|
#include <vector>
|
||||||
#define VK_USE_PLATFORM_WIN32_KHR
|
#include <algorithm>
|
||||||
#endif
|
#include <memory>
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
class VulkanSwapChain;
|
class VulkanSwapChain;
|
||||||
class VulkanSemaphore;
|
class VulkanSemaphore;
|
||||||
class VulkanFence;
|
class VulkanFence;
|
||||||
|
class VulkanPhysicalDevice;
|
||||||
class VulkanPhysicalDevice
|
class VulkanSurface;
|
||||||
{
|
class VulkanCompatibleDevice;
|
||||||
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 VulkanDevice
|
class VulkanDevice
|
||||||
{
|
{
|
||||||
public:
|
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();
|
~VulkanDevice();
|
||||||
|
|
||||||
void setDebugObjectName(const char *name, uint64_t handle, VkObjectType type)
|
std::vector<std::string> EnabledDeviceExtensions;
|
||||||
{
|
VulkanDeviceFeatures EnabledFeatures;
|
||||||
if (!debugLayerActive) return;
|
|
||||||
|
|
||||||
VkDebugUtilsObjectNameInfoEXT info = {};
|
VulkanPhysicalDevice PhysicalDevice;
|
||||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
|
||||||
info.objectHandle = handle;
|
|
||||||
info.objectType = type;
|
|
||||||
info.pObjectName = name;
|
|
||||||
vkSetDebugUtilsObjectNameEXT(device, &info);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
VmaAllocator allocator = VK_NULL_HANDLE;
|
VmaAllocator allocator = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
VkQueue GraphicsQueue = VK_NULL_HANDLE;
|
||||||
VkQueue presentQueue = VK_NULL_HANDLE;
|
VkQueue PresentQueue = VK_NULL_HANDLE;
|
||||||
|
|
||||||
int graphicsFamily = -1;
|
int GraphicsFamily = -1;
|
||||||
int presentFamily = -1;
|
int PresentFamily = -1;
|
||||||
|
bool GraphicsTimeQueries = false;
|
||||||
|
|
||||||
// Physical device info
|
bool SupportsDeviceExtension(const char* ext) const;
|
||||||
std::vector<VulkanPhysicalDevice> availableDevices;
|
|
||||||
std::vector<VulkanCompatibleDevice> supportedDevices;
|
|
||||||
|
|
||||||
uint32_t ApiVersion = VK_API_VERSION_1_2;
|
void SetObjectName(const char* name, uint64_t handle, VkObjectType type);
|
||||||
|
|
||||||
RENDERDOC_API_1_4_2* renderdoc = nullptr;
|
|
||||||
|
|
||||||
static void initVolk();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int vk_device;
|
bool DebugLayerActive = false;
|
||||||
bool vk_debug;
|
|
||||||
|
|
||||||
void createInstance();
|
void CreateDevice();
|
||||||
//void createSurface();
|
void CreateAllocator();
|
||||||
void selectPhysicalDevice();
|
void ReleaseResources();
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
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 "vulkandevice.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
class VulkanCommandPool;
|
class VulkanCommandPool;
|
||||||
class VulkanDescriptorPool;
|
class VulkanDescriptorPool;
|
||||||
class VulkanCommandBuffer;
|
class VulkanCommandBuffer;
|
||||||
|
@ -15,7 +12,7 @@ public:
|
||||||
VulkanSemaphore(VulkanDevice *device);
|
VulkanSemaphore(VulkanDevice *device);
|
||||||
~VulkanSemaphore();
|
~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;
|
VulkanDevice *device = nullptr;
|
||||||
VkSemaphore semaphore = VK_NULL_HANDLE;
|
VkSemaphore semaphore = VK_NULL_HANDLE;
|
||||||
|
@ -31,7 +28,7 @@ public:
|
||||||
VulkanFence(VulkanDevice *device);
|
VulkanFence(VulkanDevice *device);
|
||||||
~VulkanFence();
|
~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;
|
VulkanDevice *device = nullptr;
|
||||||
VkFence fence = VK_NULL_HANDLE;
|
VkFence fence = VK_NULL_HANDLE;
|
||||||
|
@ -54,7 +51,12 @@ public:
|
||||||
return vkGetBufferDeviceAddress(device->device, &info);
|
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;
|
VulkanDevice *device = nullptr;
|
||||||
|
|
||||||
|
@ -76,7 +78,7 @@ public:
|
||||||
VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer);
|
VulkanFramebuffer(VulkanDevice *device, VkFramebuffer framebuffer);
|
||||||
~VulkanFramebuffer();
|
~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;
|
VulkanDevice *device;
|
||||||
VkFramebuffer framebuffer;
|
VkFramebuffer framebuffer;
|
||||||
|
@ -92,7 +94,7 @@ public:
|
||||||
VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount);
|
VulkanImage(VulkanDevice *device, VkImage image, VmaAllocation allocation, int width, int height, int mipLevels, int layerCount);
|
||||||
~VulkanImage();
|
~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;
|
VkImage image = VK_NULL_HANDLE;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
@ -117,7 +119,7 @@ public:
|
||||||
VulkanImageView(VulkanDevice *device, VkImageView view);
|
VulkanImageView(VulkanDevice *device, VkImageView view);
|
||||||
~VulkanImageView();
|
~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;
|
VkImageView view = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
@ -134,7 +136,7 @@ public:
|
||||||
VulkanSampler(VulkanDevice *device, VkSampler sampler);
|
VulkanSampler(VulkanDevice *device, VkSampler sampler);
|
||||||
~VulkanSampler();
|
~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;
|
VkSampler sampler = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
@ -151,7 +153,7 @@ public:
|
||||||
VulkanShader(VulkanDevice *device, VkShaderModule module);
|
VulkanShader(VulkanDevice *device, VkShaderModule module);
|
||||||
~VulkanShader();
|
~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;
|
VkShaderModule module = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
@ -168,7 +170,7 @@ public:
|
||||||
VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout);
|
VulkanDescriptorSetLayout(VulkanDevice *device, VkDescriptorSetLayout layout);
|
||||||
~VulkanDescriptorSetLayout();
|
~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;
|
VulkanDevice *device;
|
||||||
VkDescriptorSetLayout layout;
|
VkDescriptorSetLayout layout;
|
||||||
|
@ -184,7 +186,12 @@ public:
|
||||||
VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set);
|
VulkanDescriptorSet(VulkanDevice *device, VulkanDescriptorPool *pool, VkDescriptorSet set);
|
||||||
~VulkanDescriptorSet();
|
~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;
|
VulkanDevice *device;
|
||||||
VulkanDescriptorPool *pool;
|
VulkanDescriptorPool *pool;
|
||||||
|
@ -201,14 +208,26 @@ public:
|
||||||
VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool);
|
VulkanDescriptorPool(VulkanDevice *device, VkDescriptorPool pool);
|
||||||
~VulkanDescriptorPool();
|
~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);
|
||||||
|
std::unique_ptr<VulkanDescriptorSet> allocate(VulkanDescriptorSetLayout* layout, uint32_t bindlessCount);
|
||||||
|
|
||||||
VulkanDevice *device;
|
VulkanDevice *device;
|
||||||
VkDescriptorPool pool;
|
VkDescriptorPool pool;
|
||||||
|
|
||||||
private:
|
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(const VulkanDescriptorPool &) = delete;
|
||||||
VulkanDescriptorPool &operator=(const VulkanDescriptorPool &) = delete;
|
VulkanDescriptorPool &operator=(const VulkanDescriptorPool &) = delete;
|
||||||
};
|
};
|
||||||
|
@ -219,7 +238,7 @@ public:
|
||||||
VulkanQueryPool(VulkanDevice *device, VkQueryPool pool);
|
VulkanQueryPool(VulkanDevice *device, VkQueryPool pool);
|
||||||
~VulkanQueryPool();
|
~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);
|
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);
|
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;
|
VulkanDevice* device;
|
||||||
VkAccelerationStructureKHR accelstruct;
|
VkAccelerationStructureKHR accelstruct;
|
||||||
|
@ -257,14 +276,13 @@ private:
|
||||||
class VulkanPipeline
|
class VulkanPipeline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanPipeline(VulkanDevice *device, VkPipeline pipeline, std::vector<uint8_t> shaderGroupHandles = {});
|
VulkanPipeline(VulkanDevice *device, VkPipeline pipeline);
|
||||||
~VulkanPipeline();
|
~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;
|
VulkanDevice *device;
|
||||||
VkPipeline pipeline;
|
VkPipeline pipeline;
|
||||||
std::vector<uint8_t> shaderGroupHandles;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VulkanPipeline(const VulkanPipeline &) = delete;
|
VulkanPipeline(const VulkanPipeline &) = delete;
|
||||||
|
@ -277,7 +295,7 @@ public:
|
||||||
VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout);
|
VulkanPipelineLayout(VulkanDevice *device, VkPipelineLayout layout);
|
||||||
~VulkanPipelineLayout();
|
~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;
|
VulkanDevice *device;
|
||||||
VkPipelineLayout layout;
|
VkPipelineLayout layout;
|
||||||
|
@ -293,7 +311,7 @@ public:
|
||||||
VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass);
|
VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass);
|
||||||
~VulkanRenderPass();
|
~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;
|
VulkanDevice *device;
|
||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
|
@ -308,9 +326,9 @@ class RenderPassBegin
|
||||||
public:
|
public:
|
||||||
RenderPassBegin();
|
RenderPassBegin();
|
||||||
|
|
||||||
RenderPassBegin& RenderPass(VulkanRenderPass *renderpass);
|
RenderPassBegin& RenderPass(VulkanRenderPass* renderpass);
|
||||||
RenderPassBegin& RenderArea(int x, int y, int width, int height);
|
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& AddClearColor(float r, float g, float b, float a);
|
||||||
RenderPassBegin& AddClearDepth(float value);
|
RenderPassBegin& AddClearDepth(float value);
|
||||||
RenderPassBegin& AddClearStencil(int 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 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(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 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 beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents);
|
||||||
void nextSubpass(VkSubpassContents contents);
|
void nextSubpass(VkSubpassContents contents);
|
||||||
void endRenderPass();
|
void endRenderPass();
|
||||||
|
@ -410,7 +429,7 @@ public:
|
||||||
VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex);
|
VulkanCommandPool(VulkanDevice *device, int queueFamilyIndex);
|
||||||
~VulkanCommandPool();
|
~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();
|
std::unique_ptr<VulkanCommandBuffer> createBuffer();
|
||||||
|
|
||||||
|
@ -432,8 +451,7 @@ inline VulkanSemaphore::VulkanSemaphore(VulkanDevice *device) : device(device)
|
||||||
VkSemaphoreCreateInfo semaphoreInfo = {};
|
VkSemaphoreCreateInfo semaphoreInfo = {};
|
||||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
VkResult result = vkCreateSemaphore(device->device, &semaphoreInfo, nullptr, &semaphore);
|
VkResult result = vkCreateSemaphore(device->device, &semaphoreInfo, nullptr, &semaphore);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create semaphore");
|
||||||
throw std::runtime_error("Failed to create semaphore!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanSemaphore::~VulkanSemaphore()
|
inline VulkanSemaphore::~VulkanSemaphore()
|
||||||
|
@ -448,8 +466,7 @@ inline VulkanFence::VulkanFence(VulkanDevice *device) : device(device)
|
||||||
VkFenceCreateInfo fenceInfo = {};
|
VkFenceCreateInfo fenceInfo = {};
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
VkResult result = vkCreateFence(device->device, &fenceInfo, nullptr, &fence);
|
VkResult result = vkCreateFence(device->device, &fenceInfo, nullptr, &fence);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create fence!");
|
||||||
throw std::runtime_error("Failed to create fence!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanFence::~VulkanFence()
|
inline VulkanFence::~VulkanFence()
|
||||||
|
@ -490,8 +507,7 @@ inline VulkanCommandPool::VulkanCommandPool(VulkanDevice *device, int queueFamil
|
||||||
poolInfo.flags = 0;
|
poolInfo.flags = 0;
|
||||||
|
|
||||||
VkResult result = vkCreateCommandPool(device->device, &poolInfo, nullptr, &pool);
|
VkResult result = vkCreateCommandPool(device->device, &poolInfo, nullptr, &pool);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create command pool");
|
||||||
throw std::runtime_error("Could not create command pool");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanCommandPool::~VulkanCommandPool()
|
inline VulkanCommandPool::~VulkanCommandPool()
|
||||||
|
@ -511,7 +527,7 @@ inline RenderPassBegin::RenderPassBegin()
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
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;
|
renderPassInfo.renderPass = renderPass->renderPass;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -526,7 +542,7 @@ inline RenderPassBegin& RenderPassBegin::RenderArea(int x, int y, int width, int
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RenderPassBegin& RenderPassBegin::Framebuffer(VulkanFramebuffer *framebuffer)
|
inline RenderPassBegin& RenderPassBegin::Framebuffer(VulkanFramebuffer* framebuffer)
|
||||||
{
|
{
|
||||||
renderPassInfo.framebuffer = framebuffer->framebuffer;
|
renderPassInfo.framebuffer = framebuffer->framebuffer;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -593,8 +609,7 @@ inline VulkanCommandBuffer::VulkanCommandBuffer(VulkanCommandPool *pool) : pool(
|
||||||
allocInfo.commandBufferCount = 1;
|
allocInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
VkResult result = vkAllocateCommandBuffers(pool->device->device, &allocInfo, &buffer);
|
VkResult result = vkAllocateCommandBuffers(pool->device->device, &allocInfo, &buffer);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not create command buffer");
|
||||||
throw std::runtime_error("Could not create command buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VulkanCommandBuffer::~VulkanCommandBuffer()
|
inline VulkanCommandBuffer::~VulkanCommandBuffer()
|
||||||
|
@ -606,19 +621,17 @@ inline void VulkanCommandBuffer::begin()
|
||||||
{
|
{
|
||||||
VkCommandBufferBeginInfo beginInfo = {};
|
VkCommandBufferBeginInfo beginInfo = {};
|
||||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
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;
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
|
|
||||||
VkResult result = vkBeginCommandBuffer(buffer, &beginInfo);
|
VkResult result = vkBeginCommandBuffer(buffer, &beginInfo);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not begin recording command buffer");
|
||||||
throw std::runtime_error("Failed to begin recording command buffer!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void VulkanCommandBuffer::end()
|
inline void VulkanCommandBuffer::end()
|
||||||
{
|
{
|
||||||
VkResult result = vkEndCommandBuffer(buffer);
|
VkResult result = vkEndCommandBuffer(buffer);
|
||||||
if (result != VK_SUCCESS)
|
CheckVulkanError(result, "Could not end command buffer recording");
|
||||||
throw std::runtime_error("Failed to record command buffer!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void VulkanCommandBuffer::debugFullPipelineBarrier()
|
inline void VulkanCommandBuffer::debugFullPipelineBarrier()
|
||||||
|
@ -910,6 +923,11 @@ inline void VulkanCommandBuffer::pushConstants(VkPipelineLayout layout, VkShader
|
||||||
vkCmdPushConstants(buffer, layout, stageFlags, offset, size, pValues);
|
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)
|
inline void VulkanCommandBuffer::beginRenderPass(const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents)
|
||||||
{
|
{
|
||||||
vkCmdBeginRenderPass(buffer, pRenderPassBegin, contents);
|
vkCmdBeginRenderPass(buffer, pRenderPassBegin, contents);
|
||||||
|
@ -947,7 +965,7 @@ inline void VulkanCommandBuffer::writeAccelerationStructuresProperties(uint32_t
|
||||||
|
|
||||||
inline void VulkanCommandBuffer::SetDebugName(const char *name)
|
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);
|
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 = {};
|
VkDescriptorSetAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
allocInfo.descriptorPool = pool;
|
allocInfo.descriptorPool = pool;
|
||||||
allocInfo.descriptorSetCount = 1;
|
allocInfo.descriptorSetCount = 1;
|
||||||
allocInfo.pSetLayouts = &layout->layout;
|
allocInfo.pSetLayouts = &layout->layout;
|
||||||
|
|
||||||
VkDescriptorSet descriptorSet;
|
VkDescriptorSet descriptorSet;
|
||||||
VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet);
|
VkResult result = vkAllocateDescriptorSets(device->device, &allocInfo, &descriptorSet);
|
||||||
if (result != VK_SUCCESS)
|
if (allocType == AllocType::TryAllocate && result != VK_SUCCESS)
|
||||||
throw std::runtime_error("Could not allocate descriptor sets");
|
return nullptr;
|
||||||
|
else
|
||||||
|
CheckVulkanError(result, "Could not allocate descriptor sets");
|
||||||
return std::make_unique<VulkanDescriptorSet>(device, this, descriptorSet);
|
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)
|
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)
|
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);
|
VkResult result = vkGetQueryPoolResults(device->device, pool, firstQuery, queryCount, dataSize, data, stride, flags);
|
||||||
if (result != VK_SUCCESS && result != VK_NOT_READY)
|
CheckVulkanError(result, "vkGetQueryPoolResults failed");
|
||||||
throw std::runtime_error("vkGetQueryPoolResults failed");
|
|
||||||
return result == VK_SUCCESS;
|
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 */
|
/* This file is part of volk library; see volk.h for version/license details */
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#include "volk.h"
|
#include "volk.h"
|
||||||
|
|
Loading…
Reference in a new issue