revert
							parent
							
								
									20a30d9192
								
							
						
					
					
						commit
						a0b8b66f2b
					
				|  | @ -120,6 +120,7 @@ namespace vks | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		/**
 | ||||
| 		* Get the index of a queue family that supports the requested queue flags | ||||
| 		* | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ void VulkanExampleBase::prepare() | |||
| 		attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | ||||
| 		attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | ||||
| 		attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | ||||
| 		attachments[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; | ||||
| 
 | ||||
| 		// This is the frame buffer attachment to where the multisampled image
 | ||||
| 		// will be resolved to and which will be presented to the swapchain
 | ||||
|  | @ -143,8 +143,15 @@ void VulkanExampleBase::prepare() | |||
| 		attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | ||||
| 		attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | ||||
| 		attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		attachments[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | ||||
| 
 | ||||
| 		if (settings.headless) | ||||
| 		{ | ||||
| 			attachments[1].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			attachments[1].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | ||||
| 		} | ||||
| 		 | ||||
| 		// Multisampled depth attachment we render to
 | ||||
| 		attachments[2].format = depthFormat; | ||||
| 		attachments[2].samples = settings.sampleCount; | ||||
|  | @ -214,30 +221,39 @@ void VulkanExampleBase::prepare() | |||
| 		renderPassCI.pDependencies = dependencies.data(); | ||||
| 		VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass)); | ||||
| 	} | ||||
| 	else { | ||||
| 		std::array<VkAttachmentDescription, 2> attachments = {}; | ||||
| 	else  | ||||
| 	{ | ||||
| 		std::array<VkAttachmentDescription, 2> attachmentDescriptions = {}; | ||||
| 		// Color attachment
 | ||||
| 		attachments[0].format = swapChain.colorFormat; | ||||
| 		attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | ||||
| 		attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; | ||||
| 		attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | ||||
| 		attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | ||||
| 		attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | ||||
| 		attachmentDescriptions[0].format = swapChain.colorFormat; | ||||
| 		attachmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		attachmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | ||||
| 		attachmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; | ||||
| 		attachmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | ||||
| 		attachmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | ||||
| 		attachmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		if (settings.headless) | ||||
| 		{ | ||||
| 			attachmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			attachmentDescriptions[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; | ||||
| 		attachmentDescriptions[1].format = depthFormat; | ||||
| 		attachmentDescriptions[1].samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		attachmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | ||||
| 		attachmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; | ||||
| 		attachmentDescriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | ||||
| 		attachmentDescriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | ||||
| 		attachmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		attachmentDescriptions[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; | ||||
|  | @ -275,13 +291,16 @@ void VulkanExampleBase::prepare() | |||
| 
 | ||||
| 		VkRenderPassCreateInfo renderPassCI{}; | ||||
| 		renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | ||||
| 		renderPassCI.attachmentCount = static_cast<uint32_t>(attachments.size()); | ||||
| 		renderPassCI.pAttachments = attachments.data(); | ||||
| 		renderPassCI.attachmentCount = static_cast<uint32_t>(attachmentDescriptions.size()); | ||||
| 		renderPassCI.pAttachments = attachmentDescriptions.data(); | ||||
| 		renderPassCI.subpassCount = 1; | ||||
| 		renderPassCI.pSubpasses = &subpassDescription; | ||||
| 		renderPassCI.dependencyCount = static_cast<uint32_t>(dependencies.size()); | ||||
| 		renderPassCI.pDependencies = dependencies.data(); | ||||
| 		VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassCI, nullptr, &renderPass)); | ||||
| 
 | ||||
| 		 | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -299,189 +318,6 @@ void VulkanExampleBase::prepare() | |||
| 
 | ||||
| void VulkanExampleBase::fileDropped(std::string filename) { } | ||||
| 
 | ||||
| void VulkanExampleBase::renderFrame() | ||||
| { | ||||
| 	auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 
 | ||||
| 	render(); | ||||
| 	frameCounter++; | ||||
| 	auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 	auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 	frameTimer = (float)tDiff / 1000.0f; | ||||
| 	camera.update(frameTimer); | ||||
| 	fpsTimer += (float)tDiff; | ||||
| 	if (fpsTimer > 1000.0f) { | ||||
| 		lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer)); | ||||
| 		fpsTimer = 0.0f; | ||||
| 		frameCounter = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void VulkanExampleBase::renderLoop() | ||||
| { | ||||
| 	destWidth = width; | ||||
| 	destHeight = height; | ||||
| #if defined(_WIN32) | ||||
| 	MSG msg; | ||||
| 	bool quitMessageReceived = false; | ||||
| 	while (!quitMessageReceived) { | ||||
| 		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | ||||
| 			TranslateMessage(&msg); | ||||
| 			DispatchMessage(&msg); | ||||
| 			if (msg.message == WM_QUIT) { | ||||
| 				quitMessageReceived = true; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (!IsIconic(window)) { | ||||
| 			renderFrame(); | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(VK_USE_PLATFORM_ANDROID_KHR) | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		int ident; | ||||
| 		int events; | ||||
| 		struct android_poll_source* source; | ||||
| 		bool destroy = false; | ||||
| 
 | ||||
| 		focused = true; | ||||
| 
 | ||||
| 		while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0) | ||||
| 		{ | ||||
| 			if (source != NULL) | ||||
| 			{ | ||||
| 				source->process(androidApp, source); | ||||
| 			} | ||||
| 			if (androidApp->destroyRequested != 0) | ||||
| 			{ | ||||
| 				LOGD("Android app destroy requested"); | ||||
| 				destroy = true; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// App destruction requested
 | ||||
| 		// Exit loop, example will be destroyed in application main
 | ||||
| 		if (destroy) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		// Render frame
 | ||||
| 		if (prepared) | ||||
| 		{ | ||||
| 			auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 			render(); | ||||
| 			frameCounter++; | ||||
| 			auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 			auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 			frameTimer = tDiff / 1000.0f; | ||||
| 			camera.update(frameTimer); | ||||
| 			fpsTimer += (float)tDiff; | ||||
| 			if (fpsTimer > 1000.0f) | ||||
| 			{ | ||||
| 				lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 				fpsTimer = 0.0f; | ||||
| 				frameCounter = 0; | ||||
| 			} | ||||
| 
 | ||||
| 			// Check gamepad state
 | ||||
| 			const float deadZone = 0.0015f; | ||||
| 			// todo : check if gamepad is present
 | ||||
| 			// todo : time based and relative axis positions
 | ||||
| 			if (camera.type != Camera::CameraType::firstperson) | ||||
| 			{ | ||||
| 				// Rotate
 | ||||
| 				if (std::abs(gamePadState.axisLeft.x) > deadZone) { | ||||
| 					camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f)); | ||||
| 				} | ||||
| 				if (std::abs(gamePadState.axisLeft.y) > deadZone) { | ||||
| 					camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f)); | ||||
| 				} | ||||
| 			} else { | ||||
| 				camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(_DIRECT2DISPLAY) | ||||
| 	while (!quit) | ||||
| 	{ | ||||
| 		auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 		render(); | ||||
| 		frameCounter++; | ||||
| 		auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 		frameTimer = tDiff / 1000.0f; | ||||
| 		camera.update(frameTimer); | ||||
| 		fpsTimer += (float)tDiff; | ||||
| 		if (fpsTimer > 1000.0f) | ||||
| 		{ | ||||
| 			lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 			fpsTimer = 0.0f; | ||||
| 			frameCounter = 0; | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) | ||||
| 	while (!quit) | ||||
| 	{ | ||||
| 		auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 
 | ||||
| 		while (wl_display_prepare_read(display) != 0) | ||||
| 			wl_display_dispatch_pending(display); | ||||
| 		wl_display_flush(display); | ||||
| 		wl_display_read_events(display); | ||||
| 		wl_display_dispatch_pending(display); | ||||
| 
 | ||||
| 		render(); | ||||
| 		frameCounter++; | ||||
| 		auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 		frameTimer = tDiff / 1000.0f; | ||||
| 		camera.update(frameTimer); | ||||
| 		fpsTimer += (float)tDiff; | ||||
| 		if (fpsTimer > 1000.0f) | ||||
| 		{ | ||||
| 			wl_shell_surface_set_title(shell_surface, title.c_str()); | ||||
| 			lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 			fpsTimer = 0.0f; | ||||
| 			frameCounter = 0; | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(VK_USE_PLATFORM_XCB_KHR) | ||||
| 	xcb_flush(connection); | ||||
| 	while (!quit) | ||||
| 	{ | ||||
| 		auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 		xcb_generic_event_t *event; | ||||
| 		while ((event = xcb_poll_for_event(connection))) | ||||
| 		{ | ||||
| 			handleEvent(event); | ||||
| 			free(event); | ||||
| 		} | ||||
| 		render(); | ||||
| 		frameCounter++; | ||||
| 		auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 		frameTimer = tDiff / 1000.0f; | ||||
| 		camera.update(frameTimer); | ||||
| 		fpsTimer += (float)tDiff; | ||||
| 		if (fpsTimer > 1000.0f) | ||||
| 		{ | ||||
| 			xcb_change_property(connection, XCB_PROP_MODE_REPLACE, | ||||
| 				window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, | ||||
| 				title.size(), title.c_str()); | ||||
| 			lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 			fpsTimer = 0.0f; | ||||
| 			frameCounter = 0; | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(VK_USE_PLATFORM_MACOS_MVK) | ||||
| 	[NSApp run]; | ||||
| #endif | ||||
| 	// Flush device to make sure all resources can be freed 
 | ||||
| 	vkDeviceWaitIdle(device); | ||||
| } | ||||
| 
 | ||||
| VulkanExampleBase::VulkanExampleBase() | ||||
| { | ||||
|  | @ -539,9 +375,9 @@ VulkanExampleBase::~VulkanExampleBase() | |||
| 	for (uint32_t i = 0; i < frameBuffers.size(); i++) { | ||||
| 		vkDestroyFramebuffer(device, frameBuffers[i], nullptr); | ||||
| 	} | ||||
| 	vkDestroyImageView(device, depthStencil.view, nullptr); | ||||
| 	vkDestroyImage(device, depthStencil.image, nullptr); | ||||
| 	vkFreeMemory(device, depthStencil.mem, nullptr); | ||||
| 	vkDestroyImageView(device, depthAttachment.view, nullptr); | ||||
| 	vkDestroyImage(device, depthAttachment.image, nullptr); | ||||
| 	vkFreeMemory(device, depthAttachment.memory, nullptr); | ||||
| 	vkDestroyPipelineCache(device, pipelineCache, nullptr); | ||||
| 	vkDestroyCommandPool(device, cmdPool, nullptr); | ||||
| 	if (settings.multiSampling) { | ||||
|  | @ -1822,8 +1658,9 @@ void VulkanExampleBase::setupFrameBuffer() | |||
| 		imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | ||||
| 		imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; | ||||
| 		imageCI.samples = settings.sampleCount; | ||||
| 		imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | ||||
| 		imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | ||||
| 		imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		 | ||||
| 		VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.color.image)); | ||||
| 
 | ||||
| 		VkMemoryRequirements memReqs; | ||||
|  | @ -1891,65 +1728,140 @@ void VulkanExampleBase::setupFrameBuffer() | |||
| 		imageViewCI.subresourceRange.levelCount = 1; | ||||
| 		imageViewCI.subresourceRange.layerCount = 1; | ||||
| 		VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &multisampleTarget.depth.view)); | ||||
| 
 | ||||
| 		VkImageCreateInfo image = {}; | ||||
| 		image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | ||||
| 		image.pNext = NULL; | ||||
| 		image.imageType = VK_IMAGE_TYPE_2D; | ||||
| 		image.format = depthFormat; | ||||
| 		image.extent = { width, height, 1 }; | ||||
| 		image.mipLevels = 1; | ||||
| 		image.arrayLayers = 1; | ||||
| 		image.samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		image.tiling = VK_IMAGE_TILING_OPTIMAL; | ||||
| 		image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | ||||
| 		image.flags = 0; | ||||
| 
 | ||||
| 		VkMemoryAllocateInfo mem_alloc = {}; | ||||
| 		mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | ||||
| 		mem_alloc.pNext = NULL; | ||||
| 		mem_alloc.allocationSize = 0; | ||||
| 		mem_alloc.memoryTypeIndex = 0; | ||||
| 
 | ||||
| 		VkImageViewCreateInfo depthStencilView = {}; | ||||
| 		depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | ||||
| 		depthStencilView.pNext = NULL; | ||||
| 		depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; | ||||
| 		depthStencilView.format = depthFormat; | ||||
| 		depthStencilView.flags = 0; | ||||
| 		depthStencilView.subresourceRange = {}; | ||||
| 		depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | ||||
| 		depthStencilView.subresourceRange.baseMipLevel = 0; | ||||
| 		depthStencilView.subresourceRange.levelCount = 1; | ||||
| 		depthStencilView.subresourceRange.baseArrayLayer = 0; | ||||
| 		depthStencilView.subresourceRange.layerCount = 1; | ||||
| 
 | ||||
| 		 | ||||
| 		VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image)); | ||||
| 		vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs); | ||||
| 		mem_alloc.allocationSize = memReqs.size; | ||||
| 		mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||
| 		VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthAttachment.memory)); | ||||
| 		VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0)); | ||||
| 
 | ||||
| 		depthStencilView.image = depthAttachment.image; | ||||
| 		VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view)); | ||||
| 	} | ||||
| 	else // color attachment when MSAA is no enabled
 | ||||
| 	{ | ||||
| 		VkFormat colorFormat = VK_FORMAT_B8G8R8A8_SRGB; | ||||
| 		VkFormat depthFormat; | ||||
| 		vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat); | ||||
| 		 | ||||
| 		// Color attachment
 | ||||
| 		VkImageCreateInfo image = vks::initializers::imageCreateInfo(); | ||||
| 		image.imageType = VK_IMAGE_TYPE_2D; | ||||
| 		image.format = colorFormat; | ||||
| 		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 = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | ||||
| 
 | ||||
| 		VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo(); | ||||
| 		VkMemoryRequirements memReqs; | ||||
| 
 | ||||
| 		VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &colorAttachment.image)); | ||||
| 		vkGetImageMemoryRequirements(device, colorAttachment.image, &memReqs); | ||||
| 		memAlloc.allocationSize = memReqs.size; | ||||
| 		memAlloc.memoryTypeIndex = vulkanDevice -> getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||
| 		VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &colorAttachment.memory)); | ||||
| 		VK_CHECK_RESULT(vkBindImageMemory(device, colorAttachment.image, colorAttachment.memory, 0)); | ||||
| 
 | ||||
| 		VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo(); | ||||
| 		colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D; | ||||
| 		colorImageView.format = colorFormat; | ||||
| 		colorImageView.subresourceRange = {}; | ||||
| 		colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | ||||
| 		colorImageView.subresourceRange.baseMipLevel = 0; | ||||
| 		colorImageView.subresourceRange.levelCount = 1; | ||||
| 		colorImageView.subresourceRange.baseArrayLayer = 0; | ||||
| 		colorImageView.subresourceRange.layerCount = 1; | ||||
| 		colorImageView.image = colorAttachment.image; | ||||
| 		VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &colorAttachment.view)); | ||||
| 
 | ||||
| 		// Depth stencil attachment
 | ||||
| 		image.format = depthFormat; | ||||
| 		image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; | ||||
| 
 | ||||
| 		VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthAttachment.image)); | ||||
| 		vkGetImageMemoryRequirements(device, depthAttachment.image, &memReqs); | ||||
| 		memAlloc.allocationSize = memReqs.size; | ||||
| 		memAlloc.memoryTypeIndex = vulkanDevice -> getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||
| 		VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthAttachment.memory)); | ||||
| 		VK_CHECK_RESULT(vkBindImageMemory(device, depthAttachment.image, depthAttachment.memory, 0)); | ||||
| 
 | ||||
| 		VkImageViewCreateInfo depthStencilView = vks::initializers::imageViewCreateInfo(); | ||||
| 		depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; | ||||
| 		depthStencilView.format = depthFormat; | ||||
| 		depthStencilView.flags = 0; | ||||
| 		depthStencilView.subresourceRange = {}; | ||||
| 		depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; | ||||
| 		if (depthFormat >= VK_FORMAT_D16_UNORM_S8_UINT) | ||||
| 			depthStencilView.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; | ||||
| 		depthStencilView.subresourceRange.baseMipLevel = 0; | ||||
| 		depthStencilView.subresourceRange.levelCount = 1; | ||||
| 		depthStencilView.subresourceRange.baseArrayLayer = 0; | ||||
| 		depthStencilView.subresourceRange.layerCount = 1; | ||||
| 		depthStencilView.image = depthAttachment.image; | ||||
| 		VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthAttachment.view));	 | ||||
| 	} | ||||
| 
 | ||||
| 	int i = 0; | ||||
| 	if (settings.multiSampling) | ||||
| 	{ | ||||
| 		i = 4; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		i = 2; | ||||
| 	} | ||||
| 
 | ||||
| 	// Depth/Stencil attachment is the same for all frame buffers
 | ||||
| 
 | ||||
| 	VkImageCreateInfo image = {}; | ||||
| 	image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | ||||
| 	image.pNext = NULL; | ||||
| 	image.imageType = VK_IMAGE_TYPE_2D; | ||||
| 	image.format = depthFormat; | ||||
| 	image.extent = { width, height, 1 }; | ||||
| 	image.mipLevels = 1; | ||||
| 	image.arrayLayers = 1; | ||||
| 	image.samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 	image.tiling = VK_IMAGE_TILING_OPTIMAL; | ||||
| 	image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; | ||||
| 	image.flags = 0; | ||||
| 
 | ||||
| 	VkMemoryAllocateInfo mem_alloc = {}; | ||||
| 	mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | ||||
| 	mem_alloc.pNext = NULL; | ||||
| 	mem_alloc.allocationSize = 0; | ||||
| 	mem_alloc.memoryTypeIndex = 0; | ||||
| 
 | ||||
| 	VkImageViewCreateInfo depthStencilView = {}; | ||||
| 	depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | ||||
| 	depthStencilView.pNext = NULL; | ||||
| 	depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D; | ||||
| 	depthStencilView.format = depthFormat; | ||||
| 	depthStencilView.flags = 0; | ||||
| 	depthStencilView.subresourceRange = {}; | ||||
| 	depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; | ||||
| 	depthStencilView.subresourceRange.baseMipLevel = 0; | ||||
| 	depthStencilView.subresourceRange.levelCount = 1; | ||||
| 	depthStencilView.subresourceRange.baseArrayLayer = 0; | ||||
| 	depthStencilView.subresourceRange.layerCount = 1; | ||||
| 
 | ||||
| 	VkMemoryRequirements memReqs; | ||||
| 	VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image)); | ||||
| 	vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs); | ||||
| 	mem_alloc.allocationSize = memReqs.size; | ||||
| 	mem_alloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||
| 	VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, nullptr, &depthStencil.mem)); | ||||
| 	VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0)); | ||||
| 
 | ||||
| 	depthStencilView.image = depthStencil.image; | ||||
| 	VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view)); | ||||
| 
 | ||||
| 	//
 | ||||
| 
 | ||||
| 	VkImageView attachments[4]; | ||||
| 	VkImageView attachments[i]; | ||||
| 
 | ||||
| 	if (settings.multiSampling) { | ||||
| 		 | ||||
| 		attachments[0] = multisampleTarget.color.view; | ||||
| 		attachments[2] = multisampleTarget.depth.view; | ||||
| 		attachments[3] = depthStencil.view; | ||||
| 		attachments[3] = depthAttachment.view; | ||||
| 	} | ||||
| 	else { | ||||
| 		attachments[1] = depthStencil.view; | ||||
| 		 | ||||
| 		attachments[1] = depthAttachment.view; | ||||
| 		attachments[0] = colorAttachment.view; | ||||
| 	} | ||||
| 
 | ||||
| 	VkFramebufferCreateInfo frameBufferCI{}; | ||||
|  | @ -1962,16 +1874,35 @@ void VulkanExampleBase::setupFrameBuffer() | |||
| 	frameBufferCI.height = height; | ||||
| 	frameBufferCI.layers = 1; | ||||
| 
 | ||||
| 	// Create frame buffers for every swap chain image
 | ||||
| 	frameBuffers.resize(swapChain.imageCount); | ||||
| 	for (uint32_t i = 0; i < frameBuffers.size(); i++) { | ||||
| 		if (settings.multiSampling) { | ||||
| 			attachments[1] = swapChain.buffers[i].view; | ||||
| 	if (settings.headless && ! settings.multiSampling) | ||||
| 	{ | ||||
| 		VkImageView attachments[2]; | ||||
| 		attachments[0] = colorAttachment.view; | ||||
| 		attachments[1] = depthAttachment.view; | ||||
| 
 | ||||
| 		VkFramebufferCreateInfo framebufferCreateInfo = vks::initializers::framebufferCreateInfo(); | ||||
| 		framebufferCreateInfo.renderPass = renderPass; | ||||
| 		framebufferCreateInfo.attachmentCount = 2; | ||||
| 		framebufferCreateInfo.pAttachments = attachments; | ||||
| 		framebufferCreateInfo.width = width; | ||||
| 		framebufferCreateInfo.height = height; | ||||
| 		framebufferCreateInfo.layers = 1; | ||||
| 		VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffer)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// Create frame buffers for every swap chain image
 | ||||
| 		frameBuffers.resize(swapChain.imageCount); | ||||
| 		for (uint32_t i = 0; i < frameBuffers.size(); i++) { | ||||
| 			if (settings.multiSampling) { | ||||
| 				attachments[1] = swapChain.buffers[i].view; | ||||
| 			} | ||||
| 			else { | ||||
| 				attachments[0] = swapChain.buffers[i].view; | ||||
| 			} | ||||
| 			VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i])); | ||||
| 		} | ||||
| 		else { | ||||
| 			attachments[0] = swapChain.buffers[i].view; | ||||
| 		} | ||||
| 		VK_CHECK_RESULT(vkCreateFramebuffer(device, &frameBufferCI, nullptr, &frameBuffers[i])); | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -1994,9 +1925,9 @@ void VulkanExampleBase::windowResize() | |||
| 		vkDestroyImage(device, multisampleTarget.depth.image, nullptr); | ||||
| 		vkFreeMemory(device, multisampleTarget.depth.memory, nullptr); | ||||
| 	} | ||||
| 	vkDestroyImageView(device, depthStencil.view, nullptr); | ||||
| 	vkDestroyImage(device, depthStencil.image, nullptr); | ||||
| 	vkFreeMemory(device, depthStencil.mem, nullptr); | ||||
| 	vkDestroyImageView(device, depthAttachment.view, nullptr); | ||||
| 	vkDestroyImage(device, depthAttachment.image, nullptr); | ||||
| 	vkFreeMemory(device, depthAttachment.memory, nullptr); | ||||
| 	for (uint32_t i = 0; i < frameBuffers.size(); i++) { | ||||
| 		vkDestroyFramebuffer(device, frameBuffers[i], nullptr); | ||||
| 	} | ||||
|  |  | |||
|  | @ -58,16 +58,7 @@ | |||
| 
 | ||||
| class VulkanExampleBase | ||||
| { | ||||
| private:	 | ||||
| 	float fpsTimer = 0.0f; | ||||
| 	uint32_t frameCounter = 0; | ||||
| 	uint32_t destWidth; | ||||
| 	uint32_t destHeight; | ||||
| 	bool resizing = false; | ||||
| 	void handleMouseMove(int32_t x, int32_t y); | ||||
| 	PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback; | ||||
| 	PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback; | ||||
| 	VkDebugReportCallbackEXT debugReportCallback; | ||||
| public: | ||||
| 	struct MultisampleTarget { | ||||
| 		struct { | ||||
| 			VkImage image; | ||||
|  | @ -80,6 +71,17 @@ private: | |||
| 			VkDeviceMemory memory; | ||||
| 		} depth; | ||||
| 	} multisampleTarget; | ||||
| 
 | ||||
| private:	 | ||||
| 	 | ||||
| 	uint32_t destWidth; | ||||
| 	uint32_t destHeight; | ||||
| 	bool resizing = false; | ||||
| 	void handleMouseMove(int32_t x, int32_t y); | ||||
| 	PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback; | ||||
| 	PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback; | ||||
| 	VkDebugReportCallbackEXT debugReportCallback; | ||||
| 	 | ||||
| protected: | ||||
| 	VkInstance instance; | ||||
| 	VkPhysicalDevice physicalDevice; | ||||
|  | @ -90,6 +92,7 @@ protected: | |||
| 	vks::VulkanDevice *vulkanDevice; | ||||
| 	VkQueue queue; | ||||
| 	VkFormat depthFormat; | ||||
| 	VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; | ||||
| 	VkCommandPool cmdPool; | ||||
| 	VkRenderPass renderPass; | ||||
| 	std::vector<VkFramebuffer>frameBuffers; | ||||
|  | @ -106,25 +109,31 @@ public: | |||
| 	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 Settings { | ||||
| 		bool validation = true; | ||||
| 		bool fullscreen = false; | ||||
| 		bool vsync = false; | ||||
| 		bool multiSampling = true; | ||||
| 		bool rotateModel = false; | ||||
| 		bool enableSaveToImageSequeue = false; | ||||
| 		uint32_t outputFrameCount = 50; | ||||
| 		bool takeScreenShot = false; | ||||
| 		bool headless = true; | ||||
| 		VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; | ||||
| 	} settings; | ||||
| 	 | ||||
| 	struct DepthStencil { | ||||
| 
 | ||||
| 	struct FrameBufferAttachment { | ||||
| 		VkImage image; | ||||
| 		VkDeviceMemory mem; | ||||
| 		VkDeviceMemory memory; | ||||
| 		VkImageView view; | ||||
| 	} depthStencil; | ||||
| 	}; | ||||
| 
 | ||||
| 	FrameBufferAttachment colorAttachment, depthAttachment; | ||||
| 	VkFramebuffer framebuffer; | ||||
| 
 | ||||
| 	struct GamePadState { | ||||
| 		glm::vec2 axisLeft = glm::vec2(0.0f); | ||||
|  |  | |||
|  | @ -189,6 +189,9 @@ PlumageRender::PlumageRender() | |||
| 			VK_CHECK_RESULT(vkEndCommandBuffer(currentCB)); | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		 | ||||
| 		 | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
|  | @ -529,6 +532,7 @@ PlumageRender::PlumageRender() | |||
| 		rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT; | ||||
| 		rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; | ||||
| 		rasterizationStateCI.lineWidth = 1.0f; | ||||
| 		 | ||||
| 
 | ||||
| 		VkPipelineColorBlendAttachmentState blendAttachmentState{}; | ||||
| 		blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | ||||
|  | @ -558,6 +562,10 @@ PlumageRender::PlumageRender() | |||
| 		if (settings.multiSampling) { | ||||
| 			multisampleStateCI.rasterizationSamples = settings.sampleCount; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		} | ||||
| 
 | ||||
| 		std::vector<VkDynamicState> dynamicStateEnables = { | ||||
| 			VK_DYNAMIC_STATE_VIEWPORT, | ||||
|  | @ -619,9 +627,7 @@ PlumageRender::PlumageRender() | |||
| 		pipelineCI.stageCount = static_cast<uint32_t>(shaderStages.size()); | ||||
| 		pipelineCI.pStages = shaderStages.data(); | ||||
| 
 | ||||
| 		if (settings.multiSampling) { | ||||
| 			multisampleStateCI.rasterizationSamples = settings.sampleCount; | ||||
| 		} | ||||
| 		 | ||||
| 
 | ||||
| 		// Skybox pipeline (background cube)
 | ||||
| 		shaderStages = { | ||||
|  | @ -1578,29 +1584,23 @@ PlumageRender::PlumageRender() | |||
| 		prepared = true; | ||||
| 	} | ||||
| 
 | ||||
| 	void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue) | ||||
| 	void PlumageRender::submitWork(VkCommandBuffer cmdBuffer, VkQueue queue, VkFence fence) | ||||
| 	{ | ||||
| 		VkSubmitInfo submitInfo = vks::initializers::submitInfo(); | ||||
| 		submitInfo.commandBufferCount = 1; | ||||
| 		submitInfo.pCommandBuffers = &cmdBuffer; | ||||
| 		VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(); | ||||
| 		VkFence fence; | ||||
| 		VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence)); | ||||
| 		VK_CHECK_RESULT(vkResetFences(device, 1, &fence)); | ||||
| 		VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence)); | ||||
| 		VK_CHECK_RESULT(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX)); | ||||
| 		vkDestroyFence(device, fence, nullptr); | ||||
| 		//vkDestroyFence(device, fence, nullptr);
 | ||||
| 	} | ||||
| 
 | ||||
| 	// todo :根据physicalDeviceIndex确定子文件夹路径,frameIndex确定fileName
 | ||||
| 	void PlumageRender::writeImageToFile(std::string filePath) | ||||
| 	{ | ||||
| 
 | ||||
| 		bool surpportBlit = true; | ||||
| 
 | ||||
| 		 | ||||
| 
 | ||||
| 		char* imageData; | ||||
| 		// create dst image to copy
 | ||||
| 		 | ||||
| 		VkImageCreateInfo imageCreateInfo(vks::initializers::imageCreateInfo()); | ||||
| 		imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; | ||||
| 		imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; | ||||
|  | @ -1610,7 +1610,14 @@ PlumageRender::PlumageRender() | |||
| 		imageCreateInfo.arrayLayers = 1; | ||||
| 		imageCreateInfo.mipLevels = 1; | ||||
| 		imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||
| 		imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		if (settings.multiSampling) | ||||
| 		{ | ||||
| 			imageCreateInfo.samples = settings.sampleCount; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; | ||||
| 		} | ||||
| 		imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; | ||||
| 		imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; | ||||
| 
 | ||||
|  | @ -1623,20 +1630,28 @@ PlumageRender::PlumageRender() | |||
| 		VkDeviceMemory dstImageMemory; | ||||
| 		vkGetImageMemoryRequirements(device, dstImage, &memRequirements); | ||||
| 		memAllocInfo.allocationSize = memRequirements.size; | ||||
| 		memAllocInfo.memoryTypeIndex = getMemoryTypeIndex(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||
| 		memAllocInfo.memoryTypeIndex = vulkanDevice -> getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||
| 		 | ||||
| 		// allocate and bind memory
 | ||||
| 		VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory)); | ||||
| 		VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0)); | ||||
| 
 | ||||
| 		// blit image and copy to host visualable memory
 | ||||
| 		VkCommandBufferAllocateInfo cmdBufferAllocInfo; | ||||
| 		VkCommandBufferAllocateInfo cmdBufferAllocInfo = vks::initializers::commandBufferAllocateInfo(cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY,1); | ||||
| 		VkCommandBuffer copyCmd; | ||||
| 		VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufferAllocInfo, ©Cmd)); | ||||
| 		VkCommandBufferBeginInfo cmdBufferBeginInfo = vks::initializers::commandBufferBeginInfo(); | ||||
| 		VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufferBeginInfo)); | ||||
| 
 | ||||
| 		vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 }); | ||||
| 		 | ||||
| 		vks::tools::insertImageMemoryBarrier(copyCmd,  | ||||
| 											dstImage,  | ||||
| 												   0, | ||||
| 						VK_ACCESS_TRANSFER_WRITE_BIT, | ||||
| 						VK_IMAGE_LAYOUT_UNDEFINED, | ||||
| 						VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,  | ||||
| 						VK_PIPELINE_STAGE_TRANSFER_BIT,  | ||||
| 						VK_PIPELINE_STAGE_TRANSFER_BIT, | ||||
| 						VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 }); | ||||
| 
 | ||||
| 		VkImageCopy imageCopyRegion{}; | ||||
| 		imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | ||||
|  | @ -1647,14 +1662,50 @@ PlumageRender::PlumageRender() | |||
| 		imageCopyRegion.extent.height = height; | ||||
| 		imageCopyRegion.extent.depth = 1; | ||||
| 
 | ||||
| 		vkCmdCopyImage(copyCmd, offscreen.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopyRegion); | ||||
| 		VkImage srcImage; | ||||
| 
 | ||||
| 		if (settings.multiSampling) | ||||
| 		{ | ||||
| 			srcImage = multisampleTarget.color.image; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			srcImage = colorAttachment.image; | ||||
| 		} | ||||
| 
 | ||||
| 		vks::tools::insertImageMemoryBarrier(copyCmd, | ||||
| 			srcImage, | ||||
| 			0, | ||||
| 			VK_ACCESS_TRANSFER_WRITE_BIT, | ||||
| 			VK_IMAGE_LAYOUT_UNDEFINED, | ||||
| 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||||
| 			VK_PIPELINE_STAGE_TRANSFER_BIT, | ||||
| 			VK_PIPELINE_STAGE_TRANSFER_BIT, | ||||
| 			VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1 }); | ||||
| 
 | ||||
| 		vkCmdCopyImage(copyCmd, | ||||
| 						srcImage, | ||||
| 						VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,  | ||||
| 						dstImage,  | ||||
| 						VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,  | ||||
| 						1, &imageCopyRegion); | ||||
| 
 | ||||
| 		// transition dst image to general layout for map memory
 | ||||
| 		vks::tools::insertImageMemoryBarrier(copyCmd, dstImage, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}); | ||||
| 		vks::tools::insertImageMemoryBarrier(copyCmd, | ||||
| 											dstImage, | ||||
| 											VK_ACCESS_TRANSFER_WRITE_BIT, | ||||
| 											VK_ACCESS_MEMORY_READ_BIT, | ||||
| 											VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||||
| 											VK_IMAGE_LAYOUT_GENERAL,  | ||||
| 											VK_PIPELINE_STAGE_TRANSFER_BIT, | ||||
| 											VK_PIPELINE_STAGE_TRANSFER_BIT, | ||||
| 											VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}); | ||||
| 
 | ||||
| 		VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); | ||||
| 
 | ||||
| 		submitWork(copyCmd, queue); | ||||
| 		submitWork(copyCmd, queue,waitFences[frameIndex]); | ||||
| 
 | ||||
| 		vkDeviceWaitIdle(device); | ||||
| 
 | ||||
| 		// Get layout of the image
 | ||||
| 		VkImageSubresource subResource{}; | ||||
|  | @ -1705,7 +1756,7 @@ PlumageRender::PlumageRender() | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	void PlumageRender::outputImageSequence() | ||||
| 	void PlumageRender::outputImageSequence(uint32_t currentFrame) | ||||
| 	{ | ||||
| 
 | ||||
| 		std::string deviceFilePath = filePath.outputPath + "/device" + std::to_string(selectedPhysicalDeviceIndex); | ||||
|  | @ -1713,33 +1764,34 @@ PlumageRender::PlumageRender() | |||
| 		{ | ||||
| 			_mkdir(deviceFilePath.c_str()); | ||||
| 		} | ||||
| 
 | ||||
| 		for (uint32_t i = 0; i < settings.outputFrameCount; i++) | ||||
| 		{ | ||||
| 			std::string fileName = "/" + std::to_string(i) + "result.pmm"; | ||||
| 			std::string outputPath = deviceFilePath + fileName; | ||||
| 		std::string fileName = "/" + std::to_string(currentFrame) + "result.pmm"; | ||||
| 		std::string outputPath = deviceFilePath + fileName; | ||||
| 			//std::cout << outputPath << std::endl;
 | ||||
| 			writeImageToFile(outputPath); | ||||
| 		} | ||||
| 		writeImageToFile(outputPath); | ||||
| 		 | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t PlumageRender::getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties) | ||||
| 	void PlumageRender::renderFrame() | ||||
| 	{ | ||||
| 		VkPhysicalDeviceMemoryProperties deviceMemoryProperties; | ||||
| 		vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); | ||||
| 		for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) | ||||
| 		{ | ||||
| 			if ((typeBits & 1) == 1) | ||||
| 			{ | ||||
| 				if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) | ||||
| 				{ | ||||
| 					return i; | ||||
| 				} | ||||
| 			} | ||||
| 			typeBits >>= 1; | ||||
| 		auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 
 | ||||
| 		render(); | ||||
| 		frameCounter++; | ||||
| 		//VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX));
 | ||||
| 		outputImageSequence(frameCounter); | ||||
| 		//VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex]));
 | ||||
| 		auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 		auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 		frameTimer = (float)tDiff / 1000.0f; | ||||
| 		camera.update(frameTimer); | ||||
| 		fpsTimer += (float)tDiff; | ||||
| 		if (fpsTimer > 1000.0f) { | ||||
| 			lastFPS = static_cast<uint32_t>((float)frameCounter * (1000.0f / fpsTimer)); | ||||
| 			fpsTimer = 0.0f; | ||||
| 			frameCounter = 0; | ||||
| 		} | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	void PlumageRender::render() | ||||
| 	{ | ||||
|  | @ -1750,12 +1802,9 @@ PlumageRender::PlumageRender() | |||
| 		updateUIOverlay(); | ||||
| 		//加入写到文件的函数
 | ||||
| 		//swapChainImage = swapChain.images[frameIndex];
 | ||||
| 		//outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath);
 | ||||
| 
 | ||||
| 		 | ||||
| 
 | ||||
| 		VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, UINT64_MAX)); | ||||
| 		VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex])); | ||||
| 		//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)) { | ||||
|  | @ -1764,7 +1813,6 @@ PlumageRender::PlumageRender() | |||
| 		else { | ||||
| 			VK_CHECK_RESULT(acquire); | ||||
| 			 | ||||
| 			 | ||||
| 		} | ||||
| 
 | ||||
| 		// Update UBOs
 | ||||
|  | @ -1784,8 +1832,10 @@ PlumageRender::PlumageRender() | |||
| 		submitInfo.signalSemaphoreCount = 1; | ||||
| 		submitInfo.pCommandBuffers = &commandBuffers[currentBuffer]; | ||||
| 		submitInfo.commandBufferCount = 1; | ||||
| 		VK_CHECK_RESULT(vkResetFences(device, 1, &waitFences[frameIndex])); | ||||
| 		VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, waitFences[frameIndex])); | ||||
| 
 | ||||
| 		VK_CHECK_RESULT(vkWaitForFences(device, 1, &waitFences[frameIndex], VK_TRUE, MAXINT64)); | ||||
| 		 | ||||
| 		//显示队列
 | ||||
| 		VkResult present = swapChain.queuePresent(queue, currentBuffer, renderCompleteSemaphores[frameIndex]); | ||||
| 		if (!((present == VK_SUCCESS) || (present == VK_SUBOPTIMAL_KHR))) { | ||||
|  | @ -1826,6 +1876,174 @@ PlumageRender::PlumageRender() | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	void PlumageRender::renderLoop() | ||||
| 	{ | ||||
| 		destWidth = width; | ||||
| 		destHeight = height; | ||||
| 
 | ||||
| 	#if defined(_WIN32) | ||||
| 		MSG msg; | ||||
| 		bool quitMessageReceived = false; | ||||
| 		while (!quitMessageReceived) { | ||||
| 			while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { | ||||
| 				TranslateMessage(&msg); | ||||
| 				DispatchMessage(&msg); | ||||
| 				if (msg.message == WM_QUIT) { | ||||
| 					quitMessageReceived = true; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!IsIconic(window)) { | ||||
| 				renderFrame(); | ||||
| 			} | ||||
| 		} | ||||
| 	#elif defined(VK_USE_PLATFORM_ANDROID_KHR) | ||||
| 		while (1) | ||||
| 		{ | ||||
| 			int ident; | ||||
| 			int events; | ||||
| 			struct android_poll_source* source; | ||||
| 			bool destroy = false; | ||||
| 
 | ||||
| 			focused = true; | ||||
| 
 | ||||
| 			while ((ident = ALooper_pollAll(focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0) | ||||
| 			{ | ||||
| 				if (source != NULL) | ||||
| 				{ | ||||
| 					source->process(androidApp, source); | ||||
| 				} | ||||
| 				if (androidApp->destroyRequested != 0) | ||||
| 				{ | ||||
| 					LOGD("Android app destroy requested"); | ||||
| 					destroy = true; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// App destruction requested
 | ||||
| 			// Exit loop, example will be destroyed in application main
 | ||||
| 			if (destroy) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			// Render frame
 | ||||
| 			if (prepared) | ||||
| 			{ | ||||
| 				auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 				render(); | ||||
| 				frameCounter++; | ||||
| 				auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 				auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 				frameTimer = tDiff / 1000.0f; | ||||
| 				camera.update(frameTimer); | ||||
| 				fpsTimer += (float)tDiff; | ||||
| 				if (fpsTimer > 1000.0f) | ||||
| 				{ | ||||
| 					lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 					fpsTimer = 0.0f; | ||||
| 					frameCounter = 0; | ||||
| 				} | ||||
| 
 | ||||
| 				// Check gamepad state
 | ||||
| 				const float deadZone = 0.0015f; | ||||
| 				// todo : check if gamepad is present
 | ||||
| 				// todo : time based and relative axis positions
 | ||||
| 				if (camera.type != Camera::CameraType::firstperson) | ||||
| 				{ | ||||
| 					// Rotate
 | ||||
| 					if (std::abs(gamePadState.axisLeft.x) > deadZone) { | ||||
| 						camera.rotate(glm::vec3(0.0f, gamePadState.axisLeft.x * 0.5f, 0.0f)); | ||||
| 					} | ||||
| 					if (std::abs(gamePadState.axisLeft.y) > deadZone) { | ||||
| 						camera.rotate(glm::vec3(gamePadState.axisLeft.y * 0.5f, 0.0f, 0.0f)); | ||||
| 					} | ||||
| 				} | ||||
| 				else { | ||||
| 					camera.updatePad(gamePadState.axisLeft, gamePadState.axisRight, frameTimer); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| #elif defined(_DIRECT2DISPLAY) | ||||
| 		while (!quit) | ||||
| 		{ | ||||
| 			auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 			render(); | ||||
| 			frameCounter++; | ||||
| 			auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 			auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 			frameTimer = tDiff / 1000.0f; | ||||
| 			camera.update(frameTimer); | ||||
| 			fpsTimer += (float)tDiff; | ||||
| 			if (fpsTimer > 1000.0f) | ||||
| 			{ | ||||
| 				lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 				fpsTimer = 0.0f; | ||||
| 				frameCounter = 0; | ||||
| 			} | ||||
| 		} | ||||
| #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) | ||||
| 		while (!quit) | ||||
| 		{ | ||||
| 			auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 
 | ||||
| 			while (wl_display_prepare_read(display) != 0) | ||||
| 				wl_display_dispatch_pending(display); | ||||
| 			wl_display_flush(display); | ||||
| 			wl_display_read_events(display); | ||||
| 			wl_display_dispatch_pending(display); | ||||
| 
 | ||||
| 			render(); | ||||
| 			frameCounter++; | ||||
| 			auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 			auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 			frameTimer = tDiff / 1000.0f; | ||||
| 			camera.update(frameTimer); | ||||
| 			fpsTimer += (float)tDiff; | ||||
| 			if (fpsTimer > 1000.0f) | ||||
| 			{ | ||||
| 				wl_shell_surface_set_title(shell_surface, title.c_str()); | ||||
| 				lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 				fpsTimer = 0.0f; | ||||
| 				frameCounter = 0; | ||||
| 			} | ||||
| 		} | ||||
| #elif defined(VK_USE_PLATFORM_XCB_KHR) | ||||
| 		xcb_flush(connection); | ||||
| 		while (!quit) | ||||
| 		{ | ||||
| 			auto tStart = std::chrono::high_resolution_clock::now(); | ||||
| 			xcb_generic_event_t* event; | ||||
| 			while ((event = xcb_poll_for_event(connection))) | ||||
| 			{ | ||||
| 				handleEvent(event); | ||||
| 				free(event); | ||||
| 			} | ||||
| 			render(); | ||||
| 			frameCounter++; | ||||
| 			auto tEnd = std::chrono::high_resolution_clock::now(); | ||||
| 			auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count(); | ||||
| 			frameTimer = tDiff / 1000.0f; | ||||
| 			camera.update(frameTimer); | ||||
| 			fpsTimer += (float)tDiff; | ||||
| 			if (fpsTimer > 1000.0f) | ||||
| 			{ | ||||
| 				xcb_change_property(connection, XCB_PROP_MODE_REPLACE, | ||||
| 					window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, | ||||
| 					title.size(), title.c_str()); | ||||
| 				lastFPS = (float)frameCounter * (1000.0f / fpsTimer); | ||||
| 				fpsTimer = 0.0f; | ||||
| 				frameCounter = 0; | ||||
| 			} | ||||
| 		} | ||||
| #elif defined(VK_USE_PLATFORM_MACOS_MVK) | ||||
| 		[NSApp run]; | ||||
| 	#endif | ||||
| 		// Flush device to make sure all resources can be freed 
 | ||||
| 		vkDeviceWaitIdle(device); | ||||
| 	} | ||||
| 
 | ||||
| 	void PlumageRender::fileDropped(std::string filename) | ||||
| 		{ | ||||
| 			vkDeviceWaitIdle(device); | ||||
|  |  | |||
|  | @ -216,19 +216,6 @@ public: | |||
| 		VkDescriptorSet tonemappingDescriptorSet = VK_NULL_HANDLE; | ||||
| 	}; | ||||
| 	 | ||||
| 	struct Settings { | ||||
| 		bool validation = true; | ||||
| 		bool fullscreen = false; | ||||
| 		bool vsync = false; | ||||
| 		bool multiSampling = true; | ||||
| 		bool rotateModel = true; | ||||
| 		bool enableSaveToImageSequeue = false; | ||||
| 		uint32_t outputFrameCount = 50; | ||||
| 		bool takeScreenShot = false; | ||||
| 		 | ||||
| 		VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; | ||||
| 	} settings; | ||||
| 
 | ||||
| 	struct DescriptorSetLayouts { | ||||
| 		VkDescriptorSetLayout scene; | ||||
| 		VkDescriptorSetLayout material; | ||||
|  | @ -260,6 +247,7 @@ public: | |||
| 		glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f); | ||||
| 	} lightSource; | ||||
| 
 | ||||
| 	 | ||||
| 
 | ||||
| 	//cube map generation
 | ||||
| 	 | ||||
|  | @ -286,7 +274,14 @@ public: | |||
| 	} prefilterPushBlock; | ||||
| 
 | ||||
| 	UI* gui; | ||||
| 	 | ||||
| 
 | ||||
| 	float frameTimer = 1.0f; | ||||
| 	uint32_t lastFPS = 0; | ||||
| 	float fpsTimer = 0.0f; | ||||
| 	uint32_t frameCounter = 0; | ||||
| 
 | ||||
| 	uint32_t destWidth; | ||||
| 	uint32_t destHeight; | ||||
| 
 | ||||
| 	PlumageRender(); | ||||
| 	~PlumageRender() | ||||
|  | @ -345,12 +340,14 @@ public: | |||
| 	void updateShaderData(); | ||||
| 	void windowResized(); | ||||
| 	void         prepare(); | ||||
| 	void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue); | ||||
| 	void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue, VkFence fence); | ||||
| 	void writeImageToFile(std::string filePath); | ||||
| 	void outputImageSequence(); | ||||
| 	void outputImageSequence(uint32_t currentFrame); | ||||
| 	void renderFrame(); | ||||
| 	void outputScreenShot(); | ||||
| 	uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties); | ||||
| 	virtual void render(); | ||||
| 	void renderLoop(); | ||||
| 	virtual void updateUIOverlay(); | ||||
| 	virtual void fileDropped(std::string filename); | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue