Преглед на файлове

Added an explicit flag to preserve render target contents on load, to improve performance when this is not required (most of the time)

BearishSun преди 9 години
родител
ревизия
7f501a8e77

+ 8 - 2
Source/BansheeCore/Include/BsRenderAPI.h

@@ -64,7 +64,8 @@ namespace BansheeEngine
 		static void setScissorRect(CoreAccessor& accessor, UINT32 left = 0, UINT32 top = 0, UINT32 right = 800, UINT32 bottom = 600);
 
 		/** @see RenderAPICore::setRenderTarget() */
-		static void setRenderTarget(CoreAccessor& accessor, const SPtr<RenderTarget>& target, bool readOnlyDepthStencil = false);
+		static void setRenderTarget(CoreAccessor& accessor, const SPtr<RenderTarget>& target, 
+			bool readOnlyDepthStencil = false, bool preserveContents = false);
 
 		/** @see RenderAPICore::beginFrame() */
 		static void beginRender(CoreAccessor& accessor);
@@ -399,12 +400,17 @@ namespace BansheeEngine
 		 * @param[in]	readOnlyDepthStencil	If true the caller guarantees he won't write to the depth/stencil buffer 
 		 *										(if any was provided). This allows the depth buffer to be bound for depth 
 		 *										testing, as well as reading in a shader, at the same time.
+		 * @param[in]	preserveContents		Determines will the current contents of the render target be preserved.
+		 *										Perserving the contents comes at a performance cost, so it's best to set
+		 *										to false if you are sure you will overwrite or clear the contents later.
+		 *										Set to true if you need to perform blending or similar operations with the
+		 *										existing contents of the render target.
 		 * @param[in]	commandBuffer			Optional command buffer to queue the operation on. If not provided operation
 		 *										is executed immediately. Otherwise it is executed when executeCommands() is
 		 *										called. Buffer must support graphics operations.
 		 */
         virtual void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false,
-			const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
+			bool preserveContents = false, const SPtr<CommandBuffer>& commandBuffer = nullptr) = 0;
 
 		/**
 		 * Clears the currently active render target.

+ 3 - 2
Source/BansheeCore/Source/BsRenderAPI.cpp

@@ -84,10 +84,11 @@ namespace BansheeEngine
 			nullptr));
 	}
 
-	void RenderAPI::setRenderTarget(CoreAccessor& accessor, const SPtr<RenderTarget>& target, bool readOnlyDepthStencil)
+	void RenderAPI::setRenderTarget(CoreAccessor& accessor, const SPtr<RenderTarget>& target, bool readOnlyDepthStencil,
+									bool preserveContents)
 	{
 		accessor.queueCommand(std::bind(&RenderAPICore::setRenderTarget, 
-			RenderAPICore::instancePtr(), target->getCore(), readOnlyDepthStencil, nullptr));
+			RenderAPICore::instancePtr(), target->getCore(), readOnlyDepthStencil, preserveContents, nullptr));
 	}
 
 	void RenderAPI::beginRender(CoreAccessor& accessor)

+ 1 - 1
Source/BansheeD3D11RenderAPI/Include/BsD3D11RenderAPI.h

@@ -52,7 +52,7 @@ namespace BansheeEngine
 
 		/** @copydoc RenderAPICore::setRenderTarget */
 		void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false, 
-			const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
+			bool preserveContents = false, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
 
 		/** @copydoc RenderAPICore::setViewport */
 		void setViewport(const Rect2& area, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;

+ 1 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11RenderAPI.cpp

@@ -1024,7 +1024,7 @@ namespace BansheeEngine
 	}
 
 	void D3D11RenderAPI::setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil, 
-		const SPtr<CommandBuffer>& commandBuffer)
+		bool preserveContents, const SPtr<CommandBuffer>& commandBuffer)
 	{
 		auto executeRef = [&](const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil)
 		{

+ 2 - 2
Source/BansheeGLRenderAPI/Include/BsGLRenderAPI.h

@@ -86,8 +86,8 @@ namespace BansheeEngine
 		void swapBuffers(const SPtr<RenderTargetCore>& target, UINT32 syncMask = 0xFFFFFFFF) override;
 
 		/** @copydoc RenderAPICore::setRenderTarget() */
-		void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false,
-			const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
+		void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false, 
+			bool preserveContents = false, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
 
 		/** @copydoc RenderAPICore::clearRenderTarget() */
 		void clearRenderTarget(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0, 

+ 1 - 1
Source/BansheeGLRenderAPI/Source/BsGLRenderAPI.cpp

@@ -740,7 +740,7 @@ namespace BansheeEngine
 	}
 
 	void GLRenderAPI::setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil, 
-		const SPtr<CommandBuffer>& commandBuffer)
+		bool preserveContents, const SPtr<CommandBuffer>& commandBuffer)
 	{
 		auto executeRef = [&](const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil)
 		{

+ 2 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -178,7 +178,7 @@ namespace BansheeEngine
 		 * Assigns a render target the the command buffer. This render target's framebuffer and render pass will be used
 		 * when beginRenderPass() is called. Command buffer must not be currently recording a render pass.
 		 */
-		void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil);
+		void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil, bool preserveContents);
 
 		/** Clears the entirety currently bound render target. */
 		void clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
@@ -286,6 +286,7 @@ namespace BansheeEngine
 		UINT32 mRenderTargetWidth;
 		UINT32 mRenderTargetHeight;
 		bool mRenderTargetDepthReadOnly;
+		bool mRenderTargetPreserveContents;
 
 		UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
 		UnorderedMap<VulkanResource*, ImageInfo> mImages;

+ 21 - 6
Source/BansheeVulkanRenderAPI/Include/BsVulkanFramebuffer.h

@@ -64,11 +64,23 @@ namespace BansheeEngine
 		/** Returns a unique ID of this framebuffer. */
 		UINT32 getId() const { return mId; }
 
-		/** Gets internal Vulkan render pass object. */
-		VkRenderPass getRenderPass() const { return mRenderPass; }
+		/** 
+		 * Gets internal Vulkan render pass object. 
+		 * 
+		 * @param[in]	preserveContents	If true, returns render pass that preserves existing framebuffer attachment 
+		 *									contents on load. Otherwise returns render pass that discards them (more 
+		 *									efficient).
+		 */
+		VkRenderPass getRenderPass(bool preserveContents) const;
 
-		/** Gets internal Vulkan framebuffer object. */
-		VkFramebuffer getFramebuffer() const { return mFramebuffer; }
+		/**
+		 * Gets internal Vulkan framebuffer object.
+		 *
+		 * @param[in]	preserveContents	If true, returns render pass that preserves existing framebuffer attachment
+		 *									contents on load. Otherwise returns render pass that discards them (more
+		 *									efficient).
+		 */
+		VkFramebuffer getFramebuffer(bool preserveContents) const;
 
 		/** 
 		 * Gets the number of layers in each framebuffer surface. A layer is an element in a texture array, or a depth 
@@ -95,8 +107,11 @@ namespace BansheeEngine
 		VkSampleCountFlagBits getSampleFlags() const { return mSampleFlags; }
 	private:
 		UINT32 mId;
-		VkRenderPass mRenderPass;
-		VkFramebuffer mFramebuffer;
+		VkRenderPass mRenderPassDiscard;
+		VkFramebuffer mFramebufferDiscard;
+
+		VkRenderPass mRenderPassPreserve;
+		VkFramebuffer mFramebufferPreserve;
 
 		UINT32 mNumAttachments;
 		UINT32 mNumColorAttachments;

+ 10 - 4
Source/BansheeVulkanRenderAPI/Include/BsVulkanGpuPipelineState.h

@@ -45,6 +45,8 @@ namespace BansheeEngine
 		 * @param[in]	deviceIdx			Index of the device to retrieve the pipeline for.
 		 * @param[in]	framebuffer			Framebuffer object that defines the surfaces this pipeline will render to.
 		 * @param[in]	readOnlyDepth		True if the pipeline is only allowed to read the depth buffer, without writes.
+		 * @param[in]	preserveContents	True if the existing framebuffer contents should be preserved for potential read
+		 *									or blend operations.
 		 * @param[in]	drawOp				Type of geometry that will be drawn using the pipeline.
 		 * @param[in]	vertexInput			State describing inputs to the vertex program.
 		 * @return							Vulkan graphics pipeline object.
@@ -52,7 +54,7 @@ namespace BansheeEngine
 		 * @note	Thread safe.
 		 */
 		VulkanPipeline* getPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, 
-			DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput);
+			bool preserveContents,DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput);
 
 		/** 
 		 * Returns a pipeline layout object for the specified device index. If the device index doesn't match a bit in the
@@ -74,23 +76,27 @@ namespace BansheeEngine
 		 * @param[in]	deviceIdx			Index of the device to create the pipeline for.
 		 * @param[in]	framebuffer			Framebuffer object that defines the surfaces this pipeline will render to.
 		 * @param[in]	readOnlyDepth		True if the pipeline is only allowed to read the depth buffer, without writes.
+		 * @param[in]	preserveContents	True if the existing framebuffer contents should be preserved for potential read
+		 *									or blend operations.
 		 * @param[in]	drawOp				Type of geometry that will be drawn using the pipeline.
 		 * @param[in]	vertexInput			State describing inputs to the vertex program.
 		 * @return							Vulkan graphics pipeline object.
 		 * 
 		 * @note	Thread safe.
 		 */
-		VulkanPipeline* createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth,
-								  DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput);
+		VulkanPipeline* createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, 
+			bool preserveContents, DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput);
 
 		/**	Key uniquely identifying GPU pipelines. */
 		struct GpuPipelineKey
 		{
-			GpuPipelineKey(UINT32 framebufferId, UINT32 vertexInputId, bool readOnlyDepth, DrawOperationType drawOp);
+			GpuPipelineKey(UINT32 framebufferId, UINT32 vertexInputId, bool readOnlyDepth, bool preserveContents,
+				DrawOperationType drawOp);
 
 			UINT32 framebufferId;
 			UINT32 vertexInputId;
 			bool readOnlyDepth;
+			bool preserveContents;
 			DrawOperationType drawOp;
 		};
 

+ 2 - 2
Source/BansheeVulkanRenderAPI/Include/BsVulkanRenderAPI.h

@@ -51,8 +51,8 @@ namespace BansheeEngine
 			UINT8 targetMask = 0xFF, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
 
 		/** @copydoc RenderAPICore::setRenderTarget */
-		void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false, 
-			const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
+		void setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil = false,
+			bool preserveContents = false, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;
 
 		/** @copydoc RenderAPICore::setViewport */
 		void setViewport(const Rect2& area, const SPtr<CommandBuffer>& commandBuffer = nullptr) override;

+ 13 - 8
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -104,10 +104,11 @@ namespace BansheeEngine
 	VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
 		: mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
 		, mFramebuffer(nullptr), mPresentSemaphore(VK_NULL_HANDLE), mRenderTargetWidth(0), mRenderTargetHeight(0)
-		, mRenderTargetDepthReadOnly(false), mGlobalQueueIdx(-1), mViewport(0.0f, 0.0f, 1.0f, 1.0f), mScissor(0, 0, 0, 0)
-		, mStencilRef(0), mDrawOp(DOT_TRIANGLE_LIST), mNumBoundDescriptorSets(0), mGfxPipelineRequiresBind(true)
-		, mCmpPipelineRequiresBind(true), mViewportRequiresBind(true), mStencilRefRequiresBind(true)
-		, mScissorRequiresBind(true), mVertexBuffersTemp(), mVertexBufferOffsetsTemp()
+		, mRenderTargetDepthReadOnly(false), mRenderTargetPreserveContents(false), mGlobalQueueIdx(-1)
+		, mViewport(0.0f, 0.0f, 1.0f, 1.0f), mScissor(0, 0, 0, 0), mStencilRef(0), mDrawOp(DOT_TRIANGLE_LIST)
+		, mNumBoundDescriptorSets(0), mGfxPipelineRequiresBind(true), mCmpPipelineRequiresBind(true)
+		, mViewportRequiresBind(true), mStencilRefRequiresBind(true), mScissorRequiresBind(true), mVertexBuffersTemp()
+		, mVertexBufferOffsetsTemp()
 	{
 		UINT32 maxBoundDescriptorSets = device.getDeviceProperties().limits.maxBoundDescriptorSets;
 		mDescriptorSetsTemp = (VkDescriptorSet*)bs_alloc(sizeof(VkDescriptorSet) * maxBoundDescriptorSets);
@@ -235,8 +236,8 @@ namespace BansheeEngine
 		VkRenderPassBeginInfo renderPassBeginInfo;
 		renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
 		renderPassBeginInfo.pNext = nullptr;
-		renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer();
-		renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass();
+		renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer(mRenderTargetPreserveContents);
+		renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass(mRenderTargetPreserveContents);
 		renderPassBeginInfo.renderArea.offset.x = 0;
 		renderPassBeginInfo.renderArea.offset.y = 0;
 		renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
@@ -532,7 +533,8 @@ namespace BansheeEngine
 			assert(!signaled); // We reset the fence along with mState so this shouldn't be possible
 	}
 
-	void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil)
+	void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil, 
+		bool preserveContents)
 	{
 		assert(mState != State::RecordingRenderPass && mState != State::Submitted);
 
@@ -543,6 +545,7 @@ namespace BansheeEngine
 			mRenderTargetWidth = 0;
 			mRenderTargetHeight = 0;
 			mRenderTargetDepthReadOnly = false;
+			mRenderTargetPreserveContents = false;
 		}
 		else
 		{
@@ -556,6 +559,7 @@ namespace BansheeEngine
 			mRenderTargetWidth = rt->getProperties().getWidth();
 			mRenderTargetHeight = rt->getProperties().getHeight();
 			mRenderTargetDepthReadOnly = readOnlyDepthStencil;
+			mRenderTargetPreserveContents = preserveContents;
 
 			registerResource(mFramebuffer, VulkanUseFlag::Write);
 		}
@@ -822,7 +826,8 @@ namespace BansheeEngine
 		SPtr<VulkanVertexInput> vertexInput = VulkanVertexInputManager::instance().getVertexInfo(mVertexDecl, inputDecl);
 
 		VulkanPipeline* pipeline = mGraphicsPipeline->getPipeline(mDevice.getIndex(), mFramebuffer,
-																  mRenderTargetDepthReadOnly, mDrawOp, vertexInput);
+																  mRenderTargetDepthReadOnly, mRenderTargetPreserveContents,
+																  mDrawOp, vertexInput);
 
 		if (pipeline == nullptr)
 			return false;

+ 52 - 6
Source/BansheeVulkanRenderAPI/Source/BsVulkanFramebuffer.cpp

@@ -134,30 +134,76 @@ namespace BansheeEngine
 
 		VkDevice device = mOwner->getDevice().getLogical();
 
-		VkResult result = vkCreateRenderPass(device, &renderPassCI, gVulkanAllocator, &mRenderPass);
+		// Create discard render pass and frame buffer
+		VkResult result = vkCreateRenderPass(device, &renderPassCI, gVulkanAllocator, &mRenderPassDiscard);
 		assert(result == VK_SUCCESS);
 
-		// Create frame buffer
+		//// Create frame buffer
 		VkFramebufferCreateInfo framebufferCI;
 		framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
 		framebufferCI.pNext = nullptr;
 		framebufferCI.flags = 0;
-		framebufferCI.renderPass = mRenderPass;
+		framebufferCI.renderPass = mRenderPassDiscard;
 		framebufferCI.attachmentCount = mNumAttachments;
 		framebufferCI.pAttachments = attachmentViews;
 		framebufferCI.width = desc.width;
 		framebufferCI.height = desc.height;
 		framebufferCI.layers = desc.layers;
 
-		result = vkCreateFramebuffer(device, &framebufferCI, gVulkanAllocator, &mFramebuffer);
+		result = vkCreateFramebuffer(device, &framebufferCI, gVulkanAllocator, &mFramebufferDiscard);
 		assert(result == VK_SUCCESS);
+
+		// Create preserving render pass and frame buffer
+		for (UINT32 i = 0; i < mNumColorAttachments; i++)
+		{
+			VkAttachmentDescription& attachmentDesc = attachments[i];
+			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+			attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		}
+
+		if (mHasDepth)
+		{
+			VkAttachmentDescription& attachmentDesc = attachments[mNumColorAttachments];
+			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+			attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+		}
+
+		vkCreateRenderPass(device, &renderPassCI, gVulkanAllocator, &mRenderPassPreserve);
+		assert(result == VK_SUCCESS);
+
+		//// Create frame buffer
+		framebufferCI.renderPass = mRenderPassPreserve;
+
+		result = vkCreateFramebuffer(device, &framebufferCI, gVulkanAllocator, &mFramebufferPreserve);
+		assert(result == VK_SUCCESS);
+
 	}
 
 	VulkanFramebuffer::~VulkanFramebuffer()
 	{
 		VkDevice device = mOwner->getDevice().getLogical();
 
-		vkDestroyFramebuffer(device, mFramebuffer, gVulkanAllocator);
-		vkDestroyRenderPass(device, mRenderPass, gVulkanAllocator);
+		vkDestroyFramebuffer(device, mFramebufferDiscard, gVulkanAllocator);
+		vkDestroyRenderPass(device, mRenderPassDiscard, gVulkanAllocator);
+
+		vkDestroyFramebuffer(device, mFramebufferPreserve, gVulkanAllocator);
+		vkDestroyRenderPass(device, mRenderPassPreserve, gVulkanAllocator);
+	}
+
+	VkRenderPass VulkanFramebuffer::getRenderPass(bool preserveContents) const
+	{
+		if (preserveContents)
+			return mRenderPassPreserve;
+		
+		return mRenderPassDiscard;
+	}
+
+	VkFramebuffer VulkanFramebuffer::getFramebuffer(bool preserveContents) const
+	{
+		if (preserveContents)
+			return mFramebufferPreserve;
+
+		return mFramebufferDiscard;
 	}
 }

+ 14 - 9
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuPipelineState.cpp

@@ -25,8 +25,9 @@ namespace BansheeEngine
 	}
 
 	VulkanGraphicsPipelineStateCore::GpuPipelineKey::GpuPipelineKey(
-		UINT32 framebufferId, UINT32 vertexInputId, bool readOnlyDepth, DrawOperationType drawOp)
-		:framebufferId(framebufferId), vertexInputId(vertexInputId), readOnlyDepth(readOnlyDepth), drawOp(drawOp)
+		UINT32 framebufferId, UINT32 vertexInputId, bool readOnlyDepth, bool preserveContents, DrawOperationType drawOp)
+		: framebufferId(framebufferId), vertexInputId(vertexInputId), readOnlyDepth(readOnlyDepth)
+		, preserveContents(preserveContents), drawOp(drawOp)
 	{
 		
 	}
@@ -37,6 +38,7 @@ namespace BansheeEngine
 		hash_combine(hash, key.framebufferId);
 		hash_combine(hash, key.vertexInputId);
 		hash_combine(hash, key.readOnlyDepth);
+		hash_combine(hash, key.preserveContents);
 		hash_combine(hash, key.drawOp);
 
 		return hash;
@@ -53,6 +55,9 @@ namespace BansheeEngine
 		if (a.readOnlyDepth != b.readOnlyDepth)
 			return false;
 
+		if (a.preserveContents != b.preserveContents)
+			return false;
+
 		if (a.drawOp != b.drawOp)
 			return false;
 
@@ -295,22 +300,23 @@ namespace BansheeEngine
 	}
 
 	VulkanPipeline* VulkanGraphicsPipelineStateCore::getPipeline(
-		UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, DrawOperationType drawOp, 
-		const SPtr<VulkanVertexInput>& vertexInput)
+		UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, bool preserveContents,
+		DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput)
 	{
 		Lock(mMutex);
 
 		if (mPerDeviceData[deviceIdx].device == nullptr)
 			return nullptr;
 
-		GpuPipelineKey key(framebuffer->getId(), vertexInput->getId(), readOnlyDepth, drawOp);
+		GpuPipelineKey key(framebuffer->getId(), vertexInput->getId(), readOnlyDepth, preserveContents, drawOp);
 
 		PerDeviceData& perDeviceData = mPerDeviceData[deviceIdx];
 		auto iterFind = perDeviceData.pipelines.find(key);
 		if (iterFind != perDeviceData.pipelines.end())
 			return iterFind->second;
 
-		VulkanPipeline* newPipeline = createPipeline(deviceIdx, framebuffer, readOnlyDepth, drawOp, vertexInput);
+		VulkanPipeline* newPipeline = createPipeline(deviceIdx, framebuffer, readOnlyDepth, preserveContents,
+			drawOp, vertexInput);
 		perDeviceData.pipelines[key] = newPipeline;
 
 		return newPipeline;
@@ -322,8 +328,7 @@ namespace BansheeEngine
 	}
 
 	VulkanPipeline* VulkanGraphicsPipelineStateCore::createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer,
-														  bool readOnlyDepth, DrawOperationType drawOp, 
-														  const SPtr<VulkanVertexInput>& vertexInput)
+		bool readOnlyDepth, bool preserveContents, DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput)
 	{
 		mInputAssemblyInfo.topology = VulkanUtility::getDrawOp(drawOp);
 		mTesselationInfo.patchControlPoints = 3; // Not provided by our shaders for now
@@ -356,7 +361,7 @@ namespace BansheeEngine
 			mDepthStencilInfo.back.depthFailOp = VK_STENCIL_OP_KEEP;
 		}
 
-		mPipelineInfo.renderPass = framebuffer->getRenderPass();
+		mPipelineInfo.renderPass = framebuffer->getRenderPass(preserveContents);
 		mPipelineInfo.layout = mPerDeviceData[deviceIdx].pipelineLayout;
 		mPipelineInfo.pVertexInputState = vertexInput->getCreateInfo();
 

+ 2 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderAPI.cpp

@@ -474,12 +474,12 @@ namespace BansheeEngine
 	}
 
 	void VulkanRenderAPI::setRenderTarget(const SPtr<RenderTargetCore>& target, bool readOnlyDepthStencil,
-		const SPtr<CommandBuffer>& commandBuffer)
+		bool preserveContents, const SPtr<CommandBuffer>& commandBuffer)
 	{
 		VulkanCommandBuffer* cb = getCB(commandBuffer);
 		VulkanCmdBuffer* vkCB = cb->getInternal();
 
-		vkCB->setRenderTarget(target, readOnlyDepthStencil);
+		vkCB->setRenderTarget(target, readOnlyDepthStencil, preserveContents);
 		
 		BS_INC_RENDER_STAT(NumRenderTargetChanges);
 	}