Ver código fonte

Vulkan render target clears implemented

BearishSun 9 anos atrás
pai
commit
3d6a7c2bb0

+ 10 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -180,6 +180,12 @@ namespace BansheeEngine
 		 */
 		void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil);
 
+		/** Clears the entirety currently bound render target. */
+		void clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
+
+		/** Clears the viewport portion of the currently bound render target. */
+		void clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
+
 		/** Assigns a pipeline state to use for subsequent draw commands. */
 		void setPipelineState(const SPtr<GraphicsPipelineStateCore>& state);
 
@@ -261,6 +267,10 @@ namespace BansheeEngine
 		 */
 		void bindDynamicStates(bool forceAll);
 
+		/** Clears the specified area of the currently bound render target. */
+		void clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil, 
+			UINT8 targetMask);
+
 		UINT32 mId;
 		UINT32 mQueueFamily;
 		State mState;

+ 19 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanFramebuffer.h

@@ -19,6 +19,9 @@ namespace BansheeEngine
 
 		/** Format of the attached image. */
 		VkFormat format;
+
+		/** Initial layer of the surface as pointed to by the provided image view. */
+		UINT32 baseLayer;
 	};
 
 	/** Contains parameters used for initializing VulkanFrameBuffer object. */
@@ -36,7 +39,7 @@ namespace BansheeEngine
 		/** Height of the images, in pixels. All images must be the same size. */
 		UINT32 height;
 
-		/** Number of image layers to render to. */
+		/** Number of image layers to render to. This value is used for all provided surfaces. */
 		UINT32 layers;
 
 		/** Number of samples in the attached images. All attachments must have the same number of samples. */
@@ -67,6 +70,18 @@ namespace BansheeEngine
 		/** Gets internal Vulkan framebuffer object. */
 		VkFramebuffer getFramebuffer() const { return mFramebuffer; }
 
+		/** 
+		 * Gets the number of layers in each framebuffer surface. A layer is an element in a texture array, or a depth 
+		 * slice in a 3D texture).
+		 */
+		UINT32 getNumLayers() const { return mNumLayers; }
+
+		/** Returns the initial layer of the color texture surface in which to start rendering. */
+		UINT32 getColorBaseLayer(UINT32 colorIdx) const { return mColorBaseLayers[colorIdx]; }
+
+		/** Returns the initial layer of the depth-stencil texture surface in which to start rendering. */
+		UINT32 getDepthStencilBaseLayer() const { return mDepthBaseLayer; }
+
 		/** Gets the total number of frame-buffer attachments, including both color and depth. */
 		UINT32 getNumAttachments() const { return mNumAttachments; }
 
@@ -85,6 +100,9 @@ namespace BansheeEngine
 
 		UINT32 mNumAttachments;
 		UINT32 mNumColorAttachments;
+		UINT32 mNumLayers;
+		UINT32 mColorBaseLayers[BS_MAX_MULTIPLE_RENDER_TARGETS];
+		UINT32 mDepthBaseLayer;
 		bool mHasDepth;
 		VkSampleCountFlagBits mSampleFlags;
 

+ 112 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -563,6 +563,118 @@ namespace BansheeEngine
 		mGfxPipelineRequiresBind = true;
 	}
 
