Browse Source

vulkan: implement discard

niki 2 years ago
parent
commit
76199688f6

+ 101 - 35
src/modules/graphics/vulkan/Graphics.cpp

@@ -170,6 +170,51 @@ void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt sten
 	vkCmdClearAttachments(commandBuffers[currentFrame], static_cast<uint32_t>(attachments.size()), attachments.data(), 1, &rect);
 }
 
+void Graphics::discard(const std::vector<bool>& colorbuffers, bool depthstencil)
+{
+	if (renderPassState.active)
+		endRenderPass();
+
+	if (renderPassState.useConfigurations)
+	{
+		auto & renderPassConfiguration = renderPassState.renderPassConfiguration;
+
+		for (size_t i = 0; i < colorbuffers.size(); i++)
+			renderPassConfiguration.colorAttachments[i].discard = colorbuffers[i];
+		renderPassConfiguration.staticData.depthAttachment.discard = depthstencil;
+	}
+	else
+	{
+		RenderPassConfiguration renderPassConfiguration{};
+		renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, colorbuffers[0] });
+		renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), depthstencil };
+		renderPassConfiguration.staticData.msaaSamples = msaaSamples;
+		if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
+			renderPassConfiguration.staticData.resolve = false;
+		else
+			renderPassConfiguration.staticData.resolve = true;
+
+		FramebufferConfiguration framebufferConfiguration{};
+		framebufferConfiguration.staticData.depthView = depthImageView;
+		if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
+		{
+			framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex));
+			framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE;
+		}
+		else
+		{
+			framebufferConfiguration.colorViews.push_back(colorImageView);
+			framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex);
+		}
+
+		renderPassState.useConfigurations = true;
+		renderPassState.renderPassConfiguration = renderPassConfiguration;
+		renderPassState.framebufferConfiguration = framebufferConfiguration;
+	}
+
+	startRenderPass();
+}
+
 void Graphics::submitGpuCommands(bool present)
 {
 	flushBatchedDraws();
@@ -357,6 +402,12 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
 	drawCalls = 0;
 	drawCallsBatched = 0;
 
+	Vulkan::cmdTransitionImageLayout(
+		commandBuffers.at(currentFrame), 
+		depthImage, 
+		VK_IMAGE_LAYOUT_UNDEFINED, 
+		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+
 	return true;
 }
 
@@ -892,7 +943,7 @@ uint32_t Graphics::getNumImagesInFlight() const
 
 uint32_t Graphics::getFrameIndex() const
 {
-	return currentFrame;
+	return static_cast<uint32_t>(currentFrame);
 }
 
 const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const
@@ -1640,9 +1691,9 @@ void Graphics::createImageViews()
 void Graphics::createDefaultRenderPass()
 {
 	RenderPassConfiguration renderPassConfiguration{};
-	renderPassConfiguration.colorFormats.push_back(swapChainImageFormat);
+	renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, false });
 	renderPassConfiguration.staticData.msaaSamples = msaaSamples;
-	renderPassConfiguration.staticData.depthFormat = findDepthFormat();
+	renderPassConfiguration.staticData.depthAttachment = { findDepthFormat(), false };
 	if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
 		renderPassConfiguration.staticData.resolve = false;
 	else
@@ -1738,7 +1789,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
 	std::vector<VkAttachmentReference> colorAttachmentRefs;
 
 	uint32_t attachment = 0;
