plumageRender/src/render/vulkanFoundation.cpp

2085 lines
79 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "vulkanFoundation.h"
void VulkanBackend::VulkanFoundation::initVulkan(PlumageRender::Setter setter,Camera camera,PlumageRender::renderMain mainRender,UI* plumageGUI)
{
// 创建instance
createInstance(setter);
// 设置校验层消息回调
setupDebugMessager(setter);
// 选择主机显卡
pickPhysicalDevice(setter);
if (!setter.settings.headless)
{
// 实时显示结果的glfw surface
createSurface(setter);
}
// 完成逻辑设备创建
createLogicalDevice(setter);
// 创建交换链
createSwapChain(setter);
// 创建交换链中的imageView
createImageView(setter);
// 创建renderpass
createRenderPass(setter);
// 创建资源描述符层级
createDescriptorSetLayout();
// 创建管线缓存
createPipelineCache();
// 创建图形管线
createGraphicPipeline(setter);
// 创建主要帧缓冲区
createFramebuffer(setter);
// 创建命令缓冲池
createCommandPool(setter);
// 创建统一缓存区
createUniformBuffer(setter,camera,mainRender);
// 创建资源描述存储池
createDescriptorPool(mainRender);
// 创建资源描述符集
createDescriptorSets(setter);
// 分配命令缓存区
allocateCommandBuffers(setter);
// 创建命令缓存区
createCommandBuffer(setter,mainRender,plumageGUI);
}
void VulkanBackend::VulkanFoundation::createInstance(PlumageRender::Setter setter)
{
// check validation layers
if (setter.settings.validation && !checkValidationLayerSupport())
{
throw std::runtime_error("validation layers requsted,but not available");
}
//setup appliaction info
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No_Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
// setup createInfo
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
auto requiredExtensions = getRequiredExtensions(setter);
createInfo.enabledExtensionCount = static_cast<uint32_t>(requiredExtensions.size());
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
// enable validation layer if available in createInfo
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
if (setter.settings.validation)
{
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
populateDebugMessengerCreateInfo(debugCreateInfo);
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
}
else
{
createInfo.enabledLayerCount = 0;
createInfo.pNext = nullptr;
}
// throw error in creating instance
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
{
throw std::runtime_error("failed to create instance");
}
}
bool VulkanBackend::VulkanFoundation::checkValidationLayerSupport()
{
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
// check if validationLayers can be found in availableLayers
for (const char* layerName : validationLayers)
{
bool layerFound = false;
for (const auto& layerProperties : availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0)
{
layerFound = true;
break;
}
}
if (!layerFound)
{
return false;
}
}
return true;
}
std::vector<const char*> VulkanBackend::VulkanFoundation::getRequiredExtensions(PlumageRender::Setter setter)
{
std::vector<const char*> extensions;
if (!setter.settings.headless)
{
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
}
if (setter.settings.validation)
{
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
void VulkanBackend::VulkanFoundation::setupDebugMessager(PlumageRender::Setter setter)
{
if (!setter.settings.validation)
{
return;
}
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
populateDebugMessengerCreateInfo(createInfo);
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS)
{
throw std::runtime_error("failed to set up debug messenger in setupDebugMessenger");
}
}
void VulkanBackend::VulkanFoundation::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugCreateInfo)
{
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
debugCreateInfo.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;
debugCreateInfo.pfnUserCallback = &debugCallback;
debugCreateInfo.pUserData = nullptr;
}
// debugCallback用于校验层
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanBackend::VulkanFoundation::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
{
{
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
return VK_FALSE;
}
}
VkResult VulkanBackend::VulkanFoundation::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
{
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
if (func != nullptr)
{
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
}
else
{
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
void VulkanBackend::VulkanFoundation::createSurface(PlumageRender::Setter setter)
{
if (setter.settings.headless)
{
return;
}
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS)
{
throw std::runtime_error("failed to create window surface in createSurface()");
}
}
void VulkanBackend::VulkanFoundation::pickPhysicalDevice(PlumageRender::Setter setter)
{
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
if (deviceCount == 0)
{
throw std::runtime_error("failed to find GPUs with Vulkan support");
}
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
if (setter.settings.selectedPhysicalDeviceIndex != NULL)
{
physicalDevice = devices[setter.settings.selectedPhysicalDeviceIndex];
}
for (const auto& device : devices)
{
if (isDeviceSuitable(device,setter))
{
physicalDevice = device;
break;
}
}
if (physicalDevice == VK_NULL_HANDLE)
{
throw std::runtime_error("failed to find a suitable GPU");
}
}
bool VulkanBackend::VulkanFoundation::isDeviceSuitable(VkPhysicalDevice device,PlumageRender::Setter setter)
{
if (setter.settings.headless)
{
bool extensionsSupported = checkDeviceExtensionSupport(device);
return extensionsSupported;
}
else
{ // 非无头下在检查扩展支持的同时要检查swapchain
bool extensionsSupported = checkDeviceExtensionSupport(device);
bool swapChainAdequate = false;
QueueFamilyIndices indices = findQueueFamilies(device,setter);
if (extensionsSupported)
{
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
}
}
}
bool VulkanBackend::VulkanFoundation::checkDeviceExtensionSupport(VkPhysicalDevice device)
{
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> requiredExtensions(swapchainExtensions.begin(), swapchainExtensions.end());
for (const auto& extension : availableExtensions)
{
requiredExtensions.erase(extension.extensionName);
}
return requiredExtensions.empty();
}
VulkanBackend::VulkanFoundation::QueueFamilyIndices VulkanBackend::VulkanFoundation::findQueueFamilies(VkPhysicalDevice device,PlumageRender::Setter setter)
{
QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
VkBool32 presentSupport = false;
// 检查显示队列支持
int i = 0;
if (!setter.settings.headless)
{
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
}
for (const auto& queueFamily : queueFamilies)
{
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
}
// 无头下不需要检查present queue
if (setter.settings.headless)
{
if (indices.isGraphicsFamilyComplete())
{
break;
}
}
else
{
if (indices.isGraphicsFamilyComplete() && indices.isPresentFamilyComplete())
{
break;
}
}
if (presentSupport)
{
indices.presentFamily = i;
}
i++;
}
return indices;
}
VulkanBackend::VulkanFoundation::SwapChainSupportDetails VulkanBackend::VulkanFoundation::querySwapChainSupport(VkPhysicalDevice device)
{
// 获得surface细节
SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
// 检查格式支持image
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0)
{
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
// 检查显示模式支持
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
if (presentModeCount != 0)
{
details.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
}
return details;
}
void VulkanBackend::VulkanFoundation::createLogicalDevice(PlumageRender::Setter setter)
{
QueueFamilyIndices indices = findQueueFamilies(physicalDevice,setter);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
if (setter.settings.headless)
{
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
else
{
std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(),indices.presentFamily.value() };
float queuePriority = 1.0f;
for (uint32_t queueFamily : uniqueQueueFamilies)
{
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
}
VkPhysicalDeviceFeatures enableFeatures{};
if (deviceFeatures.samplerAnisotropy) {
enableFeatures.samplerAnisotropy = VK_TRUE;
}
std::vector<const char*> enabledExtensions{};
if (!setter.settings.headless)
{
for (auto swapchainExtension: swapchainExtensions)
{
enabledExtensions.push_back(swapchainExtension);
}
}
VkDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
deviceCreateInfo.pEnabledFeatures = &enableFeatures;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(enabledExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data();
//新版本vulkan已不对实例和设备特定验证层做区分此处保证兼容性
if (setter.settings.validation)
{
deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
}
else
{
deviceCreateInfo.enabledLayerCount = 0;
}
if (vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device) != VK_SUCCESS)
{
throw std::runtime_error("failed to create logical device");
}
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicQueue);
if (setter.settings.headless)
{
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
}
}
void VulkanBackend::VulkanFoundation::createSwapChain(PlumageRender::Setter setter)
{
if (setter.settings.headless)
{
return;
}
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes,setter);
VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount)
{
imageCount = swapChainSupport.capabilities.maxImageCount;
}
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = surface;
createInfo.minImageCount = imageCount;
createInfo.imageFormat = surfaceFormat.format;
createInfo.imageColorSpace = surfaceFormat.colorSpace;
createInfo.imageExtent = extent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
QueueFamilyIndices indices = findQueueFamilies(physicalDevice,setter);
uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(),indices.presentFamily.value() };
if (indices.graphicsFamily != indices.presentFamily)
{
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
createInfo.queueFamilyIndexCount = 2;
createInfo.pQueueFamilyIndices = queueFamilyIndices;
}
else
{
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
}
createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = presentMode;
createInfo.clipped = VK_TRUE;
createInfo.oldSwapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS)
{
throw std::runtime_error("failed to create swap chain !");
}
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
swapChainImages.resize(imageCount);
vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
// store swap format and swap extent to member variable
swapChainImageFormat = surfaceFormat.format;
swapChainExtent = extent;
}
VkSurfaceFormatKHR VulkanBackend::VulkanFoundation::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
{
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8_SRGB && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR)
{
return availableFormat;
}
}
return availableFormats[0];
}
VkPresentModeKHR VulkanBackend::VulkanFoundation::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes, PlumageRender::Setter setter)
{
// Get available present modes
uint32_t presentModeCount;
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL));
assert(presentModeCount > 0);
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
VK_CHECK_RESULT(fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
// This mode waits for the vertical blank ("v-sync")
// 垂直同步模式
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
// If v-sync is not requested, try to find a mailbox mode
// It's the lowest latency non-tearing present mode available
if (!setter.settings.vsync)
{
for (size_t i = 0; i < presentModeCount; i++)
{
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR))
{
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
}
}
VkExtent2D VulkanBackend::VulkanFoundation::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
{
return capabilities.currentExtent;
}
else
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
VkExtent2D actualExtent = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height)
};
actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return actualExtent;
}
}
void VulkanBackend::VulkanFoundation::createImageView(PlumageRender::Setter setter)
{
VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
VkFormat depthFormat = findDepthFormat();
if (setter.settings.headless)
{
if (setter.settings.multiSampling)
{
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = colorAttachmentFormat;
imageCI.extent.width = setter.settings.width;
imageCI.extent.height = setter.settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples = setter.settings.sampleCount;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.colorAttachment.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, multisampleTarget.colorAttachment.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
VkBool32 lazyMemTypePresent;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
if (!lazyMemTypePresent) {
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.colorAttachment.memory));
vkBindImageMemory(device, multisampleTarget.colorAttachment.image, multisampleTarget.colorAttachment.memory, 0);
// Create image view for the MSAA color image target
VkImageViewCreateInfo imageViewCI{};
imageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCI.image = multisampleTarget.colorAttachment.image;
imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCI.format = colorAttachmentFormat;
imageViewCI.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewCI.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewCI.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewCI.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCI.subresourceRange.levelCount = 1;
imageViewCI.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.colorAttachment.view));
// Depth target
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = depthFormat;
imageCI.extent.width =setter.settings.width;
imageCI.extent.height =setter.settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples =setter.settings.sampleCount;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.depthAttachment.image));
vkGetImageMemoryRequirements(device, multisampleTarget.depthAttachment.image, &memReqs);
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
if (!lazyMemTypePresent) {
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &multisampleTarget.depthAttachment.memory));
vkBindImageMemory(device, multisampleTarget.depthAttachment.image, multisampleTarget.depthAttachment.memory, 0);
// Create image view for the MSAA target
imageViewCI.image = multisampleTarget.depthAttachment.image;
imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCI.format = depthFormat;
imageViewCI.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewCI.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewCI.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewCI.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
imageViewCI.subresourceRange.levelCount = 1;
imageViewCI.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.depthAttachment.view));
}
// creat color image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = colorAttachmentFormat;
imageCI.extent.width =setter.settings.width;
imageCI.extent.height =setter.settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &colorAttachment.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device,colorAttachment.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
VkBool32 lazyMemTypePresent;
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, &lazyMemTypePresent);
if (!lazyMemTypePresent) {
memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &colorAttachment.memory));
vkBindImageMemory(device, multisampleTarget.colorAttachment.image, colorAttachment.memory, 0);
// Create image view for the color image
VkImageViewCreateInfo imageViewCI{};
imageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCI.image = colorAttachment.image;
imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCI.format = colorAttachmentFormat;
imageViewCI.components.r = VK_COMPONENT_SWIZZLE_R;
imageViewCI.components.g = VK_COMPONENT_SWIZZLE_G;
imageViewCI.components.b = VK_COMPONENT_SWIZZLE_B;
imageViewCI.components.a = VK_COMPONENT_SWIZZLE_A;
imageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCI.subresourceRange.levelCount = 1;
imageViewCI.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &colorAttachment.view));
// create image for the depth image
VkImageCreateInfo image = {};
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image.pNext = NULL;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = depthFormat;
image.extent.width =setter.settings.width;
image.extent.height =setter.settings.height;
image.extent.depth = 1;
image.mipLevels = 1;
image.arrayLayers = 1;
image.samples = VK_SAMPLE_COUNT_1_BIT;
image.tiling = VK_IMAGE_TILING_OPTIMAL;
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image.flags = 0;
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image));
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAlloc.pNext = NULL;
memAlloc.allocationSize = 0;
memAlloc.memoryTypeIndex = 0;
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory));
VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0));
// create image view for depth image
VkImageViewCreateInfo depthStencilView = {};
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
depthStencilView.pNext = NULL;
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
depthStencilView.format = depthFormat;
depthStencilView.image = depthAttachment.image;
depthStencilView.flags = 0;
depthStencilView.subresourceRange = {};
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT)
{
depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
depthStencilView.subresourceRange.baseMipLevel = 0;
depthStencilView.subresourceRange.levelCount = 1;
depthStencilView.subresourceRange.baseArrayLayer = 0;
depthStencilView.subresourceRange.layerCount = 1;
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view));
}
else
{
swapChainImageViews.resize(swapChainImages.size());
for (size_t i = 0; i < swapChainImages.size(); i++)
{
VkImageViewCreateInfo creatInfo{};
creatInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
creatInfo.image = swapChainImages[i];
creatInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
creatInfo.format = swapChainImageFormat;
creatInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
creatInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
creatInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
creatInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
creatInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
creatInfo.subresourceRange.baseMipLevel = 0;
creatInfo.subresourceRange.levelCount = 1;
creatInfo.subresourceRange.baseArrayLayer = 0;
creatInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device, &creatInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS)
{
throw std::runtime_error("failed to creat image view");
}
}
}
}
void VulkanBackend::VulkanFoundation::createRenderPass(PlumageRender::Setter setter)
{
VkFormat colorAttachmentFormat;
VkFormat depthAttachmentFormat = findDepthFormat();
VkImageLayout colorAttachmentFinallayout;
if (setter.settings.headless)
{
colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
colorAttachmentFinallayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
else
{
colorAttachmentFormat = swapChainImageFormat;
colorAttachmentFinallayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
if (setter.settings.multiSampling) {
std::array<VkAttachmentDescription, 4> attachments = {};
// Multisampled attachment that we render to
attachments[0].format = colorAttachmentFormat;
attachments[0].samples =setter.settings.sampleCount;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// This is the frame buffer attachment to where the multisampled image
// will be resolved to and which will be presented to the swapchain
attachments[1].format = colorAttachmentFormat;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = colorAttachmentFinallayout;
// Multisampled depth attachment we render to
attachments[2].format = depthAttachmentFormat;
attachments[2].samples =setter.settings.sampleCount;
attachments[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[2].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// Depth resolve attachment
attachments[3].format = depthAttachmentFormat;
attachments[3].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[3].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[3].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[3].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[3].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[3].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[3].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorReference = {};
colorReference.attachment = 0;
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthReference = {};
depthReference.attachment = 2;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// Resolve attachment reference for the color attachment
VkAttachmentReference resolveReference = {};
resolveReference.attachment = 1;
resolveReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorReference;
// Pass our resolve attachments to the sub pass
subpass.pResolveAttachments = &resolveReference;
subpass.pDepthStencilAttachment = &depthReference;
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo renderPassCI = {};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassCI.pAttachments = attachments.data();
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpass;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass));
}
else {
std::array<VkAttachmentDescription, 2> attachments = {};
// Color attachment
attachments[0].format = colorAttachmentFormat;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = colorAttachmentFinallayout;
// Depth attachment
attachments[1].format = depthAttachmentFormat;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorReference = {};
colorReference.attachment = 0;
colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthReference = {};
depthReference.attachment = 1;
depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpassDescription = {};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
subpassDescription.pDepthStencilAttachment = &depthReference;
subpassDescription.inputAttachmentCount = 0;
subpassDescription.pInputAttachments = nullptr;
subpassDescription.preserveAttachmentCount = 0;
subpassDescription.pPreserveAttachments = nullptr;
subpassDescription.pResolveAttachments = nullptr;
// Subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassCI.pAttachments = attachments.data();
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = static_cast<uint32_t>(dependencies.size());
renderPassCI.pDependencies = dependencies.data();
VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass));
}
}
VkFormat VulkanBackend::VulkanFoundation::findDepthFormat()
{
return findSupportedFormat(
{ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
);
}
VkFormat VulkanBackend::VulkanFoundation::findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
{
for (VkFormat format : candidates)
{
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
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;
}
}
throw std::runtime_error("failed to find supported format");
}
bool VulkanBackend::VulkanFoundation::hasStencilComponent(VkFormat format)
{
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
}
void VulkanBackend::VulkanFoundation::createDescriptorSetLayout()
{
createSceneDescriptorSetLayout();
createMaterialDescriptorSetLayout();
createNodeDescriptorSetLayout();
}
void VulkanBackend::VulkanFoundation::createSceneDescriptorSetLayout()
{
// scene场景的资源描述符
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
};
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = setLayoutBindings.data();
descriptorSetLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.scene));
}
void VulkanBackend::VulkanFoundation::createMaterialDescriptorSetLayout()
{
// 材质或材质采样器的资源描述符
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
{ 4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr },
};
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = setLayoutBindings.data();
descriptorSetLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.material));
}
void VulkanBackend::VulkanFoundation::createNodeDescriptorSetLayout()
{
// 模型结点或矩阵的资源描述符
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr },
};
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = setLayoutBindings.data();
descriptorSetLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.node));
}
void VulkanBackend::VulkanFoundation::createPipelineCache()
{
VkPipelineCacheCreateInfo pipelineCacheCreateInfo{};
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
VK_CHECK_RESULT(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache));
}
void VulkanBackend::VulkanFoundation::createGraphicPipeline(PlumageRender::Setter setter)
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
if (setter.settings.multiSampling) {
multisampleStateCI.rasterizationSamples =setter.settings.sampleCount;
}
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
// Pipeline layout
const std::vector<VkDescriptorSetLayout> setLayouts = {
descriptorSetLayouts.scene, descriptorSetLayouts.material, descriptorSetLayouts.node
};
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
pipelineLayoutCI.pSetLayouts = setLayouts.data();
VkPushConstantRange pushConstantRange{};
pushConstantRange.size = sizeof(PBR::Material::pushConstBlockMaterial);
pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));
// Vertex bindings an attributes
VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX };
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes = {
{ 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 },
{ 1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3 },
{ 2, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 6 },
{ 3, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 8 },
{ 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 10 },
{ 5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 14 },
{ 6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(float) * 18 }
};
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputStateCI.vertexBindingDescriptionCount = 1;
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
vertexInputStateCI.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexInputAttributes.size());
vertexInputStateCI.pVertexAttributeDescriptions = vertexInputAttributes.data();
// Pipelines
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelineLayout;
pipelineCI.renderPass = renderPass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &vertexInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCI.pStages = shaderStages.data();
if (setter.settings.multiSampling) {
multisampleStateCI.rasterizationSamples =setter.settings.sampleCount;
}
// Skybox pipeline (background cube)
shaderStages = {
loadShader(device,setter.filePath.skyboxVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device,setter.filePath.skyboxFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT)
};
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.skybox));
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(device, shaderStage.module, nullptr);
}
// PBR pipeline
shaderStages = {
loadShader(device,setter.filePath.pbrVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT),
loadShader(device,setter.filePath.pbrFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT)
};
depthStencilStateCI.depthWriteEnable = VK_TRUE;
depthStencilStateCI.depthTestEnable = VK_TRUE;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbr));
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrDoubleSided));
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
blendAttachmentState.blendEnable = VK_TRUE;
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.pbrAlphaBlend));
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(device, shaderStage.module, nullptr);
}
//Create Tone Mapping render pipeline
//CreateToneMappingPipeline();
}
void VulkanBackend::VulkanFoundation::createFramebuffer(PlumageRender::Setter setter)
{
if (setter.settings.headless)
{
auto frameRange = setter.settings.endFrameIndex - setter.settings.startFrameCount;
if (setter.settings.multiSampling)
{
for (int i = 0; i < frameRange; i++)
{
VkImageView attachments[4];
attachments[0] = multisampleTarget.colorAttachment.view;
attachments[1] = multisampleTarget.depthAttachment.view;
attachments[2] = depthAttachment.view;
attachments[3] = colorAttachment.view;
VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo();
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 4;
framebufferCreateInfo.pAttachments = attachments;
framebufferCreateInfo.width =setter.settings.width;
framebufferCreateInfo.height =setter.settings.height;
framebufferCreateInfo.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
}
}
else
{
for (int i = 0; i < frameRange; i++)
{
VkImageView attachments[2];
attachments[0] = colorAttachment.view;
attachments[1] = depthAttachment.view;
VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo();
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 2;
framebufferCreateInfo.pAttachments = attachments;
framebufferCreateInfo.width =setter.settings.width;
framebufferCreateInfo.height =setter.settings.height;
framebufferCreateInfo.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
}
}
}
else
{
createSwapChainFramebuffer(setter);
}
}
void VulkanBackend::VulkanFoundation::createSwapChainFramebuffer(PlumageRender::Setter setter)
{
uint32_t attachmentCount;
VkImageView attachments[attachmentCount];
if (setter.settings.multiSampling) {
attachmentCount = 4;
attachments[0] = multisampleTarget.colorAttachment.view;
attachments[1] = multisampleTarget.depthAttachment.view;
attachments[2] = depthAttachment.view;
}
else {
attachmentCount = 2;
attachments[1] = depthAttachment.view;
}
VkFramebufferCreateInfo frameBufferCI{};
frameBufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
frameBufferCI.pNext = NULL;
frameBufferCI.renderPass = renderPass;
frameBufferCI.attachmentCount = attachmentCount;
frameBufferCI.pAttachments = attachments;
frameBufferCI.width =setter.settings.width;
frameBufferCI.height =setter.settings.height;
frameBufferCI.layers = 1;
// Create frame buffers for every swap chain image
framebuffers.resize(swapChainImageViews.size());
for (uint32_t i = 0; i < swapChainImageViews.size(); i++) {
if (setter.settings.multiSampling) {
attachments[3] = swapChainImageViews[i];
}
else {
attachments[0] = swapChainImageViews[i];
}
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &framebuffers[i]));
}
}
void VulkanBackend::VulkanFoundation::createCommandPool(PlumageRender::Setter setter)
{
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice,setter);
VkCommandPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS)
{
throw std::runtime_error("failed to create command pool in createCommandpool");
}
}
void VulkanBackend::VulkanFoundation::createUniformBuffer(PlumageRender::Setter setter,Camera camera,PlumageRender::renderMain mainRender)
{
if (setter.settings.headless)
{
auto frameRange = setter.settings.endFrameIndex - setter.settings.startFrameCount;
uniformBuffers.resize(frameRange);
}
else
{
uniformBuffers.resize(swapChainImages.size());
}
for (auto& uniformBuffer : uniformBuffers) {
uniformBuffer.scene.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataScene));
uniformBuffer.skybox.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataSkybox));
uniformBuffer.params.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(PBR::Material::shaderData));
}
updateUniformBuffers(camera,mainRender);
}
void VulkanBackend::VulkanFoundation::updateUniformBuffers(Camera camera, PlumageRender::renderMain mainRender)
{
// Scene
shaderDataScene.projection = camera.matrices.perspective;
shaderDataScene.view = camera.matrices.view;
// Center and scale model
float scale = (1.0f / std::max(mainRender.models.scene.aabb[0][0], std::max(mainRender.models.scene.aabb[1][1], mainRender.models.scene.aabb[2][2]))) * 0.5f;
glm::vec3 translate = -glm::vec3(mainRender.models.scene.aabb[3][0], mainRender.models.scene.aabb[3][1], mainRender.models.scene.aabb[3][2]);
translate += -0.5f * glm::vec3(mainRender.models.scene.aabb[0][0], mainRender.models.scene.aabb[1][1], mainRender.models.scene.aabb[2][2]);
shaderDataScene.model = glm::mat4(1.0f);
shaderDataScene.model[0][0] = scale;
shaderDataScene.model[1][1] = scale;
shaderDataScene.model[2][2] = scale;
shaderDataScene.model = glm::translate(shaderDataScene.model, translate);
shaderDataScene.camPos = glm::vec3(
-camera.position.z * sin(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x)),
-camera.position.z * sin(glm::radians(camera.rotation.x)),
camera.position.z * cos(glm::radians(camera.rotation.y)) * cos(glm::radians(camera.rotation.x))
);
// Skybox
shaderDataSkybox.projection = camera.matrices.perspective;
shaderDataSkybox.view = camera.matrices.view;
shaderDataSkybox.model = glm::mat4(glm::mat3(camera.matrices.view));
}
void VulkanBackend::VulkanFoundation::createDescriptorPool(PlumageRender::renderMain mainRender)
{
/*
Descriptor Pool
*/
uint32_t imageSamplerCount = 0;
uint32_t materialCount = 0;
uint32_t meshCount = 0;
// Environment samplers (radiance, irradiance, brdflut)
imageSamplerCount += 3;
std::vector<glTFModel::Model*> modellist = { &mainRender.models.skybox, &mainRender.models.scene };
for (auto& model : modellist) {
for (auto& material : model->materials) {
imageSamplerCount += 5;
materialCount++;
}
for (auto node : model->linearNodes) {
if (node->mesh) {
meshCount++;
}
}
}
std::vector<VkDescriptorPoolSize> poolSizes = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (4 + meshCount) * static_cast<uint32_t>(MAX_FRAME_IN_FLIGHT)},
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageSamplerCount * static_cast<uint32_t>(MAX_FRAME_IN_FLIGHT) }
};
VkDescriptorPoolCreateInfo descriptorPoolCI{};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = 2;
descriptorPoolCI.pPoolSizes = poolSizes.data();
descriptorPoolCI.maxSets = (2 + materialCount + meshCount) * static_cast<uint32_t>(MAX_FRAME_IN_FLIGHT);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));
}
void VulkanBackend::VulkanFoundation::createDescriptorSets(PlumageRender::Setter setter)
{
if (setter.settings.headless)
{
auto frameRange = setter.settings.endFrameIndex - setter.settings.startFrameCount;
descriptorSets.resize(frameRange);
}
else
{
descriptorSets.resize(swapChainImages.size());
}
createSceneDescriptorSets();
createMaterialDescriptorSets();
createModelNodeDescriptorSets();
createSkyboxDescriptorSets();
}
// Scene (matrices and environment maps)
void VulkanBackend::VulkanFoundation::createSceneDescriptorSets()
{
for (auto i = 0; i < descriptorSets.size(); i++)
{
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorPool;
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].scene));
std::array<VkWriteDescriptorSet, 5> writeDescriptorSets{};
writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSets[0].descriptorCount = 1;
writeDescriptorSets[0].dstSet = descriptorSets[i].scene;
writeDescriptorSets[0].dstBinding = 0;
writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].scene.descriptor;
writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSets[1].descriptorCount = 1;
writeDescriptorSets[1].dstSet = descriptorSets[i].scene;
writeDescriptorSets[1].dstBinding = 1;
writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor;
writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[2].descriptorCount = 1;
writeDescriptorSets[2].dstSet = descriptorSets[i].scene;
writeDescriptorSets[2].dstBinding = 2;
writeDescriptorSets[2].pImageInfo = &PBR::Material::textures.irradianceCube.descriptor;
writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[3].descriptorCount = 1;
writeDescriptorSets[3].dstSet = descriptorSets[i].scene;
writeDescriptorSets[3].dstBinding = 3;
writeDescriptorSets[3].pImageInfo = &PBR::Material::textures.prefilteredCube.descriptor;
writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[4].descriptorCount = 1;
writeDescriptorSets[4].dstSet = descriptorSets[i].scene;
writeDescriptorSets[4].dstBinding = 4;
writeDescriptorSets[4].pImageInfo = &PBR::Material::textures.lutBrdf.descriptor;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
}
}
// Per-Material descriptor sets
void VulkanBackend::VulkanFoundation::createMaterialDescriptorSets()
{
for (auto& material : PlumageRender::renderMain::models.scene.materials)
{
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorPool;
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.material;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &material.descriptorSet));
std::vector<VkDescriptorImageInfo> imageDescriptors =
{
PBR::Material::textures.empty.descriptor,
PBR::Material::textures.empty.descriptor,
material.normalTexture ? material.normalTexture->descriptor : PBR::Material::textures.empty.descriptor,
material.occlusionTexture ? material.occlusionTexture->descriptor : PBR::Material::textures.empty.descriptor,
material.emissiveTexture ? material.emissiveTexture->descriptor : PBR::Material::textures.empty.descriptor
};
if (material.pbrWorkflows.metallicRoughness)
{
if (material.baseColorTexture) {
imageDescriptors[0] = material.baseColorTexture->descriptor;
}
if (material.metallicRoughnessTexture) {
imageDescriptors[1] = material.metallicRoughnessTexture->descriptor;
}
}
if (material.pbrWorkflows.specularGlossiness)
{
if (material.extension.diffuseTexture)
{
imageDescriptors[0] = material.extension.diffuseTexture->descriptor;
}
if (material.extension.specularGlossinessTexture)
{
imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor;
}
}
std::array<VkWriteDescriptorSet, 5> writeDescriptorSets{};
for (size_t i = 0; i < imageDescriptors.size(); i++)
{
writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[i].descriptorCount = 1;
writeDescriptorSets[i].dstSet = material.descriptorSet;
writeDescriptorSets[i].dstBinding = static_cast<uint32_t>(i);
writeDescriptorSets[i].pImageInfo = &imageDescriptors[i];
}
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
}
}
// Model node (matrices)
void VulkanBackend::VulkanFoundation::createModelNodeDescriptorSets()
{
// Per-Node descriptor set
for (auto& node : PlumageRender::renderMain::models.scene.nodes)
{
setupglTFNodeDescriptorSet(node);
}
}
// attention: gltf-spec
void VulkanBackend::VulkanFoundation::setupglTFNodeDescriptorSet(glTFModel::Node* node)
{
if (node->mesh) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorPool;
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.node;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet));
VkWriteDescriptorSet writeDescriptorSet{};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
for (auto& child : node->children) {
setupglTFNodeDescriptorSet(child);
}
}
void VulkanBackend::VulkanFoundation::createSkyboxDescriptorSets()
{
// Skybox (fixed set)
for (auto i = 0; i < uniformBuffers.size(); i++) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorPool;
descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayouts.scene;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSets[i].skybox));
std::array<VkWriteDescriptorSet, 3> writeDescriptorSets{};
writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSets[0].descriptorCount = 1;
writeDescriptorSets[0].dstSet = descriptorSets[i].skybox;
writeDescriptorSets[0].dstBinding = 0;
writeDescriptorSets[0].pBufferInfo = &uniformBuffers[i].skybox.descriptor;
writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSets[1].descriptorCount = 1;
writeDescriptorSets[1].dstSet = descriptorSets[i].skybox;
writeDescriptorSets[1].dstBinding = 1;
writeDescriptorSets[1].pBufferInfo = &uniformBuffers[i].params.descriptor;
writeDescriptorSets[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[2].descriptorCount = 1;
writeDescriptorSets[2].dstSet = descriptorSets[i].skybox;
writeDescriptorSets[2].dstBinding = 2;
writeDescriptorSets[2].pImageInfo = &PBR::Material::textures.prefilteredCube.descriptor;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
}
}
void VulkanBackend::VulkanFoundation::allocateCommandBuffers(PlumageRender::Setter setter)
{
// resize
if (setter.settings.headless)
{
auto frameRange = setter.getFrameRange();
commandbuffers.resize(frameRange);
}
else
{
commandbuffers.resize(swapChainImages.size());
}
// allocate
VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdBufAllocateInfo.commandPool = commandPool;
cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmdBufAllocateInfo.commandBufferCount = static_cast<uint32_t>(commandbuffers.size());
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandbuffers.data()));
}
void VulkanBackend::VulkanFoundation::cleanupSwapChain()
{
for (auto framebuffer : framebuffers)
{
vkDestroyFramebuffer(device, framebuffer, nullptr);
}
for (auto imageView : swapChainImageViews)
{
vkDestroyImageView(device, imageView, nullptr);
}
vkDestroySwapchainKHR(device, swapChain, nullptr);
}
void VulkanBackend::VulkanFoundation::createCommandBuffer(PlumageRender::Setter setter,PlumageRender::renderMain mainRender,UI* plumageGUI)
{
VkCommandBufferBeginInfo cmdBufferBeginInfo{};
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VkClearValue clearValues[3];
if (setter.settings.multiSampling) {
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[2].depthStencil = { 1.0f, 0 };
}
else {
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
clearValues[1].depthStencil = { 1.0f, 0 };
}
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width =setter.settings.width;
renderPassBeginInfo.renderArea.extent.height =setter.settings.height;
renderPassBeginInfo.clearValueCount =setter.settings.multiSampling ? 3 : 2;
renderPassBeginInfo.pClearValues = clearValues;
for (uint32_t i = 0; i < commandbuffers.size(); ++i)
{
renderPassBeginInfo.framebuffer = framebuffers[i];
VkCommandBuffer currentCB = commandbuffers[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(currentCB, &cmdBufferBeginInfo));
vkCmdBeginRenderPass(currentCB, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
viewport.width = (float)setter.settings.width;
viewport.height = (float)setter.settings.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(currentCB, 0, 1, &viewport);
VkRect2D scissor{};
scissor.extent = {setter.settings.width,setter.settings.height };
vkCmdSetScissor(currentCB, 0, 1, &scissor);
VkDeviceSize offsets[1] = { 0 };
if (setter.settings.displayBackground) {
vkCmdBindDescriptorSets(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i].skybox, 0, nullptr);
vkCmdBindPipeline(currentCB, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.skybox);
mainRender.models.skybox.draw(currentCB);
}
glTFModel::Model& model = mainRender.models.scene;
vkCmdBindVertexBuffers(currentCB, 0, 1, &model.vertices.buffer, offsets);
if (model.indices.buffer != VK_NULL_HANDLE) {
vkCmdBindIndexBuffer(currentCB, model.indices.buffer, 0, VK_INDEX_TYPE_UINT32);
}
boundPipeline = VK_NULL_HANDLE;
// Opaque primitives first
for (auto node : model.nodes) {
createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_OPAQUE);
}
// Alpha masked primitives
for (auto node : model.nodes) {
createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_MASK);
}
// Transparent primitives
// TODO: Correct depth sorting
for (auto node : model.nodes) {
createglTFNodeCommandBuffer(node, i, glTFModel::Material::ALPHAMODE_BLEND);
}
// User interface
if (!setter.settings.headless)
{
plumageGUI->draw(currentCB);
}
vkCmdEndRenderPass(currentCB);
VK_CHECK_RESULT(vkEndCommandBuffer(currentCB));
}
}
void VulkanBackend::VulkanFoundation::createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode)
{
if (node->mesh) {
// Render mesh primitives
for (glTFModel::Primitive* primitive : node->mesh->primitives) {
if (primitive->material.alphaMode == alphaMode) {
VkPipeline pipeline = VK_NULL_HANDLE;
switch (alphaMode) {
case glTFModel::Material::ALPHAMODE_OPAQUE:
case glTFModel::Material::ALPHAMODE_MASK:
pipeline = primitive->material.doubleSided ? pipelines.pbrDoubleSided : pipelines.pbr;
break;
case glTFModel::Material::ALPHAMODE_BLEND:
pipeline = pipelines.pbrAlphaBlend;
break;
}
if (pipeline != boundPipeline) {
vkCmdBindPipeline(commandbuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
boundPipeline = pipeline;
}
const std::vector<VkDescriptorSet> descriptorsets = {
descriptorSets[cbIndex].scene,
primitive->material.descriptorSet,
node->mesh->uniformBuffer.descriptorSet,
};
vkCmdBindDescriptorSets(commandbuffers[cbIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, static_cast<uint32_t>(descriptorsets.size()), descriptorsets.data(), 0, NULL);
// Pass material parameters as push constants
PBR::Material::PushConstBlockMaterial pushConstBlockMaterial{};
pushConstBlockMaterial.emissiveFactor = primitive->material.emissiveFactor;
// To save push constant space, availabilty and texture coordiante set are combined
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1;
pushConstBlockMaterial.normalTextureSet = primitive->material.normalTexture != nullptr ? primitive->material.texCoordSets.normal : -1;
pushConstBlockMaterial.occlusionTextureSet = primitive->material.occlusionTexture != nullptr ? primitive->material.texCoordSets.occlusion : -1;
pushConstBlockMaterial.emissiveTextureSet = primitive->material.emissiveTexture != nullptr ? primitive->material.texCoordSets.emissive : -1;
pushConstBlockMaterial.alphaMask = static_cast<float>(primitive->material.alphaMode == glTFModel::Material::ALPHAMODE_MASK);
pushConstBlockMaterial.alphaMaskCutoff = primitive->material.alphaCutoff;
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
if (primitive->material.pbrWorkflows.metallicRoughness) {
// Metallic roughness workflow
pushConstBlockMaterial.workflow = static_cast<float>(PBR::Material::PBRWorkflows::PBR_WORKFLOW_METALLIC_ROUGHNESS);
pushConstBlockMaterial.baseColorFactor = primitive->material.baseColorFactor;
pushConstBlockMaterial.metallicFactor = primitive->material.metallicFactor;
pushConstBlockMaterial.roughnessFactor = primitive->material.roughnessFactor;
pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.metallicRoughnessTexture != nullptr ? primitive->material.texCoordSets.metallicRoughness : -1;
pushConstBlockMaterial.colorTextureSet = primitive->material.baseColorTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1;
}
if (primitive->material.pbrWorkflows.specularGlossiness) {
// Specular glossiness workflow
pushConstBlockMaterial.workflow = static_cast<float>(PBR::Material::PBRWorkflows::PBR_WORKFLOW_SPECULAR_GLOSINESS);
pushConstBlockMaterial.PhysicalDescriptorTextureSet = primitive->material.extension.specularGlossinessTexture != nullptr ? primitive->material.texCoordSets.specularGlossiness : -1;
pushConstBlockMaterial.colorTextureSet = primitive->material.extension.diffuseTexture != nullptr ? primitive->material.texCoordSets.baseColor : -1;
pushConstBlockMaterial.diffuseFactor = primitive->material.extension.diffuseFactor;
pushConstBlockMaterial.specularFactor = glm::vec4(primitive->material.extension.specularFactor, 1.0f);
}
vkCmdPushConstants(commandbuffers[cbIndex], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PBR::Material::PushConstBlockMaterial), &pushConstBlockMaterial);
if (primitive->hasIndices) {
vkCmdDrawIndexed(commandbuffers[cbIndex], primitive->indexCount, 1, primitive->firstIndex, 0, 0);
}
else {
vkCmdDraw(commandbuffers[cbIndex], primitive->vertexCount, 1, 0, 0);
}
}
}
};
for (auto child : node->children) {
createglTFNodeCommandBuffer(child, cbIndex, alphaMode);
}
}
void VulkanBackend::VulkanFoundation::createFenceAndSemaphore(PlumageRender::Setter setter)
{
waitFences.resize(setter.settings.MaxFrameInFlight);
presentCompleteSemaphores.resize(setter.settings.MaxFrameInFlight);
renderCompleteSemaphores.resize(setter.settings.MaxFrameInFlight);
// Command buffer execution fences
for (auto& waitFence : waitFences) {
VkFenceCreateInfo fenceCI{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
VK_CHECK_RESULT(vkCreateFence(device, &fenceCI, nullptr, &waitFence));
}
if (!setter.settings.headless)
{
for (auto& semaphore : presentCompleteSemaphores) {
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 };
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
}
}
// Queue ordering semaphores
for (auto& semaphore : renderCompleteSemaphores) {
VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 };
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
}
}
void VulkanBackend::VulkanFoundation::DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
{
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
if (func != nullptr)
{
func(instance, debugMessenger, pAllocator);
}
}
bool VulkanBackend::VulkanFoundation::acqureNextSwapchainImage(bool framebuffeerResized,uint32_t imageIndex,uint32_t frameIndex,PlumageRender::Setter setter)
{
VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, renderCompleteSemaphores[frameIndex], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebuffeerResized)
{
framebuffeerResized = false;
recreateSwapChain(setter);
return framebuffeerResized;
}
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
{
throw std::runtime_error("failed to acquire swap chain image in drawFrame");
}
}
void VulkanBackend::VulkanFoundation::submitToGraphicQueue(uint32_t frameIndex, uint32_t currentBuffer)
{
const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = &waitDstStageMask;
submitInfo.pWaitSemaphores = &presentCompleteSemaphores[frameIndex];
submitInfo.waitSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[frameIndex];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pCommandBuffers = &commandbuffers[currentBuffer];
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(graphicQueue, 1, &submitInfo, waitFences[frameIndex]));
}
void VulkanBackend::VulkanFoundation::imageToQueuePresent(uint32_t frameIndex,uint32_t imageIndex,bool framebufferResized,PlumageRender::Setter setter)
{
//显示队列
VkSemaphore signalSemaphores[] = { renderCompleteSemaphores[frameIndex] };
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = { swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr;
VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
{
framebufferResized = false;
recreateSwapChain(setter);
}
else if (result != VK_SUCCESS)
{
throw std::runtime_error("failed to present swap chain image in drawFrame");
}
}
void VulkanBackend::VulkanFoundation::destroyVulkanBackend(PlumageRender::Setter setter)
{
// Clean up Vulkan resources
cleanupSwapChain();
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
vkDestroyRenderPass(device, renderPass, nullptr);
for (uint32_t i = 0; i < framebuffers.size(); i++) {
vkDestroyFramebuffer(device, framebuffers[i], nullptr);
}
vkDestroyImageView(device, colorAttachment.view, nullptr);
vkDestroyImage(device, colorAttachment.image, nullptr);
vkFreeMemory(device, colorAttachment.memory, nullptr);
vkDestroyImageView(device, depthAttachment.view, nullptr);
vkDestroyImage(device, depthAttachment.image, nullptr);
vkFreeMemory(device, depthAttachment.memory, nullptr);
if (setter.settings.multiSampling) {
vkDestroyImage(device, multisampleTarget.colorAttachment.image, nullptr);
vkDestroyImageView(device, multisampleTarget.colorAttachment.view, nullptr);
vkFreeMemory(device, multisampleTarget.colorAttachment.memory, nullptr);
vkDestroyImage(device, multisampleTarget.depthAttachment.image, nullptr);
vkDestroyImageView(device, multisampleTarget.depthAttachment.view, nullptr);
vkFreeMemory(device, multisampleTarget.depthAttachment.memory, nullptr);
}
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipelines.skybox, nullptr);
vkDestroyPipeline(device, pipelines.pbr, nullptr);
vkDestroyPipeline(device, pipelines.pbrAlphaBlend, nullptr);
vkDestroyPipelineCache(device, pipelineCache, nullptr);
vkDestroyCommandPool(device, commandPool, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr);
for (auto buffer : uniformBuffers) {
buffer.params.destroy();
buffer.scene.destroy();
buffer.skybox.destroy();
}
for (auto fence : waitFences) {
vkDestroyFence(device, fence, nullptr);
}
for (auto semaphore : renderCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
for (auto semaphore : presentCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
delete vulkanDevice;
if (setter.settings.validation) {
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
}
vkDestroyInstance(instance, nullptr);
}
void VulkanBackend::VulkanFoundation::updateShaderData()
{
PBR::Material::shaderData.lightDir = glm::vec4(
sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
sin(glm::radians(lightSource.rotation.y)),
cos(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
0.0f);
}
void VulkanBackend::VulkanFoundation::recreateSwapChain(PlumageRender::Setter setter)
{
int width = 0, height = 0;
glfwGetFramebufferSize(window, &width, &height);
while (width == 0 || height == 0)
{
if (glfwWindowShouldClose(window))
{
return;
}
glfwGetFramebufferSize(window, &width, &height);
glfwWaitEvents();
}
vkDeviceWaitIdle(device);
cleanupSwapChain();
createSwapChain(setter);
createImageView(setter);
createFramebuffer(setter);
}