/* * 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 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 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 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 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 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(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 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 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(attachments.size()); renderPassCI.pAttachments = attachments.data(); renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpassDescription; renderPassCI.dependencyCount = static_cast(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(tEnd - tStart).count(); frameTimer = (float)tDiff / 1000.0f; camera.update(frameTimer); fpsTimer += (float)tDiff; if (fpsTimer > 1000.0f) { lastFPS = static_cast((float)frameCounter * (1000.0f / fpsTimer)); fpsTimer = 0.0f; frameCounter = 0; } } void VulkanExampleBase::renderLoop() { 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(vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); vkDestroyDebugReportCallback = reinterpret_cast(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 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 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 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); } */