parent
							
								
									14f0b51c75
								
							
						
					
					
						commit
						aceb49e0be
					
				| 
						 | 
				
			
			@ -1,329 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
* Extended sample base class for ray tracing based samples
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) 2020-2021 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "VulkanRaytracingSample.h"
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::updateRenderPass()
 | 
			
		||||
{
 | 
			
		||||
	// Update the default render pass with different color attachment load ops to keep attachment contents
 | 
			
		||||
	// With this change, we can e.g. draw an UI on top of the ray traced scene
 | 
			
		||||
 | 
			
		||||
	vkDestroyRenderPass(device, renderPass, nullptr);
 | 
			
		||||
 | 
			
		||||
	std::array<VkAttachmentDescription, 2> attachments = {};
 | 
			
		||||
	// Color attachment
 | 
			
		||||
	attachments[0].format = swapChain.colorFormat;
 | 
			
		||||
	attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
 | 
			
		||||
	attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
 | 
			
		||||
	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_PRESENT_SRC_KHR;
 | 
			
		||||
	attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 | 
			
		||||
	// 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 renderPassInfo = {};
 | 
			
		||||
	renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 | 
			
		||||
	renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
 | 
			
		||||
	renderPassInfo.pAttachments = attachments.data();
 | 
			
		||||
	renderPassInfo.subpassCount = 1;
 | 
			
		||||
	renderPassInfo.pSubpasses = &subpassDescription;
 | 
			
		||||
	renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());
 | 
			
		||||
	renderPassInfo.pDependencies = dependencies.data();
 | 
			
		||||
	VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::enableExtensions()
 | 
			
		||||
{
 | 
			
		||||
	// Require Vulkan 1.1
 | 
			
		||||
	apiVersion = VK_API_VERSION_1_1;
 | 
			
		||||
 | 
			
		||||
	// Ray tracing related extensions required by this sample
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
 | 
			
		||||
	if (!rayQueryOnly) {
 | 
			
		||||
		enabledDeviceExtensions.push_back(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Required by VK_KHR_acceleration_structure
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
 | 
			
		||||
 | 
			
		||||
	// Required for VK_KHR_ray_tracing_pipeline
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
 | 
			
		||||
 | 
			
		||||
	// Required by VK_KHR_spirv_1_4
 | 
			
		||||
	enabledDeviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VulkanRaytracingSample::ScratchBuffer VulkanRaytracingSample::createScratchBuffer(VkDeviceSize size)
 | 
			
		||||
{
 | 
			
		||||
	ScratchBuffer scratchBuffer{};
 | 
			
		||||
	// Buffer and memory
 | 
			
		||||
	VkBufferCreateInfo bufferCreateInfo{};
 | 
			
		||||
	bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 | 
			
		||||
	bufferCreateInfo.size = size;
 | 
			
		||||
	bufferCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
 | 
			
		||||
	VK_CHECK_RESULT(vkCreateBuffer(vulkanDevice->logicalDevice, &bufferCreateInfo, nullptr, &scratchBuffer.handle));
 | 
			
		||||
	VkMemoryRequirements memoryRequirements{};
 | 
			
		||||
	vkGetBufferMemoryRequirements(vulkanDevice->logicalDevice, scratchBuffer.handle, &memoryRequirements);
 | 
			
		||||
	VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{};
 | 
			
		||||
	memoryAllocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
 | 
			
		||||
	memoryAllocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
 | 
			
		||||
	VkMemoryAllocateInfo memoryAllocateInfo = {};
 | 
			
		||||
	memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
 | 
			
		||||
	memoryAllocateInfo.pNext = &memoryAllocateFlagsInfo;
 | 
			
		||||
	memoryAllocateInfo.allocationSize = memoryRequirements.size;
 | 
			
		||||
	memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 | 
			
		||||
	VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &scratchBuffer.memory));
 | 
			
		||||
	VK_CHECK_RESULT(vkBindBufferMemory(vulkanDevice->logicalDevice, scratchBuffer.handle, scratchBuffer.memory, 0));
 | 
			
		||||
	// Buffer device address
 | 
			
		||||
	VkBufferDeviceAddressInfoKHR bufferDeviceAddresInfo{};
 | 
			
		||||
	bufferDeviceAddresInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
 | 
			
		||||
	bufferDeviceAddresInfo.buffer = scratchBuffer.handle;
 | 
			
		||||
	scratchBuffer.deviceAddress = vkGetBufferDeviceAddressKHR(vulkanDevice->logicalDevice, &bufferDeviceAddresInfo);
 | 
			
		||||
	return scratchBuffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::deleteScratchBuffer(ScratchBuffer& scratchBuffer)
 | 
			
		||||
{
 | 
			
		||||
	if (scratchBuffer.memory != VK_NULL_HANDLE) {
 | 
			
		||||
		vkFreeMemory(vulkanDevice->logicalDevice, scratchBuffer.memory, nullptr);
 | 
			
		||||
	}
 | 
			
		||||
	if (scratchBuffer.handle != VK_NULL_HANDLE) {
 | 
			
		||||
		vkDestroyBuffer(vulkanDevice->logicalDevice, scratchBuffer.handle, nullptr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::createAccelerationStructure(AccelerationStructure& accelerationStructure, VkAccelerationStructureTypeKHR type, VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo)
 | 
			
		||||
{
 | 
			
		||||
	// Buffer and memory
 | 
			
		||||
	VkBufferCreateInfo bufferCreateInfo{};
 | 
			
		||||
	bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
 | 
			
		||||
	bufferCreateInfo.size = buildSizeInfo.accelerationStructureSize;
 | 
			
		||||
	bufferCreateInfo.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
 | 
			
		||||
	VK_CHECK_RESULT(vkCreateBuffer(vulkanDevice->logicalDevice, &bufferCreateInfo, nullptr, &accelerationStructure.buffer));
 | 
			
		||||
	VkMemoryRequirements memoryRequirements{};
 | 
			
		||||
	vkGetBufferMemoryRequirements(vulkanDevice->logicalDevice, accelerationStructure.buffer, &memoryRequirements);
 | 
			
		||||
	VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{};
 | 
			
		||||
	memoryAllocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
 | 
			
		||||
	memoryAllocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
 | 
			
		||||
	VkMemoryAllocateInfo memoryAllocateInfo{};
 | 
			
		||||
	memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
 | 
			
		||||
	memoryAllocateInfo.pNext = &memoryAllocateFlagsInfo;
 | 
			
		||||
	memoryAllocateInfo.allocationSize = memoryRequirements.size;
 | 
			
		||||
	memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 | 
			
		||||
	VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &accelerationStructure.memory));
 | 
			
		||||
	VK_CHECK_RESULT(vkBindBufferMemory(vulkanDevice->logicalDevice, accelerationStructure.buffer, accelerationStructure.memory, 0));
 | 
			
		||||
	// Acceleration structure
 | 
			
		||||
	VkAccelerationStructureCreateInfoKHR accelerationStructureCreate_info{};
 | 
			
		||||
	accelerationStructureCreate_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
 | 
			
		||||
	accelerationStructureCreate_info.buffer = accelerationStructure.buffer;
 | 
			
		||||
	accelerationStructureCreate_info.size = buildSizeInfo.accelerationStructureSize;
 | 
			
		||||
	accelerationStructureCreate_info.type = type;
 | 
			
		||||
	vkCreateAccelerationStructureKHR(vulkanDevice->logicalDevice, &accelerationStructureCreate_info, nullptr, &accelerationStructure.handle);
 | 
			
		||||
	// AS device address
 | 
			
		||||
	VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
 | 
			
		||||
	accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
 | 
			
		||||
	accelerationDeviceAddressInfo.accelerationStructure = accelerationStructure.handle;
 | 
			
		||||
	accelerationStructure.deviceAddress = vkGetAccelerationStructureDeviceAddressKHR(vulkanDevice->logicalDevice, &accelerationDeviceAddressInfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::deleteAccelerationStructure(AccelerationStructure& accelerationStructure)
 | 
			
		||||
{
 | 
			
		||||
	vkFreeMemory(device, accelerationStructure.memory, nullptr);
 | 
			
		||||
	vkDestroyBuffer(device, accelerationStructure.buffer, nullptr);
 | 
			
		||||
	vkDestroyAccelerationStructureKHR(device, accelerationStructure.handle, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t VulkanRaytracingSample::getBufferDeviceAddress(VkBuffer buffer)
 | 
			
		||||
{
 | 
			
		||||
	VkBufferDeviceAddressInfoKHR bufferDeviceAI{};
 | 
			
		||||
	bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
 | 
			
		||||
	bufferDeviceAI.buffer = buffer;
 | 
			
		||||
	return vkGetBufferDeviceAddressKHR(vulkanDevice->logicalDevice, &bufferDeviceAI);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::createStorageImage(VkFormat format, VkExtent3D extent)
 | 
			
		||||
{
 | 
			
		||||
	// Release ressources if image is to be recreated
 | 
			
		||||
	if (storageImage.image != VK_NULL_HANDLE) {
 | 
			
		||||
		vkDestroyImageView(device, storageImage.view, nullptr);
 | 
			
		||||
		vkDestroyImage(device, storageImage.image, nullptr);
 | 
			
		||||
		vkFreeMemory(device, storageImage.memory, nullptr);
 | 
			
		||||
		storageImage = {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkImageCreateInfo image = vks::initializers::imageCreateInfo();
 | 
			
		||||
	image.imageType = VK_IMAGE_TYPE_2D;
 | 
			
		||||
	image.format = format;
 | 
			
		||||
	image.extent = extent;
 | 
			
		||||
	image.mipLevels = 1;
 | 
			
		||||
	image.arrayLayers = 1;
 | 
			
		||||
	image.samples = VK_SAMPLE_COUNT_1_BIT;
 | 
			
		||||
	image.tiling = VK_IMAGE_TILING_OPTIMAL;
 | 
			
		||||
	image.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
 | 
			
		||||
	image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 | 
			
		||||
	VK_CHECK_RESULT(vkCreateImage(vulkanDevice->logicalDevice, &image, nullptr, &storageImage.image));
 | 
			
		||||
 | 
			
		||||
	VkMemoryRequirements memReqs;
 | 
			
		||||
	vkGetImageMemoryRequirements(vulkanDevice->logicalDevice, storageImage.image, &memReqs);
 | 
			
		||||
	VkMemoryAllocateInfo memoryAllocateInfo = vks::initializers::memoryAllocateInfo();
 | 
			
		||||
	memoryAllocateInfo.allocationSize = memReqs.size;
 | 
			
		||||
	memoryAllocateInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 | 
			
		||||
	VK_CHECK_RESULT(vkAllocateMemory(vulkanDevice->logicalDevice, &memoryAllocateInfo, nullptr, &storageImage.memory));
 | 
			
		||||
	VK_CHECK_RESULT(vkBindImageMemory(vulkanDevice->logicalDevice, storageImage.image, storageImage.memory, 0));
 | 
			
		||||
 | 
			
		||||
	VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();
 | 
			
		||||
	colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
 | 
			
		||||
	colorImageView.format = format;
 | 
			
		||||
	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 = storageImage.image;
 | 
			
		||||
	VK_CHECK_RESULT(vkCreateImageView(vulkanDevice->logicalDevice, &colorImageView, nullptr, &storageImage.view));
 | 
			
		||||
 | 
			
		||||
	VkCommandBuffer cmdBuffer = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
 | 
			
		||||
	vks::tools::setImageLayout(cmdBuffer, storageImage.image,
 | 
			
		||||
		VK_IMAGE_LAYOUT_UNDEFINED,
 | 
			
		||||
		VK_IMAGE_LAYOUT_GENERAL,
 | 
			
		||||
		{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
 | 
			
		||||
	vulkanDevice->flushCommandBuffer(cmdBuffer, queue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::deleteStorageImage()
 | 
			
		||||
{
 | 
			
		||||
	vkDestroyImageView(vulkanDevice->logicalDevice, storageImage.view, nullptr);
 | 
			
		||||
	vkDestroyImage(vulkanDevice->logicalDevice, storageImage.image, nullptr);
 | 
			
		||||
	vkFreeMemory(vulkanDevice->logicalDevice, storageImage.memory, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::prepare()
 | 
			
		||||
{
 | 
			
		||||
	VulkanExampleBase::prepare();
 | 
			
		||||
	// Get properties and features
 | 
			
		||||
	rayTracingPipelineProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
 | 
			
		||||
	VkPhysicalDeviceProperties2 deviceProperties2{};
 | 
			
		||||
	deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
 | 
			
		||||
	deviceProperties2.pNext = &rayTracingPipelineProperties;
 | 
			
		||||
	vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProperties2);
 | 
			
		||||
	accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
 | 
			
		||||
	VkPhysicalDeviceFeatures2 deviceFeatures2{};
 | 
			
		||||
	deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
 | 
			
		||||
	deviceFeatures2.pNext = &accelerationStructureFeatures;
 | 
			
		||||
	vkGetPhysicalDeviceFeatures2(physicalDevice, &deviceFeatures2);
 | 
			
		||||
	// Get the function pointers required for ray tracing
 | 
			
		||||
	vkGetBufferDeviceAddressKHR = reinterpret_cast<PFN_vkGetBufferDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
 | 
			
		||||
	vkCmdBuildAccelerationStructuresKHR = reinterpret_cast<PFN_vkCmdBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR"));
 | 
			
		||||
	vkBuildAccelerationStructuresKHR = reinterpret_cast<PFN_vkBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR"));
 | 
			
		||||
	vkCreateAccelerationStructureKHR = reinterpret_cast<PFN_vkCreateAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
 | 
			
		||||
	vkDestroyAccelerationStructureKHR = reinterpret_cast<PFN_vkDestroyAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
 | 
			
		||||
	vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast<PFN_vkGetAccelerationStructureBuildSizesKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR"));
 | 
			
		||||
	vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast<PFN_vkGetAccelerationStructureDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
 | 
			
		||||
	vkCmdTraceRaysKHR = reinterpret_cast<PFN_vkCmdTraceRaysKHR>(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
 | 
			
		||||
	vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast<PFN_vkGetRayTracingShaderGroupHandlesKHR>(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
 | 
			
		||||
	vkCreateRayTracingPipelinesKHR = reinterpret_cast<PFN_vkCreateRayTracingPipelinesKHR>(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
 | 
			
		||||
	// Update the render pass to keep the color attachment contents, so we can draw the UI on top of the ray traced output
 | 
			
		||||
	if (!rayQueryOnly) {
 | 
			
		||||
		updateRenderPass();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VkStridedDeviceAddressRegionKHR VulkanRaytracingSample::getSbtEntryStridedDeviceAddressRegion(VkBuffer buffer, uint32_t handleCount)
 | 
			
		||||
{
 | 
			
		||||
	const uint32_t handleSizeAligned = vks::tools::alignedSize(rayTracingPipelineProperties.shaderGroupHandleSize, rayTracingPipelineProperties.shaderGroupHandleAlignment);
 | 
			
		||||
	VkStridedDeviceAddressRegionKHR stridedDeviceAddressRegionKHR{};
 | 
			
		||||
	stridedDeviceAddressRegionKHR.deviceAddress = getBufferDeviceAddress(buffer);
 | 
			
		||||
	stridedDeviceAddressRegionKHR.stride = handleSizeAligned;
 | 
			
		||||
	stridedDeviceAddressRegionKHR.size = handleCount * handleSizeAligned;
 | 
			
		||||
	return stridedDeviceAddressRegionKHR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::createShaderBindingTable(ShaderBindingTable& shaderBindingTable, uint32_t handleCount)
 | 
			
		||||
{
 | 
			
		||||
	// Create buffer to hold all shader handles for the SBT
 | 
			
		||||
	VK_CHECK_RESULT(vulkanDevice->createBuffer(
 | 
			
		||||
		VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, 
 | 
			
		||||
		VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 
 | 
			
		||||
		&shaderBindingTable, 
 | 
			
		||||
		rayTracingPipelineProperties.shaderGroupHandleSize * handleCount));
 | 
			
		||||
	// Get the strided address to be used when dispatching the rays
 | 
			
		||||
	shaderBindingTable.stridedDeviceAddressRegion = getSbtEntryStridedDeviceAddressRegion(shaderBindingTable.buffer, handleCount);
 | 
			
		||||
	// Map persistent 
 | 
			
		||||
	shaderBindingTable.map();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VulkanRaytracingSample::drawUI(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer)
 | 
			
		||||
{
 | 
			
		||||
	VkClearValue clearValues[2];
 | 
			
		||||
	clearValues[0].color = defaultClearColor;
 | 
			
		||||
	clearValues[1].depthStencil = { 1.0f, 0 };
 | 
			
		||||
 | 
			
		||||
	VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
 | 
			
		||||
	renderPassBeginInfo.renderPass = renderPass;
 | 
			
		||||
	renderPassBeginInfo.renderArea.offset.x = 0;
 | 
			
		||||
	renderPassBeginInfo.renderArea.offset.y = 0;
 | 
			
		||||
	renderPassBeginInfo.renderArea.extent.width = width;
 | 
			
		||||
	renderPassBeginInfo.renderArea.extent.height = height;
 | 
			
		||||
	renderPassBeginInfo.clearValueCount = 2;
 | 
			
		||||
	renderPassBeginInfo.pClearValues = clearValues;
 | 
			
		||||
	renderPassBeginInfo.framebuffer = framebuffer;
 | 
			
		||||
 | 
			
		||||
	vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
 | 
			
		||||
	VulkanExampleBase::drawUI(commandBuffer);
 | 
			
		||||
	vkCmdEndRenderPass(commandBuffer);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,90 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
* Extended sample base class for ray tracing based samples
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "vulkan/vulkan.h"
 | 
			
		||||
#include "vulkanexamplebase.h"
 | 
			
		||||
#include "VulkanTools.h"
 | 
			
		||||
#include "VulkanDevice.hpp"
 | 
			
		||||
 | 
			
		||||
class VulkanRaytracingSample : public VulkanExampleBase
 | 
			
		||||
{
 | 
			
		||||
protected:
 | 
			
		||||
	// Update the default render pass with different color attachment load ops
 | 
			
		||||
	virtual void updateRenderPass();
 | 
			
		||||
public:
 | 
			
		||||
	// Function pointers for ray tracing related stuff
 | 
			
		||||
	PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
 | 
			
		||||
	PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR;
 | 
			
		||||
	PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR;
 | 
			
		||||
	PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR;
 | 
			
		||||
	PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR;
 | 
			
		||||
	PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR;
 | 
			
		||||
	PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR;
 | 
			
		||||
	PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR;
 | 
			
		||||
	PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR;
 | 
			
		||||
	PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
 | 
			
		||||
 | 
			
		||||
	// Available features and properties
 | 
			
		||||
	VkPhysicalDeviceRayTracingPipelinePropertiesKHR  rayTracingPipelineProperties{};
 | 
			
		||||
	VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures{};
 | 
			
		||||
 | 
			
		||||
	// Enabled features and properties
 | 
			
		||||
	VkPhysicalDeviceBufferDeviceAddressFeatures enabledBufferDeviceAddresFeatures{};
 | 
			
		||||
	VkPhysicalDeviceRayTracingPipelineFeaturesKHR enabledRayTracingPipelineFeatures{};
 | 
			
		||||
	VkPhysicalDeviceAccelerationStructureFeaturesKHR enabledAccelerationStructureFeatures{};
 | 
			
		||||
 | 
			
		||||
	// Holds information for a ray tracing scratch buffer that is used as a temporary storage
 | 
			
		||||
	struct ScratchBuffer
 | 
			
		||||
	{
 | 
			
		||||
		uint64_t deviceAddress = 0;
 | 
			
		||||
		VkBuffer handle = VK_NULL_HANDLE;
 | 
			
		||||
		VkDeviceMemory memory = VK_NULL_HANDLE;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Holds information for a ray tracing acceleration structure
 | 
			
		||||
	struct AccelerationStructure {
 | 
			
		||||
		VkAccelerationStructureKHR handle;
 | 
			
		||||
		uint64_t deviceAddress = 0;
 | 
			
		||||
		VkDeviceMemory memory;
 | 
			
		||||
		VkBuffer buffer;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Holds information for a storage image that the ray tracing shaders output to
 | 
			
		||||
	struct StorageImage {
 | 
			
		||||
		VkDeviceMemory memory = VK_NULL_HANDLE;
 | 
			
		||||
		VkImage image = VK_NULL_HANDLE;
 | 
			
		||||
		VkImageView view = VK_NULL_HANDLE;
 | 
			
		||||
		VkFormat format;
 | 
			
		||||
	} storageImage;
 | 
			
		||||
 | 
			
		||||
	// Extends the buffer class and holds information for a shader binding table
 | 
			
		||||
	class ShaderBindingTable : public vks::Buffer {
 | 
			
		||||
	public:
 | 
			
		||||
		VkStridedDeviceAddressRegionKHR stridedDeviceAddressRegion{};
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Set to true, to denote that the sample only uses ray queries (changes extension and render pass handling)
 | 
			
		||||
	bool rayQueryOnly = false;
 | 
			
		||||
 | 
			
		||||
	void enableExtensions();
 | 
			
		||||
	ScratchBuffer createScratchBuffer(VkDeviceSize size);
 | 
			
		||||
	void deleteScratchBuffer(ScratchBuffer& scratchBuffer);
 | 
			
		||||
	void createAccelerationStructure(AccelerationStructure& accelerationStructure, VkAccelerationStructureTypeKHR type, VkAccelerationStructureBuildSizesInfoKHR buildSizeInfo);
 | 
			
		||||
	void deleteAccelerationStructure(AccelerationStructure& accelerationStructure);
 | 
			
		||||
	uint64_t getBufferDeviceAddress(VkBuffer buffer);
 | 
			
		||||
	void createStorageImage(VkFormat format, VkExtent3D extent);
 | 
			
		||||
	void deleteStorageImage();
 | 
			
		||||
	VkStridedDeviceAddressRegionKHR getSbtEntryStridedDeviceAddressRegion(VkBuffer buffer, uint32_t handleCount);
 | 
			
		||||
	void createShaderBindingTable(ShaderBindingTable& shaderBindingTable, uint32_t handleCount);
 | 
			
		||||
	// Draw the ImGUI UI overlay using a render pass
 | 
			
		||||
	void drawUI(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer);
 | 
			
		||||
 | 
			
		||||
	virtual void prepare();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,616 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
* Class wrapping access to the swap chain
 | 
			
		||||
* 
 | 
			
		||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) 2016-2021 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "VulkanSwapChain.h"
 | 
			
		||||
 | 
			
		||||
/** @brief Creates the platform specific surface abstraction of the native platform window used for presentation */	
 | 
			
		||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
 | 
			
		||||
void VulkanSwapChain::initSurface(void* platformHandle, void* platformWindow)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
void VulkanSwapChain::initSurface(ANativeWindow* window)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
void VulkanSwapChain::initSurface(IDirectFB* dfb, IDirectFBSurface* window)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
void VulkanSwapChain::initSurface(wl_display *display, wl_surface *window)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
void VulkanSwapChain::initSurface(xcb_connection_t* connection, xcb_window_t window)
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
void VulkanSwapChain::initSurface(void* view)
 | 
			
		||||
#elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT))
 | 
			
		||||
void VulkanSwapChain::initSurface(uint32_t width, uint32_t height)
 | 
			
		||||
#endif
 | 
			
		||||
{
 | 
			
		||||
	VkResult err = VK_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	// Create the os-specific surface
 | 
			
		||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
 | 
			
		||||
	VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
	surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle;
 | 
			
		||||
	surfaceCreateInfo.hwnd = (HWND)platformWindow;
 | 
			
		||||
	err = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
	VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
	surfaceCreateInfo.window = window;
 | 
			
		||||
	err = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
 | 
			
		||||
	VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
 | 
			
		||||
	surfaceCreateInfo.pNext = NULL;
 | 
			
		||||
	surfaceCreateInfo.flags = 0;
 | 
			
		||||
	surfaceCreateInfo.pView = view;
 | 
			
		||||
	err = vkCreateIOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
 | 
			
		||||
	VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
 | 
			
		||||
	surfaceCreateInfo.pNext = NULL;
 | 
			
		||||
	surfaceCreateInfo.flags = 0;
 | 
			
		||||
	surfaceCreateInfo.pView = view;
 | 
			
		||||
	err = vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, NULL, &surface);
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
	createDirect2DisplaySurface(width, height);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
	VkDirectFBSurfaceCreateInfoEXT surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT;
 | 
			
		||||
	surfaceCreateInfo.dfb = dfb;
 | 
			
		||||
	surfaceCreateInfo.surface = window;
 | 
			
		||||
	err = vkCreateDirectFBSurfaceEXT(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
	VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
	surfaceCreateInfo.display = display;
 | 
			
		||||
	surfaceCreateInfo.surface = window;
 | 
			
		||||
	err = vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
	VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
	surfaceCreateInfo.connection = connection;
 | 
			
		||||
	surfaceCreateInfo.window = window;
 | 
			
		||||
	err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_HEADLESS_EXT)
 | 
			
		||||
	VkHeadlessSurfaceCreateInfoEXT surfaceCreateInfo = {};
 | 
			
		||||
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
 | 
			
		||||
	PFN_vkCreateHeadlessSurfaceEXT fpCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT)vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
 | 
			
		||||
	if (!fpCreateHeadlessSurfaceEXT){
 | 
			
		||||
		vks::tools::exitFatal("Could not fetch function pointer for the headless extension!", -1);
 | 
			
		||||
	}
 | 
			
		||||
	err = fpCreateHeadlessSurfaceEXT(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (err != VK_SUCCESS) {
 | 
			
		||||
		vks::tools::exitFatal("Could not create surface!", err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get available queue family properties
 | 
			
		||||
	uint32_t queueCount;
 | 
			
		||||
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
 | 
			
		||||
	assert(queueCount >= 1);
 | 
			
		||||
 | 
			
		||||
	std::vector<VkQueueFamilyProperties> queueProps(queueCount);
 | 
			
		||||
	vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());
 | 
			
		||||
 | 
			
		||||
	// Iterate over each queue to learn whether it supports presenting:
 | 
			
		||||
	// Find a queue with present support
 | 
			
		||||
	// Will be used to present the swap chain images to the windowing system
 | 
			
		||||
	std::vector<VkBool32> supportsPresent(queueCount);
 | 
			
		||||
	for (uint32_t i = 0; i < queueCount; i++) 
 | 
			
		||||
	{
 | 
			
		||||
		fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &supportsPresent[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Search for a graphics and a present queue in the array of queue
 | 
			
		||||
	// families, try to find one that supports both
 | 
			
		||||
	uint32_t graphicsQueueNodeIndex = UINT32_MAX;
 | 
			
		||||
	uint32_t presentQueueNodeIndex = UINT32_MAX;
 | 
			
		||||
	for (uint32_t i = 0; i < queueCount; i++) 
 | 
			
		||||
	{
 | 
			
		||||
		if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) 
 | 
			
		||||
		{
 | 
			
		||||
			if (graphicsQueueNodeIndex == UINT32_MAX) 
 | 
			
		||||
			{
 | 
			
		||||
				graphicsQueueNodeIndex = i;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (supportsPresent[i] == VK_TRUE) 
 | 
			
		||||
			{
 | 
			
		||||
				graphicsQueueNodeIndex = i;
 | 
			
		||||
				presentQueueNodeIndex = i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (presentQueueNodeIndex == UINT32_MAX) 
 | 
			
		||||
	{	
 | 
			
		||||
		// If there's no queue that supports both present and graphics
 | 
			
		||||
		// try to find a separate present queue
 | 
			
		||||
		for (uint32_t i = 0; i < queueCount; ++i) 
 | 
			
		||||
		{
 | 
			
		||||
			if (supportsPresent[i] == VK_TRUE) 
 | 
			
		||||
			{
 | 
			
		||||
				presentQueueNodeIndex = i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Exit if either a graphics or a presenting queue hasn't been found
 | 
			
		||||
	if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) 
 | 
			
		||||
	{
 | 
			
		||||
		vks::tools::exitFatal("Could not find a graphics and/or presenting queue!", -1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// todo : Add support for separate graphics and presenting queue
 | 
			
		||||
	if (graphicsQueueNodeIndex != presentQueueNodeIndex) 
 | 
			
		||||
	{
 | 
			
		||||
		vks::tools::exitFatal("Separate graphics and presenting queues are not supported yet!", -1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	queueNodeIndex = graphicsQueueNodeIndex;
 | 
			
		||||
 | 
			
		||||
	// Get list of supported surface formats
 | 
			
		||||
	uint32_t formatCount;
 | 
			
		||||
	VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL));
 | 
			
		||||
	assert(formatCount > 0);
 | 
			
		||||
 | 
			
		||||
	std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
 | 
			
		||||
	VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data()));
 | 
			
		||||
 | 
			
		||||
	// If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
 | 
			
		||||
	// there is no preferred format, so we assume VK_FORMAT_B8G8R8A8_UNORM
 | 
			
		||||
	if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
 | 
			
		||||
	{
 | 
			
		||||
		colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
 | 
			
		||||
		colorSpace = surfaceFormats[0].colorSpace;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// iterate over the list of available surface format and
 | 
			
		||||
		// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
 | 
			
		||||
		bool found_B8G8R8A8_UNORM = false;
 | 
			
		||||
		for (auto&& surfaceFormat : surfaceFormats)
 | 
			
		||||
		{
 | 
			
		||||
			if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM)
 | 
			
		||||
			{
 | 
			
		||||
				colorFormat = surfaceFormat.format;
 | 
			
		||||
				colorSpace = surfaceFormat.colorSpace;
 | 
			
		||||
				found_B8G8R8A8_UNORM = true;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// in case VK_FORMAT_B8G8R8A8_UNORM is not available
 | 
			
		||||
		// select the first available color format
 | 
			
		||||
		if (!found_B8G8R8A8_UNORM)
 | 
			
		||||
		{
 | 
			
		||||
			colorFormat = surfaceFormats[0].format;
 | 
			
		||||
			colorSpace = surfaceFormats[0].colorSpace;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Set instance, physical and logical device to use for the swapchain and get all required function pointers
 | 
			
		||||
* 
 | 
			
		||||
* @param instance Vulkan instance to use
 | 
			
		||||
* @param physicalDevice Physical device used to query properties and formats relevant to the swapchain
 | 
			
		||||
* @param device Logical representation of the device to create the swapchain for
 | 
			
		||||
*
 | 
			
		||||
*/
 | 
			
		||||
void VulkanSwapChain::connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
 | 
			
		||||
{
 | 
			
		||||
	this->instance = instance;
 | 
			
		||||
	this->physicalDevice = physicalDevice;
 | 
			
		||||
	this->device = device;
 | 
			
		||||
	fpGetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"));
 | 
			
		||||
	fpGetPhysicalDeviceSurfaceCapabilitiesKHR =  reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
 | 
			
		||||
	fpGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
 | 
			
		||||
	fpGetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
 | 
			
		||||
 | 
			
		||||
	fpCreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(vkGetDeviceProcAddr(device, "vkCreateSwapchainKHR"));
 | 
			
		||||
	fpDestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(vkGetDeviceProcAddr(device, "vkDestroySwapchainKHR"));
 | 
			
		||||
	fpGetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(vkGetDeviceProcAddr(device, "vkGetSwapchainImagesKHR"));
 | 
			
		||||
	fpAcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(vkGetDeviceProcAddr(device, "vkAcquireNextImageKHR"));
 | 
			
		||||
	fpQueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(vkGetDeviceProcAddr(device, "vkQueuePresentKHR"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 
 | 
			
		||||
* Create the swapchain and get its images with given width and height
 | 
			
		||||
* 
 | 
			
		||||
* @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain)
 | 
			
		||||
* @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain)
 | 
			
		||||
* @param vsync (Optional) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode)
 | 
			
		||||
*/
 | 
			
		||||
void VulkanSwapChain::create(uint32_t *width, uint32_t *height, bool vsync, bool fullscreen)
 | 
			
		||||
{
 | 
			
		||||
	// Store the current swap chain handle so we can use it later on to ease up recreation
 | 
			
		||||
	VkSwapchainKHR oldSwapchain = swapChain;
 | 
			
		||||
 | 
			
		||||
	// Get physical device surface properties and formats
 | 
			
		||||
	VkSurfaceCapabilitiesKHR surfCaps;
 | 
			
		||||
	VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps));
 | 
			
		||||
 | 
			
		||||
	// 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()));
 | 
			
		||||
 | 
			
		||||
	VkExtent2D swapchainExtent = {};
 | 
			
		||||
	// If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
 | 
			
		||||
	if (surfCaps.currentExtent.width == (uint32_t)-1)
 | 
			
		||||
	{
 | 
			
		||||
		// If the surface size is undefined, the size is set to
 | 
			
		||||
		// the size of the images requested.
 | 
			
		||||
		swapchainExtent.width = *width;
 | 
			
		||||
		swapchainExtent.height = *height;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// If the surface size is defined, the swap chain size must match
 | 
			
		||||
		swapchainExtent = surfCaps.currentExtent;
 | 
			
		||||
		*width = surfCaps.currentExtent.width;
 | 
			
		||||
		*height = surfCaps.currentExtent.height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// Select a present mode for the swapchain
 | 
			
		||||
 | 
			
		||||
	// 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 (!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 (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
 | 
			
		||||
			{
 | 
			
		||||
				swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Determine the number of images
 | 
			
		||||
	uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
 | 
			
		||||
#if (defined(VK_USE_PLATFORM_MACOS_MVK) && defined(VK_EXAMPLE_XCODE_GENERATED))
 | 
			
		||||
	// SRS - Work around known MoltenVK issue re 2x frame rate when vsync (VK_PRESENT_MODE_FIFO_KHR) enabled
 | 
			
		||||
	struct utsname sysInfo;
 | 
			
		||||
	uname(&sysInfo);
 | 
			
		||||
	// SRS - When vsync is on, use minImageCount when not in fullscreen or when running on Apple Silcon
 | 
			
		||||
	// This forces swapchain image acquire frame rate to match display vsync frame rate
 | 
			
		||||
	if (vsync && (!fullscreen || strcmp(sysInfo.machine, "arm64") == 0))
 | 
			
		||||
	{
 | 
			
		||||
		desiredNumberOfSwapchainImages = surfCaps.minImageCount;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
 | 
			
		||||
	{
 | 
			
		||||
		desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find the transformation of the surface
 | 
			
		||||
	VkSurfaceTransformFlagsKHR preTransform;
 | 
			
		||||
	if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
 | 
			
		||||
	{
 | 
			
		||||
		// We prefer a non-rotated transform
 | 
			
		||||
		preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		preTransform = surfCaps.currentTransform;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find a supported composite alpha format (not all devices support alpha opaque)
 | 
			
		||||
	VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
 | 
			
		||||
	// Simply select the first composite alpha format available
 | 
			
		||||
	std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
 | 
			
		||||
		VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
 | 
			
		||||
		VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
 | 
			
		||||
		VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
 | 
			
		||||
		VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
 | 
			
		||||
	};
 | 
			
		||||
	for (auto& compositeAlphaFlag : compositeAlphaFlags) {
 | 
			
		||||
		if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
 | 
			
		||||
			compositeAlpha = compositeAlphaFlag;
 | 
			
		||||
			break;
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkSwapchainCreateInfoKHR swapchainCI = {};
 | 
			
		||||
	swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
 | 
			
		||||
	swapchainCI.surface = surface;
 | 
			
		||||
	swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
 | 
			
		||||
	swapchainCI.imageFormat = colorFormat;
 | 
			
		||||
	swapchainCI.imageColorSpace = colorSpace;
 | 
			
		||||
	swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
 | 
			
		||||
	swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 | 
			
		||||
	swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
 | 
			
		||||
	swapchainCI.imageArrayLayers = 1;
 | 
			
		||||
	swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 | 
			
		||||
	swapchainCI.queueFamilyIndexCount = 0;
 | 
			
		||||
	swapchainCI.presentMode = swapchainPresentMode;
 | 
			
		||||
	// Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images
 | 
			
		||||
	swapchainCI.oldSwapchain = oldSwapchain;
 | 
			
		||||
	// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
 | 
			
		||||
	swapchainCI.clipped = VK_TRUE;
 | 
			
		||||
	swapchainCI.compositeAlpha = compositeAlpha;
 | 
			
		||||
 | 
			
		||||
	// Enable transfer source on swap chain images if supported
 | 
			
		||||
	if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
 | 
			
		||||
		swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Enable transfer destination on swap chain images if supported
 | 
			
		||||
	if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
 | 
			
		||||
		swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VK_CHECK_RESULT(fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain));
 | 
			
		||||
 | 
			
		||||
	// If an existing swap chain is re-created, destroy the old swap chain
 | 
			
		||||
	// This also cleans up all the presentable images
 | 
			
		||||
	if (oldSwapchain != VK_NULL_HANDLE) 
 | 
			
		||||
	{ 
 | 
			
		||||
		for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			vkDestroyImageView(device, buffers[i].view, nullptr);
 | 
			
		||||
		}
 | 
			
		||||
		fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
 | 
			
		||||
	}
 | 
			
		||||
	VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL));
 | 
			
		||||
 | 
			
		||||
	// Get the swap chain images
 | 
			
		||||
	images.resize(imageCount);
 | 
			
		||||
	VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data()));
 | 
			
		||||
 | 
			
		||||
	// Get the swap chain buffers containing the image and imageview
 | 
			
		||||
	buffers.resize(imageCount);
 | 
			
		||||
	for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
	{
 | 
			
		||||
		VkImageViewCreateInfo colorAttachmentView = {};
 | 
			
		||||
		colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 | 
			
		||||
		colorAttachmentView.pNext = NULL;
 | 
			
		||||
		colorAttachmentView.format = colorFormat;
 | 
			
		||||
		colorAttachmentView.components = {
 | 
			
		||||
			VK_COMPONENT_SWIZZLE_R,
 | 
			
		||||
			VK_COMPONENT_SWIZZLE_G,
 | 
			
		||||
			VK_COMPONENT_SWIZZLE_B,
 | 
			
		||||
			VK_COMPONENT_SWIZZLE_A
 | 
			
		||||
		};
 | 
			
		||||
		colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
		colorAttachmentView.subresourceRange.baseMipLevel = 0;
 | 
			
		||||
		colorAttachmentView.subresourceRange.levelCount = 1;
 | 
			
		||||
		colorAttachmentView.subresourceRange.baseArrayLayer = 0;
 | 
			
		||||
		colorAttachmentView.subresourceRange.layerCount = 1;
 | 
			
		||||
		colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
 | 
			
		||||
		colorAttachmentView.flags = 0;
 | 
			
		||||
 | 
			
		||||
		buffers[i].image = images[i];
 | 
			
		||||
 | 
			
		||||
		colorAttachmentView.image = buffers[i].image;
 | 
			
		||||
 | 
			
		||||
		VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 
 | 
			
		||||
* Acquires the next image in the swap chain
 | 
			
		||||
*
 | 
			
		||||
* @param presentCompleteSemaphore (Optional) Semaphore that is signaled when the image is ready for use
 | 
			
		||||
* @param imageIndex Pointer to the image index that will be increased if the next image could be acquired
 | 
			
		||||
*
 | 
			
		||||
* @note The function will always wait until the next image has been acquired by setting timeout to UINT64_MAX
 | 
			
		||||
*
 | 
			
		||||
* @return VkResult of the image acquisition
 | 
			
		||||
*/
 | 
			
		||||
VkResult VulkanSwapChain::acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *imageIndex)
 | 
			
		||||
{
 | 
			
		||||
	// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
 | 
			
		||||
	// With that we don't have to handle VK_NOT_READY
 | 
			
		||||
	return fpAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, imageIndex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Queue an image for presentation
 | 
			
		||||
*
 | 
			
		||||
* @param queue Presentation queue for presenting the image
 | 
			
		||||
* @param imageIndex Index of the swapchain image to queue for presentation
 | 
			
		||||
* @param waitSemaphore (Optional) Semaphore that is waited on before the image is presented (only used if != VK_NULL_HANDLE)
 | 
			
		||||
*
 | 
			
		||||
* @return VkResult of the queue presentation
 | 
			
		||||
*/
 | 
			
		||||
VkResult VulkanSwapChain::queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore)
 | 
			
		||||
{
 | 
			
		||||
	VkPresentInfoKHR presentInfo = {};
 | 
			
		||||
	presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
 | 
			
		||||
	presentInfo.pNext = NULL;
 | 
			
		||||
	presentInfo.swapchainCount = 1;
 | 
			
		||||
	presentInfo.pSwapchains = &swapChain;
 | 
			
		||||
	presentInfo.pImageIndices = &imageIndex;
 | 
			
		||||
	// Check if a wait semaphore has been specified to wait for before presenting the image
 | 
			
		||||
	if (waitSemaphore != VK_NULL_HANDLE)
 | 
			
		||||
	{
 | 
			
		||||
		presentInfo.pWaitSemaphores = &waitSemaphore;
 | 
			
		||||
		presentInfo.waitSemaphoreCount = 1;
 | 
			
		||||
	}
 | 
			
		||||
	return fpQueuePresentKHR(queue, &presentInfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Destroy and free Vulkan resources used for the swapchain
 | 
			
		||||
*/
 | 
			
		||||
void VulkanSwapChain::cleanup()
 | 
			
		||||
{
 | 
			
		||||
	if (swapChain != VK_NULL_HANDLE)
 | 
			
		||||
	{
 | 
			
		||||
		for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			vkDestroyImageView(device, buffers[i].view, nullptr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (surface != VK_NULL_HANDLE)
 | 
			
		||||
	{
 | 
			
		||||
		fpDestroySwapchainKHR(device, swapChain, nullptr);
 | 
			
		||||
		vkDestroySurfaceKHR(instance, surface, nullptr);
 | 
			
		||||
	}
 | 
			
		||||
	surface = VK_NULL_HANDLE;
 | 
			
		||||
	swapChain = VK_NULL_HANDLE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(_DIRECT2DISPLAY)
 | 
			
		||||
/**
 | 
			
		||||
* Create direct to display surface
 | 
			
		||||
*/	
 | 
			
		||||
void VulkanSwapChain::createDirect2DisplaySurface(uint32_t width, uint32_t height)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t displayPropertyCount;
 | 
			
		||||
		
 | 
			
		||||
	// Get display property
 | 
			
		||||
	vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, NULL);
 | 
			
		||||
	VkDisplayPropertiesKHR* pDisplayProperties = new VkDisplayPropertiesKHR[displayPropertyCount];
 | 
			
		||||
	vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, pDisplayProperties);
 | 
			
		||||
 | 
			
		||||
	// Get plane property
 | 
			
		||||
	uint32_t planePropertyCount;
 | 
			
		||||
	vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, NULL);
 | 
			
		||||
	VkDisplayPlanePropertiesKHR* pPlaneProperties = new VkDisplayPlanePropertiesKHR[planePropertyCount];
 | 
			
		||||
	vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, pPlaneProperties);
 | 
			
		||||
 | 
			
		||||
	VkDisplayKHR display = VK_NULL_HANDLE;
 | 
			
		||||
	VkDisplayModeKHR displayMode;
 | 
			
		||||
	VkDisplayModePropertiesKHR* pModeProperties;
 | 
			
		||||
	bool foundMode = false;
 | 
			
		||||
 | 
			
		||||
	for(uint32_t i = 0; i < displayPropertyCount;++i)
 | 
			
		||||
	{
 | 
			
		||||
		display = pDisplayProperties[i].display;
 | 
			
		||||
		uint32_t modeCount;
 | 
			
		||||
		vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, NULL);
 | 
			
		||||
		pModeProperties = new VkDisplayModePropertiesKHR[modeCount];
 | 
			
		||||
		vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, pModeProperties);
 | 
			
		||||
 | 
			
		||||
		for (uint32_t j = 0; j < modeCount; ++j)
 | 
			
		||||
		{
 | 
			
		||||
			const VkDisplayModePropertiesKHR* mode = &pModeProperties[j];
 | 
			
		||||
 | 
			
		||||
			if (mode->parameters.visibleRegion.width == width && mode->parameters.visibleRegion.height == height)
 | 
			
		||||
			{
 | 
			
		||||
				displayMode = mode->displayMode;
 | 
			
		||||
				foundMode = true;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (foundMode)
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		delete [] pModeProperties;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(!foundMode)
 | 
			
		||||
	{
 | 
			
		||||
		vks::tools::exitFatal("Can't find a display and a display mode!", -1);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Search for a best plane we can use
 | 
			
		||||
	uint32_t bestPlaneIndex = UINT32_MAX;
 | 
			
		||||
	VkDisplayKHR* pDisplays = NULL;
 | 
			
		||||
	for(uint32_t i = 0; i < planePropertyCount; i++)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t planeIndex=i;
 | 
			
		||||
		uint32_t displayCount;
 | 
			
		||||
		vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, NULL);
 | 
			
		||||
		if (pDisplays)
 | 
			
		||||
		{
 | 
			
		||||
			delete [] pDisplays;
 | 
			
		||||
		}
 | 
			
		||||
		pDisplays = new VkDisplayKHR[displayCount];
 | 
			
		||||
		vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, pDisplays);
 | 
			
		||||
 | 
			
		||||
		// Find a display that matches the current plane
 | 
			
		||||
		bestPlaneIndex = UINT32_MAX;
 | 
			
		||||
		for(uint32_t j = 0; j < displayCount; j++)
 | 
			
		||||
		{
 | 
			
		||||
			if(display == pDisplays[j])
 | 
			
		||||
			{
 | 
			
		||||
				bestPlaneIndex = i;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if(bestPlaneIndex != UINT32_MAX)
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(bestPlaneIndex == UINT32_MAX)
 | 
			
		||||
	{
 | 
			
		||||
		vks::tools::exitFatal("Can't find a plane for displaying!", -1);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkDisplayPlaneCapabilitiesKHR planeCap;
 | 
			
		||||
	vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, bestPlaneIndex, &planeCap);
 | 
			
		||||
	VkDisplayPlaneAlphaFlagBitsKHR alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)0;
 | 
			
		||||
 | 
			
		||||
	if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR)
 | 
			
		||||
	{
 | 
			
		||||
		alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
 | 
			
		||||
	}
 | 
			
		||||
	else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR)
 | 
			
		||||
	{
 | 
			
		||||
		alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
 | 
			
		||||
	}
 | 
			
		||||
	else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR)
 | 
			
		||||
	{
 | 
			
		||||
		alphaMode = VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
 | 
			
		||||
	}
 | 
			
		||||
	else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR)
 | 
			
		||||
	{
 | 
			
		||||
		alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VkDisplaySurfaceCreateInfoKHR surfaceInfo{};
 | 
			
		||||
	surfaceInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
	surfaceInfo.pNext = NULL;
 | 
			
		||||
	surfaceInfo.flags = 0;
 | 
			
		||||
	surfaceInfo.displayMode = displayMode;
 | 
			
		||||
	surfaceInfo.planeIndex = bestPlaneIndex;
 | 
			
		||||
	surfaceInfo.planeStackIndex = pPlaneProperties[bestPlaneIndex].currentStackIndex;
 | 
			
		||||
	surfaceInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
 | 
			
		||||
	surfaceInfo.globalAlpha = 1.0;
 | 
			
		||||
	surfaceInfo.alphaMode = alphaMode;
 | 
			
		||||
	surfaceInfo.imageExtent.width = width;
 | 
			
		||||
	surfaceInfo.imageExtent.height = height;
 | 
			
		||||
 | 
			
		||||
	VkResult result = vkCreateDisplayPlaneSurfaceKHR(instance, &surfaceInfo, NULL, &surface);
 | 
			
		||||
	if (result !=VK_SUCCESS) {
 | 
			
		||||
		vks::tools::exitFatal("Failed to create surface!", result);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete[] pDisplays;
 | 
			
		||||
	delete[] pModeProperties;
 | 
			
		||||
	delete[] pDisplayProperties;
 | 
			
		||||
	delete[] pPlaneProperties;
 | 
			
		||||
}
 | 
			
		||||
#endif 
 | 
			
		||||
| 
						 | 
				
			
			@ -1,84 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
* Class wrapping access to the swap chain
 | 
			
		||||
* 
 | 
			
		||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <vulkan/vulkan.h>
 | 
			
		||||
#include "VulkanTools.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
#include "VulkanAndroid.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _SwapChainBuffers {
 | 
			
		||||
	VkImage image;
 | 
			
		||||
	VkImageView view;
 | 
			
		||||
} SwapChainBuffer;
 | 
			
		||||
 | 
			
		||||
class VulkanSwapChain
 | 
			
		||||
{
 | 
			
		||||
private: 
 | 
			
		||||
	VkInstance instance;
 | 
			
		||||
	VkDevice device;
 | 
			
		||||
	VkPhysicalDevice physicalDevice;
 | 
			
		||||
	VkSurfaceKHR surface;
 | 
			
		||||
	// Function pointers
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR; 
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
 | 
			
		||||
	PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
 | 
			
		||||
	PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
 | 
			
		||||
	PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
 | 
			
		||||
	PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
 | 
			
		||||
	PFN_vkQueuePresentKHR fpQueuePresentKHR;
 | 
			
		||||
public:
 | 
			
		||||
	VkFormat colorFormat;
 | 
			
		||||
	VkColorSpaceKHR colorSpace;
 | 
			
		||||
	VkSwapchainKHR swapChain = VK_NULL_HANDLE;	
 | 
			
		||||
	uint32_t imageCount;
 | 
			
		||||
	std::vector<VkImage> images;
 | 
			
		||||
	std::vector<SwapChainBuffer> buffers;
 | 
			
		||||
	uint32_t queueNodeIndex = UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
 | 
			
		||||
	void initSurface(void* platformHandle, void* platformWindow);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
	void initSurface(ANativeWindow* window);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
	void initSurface(IDirectFB* dfb, IDirectFBSurface* window);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
	void initSurface(wl_display* display, wl_surface* window);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
	void initSurface(xcb_connection_t* connection, xcb_window_t window);
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
	void initSurface(void* view);
 | 
			
		||||
#elif (defined(_DIRECT2DISPLAY) || defined(VK_USE_PLATFORM_HEADLESS_EXT))
 | 
			
		||||
	void initSurface(uint32_t width, uint32_t height);
 | 
			
		||||
#if defined(_DIRECT2DISPLAY)
 | 
			
		||||
	void createDirect2DisplaySurface(uint32_t width, uint32_t height);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
	void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device);
 | 
			
		||||
	void create(uint32_t* width, uint32_t* height, bool vsync = false, bool fullscreen = false);
 | 
			
		||||
	VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t* imageIndex);
 | 
			
		||||
	VkResult queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE);
 | 
			
		||||
	void cleanup();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,662 @@
 | 
			
		|||
/*
 | 
			
		||||
* Class wrapping access to the swap chain
 | 
			
		||||
* 
 | 
			
		||||
* A swap chain is a collection of framebuffers used for rendering and presentation to the windowing system
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) 2016-2017 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <vulkan/vulkan.h>
 | 
			
		||||
#include "macros.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
#include "VulkanAndroid.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _SwapChainBuffers {
 | 
			
		||||
	VkImage image;
 | 
			
		||||
	VkImageView view;
 | 
			
		||||
} SwapChainBuffer;
 | 
			
		||||
 | 
			
		||||
class VulkanSwapChain
 | 
			
		||||
{
 | 
			
		||||
private: 
 | 
			
		||||
	VkInstance instance;
 | 
			
		||||
	VkDevice device;
 | 
			
		||||
	VkPhysicalDevice physicalDevice;
 | 
			
		||||
	VkSurfaceKHR surface = VK_NULL_HANDLE;
 | 
			
		||||
	// Function pointers
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR; 
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
 | 
			
		||||
	PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
 | 
			
		||||
	PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
 | 
			
		||||
	PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
 | 
			
		||||
	PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
 | 
			
		||||
	PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
 | 
			
		||||
	PFN_vkQueuePresentKHR fpQueuePresentKHR;
 | 
			
		||||
public:
 | 
			
		||||
	VkFormat colorFormat;
 | 
			
		||||
	VkColorSpaceKHR colorSpace;
 | 
			
		||||
	VkSwapchainKHR swapChain = VK_NULL_HANDLE;
 | 
			
		||||
	uint32_t imageCount;
 | 
			
		||||
	std::vector<VkImage> images;
 | 
			
		||||
	std::vector<SwapChainBuffer> buffers;
 | 
			
		||||
	VkExtent2D extent = {};
 | 
			
		||||
	uint32_t queueNodeIndex = UINT32_MAX;
 | 
			
		||||
 | 
			
		||||
	/** @brief Creates the platform specific surface abstraction of the native platform window used for presentation */	
 | 
			
		||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
 | 
			
		||||
	void initSurface(void* platformHandle, void* platformWindow)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
	void initSurface(ANativeWindow* window)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
	void initSurface(wl_display *display, wl_surface *window)
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
	void initSurface(xcb_connection_t* connection, xcb_window_t window)
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
	void initSurface(void* view)
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
	void initSurface(uint32_t width, uint32_t height)
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
		VkResult err = VK_SUCCESS;
 | 
			
		||||
 | 
			
		||||
		// Create the os-specific surface
 | 
			
		||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
 | 
			
		||||
		VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
		surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle;
 | 
			
		||||
		surfaceCreateInfo.hwnd = (HWND)platformWindow;
 | 
			
		||||
		err = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
		VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
		surfaceCreateInfo.window = window;
 | 
			
		||||
		err = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_IOS_MVK)
 | 
			
		||||
		VkIOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
 | 
			
		||||
		surfaceCreateInfo.pNext = NULL;
 | 
			
		||||
		surfaceCreateInfo.flags = 0;
 | 
			
		||||
		surfaceCreateInfo.pView = view;
 | 
			
		||||
		err = vkCreateIOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
 | 
			
		||||
		VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
 | 
			
		||||
		surfaceCreateInfo.pNext = NULL;
 | 
			
		||||
		surfaceCreateInfo.flags = 0;
 | 
			
		||||
		surfaceCreateInfo.pView = view;
 | 
			
		||||
		err = vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, NULL, &surface);
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
		createDirect2DisplaySurface(width, height);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
		VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
		surfaceCreateInfo.display = display;
 | 
			
		||||
		surfaceCreateInfo.surface = window;
 | 
			
		||||
		err = vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
		VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
 | 
			
		||||
		surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
		surfaceCreateInfo.connection = connection;
 | 
			
		||||
		surfaceCreateInfo.window = window;
 | 
			
		||||
		err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (err != VK_SUCCESS) {
 | 
			
		||||
			std::cerr << "Could not create surface!" << std::endl;
 | 
			
		||||
			exit(err);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Get available queue family properties
 | 
			
		||||
		uint32_t queueCount;
 | 
			
		||||
		vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
 | 
			
		||||
		assert(queueCount >= 1);
 | 
			
		||||
 | 
			
		||||
		std::vector<VkQueueFamilyProperties> queueProps(queueCount);
 | 
			
		||||
		vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data());
 | 
			
		||||
 | 
			
		||||
		// Iterate over each queue to learn whether it supports presenting:
 | 
			
		||||
		// Find a queue with present support
 | 
			
		||||
		// Will be used to present the swap chain images to the windowing system
 | 
			
		||||
		std::vector<VkBool32> supportsPresent(queueCount);
 | 
			
		||||
		for (uint32_t i = 0; i < queueCount; i++) 
 | 
			
		||||
		{
 | 
			
		||||
			fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &supportsPresent[i]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Search for a graphics and a present queue in the array of queue
 | 
			
		||||
		// families, try to find one that supports both
 | 
			
		||||
		uint32_t graphicsQueueNodeIndex = UINT32_MAX;
 | 
			
		||||
		uint32_t presentQueueNodeIndex = UINT32_MAX;
 | 
			
		||||
		for (uint32_t i = 0; i < queueCount; i++) 
 | 
			
		||||
		{
 | 
			
		||||
			if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) 
 | 
			
		||||
			{
 | 
			
		||||
				if (graphicsQueueNodeIndex == UINT32_MAX) 
 | 
			
		||||
				{
 | 
			
		||||
					graphicsQueueNodeIndex = i;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (supportsPresent[i] == VK_TRUE) 
 | 
			
		||||
				{
 | 
			
		||||
					graphicsQueueNodeIndex = i;
 | 
			
		||||
					presentQueueNodeIndex = i;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (presentQueueNodeIndex == UINT32_MAX) 
 | 
			
		||||
		{	
 | 
			
		||||
			// If there's no queue that supports both present and graphics
 | 
			
		||||
			// try to find a separate present queue
 | 
			
		||||
			for (uint32_t i = 0; i < queueCount; ++i) 
 | 
			
		||||
			{
 | 
			
		||||
				if (supportsPresent[i] == VK_TRUE) 
 | 
			
		||||
				{
 | 
			
		||||
					presentQueueNodeIndex = i;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Exit if either a graphics or a presenting queue hasn't been found
 | 
			
		||||
		if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
 | 
			
		||||
			std::cerr << "Could not find a graphics and/or presenting queue!" << std::endl;
 | 
			
		||||
			exit(-1);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// todo : Add support for separate graphics and presenting queue
 | 
			
		||||
		if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
 | 
			
		||||
			std::cerr << "Separate graphics and presenting queues are not supported yet!" << std::endl;
 | 
			
		||||
			exit(-1);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		queueNodeIndex = graphicsQueueNodeIndex;
 | 
			
		||||
 | 
			
		||||
		// Get list of supported surface formats
 | 
			
		||||
		uint32_t formatCount;
 | 
			
		||||
		VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL));
 | 
			
		||||
		assert(formatCount > 0);
 | 
			
		||||
 | 
			
		||||
		std::vector<VkSurfaceFormatKHR> surfaceFormats(formatCount);
 | 
			
		||||
		VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfaceFormats.data()));
 | 
			
		||||
 | 
			
		||||
		// If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
 | 
			
		||||
		// there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM
 | 
			
		||||
		if ((formatCount == 1) && (surfaceFormats[0].format == VK_FORMAT_UNDEFINED))
 | 
			
		||||
		{
 | 
			
		||||
			colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
 | 
			
		||||
			colorSpace = surfaceFormats[0].colorSpace;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// iterate over the list of available surface format and
 | 
			
		||||
			// check for the presence of VK_FORMAT_B8G8R8A8_UNORM
 | 
			
		||||
			bool found_B8G8R8A8_UNORM = false;
 | 
			
		||||
			for (auto&& surfaceFormat : surfaceFormats)
 | 
			
		||||
			{
 | 
			
		||||
				// Prefer SRGB
 | 
			
		||||
				if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_SRGB)
 | 
			
		||||
				{
 | 
			
		||||
					colorFormat = surfaceFormat.format;
 | 
			
		||||
					colorSpace = surfaceFormat.colorSpace;
 | 
			
		||||
					found_B8G8R8A8_UNORM = true;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				//if (surfaceFormat.format == VK_FORMAT_B8G8R8A8_UNORM)
 | 
			
		||||
				//{
 | 
			
		||||
				//	colorFormat = surfaceFormat.format;
 | 
			
		||||
				//	colorSpace = surfaceFormat.colorSpace;
 | 
			
		||||
				//	found_B8G8R8A8_UNORM = true;
 | 
			
		||||
				//	break;
 | 
			
		||||
				//}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// in case VK_FORMAT_B8G8R8A8_UNORM is not available
 | 
			
		||||
			// select the first available color format
 | 
			
		||||
			if (!found_B8G8R8A8_UNORM)
 | 
			
		||||
			{
 | 
			
		||||
				colorFormat = surfaceFormats[0].format;
 | 
			
		||||
				colorSpace = surfaceFormats[0].colorSpace;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	* Set instance, physical and logical device to use for the swapchain and get all required function pointers
 | 
			
		||||
	* 
 | 
			
		||||
	* @param instance Vulkan instance to use
 | 
			
		||||
	* @param physicalDevice Physical device used to query properties and formats relevant to the swapchain
 | 
			
		||||
	* @param device Logical representation of the device to create the swapchain for
 | 
			
		||||
	*
 | 
			
		||||
	*/
 | 
			
		||||
	void connect(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
 | 
			
		||||
	{
 | 
			
		||||
		this->instance = instance;
 | 
			
		||||
		this->physicalDevice = physicalDevice;
 | 
			
		||||
		this->device = device;
 | 
			
		||||
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
 | 
			
		||||
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
 | 
			
		||||
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
 | 
			
		||||
		GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
 | 
			
		||||
		GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
 | 
			
		||||
		GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
 | 
			
		||||
		GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
 | 
			
		||||
		GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
 | 
			
		||||
		GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** 
 | 
			
		||||
	* Create the swapchain and get it's images with given width and height
 | 
			
		||||
	* 
 | 
			
		||||
	* @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain)
 | 
			
		||||
	* @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain)
 | 
			
		||||
	* @param vsync (Optional) Can be used to force vsync'd rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode)
 | 
			
		||||
	*/
 | 
			
		||||
	void create(uint32_t *width, uint32_t *height, bool vsync = false)
 | 
			
		||||
	{
 | 
			
		||||
		VkSwapchainKHR oldSwapchain = swapChain;
 | 
			
		||||
 | 
			
		||||
		// Get physical device surface properties and formats
 | 
			
		||||
		VkSurfaceCapabilitiesKHR surfCaps;
 | 
			
		||||
		VK_CHECK_RESULT(fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps));
 | 
			
		||||
 | 
			
		||||
		// 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()));
 | 
			
		||||
 | 
			
		||||
		// If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
 | 
			
		||||
		if (surfCaps.currentExtent.width == (uint32_t)-1)
 | 
			
		||||
		{
 | 
			
		||||
			// If the surface size is undefined, the size is set to
 | 
			
		||||
			// the size of the images requested.
 | 
			
		||||
			extent.width = *width;
 | 
			
		||||
			extent.height = *height;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// If the surface size is defined, the swap chain size must match
 | 
			
		||||
			extent = surfCaps.currentExtent;
 | 
			
		||||
			*width = surfCaps.currentExtent.width;
 | 
			
		||||
			*height = surfCaps.currentExtent.height;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		// Select a present mode for the swapchain
 | 
			
		||||
 | 
			
		||||
		// 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 (!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;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Determine the number of images
 | 
			
		||||
		uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
 | 
			
		||||
		if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
 | 
			
		||||
		{
 | 
			
		||||
			desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Find the transformation of the surface
 | 
			
		||||
		VkSurfaceTransformFlagsKHR preTransform;
 | 
			
		||||
		if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
 | 
			
		||||
		{
 | 
			
		||||
			// We prefer a non-rotated transform
 | 
			
		||||
			preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			preTransform = surfCaps.currentTransform;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Find a supported composite alpha format (not all devices support alpha opaque)
 | 
			
		||||
		VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
 | 
			
		||||
		// Simply select the first composite alpha format available
 | 
			
		||||
		std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
 | 
			
		||||
			VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
 | 
			
		||||
			VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
 | 
			
		||||
			VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
 | 
			
		||||
			VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
 | 
			
		||||
		};
 | 
			
		||||
		for (auto& compositeAlphaFlag : compositeAlphaFlags) {
 | 
			
		||||
			if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
 | 
			
		||||
				compositeAlpha = compositeAlphaFlag;
 | 
			
		||||
				break;
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VkSwapchainCreateInfoKHR swapchainCI = {};
 | 
			
		||||
		swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
 | 
			
		||||
		swapchainCI.pNext = NULL;
 | 
			
		||||
		swapchainCI.surface = surface;
 | 
			
		||||
		swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
 | 
			
		||||
		swapchainCI.imageFormat = colorFormat;
 | 
			
		||||
		swapchainCI.imageColorSpace = colorSpace;
 | 
			
		||||
		swapchainCI.imageExtent = { extent.width, extent.height };
 | 
			
		||||
		swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
 | 
			
		||||
		swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
 | 
			
		||||
		swapchainCI.imageArrayLayers = 1;
 | 
			
		||||
		swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
 | 
			
		||||
		swapchainCI.queueFamilyIndexCount = 0;
 | 
			
		||||
		swapchainCI.pQueueFamilyIndices = NULL;
 | 
			
		||||
		swapchainCI.presentMode = swapchainPresentMode;
 | 
			
		||||
		swapchainCI.oldSwapchain = oldSwapchain;
 | 
			
		||||
		// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
 | 
			
		||||
		swapchainCI.clipped = VK_TRUE;
 | 
			
		||||
		swapchainCI.compositeAlpha = compositeAlpha;
 | 
			
		||||
 | 
			
		||||
		// Set additional usage flag for blitting from the swapchain images if supported
 | 
			
		||||
		VkFormatProperties formatProps;
 | 
			
		||||
		vkGetPhysicalDeviceFormatProperties(physicalDevice, colorFormat, &formatProps);
 | 
			
		||||
		if ((formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR) || (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
 | 
			
		||||
			swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VK_CHECK_RESULT(fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain));
 | 
			
		||||
 | 
			
		||||
		// If an existing swap chain is re-created, destroy the old swap chain
 | 
			
		||||
		// This also cleans up all the presentable images
 | 
			
		||||
		if (oldSwapchain != VK_NULL_HANDLE) 
 | 
			
		||||
		{ 
 | 
			
		||||
			for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
			{
 | 
			
		||||
				vkDestroyImageView(device, buffers[i].view, nullptr);
 | 
			
		||||
			}
 | 
			
		||||
			fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
 | 
			
		||||
		}
 | 
			
		||||
		VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL));
 | 
			
		||||
 | 
			
		||||
		// Get the swap chain images
 | 
			
		||||
		images.resize(imageCount);
 | 
			
		||||
		VK_CHECK_RESULT(fpGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data()));
 | 
			
		||||
 | 
			
		||||
		// Get the swap chain buffers containing the image and imageview
 | 
			
		||||
		buffers.resize(imageCount);
 | 
			
		||||
		for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			VkImageViewCreateInfo colorAttachmentView = {};
 | 
			
		||||
			colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 | 
			
		||||
			colorAttachmentView.pNext = NULL;
 | 
			
		||||
			colorAttachmentView.format = colorFormat;
 | 
			
		||||
			colorAttachmentView.components = {
 | 
			
		||||
				VK_COMPONENT_SWIZZLE_R,
 | 
			
		||||
				VK_COMPONENT_SWIZZLE_G,
 | 
			
		||||
				VK_COMPONENT_SWIZZLE_B,
 | 
			
		||||
				VK_COMPONENT_SWIZZLE_A
 | 
			
		||||
			};
 | 
			
		||||
			colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
			colorAttachmentView.subresourceRange.baseMipLevel = 0;
 | 
			
		||||
			colorAttachmentView.subresourceRange.levelCount = 1;
 | 
			
		||||
			colorAttachmentView.subresourceRange.baseArrayLayer = 0;
 | 
			
		||||
			colorAttachmentView.subresourceRange.layerCount = 1;
 | 
			
		||||
			colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
 | 
			
		||||
			colorAttachmentView.flags = 0;
 | 
			
		||||
 | 
			
		||||
			buffers[i].image = images[i];
 | 
			
		||||
 | 
			
		||||
			colorAttachmentView.image = buffers[i].image;
 | 
			
		||||
 | 
			
		||||
			VK_CHECK_RESULT(vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/** 
 | 
			
		||||
	* Acquires the next image in the swap chain
 | 
			
		||||
	*
 | 
			
		||||
	* @param presentCompleteSemaphore (Optional) Semaphore that is signaled when the image is ready for use
 | 
			
		||||
	* @param imageIndex Pointer to the image index that will be increased if the next image could be acquired
 | 
			
		||||
	*
 | 
			
		||||
	* @note The function will always wait until the next image has been acquired by setting timeout to UINT64_MAX
 | 
			
		||||
	*
 | 
			
		||||
	* @return VkResult of the image acquisition
 | 
			
		||||
	*/
 | 
			
		||||
	VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *imageIndex)
 | 
			
		||||
	{
 | 
			
		||||
		if (swapChain == VK_NULL_HANDLE) {
 | 
			
		||||
			// Probably acquireNextImage() is called just after cleanup() (e.g. window has been terminated on Android).
 | 
			
		||||
			// todo : Use a dedicated error code.
 | 
			
		||||
			return VK_ERROR_OUT_OF_DATE_KHR;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
 | 
			
		||||
		// With that we don't have to handle VK_NOT_READY
 | 
			
		||||
		return fpAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, imageIndex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	* Queue an image for presentation
 | 
			
		||||
	*
 | 
			
		||||
	* @param queue Presentation queue for presenting the image
 | 
			
		||||
	* @param imageIndex Index of the swapchain image to queue for presentation
 | 
			
		||||
	* @param waitSemaphore (Optional) Semaphore that is waited on before the image is presented (only used if != VK_NULL_HANDLE)
 | 
			
		||||
	*
 | 
			
		||||
	* @return VkResult of the queue presentation
 | 
			
		||||
	*/
 | 
			
		||||
	VkResult queuePresent(VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE)
 | 
			
		||||
	{
 | 
			
		||||
		VkPresentInfoKHR presentInfo = {};
 | 
			
		||||
		presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
 | 
			
		||||
		presentInfo.pNext = NULL;
 | 
			
		||||
		presentInfo.swapchainCount = 1;
 | 
			
		||||
		presentInfo.pSwapchains = &swapChain;
 | 
			
		||||
		presentInfo.pImageIndices = &imageIndex;
 | 
			
		||||
		// Check if a wait semaphore has been specified to wait for before presenting the image
 | 
			
		||||
		if (waitSemaphore != VK_NULL_HANDLE)
 | 
			
		||||
		{
 | 
			
		||||
			presentInfo.pWaitSemaphores = &waitSemaphore;
 | 
			
		||||
			presentInfo.waitSemaphoreCount = 1;
 | 
			
		||||
		}
 | 
			
		||||
		return fpQueuePresentKHR(queue, &presentInfo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	* Destroy and free Vulkan resources used for the swapchain
 | 
			
		||||
	*/
 | 
			
		||||
	void cleanup()
 | 
			
		||||
	{
 | 
			
		||||
		if (swapChain != VK_NULL_HANDLE)
 | 
			
		||||
		{
 | 
			
		||||
			for (uint32_t i = 0; i < imageCount; i++)
 | 
			
		||||
			{
 | 
			
		||||
				vkDestroyImageView(device, buffers[i].view, nullptr);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (surface != VK_NULL_HANDLE)
 | 
			
		||||
		{
 | 
			
		||||
			fpDestroySwapchainKHR(device, swapChain, nullptr);
 | 
			
		||||
			vkDestroySurfaceKHR(instance, surface, nullptr);
 | 
			
		||||
		}
 | 
			
		||||
		surface = VK_NULL_HANDLE;
 | 
			
		||||
		swapChain = VK_NULL_HANDLE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined(_DIRECT2DISPLAY)
 | 
			
		||||
 | 
			
		||||
    void exitFatal(const std::string& message, int32_t exitCode)
 | 
			
		||||
    {
 | 
			
		||||
    #if defined(_WIN32)
 | 
			
		||||
      if (!errorModeSilent) {
 | 
			
		||||
                  MessageBox(NULL, message.c_str(), NULL, MB_OK | MB_ICONERROR);
 | 
			
		||||
              }
 | 
			
		||||
    #elif defined(__ANDROID__)
 | 
			
		||||
      LOGE("Fatal error: %s", message.c_str());
 | 
			
		||||
              vks::android::showAlert(message.c_str());
 | 
			
		||||
    #endif
 | 
			
		||||
      std::cerr << message << "\n";
 | 
			
		||||
    #if !defined(__ANDROID__)
 | 
			
		||||
      exit(exitCode);
 | 
			
		||||
    #endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	* Create direct to display surface
 | 
			
		||||
	*/	
 | 
			
		||||
	void createDirect2DisplaySurface(uint32_t width, uint32_t height)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t displayPropertyCount;
 | 
			
		||||
		
 | 
			
		||||
		// Get display property
 | 
			
		||||
		vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, NULL);
 | 
			
		||||
		VkDisplayPropertiesKHR* pDisplayProperties = new VkDisplayPropertiesKHR[displayPropertyCount];
 | 
			
		||||
		vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertyCount, pDisplayProperties);
 | 
			
		||||
 | 
			
		||||
		// Get plane property
 | 
			
		||||
		uint32_t planePropertyCount;
 | 
			
		||||
		vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, NULL);
 | 
			
		||||
		VkDisplayPlanePropertiesKHR* pPlaneProperties = new VkDisplayPlanePropertiesKHR[planePropertyCount];
 | 
			
		||||
		vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertyCount, pPlaneProperties);
 | 
			
		||||
 | 
			
		||||
		VkDisplayKHR display = VK_NULL_HANDLE;
 | 
			
		||||
		VkDisplayModeKHR displayMode;
 | 
			
		||||
		VkDisplayModePropertiesKHR* pModeProperties;
 | 
			
		||||
		bool foundMode = false;
 | 
			
		||||
 | 
			
		||||
		for(uint32_t i = 0; i < displayPropertyCount;++i)
 | 
			
		||||
		{
 | 
			
		||||
			display = pDisplayProperties[i].display;
 | 
			
		||||
			uint32_t modeCount;
 | 
			
		||||
			vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, NULL);
 | 
			
		||||
			pModeProperties = new VkDisplayModePropertiesKHR[modeCount];
 | 
			
		||||
			vkGetDisplayModePropertiesKHR(physicalDevice, display, &modeCount, pModeProperties);
 | 
			
		||||
 | 
			
		||||
			for (uint32_t j = 0; j < modeCount; ++j)
 | 
			
		||||
			{
 | 
			
		||||
				const VkDisplayModePropertiesKHR* mode = &pModeProperties[j];
 | 
			
		||||
 | 
			
		||||
				if (mode->parameters.visibleRegion.width == width && mode->parameters.visibleRegion.height == height)
 | 
			
		||||
				{
 | 
			
		||||
					displayMode = mode->displayMode;
 | 
			
		||||
					foundMode = true;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (foundMode)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			delete [] pModeProperties;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(!foundMode)
 | 
			
		||||
		{
 | 
			
		||||
			exitFatal("Can't find a display and a display mode!", -1);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Search for a best plane we can use
 | 
			
		||||
		uint32_t bestPlaneIndex = UINT32_MAX;
 | 
			
		||||
		VkDisplayKHR* pDisplays = NULL;
 | 
			
		||||
		for(uint32_t i = 0; i < planePropertyCount; i++)
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t planeIndex=i;
 | 
			
		||||
			uint32_t displayCount;
 | 
			
		||||
			vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, NULL);
 | 
			
		||||
			if (pDisplays)
 | 
			
		||||
			{
 | 
			
		||||
				delete [] pDisplays;
 | 
			
		||||
			}
 | 
			
		||||
			pDisplays = new VkDisplayKHR[displayCount];
 | 
			
		||||
			vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, &displayCount, pDisplays);
 | 
			
		||||
 | 
			
		||||
			// Find a display that matches the current plane
 | 
			
		||||
			bestPlaneIndex = UINT32_MAX;
 | 
			
		||||
			for(uint32_t j = 0; j < displayCount; j++)
 | 
			
		||||
			{
 | 
			
		||||
				if(display == pDisplays[j])
 | 
			
		||||
				{
 | 
			
		||||
					bestPlaneIndex = i;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if(bestPlaneIndex != UINT32_MAX)
 | 
			
		||||
			{
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if(bestPlaneIndex == UINT32_MAX)
 | 
			
		||||
		{
 | 
			
		||||
			exitFatal("Can't find a plane for displaying!", -1);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VkDisplayPlaneCapabilitiesKHR planeCap;
 | 
			
		||||
		vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, bestPlaneIndex, &planeCap);
 | 
			
		||||
		VkDisplayPlaneAlphaFlagBitsKHR alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)0;
 | 
			
		||||
 | 
			
		||||
		if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR)
 | 
			
		||||
		{
 | 
			
		||||
			alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
 | 
			
		||||
		}
 | 
			
		||||
		else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR)
 | 
			
		||||
		{
 | 
			
		||||
			alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
 | 
			
		||||
		}
 | 
			
		||||
		else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR)
 | 
			
		||||
		{
 | 
			
		||||
			alphaMode = VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
 | 
			
		||||
		}
 | 
			
		||||
		else if (planeCap.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR)
 | 
			
		||||
		{
 | 
			
		||||
			alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VkDisplaySurfaceCreateInfoKHR surfaceInfo{};
 | 
			
		||||
		surfaceInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
 | 
			
		||||
		surfaceInfo.pNext = NULL;
 | 
			
		||||
		surfaceInfo.flags = 0;
 | 
			
		||||
		surfaceInfo.displayMode = displayMode;
 | 
			
		||||
		surfaceInfo.planeIndex = bestPlaneIndex;
 | 
			
		||||
		surfaceInfo.planeStackIndex = pPlaneProperties[bestPlaneIndex].currentStackIndex;
 | 
			
		||||
		surfaceInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
 | 
			
		||||
		surfaceInfo.globalAlpha = 1.0;
 | 
			
		||||
		surfaceInfo.alphaMode = alphaMode;
 | 
			
		||||
		surfaceInfo.imageExtent.width = width;
 | 
			
		||||
		surfaceInfo.imageExtent.height = height;
 | 
			
		||||
 | 
			
		||||
		VkResult result = vkCreateDisplayPlaneSurfaceKHR(instance, &surfaceInfo, NULL, &surface);
 | 
			
		||||
		if (result !=VK_SUCCESS) {
 | 
			
		||||
			exitFatal("Failed to create surface!", result);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		delete[] pDisplays;
 | 
			
		||||
		delete[] pModeProperties;
 | 
			
		||||
		delete[] pDisplayProperties;
 | 
			
		||||
		delete[] pPlaneProperties;
 | 
			
		||||
	}
 | 
			
		||||
#endif 
 | 
			
		||||
};
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
/*
 | 
			
		||||
* Vulkan Example base class
 | 
			
		||||
*
 | 
			
		||||
* Copyright (C) by Sascha Willems - www.saschawillems.de
 | 
			
		||||
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
 | 
			
		||||
*
 | 
			
		||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
 | 
			
		||||
*/
 | 
			
		||||
| 
						 | 
				
			
			@ -13,252 +13,156 @@
 | 
			
		|||
#include <windows.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <io.h>
 | 
			
		||||
#include <ShellScalingAPI.h>
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
#include <android/native_activity.h>
 | 
			
		||||
#include <android/asset_manager.h>
 | 
			
		||||
#include <android_native_app_glue.h>
 | 
			
		||||
#include <sys/system_properties.h>
 | 
			
		||||
#include "VulkanAndroid.h"
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
#include <directfb.h>
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
#include <wayland-client.h>
 | 
			
		||||
#include "xdg-shell-client-protocol.h"
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
//
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
#include <xcb/xcb.h>
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
 | 
			
		||||
#include <Cocoa/Cocoa.h>
 | 
			
		||||
#include <Carbon/Carbon.h>
 | 
			
		||||
#include <QuartzCore/CAMetalLayer.h>
 | 
			
		||||
#include <CoreVideo/CVDisplayLink.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <numeric>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#define GLM_FORCE_RADIANS
 | 
			
		||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
 | 
			
		||||
#define GLM_ENABLE_EXPERIMENTAL
 | 
			
		||||
#include <glm/glm.hpp>
 | 
			
		||||
#include <glm/gtc/matrix_transform.hpp>
 | 
			
		||||
#include <glm/gtc/matrix_inverse.hpp>
 | 
			
		||||
#include <glm/gtc/type_ptr.hpp>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <numeric>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <numeric>
 | 
			
		||||
 | 
			
		||||
#include "vulkan/vulkan.h"
 | 
			
		||||
 | 
			
		||||
#include "CommandLineParser.hpp"
 | 
			
		||||
#include "keycodes.hpp"
 | 
			
		||||
#include "VulkanTools.h"
 | 
			
		||||
#include "VulkanDebug.h"
 | 
			
		||||
#include "VulkanUIOverlay.h"
 | 
			
		||||
#include "VulkanSwapChain.h"
 | 
			
		||||
#include "VulkanBuffer.h"
 | 
			
		||||
#include "VulkanDevice.hpp"
 | 
			
		||||
#include "VulkanTexture.h"
 | 
			
		||||
 | 
			
		||||
#include "VulkanInitializers.hpp"
 | 
			
		||||
#include "macros.h"
 | 
			
		||||
#include "camera.hpp"
 | 
			
		||||
#include "benchmark.hpp"
 | 
			
		||||
#include "keycodes.hpp"
 | 
			
		||||
 | 
			
		||||
#include "VulkanDevice.hpp"
 | 
			
		||||
#include "VulkanSwapChain.hpp"
 | 
			
		||||
 | 
			
		||||
#include "imgui/imgui.h"
 | 
			
		||||
 | 
			
		||||
class VulkanExampleBase
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	std::string getWindowTitle();
 | 
			
		||||
private:	
 | 
			
		||||
	float fpsTimer = 0.0f;
 | 
			
		||||
	uint32_t frameCounter = 0;
 | 
			
		||||
	uint32_t destWidth;
 | 
			
		||||
	uint32_t destHeight;
 | 
			
		||||
	bool resizing = false;
 | 
			
		||||
	void windowResize();
 | 
			
		||||
	void handleMouseMove(int32_t x, int32_t y);
 | 
			
		||||
	void nextFrame();
 | 
			
		||||
	void updateOverlay();
 | 
			
		||||
	void createPipelineCache();
 | 
			
		||||
	void createCommandPool();
 | 
			
		||||
	void createSynchronizationPrimitives();
 | 
			
		||||
	void initSwapchain();
 | 
			
		||||
	void setupSwapChain();
 | 
			
		||||
	void createCommandBuffers();
 | 
			
		||||
	void destroyCommandBuffers();
 | 
			
		||||
	std::string shaderDir = "glsl";
 | 
			
		||||
	PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback;
 | 
			
		||||
	PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback;
 | 
			
		||||
	VkDebugReportCallbackEXT debugReportCallback;
 | 
			
		||||
	struct MultisampleTarget {
 | 
			
		||||
		struct {
 | 
			
		||||
			VkImage image;
 | 
			
		||||
			VkImageView view;
 | 
			
		||||
			VkDeviceMemory memory;
 | 
			
		||||
		} color;
 | 
			
		||||
		struct {
 | 
			
		||||
			VkImage image;
 | 
			
		||||
			VkImageView view;
 | 
			
		||||
			VkDeviceMemory memory;
 | 
			
		||||
		} depth;
 | 
			
		||||
	} multisampleTarget;
 | 
			
		||||
protected:
 | 
			
		||||
	// Returns the path to the root of the glsl or hlsl shader directory.
 | 
			
		||||
	std::string getShadersPath() const;
 | 
			
		||||
	// Returns the path to the root of the homework glsl or hlsl shader directory.
 | 
			
		||||
	std::string getHomeworkShadersPath() const;
 | 
			
		||||
	// Frame counter to display fps
 | 
			
		||||
	uint32_t frameCounter = 0;
 | 
			
		||||
	uint32_t lastFPS = 0;
 | 
			
		||||
	std::chrono::time_point<std::chrono::high_resolution_clock> lastTimestamp, tPrevEnd;
 | 
			
		||||
	// Vulkan instance, stores all per-application states
 | 
			
		||||
	VkInstance instance;
 | 
			
		||||
	std::vector<std::string> supportedInstanceExtensions;
 | 
			
		||||
	// Physical device (GPU) that Vulkan will use
 | 
			
		||||
	VkPhysicalDevice physicalDevice;
 | 
			
		||||
	// Stores physical device properties (for e.g. checking device limits)
 | 
			
		||||
	VkPhysicalDeviceProperties deviceProperties;
 | 
			
		||||
	// Stores the features available on the selected physical device (for e.g. checking if a feature is available)
 | 
			
		||||
	VkPhysicalDeviceFeatures deviceFeatures;
 | 
			
		||||
	// Stores all available memory (type) properties for the physical device
 | 
			
		||||
	VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
 | 
			
		||||
	/** @brief Set of physical device features to be enabled for this example (must be set in the derived constructor) */
 | 
			
		||||
	VkPhysicalDeviceFeatures enabledFeatures{};
 | 
			
		||||
	/** @brief Set of device extensions to be enabled for this example (must be set in the derived constructor) */
 | 
			
		||||
	std::vector<const char*> enabledDeviceExtensions;
 | 
			
		||||
	std::vector<const char*> enabledInstanceExtensions;
 | 
			
		||||
	/** @brief Optional pNext structure for passing extension structures to device creation */
 | 
			
		||||
	void* deviceCreatepNextChain = nullptr;
 | 
			
		||||
	/** @brief Logical device, application's view of the physical device (GPU) */
 | 
			
		||||
	VkDevice device;
 | 
			
		||||
	// Handle to the device graphics queue that command buffers are submitted to
 | 
			
		||||
	VkQueue queue;
 | 
			
		||||
	// Depth buffer format (selected during Vulkan initialization)
 | 
			
		||||
	VkFormat depthFormat;
 | 
			
		||||
	// Command buffer pool
 | 
			
		||||
	VkCommandPool cmdPool;
 | 
			
		||||
	/** @brief Pipeline stages used to wait at for graphics queue submissions */
 | 
			
		||||
	VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 | 
			
		||||
	// Contains command buffers and semaphores to be presented to the queue
 | 
			
		||||
	VkSubmitInfo submitInfo;
 | 
			
		||||
	// Command buffers used for rendering
 | 
			
		||||
	std::vector<VkCommandBuffer> drawCmdBuffers;
 | 
			
		||||
	// Global render pass for frame buffer writes
 | 
			
		||||
	VkRenderPass renderPass = VK_NULL_HANDLE;
 | 
			
		||||
	// List of available frame buffers (same as number of swap chain images)
 | 
			
		||||
	std::vector<VkFramebuffer>frameBuffers;
 | 
			
		||||
	// Active frame buffer index
 | 
			
		||||
	uint32_t currentBuffer = 0;
 | 
			
		||||
	// Descriptor set pool
 | 
			
		||||
	VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
 | 
			
		||||
	// List of shader modules created (stored for cleanup)
 | 
			
		||||
	std::vector<VkShaderModule> shaderModules;
 | 
			
		||||
	// Pipeline cache object
 | 
			
		||||
	VkPipelineCache pipelineCache;
 | 
			
		||||
	// Wraps the swap chain to present images (framebuffers) to the windowing system
 | 
			
		||||
	VulkanSwapChain swapChain;
 | 
			
		||||
	// Synchronization semaphores
 | 
			
		||||
	struct {
 | 
			
		||||
		// Swap chain image presentation
 | 
			
		||||
		VkSemaphore presentComplete;
 | 
			
		||||
		// Command buffer submission and execution
 | 
			
		||||
		VkSemaphore renderComplete;
 | 
			
		||||
	} semaphores;
 | 
			
		||||
	std::vector<VkFence> waitFences;
 | 
			
		||||
public:
 | 
			
		||||
	bool prepared = false;
 | 
			
		||||
	bool resized = false;
 | 
			
		||||
	bool viewUpdated = false;
 | 
			
		||||
	uint32_t width = 1280;
 | 
			
		||||
	uint32_t height = 720;
 | 
			
		||||
 | 
			
		||||
	vks::UIOverlay UIOverlay;
 | 
			
		||||
	CommandLineParser commandLineParser;
 | 
			
		||||
 | 
			
		||||
	/** @brief Last frame time measured using a high performance timer (if available) */
 | 
			
		||||
	float frameTimer = 1.0f;
 | 
			
		||||
 | 
			
		||||
	vks::Benchmark benchmark;
 | 
			
		||||
 | 
			
		||||
	/** @brief Encapsulated physical and logical vulkan device */
 | 
			
		||||
	vks::VulkanDevice *vulkanDevice;
 | 
			
		||||
 | 
			
		||||
	/** @brief Example settings that can be changed e.g. by command line arguments */
 | 
			
		||||
	struct Settings {
 | 
			
		||||
		/** @brief Activates validation layers (and message output) when set to true */
 | 
			
		||||
		bool validation = false;
 | 
			
		||||
		/** @brief Set to true if fullscreen mode has been requested via command line */
 | 
			
		||||
		bool fullscreen = false;
 | 
			
		||||
		/** @brief Set to true if v-sync will be forced for the swapchain */
 | 
			
		||||
		bool vsync = false;
 | 
			
		||||
		/** @brief Enable UI overlay */
 | 
			
		||||
		bool overlay = true;
 | 
			
		||||
	} settings;
 | 
			
		||||
 | 
			
		||||
	VkClearColorValue defaultClearColor = { { 0.025f, 0.025f, 0.025f, 1.0f } };
 | 
			
		||||
 | 
			
		||||
	static std::vector<const char*> args;
 | 
			
		||||
 | 
			
		||||
	// Defines a frame rate independent timer value clamped from -1.0...1.0
 | 
			
		||||
	// For use in animations, rotations, etc.
 | 
			
		||||
	float timer = 0.0f;
 | 
			
		||||
	// Multiplier for speeding up (or slowing down) the global timer
 | 
			
		||||
	float timerSpeed = 0.25f;
 | 
			
		||||
	bool paused = false;
 | 
			
		||||
 | 
			
		||||
	Camera camera;
 | 
			
		||||
	glm::vec2 mousePos;
 | 
			
		||||
 | 
			
		||||
	VkQueue queue;
 | 
			
		||||
	VkFormat depthFormat;
 | 
			
		||||
	VkCommandPool cmdPool;
 | 
			
		||||
	VkRenderPass renderPass;
 | 
			
		||||
	std::vector<VkFramebuffer>frameBuffers;
 | 
			
		||||
	uint32_t currentBuffer = 0;
 | 
			
		||||
	VkDescriptorPool descriptorPool;
 | 
			
		||||
	VkPipelineCache pipelineCache;
 | 
			
		||||
	VulkanSwapChain swapChain;
 | 
			
		||||
	std::string title = "Vulkan Example";
 | 
			
		||||
	std::string name = "vulkanExample";
 | 
			
		||||
	uint32_t apiVersion = VK_API_VERSION_1_0;
 | 
			
		||||
	void windowResize();
 | 
			
		||||
public: 
 | 
			
		||||
	static std::vector<const char*> args;
 | 
			
		||||
	bool prepared = false;
 | 
			
		||||
	uint32_t width = 1280;
 | 
			
		||||
	uint32_t height = 720;
 | 
			
		||||
	float frameTimer = 1.0f;
 | 
			
		||||
	Camera camera;
 | 
			
		||||
	glm::vec2 mousePos;
 | 
			
		||||
	bool paused = false;
 | 
			
		||||
	uint32_t lastFPS = 0;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
	struct Settings {
 | 
			
		||||
		bool validation = false;
 | 
			
		||||
		bool fullscreen = false;
 | 
			
		||||
		bool vsync = false;
 | 
			
		||||
		bool multiSampling = true;
 | 
			
		||||
		VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT;
 | 
			
		||||
	} settings;
 | 
			
		||||
	
 | 
			
		||||
	struct DepthStencil {
 | 
			
		||||
		VkImage image;
 | 
			
		||||
		VkDeviceMemory mem;
 | 
			
		||||
		VkImageView view;
 | 
			
		||||
	} depthStencil;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
	struct GamePadState {
 | 
			
		||||
		glm::vec2 axisLeft = glm::vec2(0.0f);
 | 
			
		||||
		glm::vec2 axisRight = glm::vec2(0.0f);
 | 
			
		||||
	} gamePadState;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
	struct MouseButtons {
 | 
			
		||||
		bool left = false;
 | 
			
		||||
		bool right = false;
 | 
			
		||||
		bool middle = false;
 | 
			
		||||
	} mouseButtons;
 | 
			
		||||
 | 
			
		||||
	// OS specific
 | 
			
		||||
	// OS specific 
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
	HWND window;
 | 
			
		||||
	HINSTANCE windowInstance;
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
	// true if application has focused, false if moved to background
 | 
			
		||||
	bool focused = false;
 | 
			
		||||
	struct TouchPos {
 | 
			
		||||
		int32_t x;
 | 
			
		||||
		int32_t y;
 | 
			
		||||
	} touchPos;
 | 
			
		||||
	bool touchDown = false;
 | 
			
		||||
	double touchTimer = 0.0;
 | 
			
		||||
	int64_t lastTapTime = 0;
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
	void* view;
 | 
			
		||||
#if defined(VK_EXAMPLE_XCODE_GENERATED)
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
#endif
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
	IDirectFB *dfb = nullptr;
 | 
			
		||||
	IDirectFBDisplayLayer *layer = nullptr;
 | 
			
		||||
	IDirectFBWindow *window = nullptr;
 | 
			
		||||
	IDirectFBSurface *surface = nullptr;
 | 
			
		||||
	IDirectFBEventBuffer *event_buffer = nullptr;
 | 
			
		||||
	std::string androidProduct;
 | 
			
		||||
	struct TouchPoint {
 | 
			
		||||
	    int32_t id;
 | 
			
		||||
	    float x;
 | 
			
		||||
	    float y;
 | 
			
		||||
	    bool down = false;
 | 
			
		||||
	};
 | 
			
		||||
	float pinchDist = 0.0f;
 | 
			
		||||
	std::array<TouchPoint, 2> touchPoints;
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
	wl_display *display = nullptr;
 | 
			
		||||
	wl_registry *registry = nullptr;
 | 
			
		||||
	wl_compositor *compositor = nullptr;
 | 
			
		||||
	struct xdg_wm_base *shell = nullptr;
 | 
			
		||||
	wl_shell *shell = nullptr;
 | 
			
		||||
	wl_seat *seat = nullptr;
 | 
			
		||||
	wl_pointer *pointer = nullptr;
 | 
			
		||||
	wl_keyboard *keyboard = nullptr;
 | 
			
		||||
	wl_surface *surface = nullptr;
 | 
			
		||||
	struct xdg_surface *xdg_surface;
 | 
			
		||||
	struct xdg_toplevel *xdg_toplevel;
 | 
			
		||||
	wl_shell_surface *shell_surface = nullptr;
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
	bool configured = false;
 | 
			
		||||
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -268,36 +172,19 @@ public:
 | 
			
		|||
	xcb_screen_t *screen;
 | 
			
		||||
	xcb_window_t window;
 | 
			
		||||
	xcb_intern_atom_reply_t *atom_wm_delete_window;
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_HEADLESS_EXT)
 | 
			
		||||
	bool quit = false;
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
 | 
			
		||||
	NSWindow* window;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	VulkanExampleBase(bool enableValidation = false);
 | 
			
		||||
	virtual ~VulkanExampleBase();
 | 
			
		||||
	/** @brief Setup the vulkan instance, enable required extensions and connect to the physical device (GPU) */
 | 
			
		||||
	bool initVulkan();
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
	void setupConsole(std::string title);
 | 
			
		||||
	void setupDPIAwareness();
 | 
			
		||||
	HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
 | 
			
		||||
	void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
	static int32_t handleAppInput(struct android_app* app, AInputEvent* event);
 | 
			
		||||
	static void handleAppCommand(android_app* app, int32_t cmd);
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
	void* setupWindow(void* view);
 | 
			
		||||
	void displayLinkOutputCb();
 | 
			
		||||
	void mouseDragged(float x, float y);
 | 
			
		||||
	void windowWillResize(float x, float y);
 | 
			
		||||
	void windowDidResize();
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
	IDirectFBSurface *setupWindow();
 | 
			
		||||
	void handleEvent(const DFBWindowEvent *event);
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
 | 
			
		||||
	struct xdg_surface *setupWindow();
 | 
			
		||||
	wl_shell_surface *setupWindow();
 | 
			
		||||
	void initWaylandConnection();
 | 
			
		||||
	void setSize(int width, int height);
 | 
			
		||||
	static void registryGlobalCb(void *data, struct wl_registry *registry,
 | 
			
		||||
			uint32_t name, const char *interface, uint32_t version);
 | 
			
		||||
	void registryGlobal(struct wl_registry *registry, uint32_t name,
 | 
			
		||||
| 
						 | 
				
			
			@ -343,192 +230,28 @@ public:
 | 
			
		|||
	xcb_window_t setupWindow();
 | 
			
		||||
	void initxcbConnection();
 | 
			
		||||
	void handleEvent(const xcb_generic_event_t *event);
 | 
			
		||||
#else
 | 
			
		||||
	void setupWindow();
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
 | 
			
		||||
	NSWindow* setupWindow();
 | 
			
		||||
	void mouseDragged(float x, float y);
 | 
			
		||||
	void windowWillResize(float x, float y);
 | 
			
		||||
	void windowDidResize();
 | 
			
		||||
#endif
 | 
			
		||||
	/** @brief (Virtual) Creates the application wide Vulkan instance */
 | 
			
		||||
 | 
			
		||||
	VulkanExampleBase();
 | 
			
		||||
	virtual ~VulkanExampleBase();
 | 
			
		||||
	
 | 
			
		||||
	void initVulkan();
 | 
			
		||||
 | 
			
		||||
	virtual VkResult createInstance(bool enableValidation);
 | 
			
		||||
	/** @brief (Pure virtual) Render function to be implemented by the sample application */
 | 
			
		||||
	virtual void render() = 0;
 | 
			
		||||
	/** @brief (Virtual) Called when the camera view has changed */
 | 
			
		||||
	virtual void viewChanged();
 | 
			
		||||
	/** @brief (Virtual) Called after a key was pressed, can be used to do custom key handling */
 | 
			
		||||
	virtual void keyPressed(uint32_t);
 | 
			
		||||
	/** @brief (Virtual) Called after the mouse cursor moved and before internal events (like camera rotation) is handled */
 | 
			
		||||
	virtual void mouseMoved(double x, double y, bool &handled);
 | 
			
		||||
	/** @brief (Virtual) Called when the window has been resized, can be used by the sample application to recreate resources */
 | 
			
		||||
	virtual void windowResized();
 | 
			
		||||
	/** @brief (Virtual) Called when resources have been recreated that require a rebuild of the command buffers (e.g. frame buffer), to be implemented by the sample application */
 | 
			
		||||
	virtual void buildCommandBuffers();
 | 
			
		||||
	/** @brief (Virtual) Setup default depth and stencil views */
 | 
			
		||||
	virtual void setupDepthStencil();
 | 
			
		||||
	/** @brief (Virtual) Setup default framebuffers for all requested swapchain images */
 | 
			
		||||
	virtual void setupFrameBuffer();
 | 
			
		||||
	/** @brief (Virtual) Setup a default renderpass */
 | 
			
		||||
	virtual void setupRenderPass();
 | 
			
		||||
	/** @brief (Virtual) Called after the physical device features have been read, can be used to set features to enable on the device */
 | 
			
		||||
	virtual void getEnabledFeatures();
 | 
			
		||||
	/** @brief (Virtual) Called after the physical device extensions have been read, can be used to enable extensions based on the supported extension listing*/
 | 
			
		||||
	virtual void getEnabledExtensions();
 | 
			
		||||
 | 
			
		||||
	/** @brief Prepares all Vulkan resources and functions required to run the sample */
 | 
			
		||||
	virtual void prepare();
 | 
			
		||||
	virtual void fileDropped(std::string filename);
 | 
			
		||||
 | 
			
		||||
	/** @brief Loads a SPIR-V shader file for the given shader stage */
 | 
			
		||||
	VkPipelineShaderStageCreateInfo loadShader(std::string fileName, VkShaderStageFlagBits stage);
 | 
			
		||||
	void initSwapchain();
 | 
			
		||||
	void setupSwapChain();
 | 
			
		||||
 | 
			
		||||
	/** @brief Entry point for the main render loop */
 | 
			
		||||
	void renderLoop();
 | 
			
		||||
 | 
			
		||||
	/** @brief Adds the drawing commands for the ImGui overlay to the given command buffer */
 | 
			
		||||
	void drawUI(const VkCommandBuffer commandBuffer);
 | 
			
		||||
 | 
			
		||||
	/** Prepare the next frame for workload submission by acquiring the next swap chain image */
 | 
			
		||||
	void prepareFrame();
 | 
			
		||||
	/** @brief Presents the current image to the swap chain */
 | 
			
		||||
	void submitFrame();
 | 
			
		||||
	/** @brief (Virtual) Default image acquire + submission and command buffer submission function */
 | 
			
		||||
	virtual void renderFrame();
 | 
			
		||||
 | 
			
		||||
	/** @brief (Virtual) Called when the UI overlay is updating, can be used to add custom elements to the overlay */
 | 
			
		||||
	virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay);
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
	virtual void OnHandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 | 
			
		||||
#endif
 | 
			
		||||
	void renderFrame();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// OS specific macros for the example main entry points
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
// Windows entry point
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)						\
 | 
			
		||||
{																									\
 | 
			
		||||
	if (plumageRender != NULL)																		\
 | 
			
		||||
	{																								\
 | 
			
		||||
		plumageRender->handleMessages(hWnd, uMsg, wParam, lParam);									\
 | 
			
		||||
	}																								\
 | 
			
		||||
	return (DefWindowProc(hWnd, uMsg, wParam, lParam));												\
 | 
			
		||||
}																									\
 | 
			
		||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)									\
 | 
			
		||||
{																									\
 | 
			
		||||
	for (int32_t i = 0; i < __argc; i++) { PlumageRender::args.push_back(__argv[i]); };  			\
 | 
			
		||||
	plumageRender = new PlumageRender();															\
 | 
			
		||||
	plumageRender->initVulkan();																	\
 | 
			
		||||
	plumageRender->setupWindow(hInstance, WndProc);													\
 | 
			
		||||
	plumageRender->prepare();																		\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
 | 
			
		||||
// Android entry point
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
void android_main(android_app* state)																\
 | 
			
		||||
{																									\
 | 
			
		||||
	plumageRender = new PlumageRender();															\
 | 
			
		||||
	state->userData = plumageRender;																\
 | 
			
		||||
	state->onAppCmd = PlumageRender::handleAppCommand;												\
 | 
			
		||||
	state->onInputEvent = PlumageRender::handleAppInput;											\
 | 
			
		||||
	androidApp = state;																				\
 | 
			
		||||
	vks::android::getDeviceConfig();																\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
}
 | 
			
		||||
#elif defined(_DIRECT2DISPLAY)
 | 
			
		||||
// Linux entry point with direct to display wsi
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
static void handleEvent()                                											\
 | 
			
		||||
{																									\
 | 
			
		||||
}																									\
 | 
			
		||||
int main(const int argc, const char *argv[])													    \
 | 
			
		||||
{																									\
 | 
			
		||||
	for (size_t i = 0; i < argc; i++) { PlumageRender::args.push_back(argv[i]); };  				\
 | 
			
		||||
	plumageRender = new PlumageRender();															\
 | 
			
		||||
	plumageRender->initVulkan();																	\
 | 
			
		||||
	plumageRender->prepare();																		\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
static void handleEvent(const DFBWindowEvent *event)												\
 | 
			
		||||
{																									\
 | 
			
		||||
	if (plumageRender != NULL)																		\
 | 
			
		||||
	{																								\
 | 
			
		||||
		plumageRender->handleEvent(event);															\
 | 
			
		||||
	}																								\
 | 
			
		||||
}																									\
 | 
			
		||||
int main(const int argc, const char *argv[])													    \
 | 
			
		||||
{																									\
 | 
			
		||||
	for (size_t i = 0; i < argc; i++) { PlumageRender::args.push_back(argv[i]); };  				\
 | 
			
		||||
	plumageRender = new PlumageRender();															\
 | 
			
		||||
	plumageRender->initVulkan();																	\
 | 
			
		||||
	plumageRender->setupWindow();					 												\
 | 
			
		||||
	plumageRender->prepare();																		\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_WAYLAND_KHR) || defined(VK_USE_PLATFORM_HEADLESS_EXT))
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
int main(const int argc, const char *argv[])													    \
 | 
			
		||||
{																									\
 | 
			
		||||
	for (size_t i = 0; i < argc; i++) { PlumageRender::args.push_back(argv[i]); };  				\
 | 
			
		||||
	plumageRender = new PlumageRender();															\
 | 
			
		||||
	plumageRender->initVulkan();																	\
 | 
			
		||||
	plumageRender->setupWindow();					 												\
 | 
			
		||||
	plumageRender->prepare();																		\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
static void handleEvent(const xcb_generic_event_t *event)											\
 | 
			
		||||
{																									\
 | 
			
		||||
	if (plumageRender != NULL)																		\
 | 
			
		||||
	{																								\
 | 
			
		||||
		plumageRender->handleEvent(event);															\
 | 
			
		||||
	}																								\
 | 
			
		||||
}																									\
 | 
			
		||||
int main(const int argc, const char *argv[])													    \
 | 
			
		||||
{																									\
 | 
			
		||||
	for (size_t i = 0; i < argc; i++) { PlumageRender::args.push_back(argv[i]); };  				\
 | 
			
		||||
	plumageRender = new VulkanExample();															\
 | 
			
		||||
	plumageRender->initVulkan();																	\
 | 
			
		||||
	plumageRender->setupWindow();					 												\
 | 
			
		||||
	plumageRender->prepare();																		\
 | 
			
		||||
	plumageRender->renderLoop();																	\
 | 
			
		||||
	delete(plumageRender);																			\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#elif (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK))
 | 
			
		||||
#if defined(VK_EXAMPLE_XCODE_GENERATED)
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()																		\
 | 
			
		||||
PlumageRender *plumageRender;																		\
 | 
			
		||||
int main(const int argc, const char *argv[])														\
 | 
			
		||||
{																									\
 | 
			
		||||
	@autoreleasepool																				\
 | 
			
		||||
	{																								\
 | 
			
		||||
		for (size_t i = 0; i < argc; i++) { PlumageRender::args.push_back(argv[i]); };				\
 | 
			
		||||
		plumageRender = new PlumageRender();														\
 | 
			
		||||
		plumageRender->initVulkan();																\
 | 
			
		||||
		plumageRender->setupWindow(nullptr);														\
 | 
			
		||||
		plumageRender->prepare();																	\
 | 
			
		||||
		plumageRender->renderLoop();																\
 | 
			
		||||
		delete(plumageRender);																		\
 | 
			
		||||
	}																								\
 | 
			
		||||
	return 0;																						\
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define PLUMAGE_RENDER_MAIN()
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
 | 
			
		||||
#include "tiny_gltf.h"
 | 
			
		||||
#include "VulkanDevice.hpp"
 | 
			
		||||
//#include "VulkanUtils.hpp"
 | 
			
		||||
#include "vulkan/vulkan.h"
 | 
			
		||||
 | 
			
		||||
#define ENABLE_VALIDATION false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -722,10 +722,9 @@ PlumageRender::PlumageRender():
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	//----------------------------Prepare precompute Lighting or BRDF LUT-----------------------------------------------//
 | 
			
		||||
	//Irradiance map for diffuse lighting
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// generate two cube maps
 | 
			
		||||
	// irradiance cube map
 | 
			
		||||
	// prefileter environment cube map
 | 
			
		||||
	void PlumageRender::generateCubemaps()
 | 
			
		||||
	{
 | 
			
		||||
		enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 };
 | 
			
		||||
| 
						 | 
				
			
			@ -1138,12 +1137,12 @@ PlumageRender::PlumageRender():
 | 
			
		|||
					switch (target) {
 | 
			
		||||
					case IRRADIANCE:
 | 
			
		||||
						irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
 | 
			
		||||
						vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlockIrradiance), &pushBlockIrradiance);
 | 
			
		||||
						vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock);
 | 
			
		||||
						break;
 | 
			
		||||
					case PREFILTEREDENV:
 | 
			
		||||
						prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
 | 
			
		||||
						prefilterPushBlock.roughness = (float)m / (float)(numMips - 1);
 | 
			
		||||
						vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlockPrefilterEnv), &pushBlockPrefilterEnv);
 | 
			
		||||
						vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PrefilterPushBlock), &prefilterPushBlock);
 | 
			
		||||
						break;
 | 
			
		||||
					};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1263,8 +1262,8 @@ PlumageRender::PlumageRender():
 | 
			
		|||
			std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PlumageRender::GenerateBRDFLUT()
 | 
			
		||||
	// generate BRDF integration map for roughness/NdotV
 | 
			
		||||
	void PlumageRender::generateBRDFLUT()
 | 
			
		||||
	{
 | 
			
		||||
		auto tStart = std::chrono::high_resolution_clock::now();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1461,8 +1460,8 @@ PlumageRender::PlumageRender():
 | 
			
		|||
 | 
			
		||||
		// Look-up-table (from BRDF) pipeline		
 | 
			
		||||
		shaderStages = {
 | 
			
		||||
			loadShader(device, "genbrdflut.vert.spv", VK_SHADER_STAGE_VERTEX_BIT),
 | 
			
		||||
			loadShader(device, "genbrdflut.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT)
 | 
			
		||||
			loadShader(filePath.brdfVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT),
 | 
			
		||||
			loadShader(filePath.brdfFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT)
 | 
			
		||||
		};
 | 
			
		||||
		VkPipeline pipeline;
 | 
			
		||||
		VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
 | 
			
		||||
| 
						 | 
				
			
			@ -1520,136 +1519,196 @@ PlumageRender::PlumageRender():
 | 
			
		|||
		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
 | 
			
		||||
		std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
	//----------------------------End Precompute brick------------------------------------------------------------------//
 | 
			
		||||
#pragma region pbr render pass setting
 | 
			
		||||
 | 
			
		||||
	void PlumageRender::createAttachment(
 | 
			
		||||
		VkFormat format,
 | 
			
		||||
		VkImageUsageFlagBits usage,
 | 
			
		||||
		FrameBufferAttachment* attachment,
 | 
			
		||||
		uint32_t width,
 | 
			
		||||
		uint32_t height)
 | 
			
		||||
	{
 | 
			
		||||
		VkImageAspectFlags aspectMask = 0;
 | 
			
		||||
		VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
 | 
			
		||||
		attachment->format = format;
 | 
			
		||||
		if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
 | 
			
		||||
		{
 | 
			
		||||
			aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 | 
			
		||||
			imageUsage |= VK_IMAGE_USAGE_SAMPLED_BIT;
 | 
			
		||||
		}
 | 
			
		||||
		if (usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
 | 
			
		||||
		{
 | 
			
		||||
			aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
 | 
			
		||||
			if (format >= VK_FORMAT_D16_UNORM_S8_UINT)
 | 
			
		||||
				aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		assert(aspectMask > 0);
 | 
			
		||||
 | 
			
		||||
		VkImageCreateInfo image = vks::initializers::imageCreateInfo();
 | 
			
		||||
		image.imageType = VK_IMAGE_TYPE_2D;
 | 
			
		||||
		image.format = format;
 | 
			
		||||
		image.extent.width = width;
 | 
			
		||||
		image.extent.height = 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 = imageUsage | usage;
 | 
			
		||||
 | 
			
		||||
		VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();
 | 
			
		||||
		VkMemoryRequirements memReqs;
 | 
			
		||||
 | 
			
		||||
		VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &attachment->image));
 | 
			
		||||
		vkGetImageMemoryRequirements(device, attachment->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, &attachment->deviceMemory));
 | 
			
		||||
		VK_CHECK_RESULT(vkBindImageMemory(device, attachment->image, attachment->deviceMemory, 0));
 | 
			
		||||
 | 
			
		||||
		VkImageViewCreateInfo imageView = vks::initializers::imageViewCreateInfo();
 | 
			
		||||
		imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
 | 
			
		||||
		imageView.format = format;
 | 
			
		||||
		imageView.subresourceRange = {};
 | 
			
		||||
		imageView.subresourceRange.aspectMask = aspectMask;
 | 
			
		||||
		imageView.subresourceRange.baseMipLevel = 0;
 | 
			
		||||
		imageView.subresourceRange.levelCount = 1;
 | 
			
		||||
		imageView.subresourceRange.baseArrayLayer = 0;
 | 
			
		||||
		imageView.subresourceRange.layerCount = 1;
 | 
			
		||||
		imageView.image = attachment->image;
 | 
			
		||||
		VK_CHECK_RESULT(vkCreateImageView(device, &imageView, nullptr, &attachment->imageView));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#pragma endregion
 | 
			
		||||
	
 | 
			
		||||
	// Prepare and initialize uniform buffer containing shader uniforms
 | 
			
		||||
	void PlumageRender::prepareUniformBuffers()
 | 
			
		||||
	{
 | 
			
		||||
		// Vertex shader uniform buffer block
 | 
			
		||||
		VK_CHECK_RESULT(vulkanDevice->createBuffer(
 | 
			
		||||
			VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
 | 
			
		||||
			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
			
		||||
			&shaderData.buffer,
 | 
			
		||||
			sizeof(shaderData.values)));
 | 
			
		||||
 | 
			
		||||
		VK_CHECK_RESULT(vulkanDevice->createBuffer(
 | 
			
		||||
			VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
 | 
			
		||||
			VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
			
		||||
			&shaderData.skinSSBO,
 | 
			
		||||
			sizeof(glm::mat4) * glTFModel.nodeCount));
 | 
			
		||||
 | 
			
		||||
		// Map persistent
 | 
			
		||||
		VK_CHECK_RESULT(shaderData.buffer.map());
 | 
			
		||||
		VK_CHECK_RESULT(shaderData.skinSSBO.map());
 | 
			
		||||
 | 
			
		||||
		for (auto& material : glTFModel.materials)
 | 
			
		||||
		{
 | 
			
		||||
			VK_CHECK_RESULT(vulkanDevice->createBuffer(
 | 
			
		||||
				VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
 | 
			
		||||
				VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
 | 
			
		||||
				&material.materialData.buffer,
 | 
			
		||||
				sizeof(VulkanglTFModel::MaterialData::Values),
 | 
			
		||||
				&material.materialData.values));
 | 
			
		||||
		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(shaderData));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		updateUniformBuffers();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PlumageRender::updateUniformBuffers()
 | 
			
		||||
	{
 | 
			
		||||
		shaderData.values.projection = camera.matrices.perspective;
 | 
			
		||||
		shaderData.values.model = camera.matrices.view;
 | 
			
		||||
		shaderData.values.viewPos = camera.viewPos;
 | 
			
		||||
		shaderData.values.bFlagSet.x = normalMapping;
 | 
			
		||||
		shaderData.values.bFlagSet.y = pbrEnabled;
 | 
			
		||||
		memcpy(shaderData.buffer.mapped, &shaderData.values, sizeof(shaderData.values));
 | 
			
		||||
		// Scene
 | 
			
		||||
		shaderDataScene.projection = camera.matrices.perspective;
 | 
			
		||||
		shaderDataScene.view = camera.matrices.view;
 | 
			
		||||
 | 
			
		||||
		// Center and scale model
 | 
			
		||||
		float scale = (1.0f / std::max(models.scene.aabb[0][0], std::max(models.scene.aabb[1][1], models.scene.aabb[2][2]))) * 0.5f;
 | 
			
		||||
		glm::vec3 translate = -glm::vec3(models.scene.aabb[3][0], models.scene.aabb[3][1], models.scene.aabb[3][2]);
 | 
			
		||||
		translate += -0.5f * glm::vec3(models.scene.aabb[0][0], models.scene.aabb[1][1], 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 PlumageRender::updateShaderData()
 | 
			
		||||
	{
 | 
			
		||||
		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 PlumageRender::windowResized()
 | 
			
		||||
	{
 | 
			
		||||
		buildCommandBuffers();
 | 
			
		||||
		vkDeviceWaitIdle(device);
 | 
			
		||||
		updateUniformBuffers();
 | 
			
		||||
		// update UI
 | 
			
		||||
		//updateUIOverlay();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PlumageRender::prepare()
 | 
			
		||||
	{
 | 
			
		||||
		VulkanExampleBase::prepare();
 | 
			
		||||
 | 
			
		||||
		camera.type = Camera::CameraType::lookat;
 | 
			
		||||
 | 
			
		||||
		camera.setPerspective(45.0f, (float)width / (float)height, 0.1f, 256.0f);
 | 
			
		||||
		camera.rotationSpeed = 0.25f;
 | 
			
		||||
		camera.movementSpeed = 0.1f;
 | 
			
		||||
		camera.setPosition({ 0.0f, 0.0f, 1.0f });
 | 
			
		||||
		camera.setRotation({ 0.0f, 0.0f, 0.0f });
 | 
			
		||||
 | 
			
		||||
		waitFences.resize(renderAhead);
 | 
			
		||||
		presentCompleteSemaphores.resize(renderAhead);
 | 
			
		||||
		renderCompleteSemaphores.resize(renderAhead);
 | 
			
		||||
		commandBuffers.resize(swapChain.imageCount);
 | 
			
		||||
		uniformBuffers.resize(swapChain.imageCount);
 | 
			
		||||
		descriptorSets.resize(swapChain.imageCount);
 | 
			
		||||
		// 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));
 | 
			
		||||
		}
 | 
			
		||||
		// Queue ordering semaphores
 | 
			
		||||
		for (auto& semaphore : presentCompleteSemaphores) {
 | 
			
		||||
			VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 };
 | 
			
		||||
			VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
 | 
			
		||||
		}
 | 
			
		||||
		for (auto& semaphore : renderCompleteSemaphores) {
 | 
			
		||||
			VkSemaphoreCreateInfo semaphoreCI{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 };
 | 
			
		||||
			VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCI, nullptr, &semaphore));
 | 
			
		||||
		}
 | 
			
		||||
		// Command buffers
 | 
			
		||||
		{
 | 
			
		||||
			VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
 | 
			
		||||
			cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
 | 
			
		||||
			cmdBufAllocateInfo.commandPool = cmdPool;
 | 
			
		||||
			cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
 | 
			
		||||
			cmdBufAllocateInfo.commandBufferCount = static_cast<uint32_t>(commandBuffers.size());
 | 
			
		||||
			VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, commandBuffers.data()));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		loadAssets();
 | 
			
		||||
		GenerateBRDFLUT();
 | 
			
		||||
		GenerateIrradianceCubemap();
 | 
			
		||||
		GeneratePrefilteredCubemap();
 | 
			
		||||
		generateBRDFLUT();
 | 
			
		||||
		generateCubemaps();
 | 
			
		||||
		prepareUniformBuffers();
 | 
			
		||||
		setupDescriptors();
 | 
			
		||||
		preparePipelines();
 | 
			
		||||
 | 
			
		||||
		//ui = new UI(vulkanDevice, renderPass, queue, pipelineCache, settings.sampleCount);
 | 
			
		||||
		//updateOverlay();
 | 
			
		||||
 | 
			
		||||
		buildCommandBuffers();
 | 
			
		||||
 | 
			
		||||
		prepared = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void PlumageRender::render()
 | 
			
		||||
	{
 | 
			
		||||
		renderFrame();
 | 
			
		||||
		if (!prepared) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//updateOverlay();
 | 
			
		||||
 | 
			
		||||
		VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
 | 
			
		||||
		VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
 | 
			
		||||
 | 
			
		||||
		VkResult acquire = swapChain.acquireNextImage(presentCompleteSemaphores[frameIndex], ¤tBuffer);
 | 
			
		||||
		if ((acquire == VK_ERROR_OUT_OF_DATE_KHR) || (acquire == VK_SUBOPTIMAL_KHR)) {
 | 
			
		||||
			windowResize();
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			VK_CHECK_RESULT(acquire);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Update UBOs
 | 
			
		||||
		updateUniformBuffers();
 | 
			
		||||
		UniformBufferSet currentUB = uniformBuffers[currentBuffer];
 | 
			
		||||
		memcpy(currentUB.scene.mapped, &shaderDataScene, sizeof(shaderDataScene));
 | 
			
		||||
		memcpy(currentUB.params.mapped, &shaderData, sizeof(shaderData));
 | 
			
		||||
		memcpy(currentUB.skybox.mapped, &shaderDataSkybox, sizeof(shaderDataSkybox));
 | 
			
		||||
 | 
			
		||||
		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(queue, 1, &submitInfo, waitFences[frameIndex]));
 | 
			
		||||
 | 
			
		||||
		VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]);
 | 
			
		||||
		if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) {
 | 
			
		||||
			if (present == VK_ERROR_OUT_OF_DATE_KHR) {
 | 
			
		||||
				windowResize();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				VK_CHECK_RESULT(present);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		frameIndex += 1;
 | 
			
		||||
		frameIndex %= renderAhead;
 | 
			
		||||
 | 
			
		||||
		if (!paused) {
 | 
			
		||||
			if (rotateModel) {
 | 
			
		||||
				modelrot.y += frameTimer * 35.0f;
 | 
			
		||||
				if (modelrot.y > 360.0f) {
 | 
			
		||||
					modelrot.y -= 360.0f;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if ((animate) && (models.scene.animations.size() > 0)) {
 | 
			
		||||
				animationTimer += frameTimer;
 | 
			
		||||
				if (animationTimer > models.scene.animations[animationIndex].end) {
 | 
			
		||||
					animationTimer -= models.scene.animations[animationIndex].end;
 | 
			
		||||
				}
 | 
			
		||||
				models.scene.updateAnimation(animationIndex, animationTimer);
 | 
			
		||||
			}
 | 
			
		||||
			updateShaderData();
 | 
			
		||||
			if (rotateModel) {
 | 
			
		||||
				updateUniformBuffers();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (camera.updated) {
 | 
			
		||||
			updateUniformBuffers();
 | 
			
		||||
		}
 | 
			
		||||
		if (!paused && glTFModel.animations.size() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			glTFModel.updateAnimation(frameTimer, shaderData.skinSSBO);
 | 
			
		||||
		}
 | 
			
		||||
			
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
#include <vulkan/vulkan.h>
 | 
			
		||||
#include "VulkanExampleBase.h"
 | 
			
		||||
#include "glTFModel.h"
 | 
			
		||||
#include "VulkanUtils.hpp"
 | 
			
		||||
//#include "VulkanDevice.hpp"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,9 +61,9 @@ public:
 | 
			
		|||
	} shaderData;
 | 
			
		||||
 | 
			
		||||
	struct UniformBufferSet {
 | 
			
		||||
		vks::Buffer scene;
 | 
			
		||||
		vks::Buffer skybox;
 | 
			
		||||
		vks::Buffer params;
 | 
			
		||||
		Buffer scene;
 | 
			
		||||
		Buffer skybox;
 | 
			
		||||
		Buffer params;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct UBOMatrices {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +71,7 @@ public:
 | 
			
		|||
		glm::mat4 model;
 | 
			
		||||
		glm::mat4 view;
 | 
			
		||||
		glm::vec3 camPos;
 | 
			
		||||
	} shaderValuesScene, shaderValuesSkybox;
 | 
			
		||||
	} shaderDataScene, shaderDataSkybox;
 | 
			
		||||
 | 
			
		||||
	struct PushConstBlockMaterial {
 | 
			
		||||
		glm::vec4 baseColorFactor;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,8 +113,8 @@ public:
 | 
			
		|||
		std::string filterVertShaderPath = getAssetPath() + "shaders/filtercube.vert.spv";
 | 
			
		||||
		std::string prefilterEnvmapFragShaderPath = getAssetPath() + "shaders/prefilterenvmap.frag.spv";
 | 
			
		||||
		//brdf cube map
 | 
			
		||||
		std::string brdfVertShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.vert.spv";
 | 
			
		||||
		std::string brdfFragShaderPath = getAssetPath() + "buster_drone/shaders/glsl/genbrdflut.frag.spv";
 | 
			
		||||
		std::string brdfVertShaderPath = getAssetPath() + "shaders/genbrdflut.vert.spv";
 | 
			
		||||
		std::string brdfFragShaderPath = getAssetPath() + "shaders/genbrdflut.frag.spv";
 | 
			
		||||
		// environment map texture
 | 
			
		||||
		std::string envMapFilePath = getAssetPath() + "environments/papermill.ktx";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -284,9 +285,11 @@ public:
 | 
			
		|||
	void         preparePipelines();
 | 
			
		||||
	void CreateToneMappingPipeline();
 | 
			
		||||
	void generateCubemaps();
 | 
			
		||||
	void GenerateBRDFLUT();
 | 
			
		||||
	void generateBRDFLUT();
 | 
			
		||||
	void         prepareUniformBuffers();
 | 
			
		||||
	void         updateUniformBuffers();
 | 
			
		||||
	void updateShaderData();
 | 
			
		||||
	void windowResized();
 | 
			
		||||
	void         prepare();
 | 
			
		||||
	virtual void render();
 | 
			
		||||
	virtual void viewChanged();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue