816 lines
30 KiB
C++
816 lines
30 KiB
C++
/*
|
|
* Vulkan Example base class, stripped down version
|
|
*
|
|
* Copyright (C) 2016-2018 by Sascha Willems - www.saschawillems.de
|
|
*
|
|
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
|
*/
|
|
|
|
#include "VulkanExampleBase.h"
|
|
|
|
|
|
std::vector<const char*> VulkanExampleBase::args;
|
|
|
|
VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char * pLayerPrefix, const char * pMsg, void * pUserData)
|
|
{
|
|
std::string prefix("");
|
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
|
prefix += "ERROR:";
|
|
};
|
|
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
|
|
prefix += "WARNING:";
|
|
};
|
|
if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
|
|
prefix += "DEBUG:";
|
|
}
|
|
std::stringstream debugMessage;
|
|
debugMessage << prefix << " [" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg;
|
|
#if defined(__ANDROID__)
|
|
LOGD("%s", debugMessage.str().c_str());
|
|
#else
|
|
std::cout << debugMessage.str() << "\n \n";
|
|
#endif
|
|
fflush(stdout);
|
|
return VK_FALSE;
|
|
}
|
|
|
|
VkResult VulkanExampleBase::createInstance(bool enableValidation)
|
|
{
|
|
this->settings.validation = enableValidation;
|
|
|
|
// Validation can also be forced via a define
|
|
#if defined(_VALIDATION)
|
|
this->settings.validation = true;
|
|
#endif
|
|
|
|
VkApplicationInfo appInfo = {};
|
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
appInfo.pApplicationName = name.c_str();
|
|
appInfo.pEngineName = name.c_str();
|
|
appInfo.apiVersion = VK_API_VERSION_1_0;
|
|
|
|
std::vector<const char*> instanceExtensions = { };
|
|
|
|
if (!settings.headless)
|
|
{
|
|
//instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
// Enable surface extensions depending on os
|
|
#if defined(_WIN32)
|
|
instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
instanceExtensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
instanceExtensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME);
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
instanceExtensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
|
instanceExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
instanceExtensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
|
#endif
|
|
|
|
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
|
|
instanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
|
instanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VkInstanceCreateInfo instanceCreateInfo = {};
|
|
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
instanceCreateInfo.pNext = NULL;
|
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
|
|
|
#if defined(VK_USE_PLATFORM_MACOS_MVK) && (VK_HEADER_VERSION >= 216)
|
|
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
|
#endif
|
|
|
|
if (settings.validation) {
|
|
instanceExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
|
}
|
|
if (instanceExtensions.size() > 0)
|
|
{
|
|
instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.size();
|
|
instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
|
|
}
|
|
std::vector<const char *> validationLayerNames;
|
|
if (settings.validation) {
|
|
validationLayerNames.push_back("VK_LAYER_KHRONOS_validation");
|
|
instanceCreateInfo.enabledLayerCount = (uint32_t)validationLayerNames.size();
|
|
instanceCreateInfo.ppEnabledLayerNames = validationLayerNames.data();
|
|
}
|
|
return vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
|
|
|
|
|
|
}
|
|
void VulkanExampleBase::prepare()
|
|
{
|
|
/*
|
|
Swapchain
|
|
*/
|
|
//initSwapchain();
|
|
//setupSwapChain();
|
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
width = swapChain.extent.width;
|
|
height = swapChain.extent.height;
|
|
#endif
|
|
|
|
/*
|
|
Command pool
|
|
*/
|
|
VkCommandPoolCreateInfo cmdPoolInfo = {};
|
|
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
cmdPoolInfo.queueFamilyIndex = queueFamilyIndex;
|
|
cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &cmdPool));
|
|
vulkanDevice->setCommandPool(cmdPool);
|
|
/*
|
|
Render pass
|
|
*/
|
|
|
|
if (settings.multiSampling) {
|
|
std::array<VkAttachmentDescription, 4> attachments = {};
|
|
|
|
// Multisampled attachment that we render to
|
|
attachments[0].format = colorFormat;
|
|
attachments[0].samples = 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 = colorFormat;
|
|
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 = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
|
|
|
// Multisampled depth attachment we render to
|
|
attachments[2].format = depthFormat;
|
|
attachments[2].samples = 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 = depthFormat;
|
|
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 = colorFormat;
|
|
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 = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
|
// Depth attachment
|
|
attachments[1].format = depthFormat;
|
|
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));
|
|
}
|
|
|
|
/*
|
|
Pipeline cache
|
|
*/
|
|
VkPipelineCacheCreateInfo pipelineCacheCreateInfo{};
|
|
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
|
VK_CHECK_RESULT(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache));
|
|
|
|
/*
|
|
Frame buffer
|
|
*/
|
|
setupFrameBuffer();
|
|
}
|
|
|
|
void VulkanExampleBase::fileDropped(std::string filename) { }
|
|
|
|
void VulkanExampleBase::renderFrame()
|
|
{
|
|
auto tStart = std::chrono::high_resolution_clock::now();
|
|
|
|
render();
|
|
|
|
frameCounter++;
|
|
auto tEnd = std::chrono::high_resolution_clock::now();
|
|
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
|
|
frameTimer = (float)tDiff / 1000.0f;
|
|
camera.update(frameTimer);
|
|
fpsTimer += (float)tDiff;
|
|
if (fpsTimer > 1000.0f) {
|
|
lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer));
|
|
fpsTimer = 0.0f;
|
|
frameCounter = 0;
|
|
}
|
|
}
|
|
|
|
void VulkanExampleBase::renderLoop()
|
|
{
|
|
uint32_t currentFrame = 0;
|
|
while (!signal.imageSequenceToVideoComplete)
|
|
{
|
|
|
|
camera.setPosition(settings.cameraTracks[currentFrame]);
|
|
camera.setRotation(settings.cameraAngle[currentFrame]);
|
|
|
|
renderFrame();
|
|
currentFrame++;
|
|
if (currentFrame>=settings.cameraAngle.size()-1)
|
|
{
|
|
currentFrame = settings.cameraAngle.size()-1;
|
|
}
|
|
}
|
|
|
|
// Flush device to make sure all resources can be freed
|
|
vkDeviceWaitIdle(device);
|
|
}
|
|
|
|
VulkanExampleBase::VulkanExampleBase()
|
|
{
|
|
//char* numConvPtr;
|
|
// Parse command line arguments
|
|
for (size_t i = 0; i < args.size(); i++)
|
|
{
|
|
if ((args[i] == std::string("--config")))
|
|
{
|
|
std::string configFile = args[i + 1];
|
|
if (std::filesystem::exists(configFile))
|
|
{
|
|
std::cout << "loading config file from: " << configFile << std::endl;
|
|
filePath.configFilePath = configFile;
|
|
settings.debugMode = false;
|
|
settings.validation = false;
|
|
settings.cleanUpImageSequece = true;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "config file no exists, please check file path" << std::endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (settings.debugMode)
|
|
{
|
|
std::cout << "=====================================WARNNING=================================" << std::endl;
|
|
std::cout << "debug Mode enabled,config file with command line argument will be ignore " << std::endl;
|
|
std::cout << "validation layer force to be enabled" << std::endl;
|
|
std::cout << "image sequece will not to be cleaned up after viedo generated" << std::endl;
|
|
settings.validation = true;
|
|
settings.cleanUpImageSequece = false;
|
|
std::cout << "=====================================WARNNING=================================" << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::cout << " [error] no config file path input with command line arguments" << std::endl;
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
// Vulkan library is loaded dynamically on Android
|
|
bool libLoaded = vks::android::loadVulkanLibrary();
|
|
assert(libLoaded);
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
initWaylandConnection();
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
|
initxcbConnection();
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
AllocConsole();
|
|
AttachConsole(GetCurrentProcessId());
|
|
FILE *stream;
|
|
freopen_s(&stream, "CONOUT$", "w+", stdout);
|
|
freopen_s(&stream, "CONOUT$", "w+", stderr);
|
|
SetConsoleTitle(TEXT("Vulkan validation output"));
|
|
#endif
|
|
|
|
*/
|
|
}
|
|
|
|
VulkanExampleBase::~VulkanExampleBase()
|
|
{
|
|
// Clean up Vulkan resources
|
|
//swapChain.cleanup();
|
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
|
vkDestroyRenderPass(device, renderPass, nullptr);
|
|
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
|
|
vkDestroyFramebuffer(device, frameBuffers[i], nullptr);
|
|
}
|
|
vkDestroyImageView(device, depthStencil.view, nullptr);
|
|
vkDestroyImage(device, depthStencil.image, nullptr);
|
|
vkFreeMemory(device, depthStencil.mem, nullptr);
|
|
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
|
vkDestroyCommandPool(device, cmdPool, nullptr);
|
|
if (settings.multiSampling) {
|
|
vkDestroyImage(device, multisampleTarget.color.image, nullptr);
|
|
vkDestroyImageView(device, multisampleTarget.color.view, nullptr);
|
|
vkFreeMemory(device, multisampleTarget.color.memory, nullptr);
|
|
vkDestroyImage(device, multisampleTarget.depth.image, nullptr);
|
|
vkDestroyImageView(device, multisampleTarget.depth.view, nullptr);
|
|
vkFreeMemory(device, multisampleTarget.depth.memory, nullptr);
|
|
}
|
|
delete vulkanDevice;
|
|
if (settings.validation) {
|
|
vkDestroyDebugReportCallback(instance, debugReportCallback, nullptr);
|
|
}
|
|
vkDestroyInstance(instance, nullptr);
|
|
/*
|
|
#if defined(_DIRECT2DISPLAY)
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
wl_shell_surface_destroy(shell_surface);
|
|
wl_surface_destroy(surface);
|
|
if (keyboard)
|
|
wl_keyboard_destroy(keyboard);
|
|
if (pointer)
|
|
wl_pointer_destroy(pointer);
|
|
wl_seat_destroy(seat);
|
|
wl_shell_destroy(shell);
|
|
wl_compositor_destroy(compositor);
|
|
wl_registry_destroy(registry);
|
|
wl_display_disconnect(display);
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
// todo : android cleanup (if required)
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
|
xcb_destroy_window(connection, window);
|
|
xcb_disconnect(connection);
|
|
#endif
|
|
|
|
*/
|
|
}
|
|
|
|
void VulkanExampleBase::initVulkan()
|
|
{
|
|
VkResult err;
|
|
|
|
/*
|
|
Instance creation
|
|
*/
|
|
err = createInstance(settings.validation);
|
|
if (err) {
|
|
std::cerr << "Could not create Vulkan instance!" << std::endl;
|
|
exit(err);
|
|
}
|
|
|
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
vks::android::loadVulkanFunctions(instance);
|
|
#endif
|
|
|
|
/*
|
|
Validation layers
|
|
*/
|
|
if (settings.validation) {
|
|
vkCreateDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
|
|
vkDestroyDebugReportCallback = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
|
|
VkDebugReportCallbackCreateInfoEXT debugCreateInfo{};
|
|
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
|
debugCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)debugMessageCallback;
|
|
debugCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
|
|
VK_CHECK_RESULT(vkCreateDebugReportCallback(instance, &debugCreateInfo, nullptr, &debugReportCallback));
|
|
}
|
|
|
|
/*
|
|
GPU selection
|
|
*/
|
|
uint32_t gpuCount = 0;
|
|
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
|
assert(gpuCount > 0);
|
|
std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
|
|
err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
|
|
if (err) {
|
|
std::cerr << "Could not enumerate physical devices!" << std::endl;
|
|
exit(err);
|
|
}
|
|
uint32_t selectedDevice = settings.selectedPhysicalDeviceIndex;
|
|
if (settings.selectedPhysicalDeviceIndex > gpuCount)
|
|
{
|
|
std::cerr << "wrong GPU selection,check selectedPhysicalDeviceIndex in config file,fallback to 0" << std::endl;
|
|
selectedDevice = 0;
|
|
}
|
|
|
|
physicalDevice = physicalDevices[selectedDevice];
|
|
|
|
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
|
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
|
|
|
|
/*
|
|
queueFamilyIndex creation
|
|
*/
|
|
|
|
/*
|
|
Device creation
|
|
*/
|
|
vulkanDevice = new vks::VulkanDevice(physicalDevice);
|
|
VkPhysicalDeviceFeatures enabledFeatures{};
|
|
if (deviceFeatures.samplerAnisotropy) {
|
|
enabledFeatures.samplerAnisotropy = VK_TRUE;
|
|
}
|
|
std::vector<const char*> enabledExtensions{};
|
|
VkResult res = vulkanDevice->createLogicalDevice(enabledFeatures, enabledExtensions);
|
|
if (res != VK_SUCCESS) {
|
|
std::cerr << "Could not create Vulkan device!" << std::endl;
|
|
exit(res);
|
|
}
|
|
device = vulkanDevice->logicalDevice;
|
|
|
|
/*
|
|
Graphics queue
|
|
*/
|
|
vkGetDeviceQueue(device, vulkanDevice->queueFamilyIndices.graphics, 0, &queue);
|
|
queueFamilyIndex = vulkanDevice->queueFamilyIndices.graphics;
|
|
/*
|
|
Suitable depth format
|
|
*/
|
|
std::vector<VkFormat> depthFormats = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM };
|
|
VkBool32 validDepthFormat = false;
|
|
for (auto& format : depthFormats) {
|
|
VkFormatProperties formatProps;
|
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
|
|
if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
|
depthFormat = format;
|
|
validDepthFormat = true;
|
|
break;
|
|
}
|
|
}
|
|
assert(validDepthFormat);
|
|
|
|
//swapChain.connect(instance, physicalDevice, device);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanExampleBase::setupFrameBuffer()
|
|
{
|
|
/*
|
|
MSAA
|
|
*/
|
|
|
|
if (settings.multiSampling) {
|
|
// Check if device supports requested sample count for color and depth frame buffer
|
|
//assert((deviceProperties.limits.framebufferColorSampleCounts >= sampleCount) && (deviceProperties.limits.framebufferDepthSampleCounts >= sampleCount));
|
|
|
|
VkImageCreateInfo imageCI{};
|
|
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
|
imageCI.format = colorFormat;
|
|
imageCI.extent.width = settings.width;
|
|
imageCI.extent.height = 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 = 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.color.image));
|
|
|
|
VkMemoryRequirements memReqs;
|
|
vkGetImageMemoryRequirements(device, multisampleTarget.color.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.color.memory));
|
|
vkBindImageMemory(device, multisampleTarget.color.image, multisampleTarget.color.memory, 0);
|
|
|
|
// Create image view for the MSAA target
|
|
VkImageViewCreateInfo imageViewCI{};
|
|
imageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
imageViewCI.image = multisampleTarget.color.image;
|
|
imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
imageViewCI.format = colorFormat;
|
|
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.color.view));
|
|
|
|
// Depth target
|
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
|
imageCI.format = depthFormat;
|
|
imageCI.extent.width = settings.width;
|
|
imageCI.extent.height = 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 = 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.depth.image));
|
|
|
|
vkGetImageMemoryRequirements(device, multisampleTarget.depth.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.depth.memory));
|
|
vkBindImageMemory(device, multisampleTarget.depth.image, multisampleTarget.depth.memory, 0);
|
|
|
|
// Create image view for the MSAA target
|
|
imageViewCI.image = multisampleTarget.depth.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.depth.view));
|
|
}
|
|
else
|
|
{
|
|
// Color attachment
|
|
VkImageCreateInfo image = vks::initializers::imageCreateInfo();
|
|
image.imageType = VK_IMAGE_TYPE_2D;
|
|
image.format = colorFormat;
|
|
image.extent.width = settings.width;
|
|
image.extent.height = 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_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
|
|
VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();
|
|
VkMemoryRequirements memReqs;
|
|
|
|
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &colorAttachment.image));
|
|
vkGetImageMemoryRequirements(device, colorAttachment.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, &colorAttachment.memory));
|
|
VK_CHECK_RESULT(vkBindImageMemory(device, colorAttachment.image, colorAttachment.memory, 0));
|
|
|
|
VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
|
|
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
colorImageView.format = colorFormat;
|
|
colorImageView.subresourceRange = {};
|
|
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
colorImageView.subresourceRange.baseMipLevel = 0;
|
|
colorImageView.subresourceRange.levelCount = 1;
|
|
colorImageView.subresourceRange.baseArrayLayer = 0;
|
|
colorImageView.subresourceRange.layerCount = 1;
|
|
colorImageView.image = colorAttachment.image;
|
|
VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &colorAttachment.view));
|
|
}
|
|
|
|
|
|
// Depth/Stencil attachment is the same for all frame buffers
|
|
|
|
VkImageCreateInfo depthImageCI = {};
|
|
depthImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
depthImageCI.pNext = NULL;
|
|
depthImageCI.imageType = VK_IMAGE_TYPE_2D;
|
|
depthImageCI.format = depthFormat;
|
|
depthImageCI.extent = { settings.width, settings.height, 1 };
|
|
depthImageCI.mipLevels = 1;
|
|
depthImageCI.arrayLayers = 1;
|
|
depthImageCI.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
depthImageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
depthImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
depthImageCI.flags = 0;
|
|
|
|
VkMemoryAllocateInfo mem_alloc = {};
|
|
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
mem_alloc.pNext = NULL;
|
|
mem_alloc.allocationSize = 0;
|
|
mem_alloc.memoryTypeIndex = 0;
|
|
|
|
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.flags = 0;
|
|
depthStencilView.subresourceRange = {};
|
|
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
depthStencilView.subresourceRange.baseMipLevel = 0;
|
|
depthStencilView.subresourceRange.levelCount = 1;
|
|
depthStencilView.subresourceRange.baseArrayLayer = 0;
|
|
depthStencilView.subresourceRange.layerCount = 1;
|
|
|
|
VkMemoryRequirements depthMemReqs;
|
|
VK_CHECK_RESULT(vkCreateImage(device, &depthImageCI, nullptr, &depthStencil.image));
|
|
vkGetImageMemoryRequirements(device, depthStencil.image, &depthMemReqs);
|
|
mem_alloc.allocationSize = depthMemReqs.size;
|
|
mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(depthMemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthStencil.mem));
|
|
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
|
|
|
|
depthStencilView.image = depthStencil.image;
|
|
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
|
|
|
|
//
|
|
|
|
VkImageView attachments[settings.multiSampling ? 4 : 2];
|
|
|
|
if (settings.multiSampling) {
|
|
|
|
attachments[0] = multisampleTarget.color.view;
|
|
attachments[2] = multisampleTarget.depth.view;
|
|
attachments[3] = depthStencil.view;
|
|
}
|
|
else {
|
|
|
|
attachments[1] = depthStencil.view;
|
|
}
|
|
|
|
VkFramebufferCreateInfo frameBufferCI{};
|
|
frameBufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
frameBufferCI.pNext = NULL;
|
|
frameBufferCI.renderPass = renderPass;
|
|
frameBufferCI.attachmentCount = settings.multiSampling ? 4 :2;
|
|
frameBufferCI.pAttachments = attachments;
|
|
frameBufferCI.width = settings.width;
|
|
frameBufferCI.height = settings.height;
|
|
frameBufferCI.layers = 1;
|
|
|
|
// Create frame buffers for every swap chain image
|
|
frameBuffers.resize(settings.endFrameIndex - settings.startFrameIndex + 1);
|
|
for (uint32_t i = 0; i < frameBuffers.size(); i++) {
|
|
if (settings.multiSampling) {
|
|
attachments[1] = colorAttachment.view;
|
|
}
|
|
else {
|
|
attachments[0] = colorAttachment.view;
|
|
}
|
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i]));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void VulkanExampleBase::initSwapchain()
|
|
{
|
|
/*
|
|
#if defined(_WIN32)
|
|
swapChain.initSurface(windowInstance, window);
|
|
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
|
|
swapChain.initSurface(androidApp->window);
|
|
#elif defined(_DIRECT2DISPLAY)
|
|
swapChain.initSurface(width, height);
|
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
|
swapChain.initSurface(display, surface);
|
|
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
|
swapChain.initSurface(connection, window);
|
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
|
swapChain.initSurface((__bridge void*)[window contentView]);
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
/*
|
|
|
|
void VulkanExampleBase::setupSwapChain()
|
|
{
|
|
//swapChain.create(&width, &height, settings.vsync);
|
|
}
|
|
*/
|