+	void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
+					   UINT8 targetMask)
+	{
+		if (buffers == 0 || mFramebuffer == nullptr)
+			return;
+
+		VkClearAttachment attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
+		UINT32 baseLayer = 0;
+
+		UINT32 attachmentIdx = 0;
+		if ((buffers & FBT_COLOR) != 0)
+		{
+			UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
+			for (UINT32 i = 0; i < numColorAttachments; i++)
+			{
+				if (((1 << i) & targetMask) == 0)
+					continue;
+
+				attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+				attachments[attachmentIdx].colorAttachment = i;
+
+				VkClearColorValue& colorValue = attachments[attachmentIdx].clearValue.color;
+				colorValue.float32[0] = color.r;
+				colorValue.float32[1] = color.g;
+				colorValue.float32[2] = color.b;
+				colorValue.float32[3] = color.a;
+
+				UINT32 curBaseLayer = mFramebuffer->getColorBaseLayer(i);
+				if (attachmentIdx == 0)
+					baseLayer = curBaseLayer;
+				else
+				{
+					
+					if(baseLayer != curBaseLayer)
+					{
+						// Note: This could be supported relatively easily: we would need to issue multiple separate
+						// clear commands for such framebuffers. 
+						LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
+								"starting layers. This is currently not supported.");
+					}
+				}
+
+				attachmentIdx++;
+			}
+		}
+
+		if ((buffers & FBT_DEPTH) != 0 || (buffers & FBT_STENCIL) != 0)
+		{
+			if (mFramebuffer->hasDepthAttachment())
+			{
+				if ((buffers & FBT_DEPTH) != 0)
+				{
+					attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
+					attachments[attachmentIdx].clearValue.depthStencil.depth = depth;
+				}
+
+				if ((buffers & FBT_STENCIL) != 0)
+				{
+					attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
+					attachments[attachmentIdx].clearValue.depthStencil.stencil = stencil;
+				}
+
+				attachments[attachmentIdx].colorAttachment = 0;
+
+				UINT32 curBaseLayer = mFramebuffer->getDepthStencilBaseLayer();
+				if (attachmentIdx == 0)
+					baseLayer = curBaseLayer;
+				else
+				{
+
+					if (baseLayer != curBaseLayer)
+					{
+						// Note: This could be supported relatively easily: we would need to issue multiple separate
+						// clear commands for such framebuffers. 
+						LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
+							   "starting layers. This is currently not supported.");
+					}
+				}
+
+				attachmentIdx++;
+			}
+		}
+
+		VkClearRect clearRect;
+		clearRect.baseArrayLayer = baseLayer;
+		clearRect.layerCount = mFramebuffer->getNumLayers();
+		clearRect.rect.offset.x = area.x;
+		clearRect.rect.offset.y = area.y;
+		clearRect.rect.extent.width = area.width;
+		clearRect.rect.extent.height = area.height;
+
+		UINT32 numAttachments = attachmentIdx;
+		vkCmdClearAttachments(mCmdBuffer, numAttachments, attachments, 1, &clearRect);
+	}
+
+	void VulkanCmdBuffer::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
+	{
+		Rect2I area(0, 0, mRenderTargetWidth, mRenderTargetHeight);
+		clearViewport(area, buffers, color, depth, stencil, targetMask);
+	}
+
+	void VulkanCmdBuffer::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
+	{
+		Rect2I area;
+		area.x = (UINT32)(mViewport.x * mRenderTargetWidth);
+		area.y = (UINT32)(mViewport.y * mRenderTargetHeight);
+		area.width = (UINT32)(mViewport.width * mRenderTargetWidth);
+		area.height = (UINT32)(mViewport.height * mRenderTargetHeight);
+
+		clearViewport(area, buffers, color, depth, stencil, targetMask);
+	}
+
 	void VulkanCmdBuffer::setPipelineState(const SPtr<GraphicsPipelineStateCore>& state)
 	{
 		if (mGraphicsPipeline == state)

+ 9 - 5
Source/BansheeVulkanRenderAPI/Source/BsVulkanFramebuffer.cpp

@@ -9,8 +9,8 @@ namespace BansheeEngine
 	UINT32 VulkanFramebuffer::sNextValidId = 1;
 
 	VulkanFramebuffer::VulkanFramebuffer(VulkanResourceManager* owner, const VULKAN_FRAMEBUFFER_DESC& desc)
-		: VulkanResource(owner, false), mNumAttachments(0), mNumColorAttachments(0), mHasDepth(false)
-		, mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
+		: VulkanResource(owner, false), mNumAttachments(0), mNumColorAttachments(0), mNumLayers(desc.layers)
+		, mColorBaseLayers(), mDepthBaseLayer(0), mHasDepth(false), mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
 	{
 		mId = sNextValidId++;
 
@@ -32,7 +32,7 @@ namespace BansheeEngine
 			attachmentDesc.flags = 0;
 			attachmentDesc.format = desc.color[i].format;
 			attachmentDesc.samples = mSampleFlags;
-			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 			attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@@ -44,6 +44,8 @@ namespace BansheeEngine
 			else
 				attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 
+			mColorBaseLayers[i] = desc.color[i].baseLayer;
+
 			VkAttachmentReference& ref = colorReferences[attachmentIdx];
 			ref.attachment = attachmentIdx;
 			ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -61,13 +63,15 @@ namespace BansheeEngine
 			attachmentDesc.flags = 0;
 			attachmentDesc.format = desc.depth.format;
 			attachmentDesc.samples = mSampleFlags;
-			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+			attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 			attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+			attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
 			attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
 			attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
 			attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 
+			mDepthBaseLayer = desc.depth.baseLayer;
+
 			VkAttachmentReference& ref = depthReference;
 			ref.attachment = attachmentIdx;
 			ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

+ 8 - 4
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderAPI.cpp

@@ -454,8 +454,10 @@ namespace BansheeEngine
 	void VulkanRenderAPI::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask,
 		const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO - If clearing the whole viewport, call clearRenderTarget, otherwise begin render pass (if needed), and
-		// execute vkCmdClearAttachments with a valid rect. If no RT is bound, this is a no-op (log warning)
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->clearViewport(buffers, color, depth, stencil, targetMask);
 
 		BS_INC_RENDER_STAT(NumClears);
 	}
@@ -463,8 +465,10 @@ namespace BansheeEngine
 	void VulkanRenderAPI::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil,
 		UINT8 targetMask, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		// TODO - If currently within render pass, call vkCmdClearAttachments. Otherwise call cb->setClearValues
-		// which should then queue CB clear on render pass begin.
+		VulkanCommandBuffer* cb = getCB(commandBuffer);
+		VulkanCmdBuffer* vkCB = cb->getInternal();
+
+		vkCB->clearRenderTarget(buffers, color, depth, stencil, targetMask);
 
 		BS_INC_RENDER_STAT(NumClears);
 	}

+ 2 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanSwapChain.cpp

@@ -226,8 +226,10 @@ namespace BansheeEngine
 			desc.offscreen = false;
 			desc.color[0].format = colorFormat;
 			desc.color[0].view = mSurfaces[i].view;
+			desc.color[0].baseLayer = 0;
 			desc.depth.format = depthFormat;
 			desc.depth.view = mDepthStencilView;
+			desc.depth.baseLayer = 0;
 
 			mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(desc);
 		}