-	for (const auto &colorFormat : configuration.colorFormats)
+	for (const auto &colorAttachment : configuration.colorAttachments)
 	{
 		VkAttachmentReference reference{};
 		reference.attachment = attachment++;
@@ -1746,9 +1797,12 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
 		colorAttachmentRefs.push_back(reference);
 
 		VkAttachmentDescription colorDescription{};
-		colorDescription.format = colorFormat;
+		colorDescription.format = colorAttachment.format;
 		colorDescription.samples = configuration.staticData.msaaSamples;
-		colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+		if (colorAttachment.discard)
+			colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		else
+			colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
 		colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 		colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 		colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@@ -1761,20 +1815,23 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
     subPass.pColorAttachments = colorAttachmentRefs.data();
 
 	VkAttachmentReference depthStencilAttachmentRef{};
-	if (configuration.staticData.depthFormat != VK_FORMAT_UNDEFINED)
+	if (configuration.staticData.depthAttachment.format != VK_FORMAT_UNDEFINED)
 	{
 		depthStencilAttachmentRef.attachment = attachment++;
 		depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 		subPass.pDepthStencilAttachment = &depthStencilAttachmentRef;
 
 		VkAttachmentDescription depthStencilAttachment{};
-		depthStencilAttachment.format = configuration.staticData.depthFormat;
+		depthStencilAttachment.format = configuration.staticData.depthAttachment.format;
 		depthStencilAttachment.samples = configuration.staticData.msaaSamples;
-		depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-		depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+		if (configuration.staticData.depthAttachment.discard)
+			depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+		else
+			depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+		depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 		depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 		depthStencilAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-		depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+		depthStencilAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 		depthStencilAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 		attachments.push_back(depthStencilAttachment);
 	}
@@ -1787,7 +1844,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
 		subPass.pResolveAttachments = &colorAttachmentResolveRef;
 
 		VkAttachmentDescription colorAttachmentResolve{};
-		colorAttachmentResolve.format = configuration.colorFormats.at(0);
+		colorAttachmentResolve.format = configuration.colorAttachments.at(0).format;
 		colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
 		colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 		colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -1861,7 +1918,7 @@ void Graphics::createVulkanVertexFormat(
 
 			auto attrib = vertexAttributes.attribs[i];
 			auto bufferBinding = attrib.bufferIndex;
-			if (usedBuffers.find(bufferBinding) == usedBuffers.end())	// use .contains() when c++20 is enabled
+			if (usedBuffers.find(bufferBinding) == usedBuffers.end())
 			{
 				usedBuffers.insert(bufferBinding);
 
@@ -1918,7 +1975,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
 
 	GraphicsPipelineConfiguration configuration{};
 
-    configuration.renderPass = renderPassState.renderPass;
+    configuration.renderPass = renderPassState.beginInfo.renderPass;
 	configuration.vertexAttributes = attributes;
 	configuration.shader = (Shader*)Shader::current;
 	configuration.wireFrame = states.back().wireframe;
@@ -1976,7 +2033,7 @@ void Graphics::setDefaultRenderPass()
 	renderPassState.beginInfo.renderArea.extent = swapChainExtent;
 	renderPassState.beginInfo.clearValueCount = 0;
 
-	renderPassState.renderPass = defaultRenderPass;
+	renderPassState.useConfigurations = false;
 	renderPassState.pipeline = VK_NULL_HANDLE;
 	renderPassState.width = static_cast<float>(swapChainExtent.width);
 	renderPassState.height = static_cast<float>(swapChainExtent.height);
@@ -2017,7 +2074,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
 		// fixme: use mipmap and slice.
 		color.mipmap;
 		color.slice;
-		renderPassConfiguration.colorFormats.push_back(Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat);
+		renderPassConfiguration.colorAttachments.push_back({ Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat, false });
 	}
 	if (rts.depthStencil.texture != nullptr)
 	{
@@ -2025,17 +2082,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
 		rts.depthStencil.mipmap;
 		rts.depthStencil.slice;
 		if (rts.depthStencil.texture != nullptr)
-			renderPassConfiguration.staticData.depthFormat =  Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat;
-	}
-
-    VkRenderPass renderPass;
-	auto it = renderPasses.find(renderPassConfiguration);
-	if (it != renderPasses.end())
-		renderPass = it->second;
-	else
-	{
-		renderPass = createRenderPass(renderPassConfiguration);
-		renderPasses[renderPassConfiguration] = renderPass;
+			renderPassConfiguration.staticData.depthAttachment = { Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat, false };
 	}
 
 	FramebufferConfiguration configuration{};
@@ -2051,20 +2098,20 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
 		// fixme: layout transition of depth stencil image?
 		configuration.staticData.depthView = (VkImageView)rts.depthStencil.texture->getRenderTargetHandle();
 
-	configuration.staticData.renderPass = renderPass;
 	configuration.staticData.width = static_cast<uint32_t>(pixelw);
 	configuration.staticData.height = static_cast<uint32_t>(pixelh);
-	VkFramebuffer framebuffer = getFramebuffer(configuration);
 
 	renderPassState.beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-	renderPassState.beginInfo.renderPass = renderPass;
-	renderPassState.beginInfo.framebuffer = framebuffer;
+	renderPassState.beginInfo.renderPass = VK_NULL_HANDLE;
+	renderPassState.beginInfo.framebuffer = VK_NULL_HANDLE;
 	renderPassState.beginInfo.renderArea.offset = {0, 0};
 	renderPassState.beginInfo.renderArea.extent.width = static_cast<uint32_t>(pixelw);
 	renderPassState.beginInfo.renderArea.extent.height = static_cast<uint32_t>(pixelh);
 	renderPassState.beginInfo.clearValueCount = 0;
 
-	renderPassState.renderPass = renderPass;
+	renderPassState.useConfigurations = true;
+	renderPassState.renderPassConfiguration = renderPassConfiguration;
+	renderPassState.framebufferConfiguration = configuration;
 	renderPassState.pipeline = VK_NULL_HANDLE;
 	renderPassState.width = static_cast<float>(pixelw);
 	renderPassState.height = static_cast<float>(pixelh);
@@ -2077,6 +2124,25 @@ void Graphics::startRenderPass()
 {
 	renderPassState.active = true;
 
+	if (renderPassState.useConfigurations)
+	{
+		auto &renderPassConfiguration = renderPassState.renderPassConfiguration;
+		VkRenderPass renderPass;
+		auto it = renderPasses.find(renderPassConfiguration);
+		if (it != renderPasses.end())
+			renderPass = it->second;
+		else
+		{
+			renderPass = createRenderPass(renderPassConfiguration);
+			renderPasses[renderPassConfiguration] = renderPass;
+		}
+		renderPassState.beginInfo.renderPass = renderPass;
+
+		auto &framebufferConfiguration = renderPassState.framebufferConfiguration;
+		framebufferConfiguration.staticData.renderPass = renderPass;
+		renderPassState.beginInfo.framebuffer = getFramebuffer(framebufferConfiguration);
+	}
+
 	for (const auto& image : renderPassState.transitionImages)
 		Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
 
@@ -2429,12 +2495,12 @@ VkFormat Graphics::findDepthFormat()
 
 void Graphics::createDepthResources()
 {
-	VkFormat depthFormat = findDepthFormat();
+	VkFormat depthAttachment = findDepthFormat();
 
 	VkImageCreateInfo imageInfo{};
 	imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 	imageInfo.imageType = VK_IMAGE_TYPE_2D;
-	imageInfo.format = depthFormat;
+	imageInfo.format = depthAttachment;
 	imageInfo.extent.width = swapChainExtent.width;
 	imageInfo.extent.height = swapChainExtent.height;
 	imageInfo.extent.depth = 1;
@@ -2456,7 +2522,7 @@ void Graphics::createDepthResources()
 	imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 	imageViewInfo.image = depthImage;
 	imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
-	imageViewInfo.format = depthFormat;
+	imageViewInfo.format = depthAttachment;
 	imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
 	imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
 	imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;

+ 19 - 6
src/modules/graphics/vulkan/Graphics.h

@@ -27,20 +27,31 @@ namespace graphics
 namespace vulkan
 {
 
+struct RenderPassAttachment
+{
+	VkFormat format = VK_FORMAT_UNDEFINED;
+	bool discard = true;
+
+	bool operator==(const RenderPassAttachment &attachment) const
+	{
+		return format == attachment.format && discard == attachment.discard;
+	}
+};
+
 struct RenderPassConfiguration
 {
-	std::vector<VkFormat> colorFormats;
+	std::vector<RenderPassAttachment> colorAttachments;
 
 	struct StaticRenderPassConfiguration
 	{
 		VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
-		VkFormat depthFormat = VK_FORMAT_UNDEFINED;
+		RenderPassAttachment depthAttachment;
 		bool resolve = false;
 	} staticData;
 
     bool operator==(const RenderPassConfiguration &conf) const
 	{
-		return colorFormats == conf.colorFormats && 
+		return colorAttachments == conf.colorAttachments && 
 			(memcmp(&staticData, &conf.staticData, sizeof(StaticRenderPassConfiguration)) == 0);
     }
 };
@@ -50,7 +61,7 @@ struct RenderPassConfigurationHasher
     size_t operator()(const RenderPassConfiguration &configuration) const
 	{
 		size_t hashes[] = { 
-			XXH32(configuration.colorFormats.data(), configuration.colorFormats.size() * sizeof(VkFormat), 0),
+			XXH32(configuration.colorAttachments.data(), configuration.colorAttachments.size() * sizeof(VkFormat), 0),
 			XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
 		};
 		return XXH32(hashes, sizeof(hashes), 0);
@@ -233,7 +244,9 @@ struct RenderpassState
 {
 	bool active = false;
 	VkRenderPassBeginInfo beginInfo{};
-	VkRenderPass renderPass = VK_NULL_HANDLE;
+	bool useConfigurations = false;
+	RenderPassConfiguration renderPassConfiguration{};
+	FramebufferConfiguration framebufferConfiguration{};
 	VkPipeline pipeline = VK_NULL_HANDLE;
 	std::vector<VkImage> transitionImages;
 	uint32_t numColorAttachments = 0;
@@ -268,7 +281,7 @@ public:
 	void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
 	void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
 	Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
-	void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override { }
+	void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override;
 	void present(void *screenshotCallbackdata) override;
 	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
 	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;

+ 6 - 0
src/modules/graphics/vulkan/Vulkan.cpp

@@ -792,6 +792,8 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 	else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && 
 			(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
 	{
+		barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+
 		barrier.srcAccessMask = 0;
 		barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
 
@@ -801,6 +803,8 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 	else if ((oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || oldLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) && 
 			  newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
 	{
+		barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+
 		barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
 		barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 
@@ -810,6 +814,8 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
 	else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
 			(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
 	{
+		barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+
 		barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
 		barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;