mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 21:58:45 +03:00
371 lines
16 KiB
C++
371 lines
16 KiB
C++
#include "rhi.h"
|
|
|
|
namespace engine
|
|
{
|
|
static AutoCVarBool cVarRHIHDRFeatureEnable(
|
|
"r.RHI.HDREnable",
|
|
"Enable hdr feature or not.",
|
|
"RHI",
|
|
false,
|
|
CVarFlags::ReadOnly
|
|
);
|
|
|
|
static AutoCVarBool cVarRHIRayTraceFeatureEnable(
|
|
"r.RHI.RayTraceEnable",
|
|
"Enable ray trace feature or not.",
|
|
"RHI",
|
|
true,
|
|
CVarFlags::ReadOnly
|
|
);
|
|
|
|
void VulkanContext::initDeviceAndQueue()
|
|
{
|
|
ASSERT(m_gpu != VK_NULL_HANDLE, "You must select one gpu before init device.");
|
|
|
|
// Query all useful device extensions.
|
|
uint32_t deviceExtensionCount;
|
|
vkEnumerateDeviceExtensionProperties(m_gpu, nullptr, &deviceExtensionCount, nullptr);
|
|
std::vector<VkExtensionProperties> availableDeviceExtensions(deviceExtensionCount);
|
|
vkEnumerateDeviceExtensionProperties(m_gpu, nullptr, &deviceExtensionCount, availableDeviceExtensions.data());
|
|
|
|
auto existDeviceExtension = [&](const char* name)
|
|
{
|
|
for (auto& availableExtension : availableDeviceExtensions)
|
|
{
|
|
if (strcmp(availableExtension.extensionName, name) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
std::vector<const char*> deviceExtensionNames{ };
|
|
|
|
// Some basic device extension always require support.
|
|
deviceExtensionNames.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_KHR_8BIT_STORAGE_EXTENSION_NAME);
|
|
deviceExtensionNames.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
|
|
|
if (m_engine->isWindowApp())
|
|
{
|
|
deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
}
|
|
|
|
auto tryInsertIfExistExtension = [&](const char* name)
|
|
{
|
|
if (existDeviceExtension(name))
|
|
{
|
|
deviceExtensionNames.push_back(name);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// HDR extension.
|
|
m_graphicsSupportStates.bSupportHDR = m_engine->isWindowApp() && cVarRHIHDRFeatureEnable.get();
|
|
if (m_graphicsSupportStates.bSupportHDR)
|
|
{
|
|
m_graphicsSupportStates.bSupportHDR &= tryInsertIfExistExtension(VK_EXT_HDR_METADATA_EXTENSION_NAME);
|
|
}
|
|
|
|
// Raytracing extension.
|
|
m_graphicsSupportStates.bSupportRaytrace = cVarRHIRayTraceFeatureEnable.get();
|
|
if (m_graphicsSupportStates.bSupportRaytrace)
|
|
{
|
|
m_graphicsSupportStates.bSupportRaytrace &= tryInsertIfExistExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
|
m_graphicsSupportStates.bSupportRaytrace &= tryInsertIfExistExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
|
|
m_graphicsSupportStates.bSupportRaytrace &= tryInsertIfExistExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME);
|
|
m_graphicsSupportStates.bSupportRaytrace &= tryInsertIfExistExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
|
|
}
|
|
|
|
// Current only nvidia support Meshshader, so we don't use it, we simulate by compute shader.
|
|
// deviceExtensionNames.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME);
|
|
|
|
// Standard core features.
|
|
VkPhysicalDeviceFeatures enable10GpuFeatures = {}; // vulkan 1.0
|
|
VkPhysicalDeviceVulkan11Features enable11GpuFeatures = {}; // vulkan 1.1
|
|
VkPhysicalDeviceVulkan12Features enable12GpuFeatures = {}; // vulkan 1.2
|
|
VkPhysicalDeviceVulkan13Features enable13GpuFeatures = {}; // vulkan 1.3
|
|
|
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR };
|
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR };
|
|
VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR };
|
|
|
|
// Enable gpu features 1.0 here.
|
|
enable10GpuFeatures.samplerAnisotropy = true;
|
|
enable10GpuFeatures.depthClamp = true;
|
|
enable10GpuFeatures.shaderSampledImageArrayDynamicIndexing = true;
|
|
enable10GpuFeatures.multiDrawIndirect = VK_TRUE;
|
|
enable10GpuFeatures.drawIndirectFirstInstance = VK_TRUE;
|
|
enable10GpuFeatures.independentBlend = VK_TRUE;
|
|
enable10GpuFeatures.multiViewport = VK_TRUE;
|
|
enable10GpuFeatures.fragmentStoresAndAtomics = VK_TRUE;
|
|
enable10GpuFeatures.shaderInt16 = VK_TRUE;
|
|
enable10GpuFeatures.fillModeNonSolid = VK_TRUE;
|
|
|
|
// Enable gpu features 1.1 here.
|
|
enable11GpuFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
|
|
enable11GpuFeatures.pNext = &enable12GpuFeatures;
|
|
enable11GpuFeatures.shaderDrawParameters = VK_TRUE;
|
|
|
|
// Enable gpu features 1.2 here.
|
|
enable12GpuFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
|
enable12GpuFeatures.pNext = &enable13GpuFeatures;
|
|
enable12GpuFeatures.drawIndirectCount = VK_TRUE;
|
|
enable12GpuFeatures.drawIndirectCount = VK_TRUE;
|
|
enable12GpuFeatures.imagelessFramebuffer = VK_TRUE;
|
|
enable12GpuFeatures.separateDepthStencilLayouts = VK_TRUE;
|
|
enable12GpuFeatures.descriptorIndexing = VK_TRUE;
|
|
enable12GpuFeatures.runtimeDescriptorArray = VK_TRUE;
|
|
enable12GpuFeatures.descriptorBindingPartiallyBound = VK_TRUE;
|
|
enable12GpuFeatures.descriptorBindingVariableDescriptorCount = VK_TRUE;
|
|
enable12GpuFeatures.shaderSampledImageArrayNonUniformIndexing = VK_TRUE;
|
|
enable12GpuFeatures.descriptorBindingUpdateUnusedWhilePending = VK_TRUE;
|
|
enable12GpuFeatures.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE;
|
|
enable12GpuFeatures.descriptorBindingStorageBufferUpdateAfterBind = VK_TRUE;
|
|
enable12GpuFeatures.shaderStorageBufferArrayNonUniformIndexing = VK_TRUE;
|
|
enable12GpuFeatures.timelineSemaphore = VK_TRUE;
|
|
enable12GpuFeatures.bufferDeviceAddress = VK_TRUE;
|
|
enable12GpuFeatures.shaderFloat16 = VK_TRUE;
|
|
enable12GpuFeatures.hostQueryReset = VK_TRUE;
|
|
|
|
// Enable gpu features 1.3 here.
|
|
enable13GpuFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
|
enable13GpuFeatures.dynamicRendering = VK_TRUE;
|
|
enable13GpuFeatures.synchronization2 = VK_TRUE;
|
|
enable13GpuFeatures.maintenance4 = VK_TRUE;
|
|
enable13GpuFeatures.pNext = &accelFeature;
|
|
|
|
accelFeature.pNext = &rtPipelineFeature;
|
|
rtPipelineFeature.pNext = &rayQueryFeatures;
|
|
if (m_graphicsSupportStates.bSupportRaytrace)
|
|
{
|
|
accelFeature.accelerationStructure = VK_TRUE;
|
|
rtPipelineFeature.rayTracingPipeline = VK_TRUE;
|
|
rayQueryFeatures.rayQuery = VK_TRUE;
|
|
}
|
|
|
|
// Other features in the future.
|
|
rayQueryFeatures.pNext = nullptr;
|
|
|
|
|
|
// Prepare graphics queue.
|
|
uint32_t queueFamilyCount = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, nullptr);
|
|
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(m_gpu, &queueFamilyCount, queueFamilies.data());
|
|
|
|
uint32_t graphicsQueueCounts = 0;
|
|
uint32_t computeQueueCounts = 0;
|
|
uint32_t copyQueueCounts = 0;
|
|
|
|
bool bGraphicsQueueSet = false;
|
|
bool bCopyQueueSet = false;
|
|
bool bComputeQueueSet = false;
|
|
|
|
uint32_t queueIndex = 0;
|
|
|
|
// NOTE: queueFamilies sort by VkQueueFlagBits in my graphics card, no ensure the order is same with AMD graphics card.
|
|
for (const auto& queueFamily : queueFamilies)
|
|
{
|
|
const bool bSupportGraphics = queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
|
const bool bSupportCompute = (!bSupportGraphics) && (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT); // Only support compute queue.
|
|
const bool bSupportCopy = (!bSupportGraphics) && (!bSupportCompute) && (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT); // Only support copy queue.
|
|
|
|
// Sparse binding.
|
|
const bool bSupportSparseBinding = queueFamily.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT;
|
|
|
|
if (bSupportGraphics && (!bGraphicsQueueSet))
|
|
{
|
|
m_queues.graphicsFamily = queueIndex;
|
|
graphicsQueueCounts = queueFamily.queueCount;
|
|
|
|
bGraphicsQueueSet = true;
|
|
}
|
|
else if (bSupportCompute && (!bComputeQueueSet))
|
|
{
|
|
m_queues.computeFamily = queueIndex;
|
|
computeQueueCounts = queueFamily.queueCount;
|
|
|
|
bComputeQueueSet = true;
|
|
}
|
|
else if (bSupportCopy && (!bCopyQueueSet))
|
|
{
|
|
m_queues.copyFamily = queueIndex;
|
|
copyQueueCounts = queueFamily.queueCount;
|
|
|
|
bCopyQueueSet = true;
|
|
}
|
|
|
|
queueIndex++;
|
|
}
|
|
|
|
ASSERT(graphicsQueueCounts > 2, "We need more than two graphics queues to do some async dispatch.");
|
|
ASSERT(computeQueueCounts > 1, "We need more than one compute queues to do some async dispatch.");
|
|
ASSERT(copyQueueCounts > 1, "We need more than one copy queues to do some async dispatch.");
|
|
|
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
|
|
|
// Prepare queue priority. all 0.5f.
|
|
std::vector<float> graphicsQueuePriority(graphicsQueueCounts, 0.5f);
|
|
std::vector<float> computeQueuePriority(computeQueueCounts, 0.5f);
|
|
std::vector<float> copyQueuePriority(copyQueueCounts, 0.5f);
|
|
|
|
// Major queue use for present and render UI.
|
|
graphicsQueuePriority[0] = 1.0f;
|
|
|
|
// Major compute queue and second major graphics queue.
|
|
computeQueuePriority[0] = 0.8f;
|
|
graphicsQueuePriority[1] = 0.8f;
|
|
|
|
VkDeviceQueueCreateInfo queueCreateInfo{};
|
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
queueCreateInfo.queueFamilyIndex = m_queues.graphicsFamily;
|
|
queueCreateInfo.queueCount = graphicsQueueCounts;
|
|
queueCreateInfo.pQueuePriorities = graphicsQueuePriority.data();
|
|
queueCreateInfos.push_back(queueCreateInfo);
|
|
|
|
if (computeQueueCounts > 0)
|
|
{
|
|
queueCreateInfo.queueFamilyIndex = m_queues.computeFamily;
|
|
queueCreateInfo.queueCount = computeQueueCounts;
|
|
queueCreateInfo.pQueuePriorities = computeQueuePriority.data();
|
|
queueCreateInfos.push_back(queueCreateInfo);
|
|
}
|
|
|
|
if (copyQueueCounts > 0)
|
|
{
|
|
queueCreateInfo.queueFamilyIndex = m_queues.copyFamily;
|
|
queueCreateInfo.queueCount = copyQueueCounts;
|
|
queueCreateInfo.pQueuePriorities = copyQueuePriority.data();
|
|
queueCreateInfos.push_back(queueCreateInfo);
|
|
}
|
|
|
|
VkDeviceCreateInfo createInfo{};
|
|
VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{};
|
|
|
|
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
|
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
|
|
|
// we use physical device features2.
|
|
createInfo.pEnabledFeatures = nullptr;
|
|
createInfo.pNext = &physicalDeviceFeatures2;
|
|
{
|
|
physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
physicalDeviceFeatures2.features = enable10GpuFeatures;
|
|
physicalDeviceFeatures2.pNext = &enable11GpuFeatures;
|
|
}
|
|
|
|
// device extension.
|
|
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensionNames.size());
|
|
createInfo.ppEnabledExtensionNames = deviceExtensionNames.data();
|
|
|
|
// no special device layer, all control by instance layer.
|
|
createInfo.ppEnabledLayerNames = NULL;
|
|
createInfo.enabledLayerCount = 0;
|
|
|
|
RHICheck(vkCreateDevice(m_gpu, &createInfo, nullptr, &m_device));
|
|
|
|
// get major queues.
|
|
m_queues.graphcisQueues.resize(graphicsQueueCounts);
|
|
for (uint32_t id = 0; id < graphicsQueueCounts; id++)
|
|
{
|
|
vkGetDeviceQueue(m_device, m_queues.graphicsFamily, id, &m_queues.graphcisQueues[id]);
|
|
}
|
|
|
|
m_queues.computeQueues.resize(computeQueueCounts);
|
|
for (uint32_t id = 0; id < computeQueueCounts; id++)
|
|
{
|
|
vkGetDeviceQueue(m_device, m_queues.computeFamily, id, &m_queues.computeQueues[id]);
|
|
}
|
|
|
|
m_queues.copyQueues.resize(copyQueueCounts);
|
|
for (uint32_t id = 0; id < copyQueueCounts; id++)
|
|
{
|
|
vkGetDeviceQueue(m_device, m_queues.copyFamily, id, &m_queues.copyQueues[id]);
|
|
}
|
|
|
|
// After create, check feature state to ensure the device is actually support or not.
|
|
if (m_graphicsSupportStates.bSupportRaytrace)
|
|
{
|
|
// Get the acceleration structure features, which we'll need later.
|
|
VkPhysicalDeviceAccelerationStructureFeaturesKHR asFeatures{};
|
|
asFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
|
|
|
|
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeatures{};
|
|
rtPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
|
|
asFeatures.pNext = &rtPipelineFeatures;
|
|
|
|
VkPhysicalDeviceFeatures2 deviceFeatures{};
|
|
deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
deviceFeatures.pNext = &asFeatures;
|
|
|
|
vkGetPhysicalDeviceFeatures2(m_gpu, &deviceFeatures);
|
|
|
|
m_graphicsSupportStates.bSupportRaytrace = (asFeatures.accelerationStructure && rtPipelineFeatures.rayTracingPipeline);
|
|
if (!m_graphicsSupportStates.bSupportRaytrace)
|
|
{
|
|
LOG_WARN("Try enable hardware ray tracing, but no support in your machine, close here.");
|
|
}
|
|
else
|
|
{
|
|
LOG_TRACE("Raytrace extension and feature enable and opening...");
|
|
}
|
|
}
|
|
}
|
|
|
|
void VulkanContext::destroyDevice()
|
|
{
|
|
if (m_device != VK_NULL_HANDLE)
|
|
{
|
|
vkDestroyDevice(m_device, nullptr);
|
|
}
|
|
}
|
|
|
|
VkFormat findSupportedFormat(VkPhysicalDevice gpu, const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
|
|
{
|
|
for (VkFormat format : candidates)
|
|
{
|
|
VkFormatProperties props;
|
|
vkGetPhysicalDeviceFormatProperties(gpu, format, &props);
|
|
|
|
// We hope texture format support tiling for performance.
|
|
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features)
|
|
{
|
|
return format;
|
|
}
|
|
else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features)
|
|
{
|
|
return format;
|
|
}
|
|
}
|
|
return VK_FORMAT_UNDEFINED;
|
|
}
|
|
|
|
void VulkanContext::quertDepthFormatSupportState()
|
|
{
|
|
// Cache some support format.
|
|
m_cacheSupportDepthOnlyFormat = findSupportedFormat(m_gpu,
|
|
{ VK_FORMAT_D32_SFLOAT },
|
|
VK_IMAGE_TILING_OPTIMAL,
|
|
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
|
);
|
|
ASSERT(m_cacheSupportDepthOnlyFormat != VK_FORMAT_UNDEFINED, "No supported depth only format found on require!");
|
|
|
|
m_cacheSupportDepthStencilFormat = findSupportedFormat(m_gpu,
|
|
{ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
|
|
VK_IMAGE_TILING_OPTIMAL,
|
|
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
|
|
);
|
|
ASSERT(m_cacheSupportDepthStencilFormat != VK_FORMAT_UNDEFINED, "No supported depth stencil format found on require!");
|
|
}
|
|
} |