Kaynağa Gözat

Texture copy operations no longer occurr on the transfer queue, but instead on the user-provided command buffer, in order to avoid user needing to worry about submitting previous rendering operations manually

BearishSun 8 yıl önce
ebeveyn
işleme
8ffa542fb5

+ 4 - 3
Source/BansheeCore/Include/BsTexture.h

@@ -363,10 +363,11 @@ namespace bs
 		 * @param[in]	srcMipLevel			Mip level to copy from.
 		 * @param[in]	dstFace				Face to copy to.
 		 * @param[in]	dstMipLevel			Mip level to copy to.
-		 * @param[in]	queueIdx			Device queue to perform the copy operation on. See @ref queuesDoc.
+		 * @param[in]	commandBuffer		Command buffer to queue the copy operation on. If null, main command buffer is
+		 *									used.
 		 */
 		void copy(const SPtr<Texture>& target, UINT32 srcFace = 0, UINT32 srcMipLevel = 0, UINT32 dstFace = 0,
-			UINT32 dstMipLevel = 0, UINT32 queueIdx = 0);
+			UINT32 dstMipLevel = 0, const SPtr<CommandBuffer>& commandBuffer = nullptr);
 
 		/**
 		 * Reads data from the texture buffer into the provided buffer.
@@ -445,7 +446,7 @@ namespace bs
 
 		/** @copydoc copy */
 		virtual void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 dstFace, UINT32 dstMipLevel, 
-			const SPtr<Texture>& target, UINT32 queueIdx = 0) = 0;
+			const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer) = 0;
 
 		/** @copydoc readData */
 		virtual void readDataImpl(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,

+ 2 - 2
Source/BansheeCore/Source/BsTexture.cpp

@@ -408,7 +408,7 @@ namespace bs
 	}
 
 	void Texture::copy(const SPtr<Texture>& target, UINT32 srcFace, UINT32 srcMipLevel, UINT32 dstFace,
-						   UINT32 dstMipLevel, UINT32 queueIdx)
+						   UINT32 dstMipLevel, const SPtr<CommandBuffer>& commandBuffer)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -468,7 +468,7 @@ namespace bs
 			return;
 		}
 
-		copyImpl(srcFace, srcMipLevel, dstFace, dstMipLevel, target, queueIdx);
+		copyImpl(srcFace, srcMipLevel, dstFace, dstMipLevel, target, commandBuffer);
 	}
 
 	/************************************************************************/

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

@@ -49,7 +49,7 @@ namespace bs { namespace ct
 
 		/** @copydoc Texture::copyImpl */
 		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 dstFace, UINT32 dstMipLevel,
-					  const SPtr<Texture>& target, UINT32 queueIdx = 0) override;
+					  const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer) override;
 
 		/** @copydoc Texture::readData */
 		void readDataImpl(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,

+ 39 - 24
Source/BansheeD3D11RenderAPI/Source/BsD3D11Texture.cpp

@@ -10,6 +10,7 @@
 #include "BsAsyncOp.h"
 #include "BsRenderStats.h"
 #include "BsMath.h"
+#include "BsD3D11CommandBuffer.h"
 
 namespace bs { namespace ct
 {
@@ -61,38 +62,52 @@ namespace bs { namespace ct
 	}
 
 	void D3D11Texture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
-									const SPtr<Texture>& target, UINT32 queueIdx)
+									const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
+		auto executeRef = [this](UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
+			const SPtr<Texture>& target)
+		{
+			D3D11Texture* other = static_cast<D3D11Texture*>(target.get());
 
-		UINT32 srcResIdx = D3D11CalcSubresource(srcMipLevel, srcFace, mProperties.getNumMipmaps() + 1);
-		UINT32 destResIdx = D3D11CalcSubresource(destMipLevel, destFace, target->getProperties().getNumMipmaps() + 1);
+			UINT32 srcResIdx = D3D11CalcSubresource(srcMipLevel, srcFace, mProperties.getNumMipmaps() + 1);
+			UINT32 destResIdx = D3D11CalcSubresource(destMipLevel, destFace, target->getProperties().getNumMipmaps() + 1);
 
-		D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
-		D3D11Device& device = rs->getPrimaryDevice();
+			D3D11RenderAPI* rs = static_cast<D3D11RenderAPI*>(RenderAPI::instancePtr());
+			D3D11Device& device = rs->getPrimaryDevice();
 
-		bool srcHasMultisample = mProperties.getNumSamples() > 1;
-		bool destHasMultisample = target->getProperties().getNumSamples() > 1;
+			bool srcHasMultisample = mProperties.getNumSamples() > 1;
+			bool destHasMultisample = target->getProperties().getNumSamples() > 1;
 
-		if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
-		{
-			device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
-		}
-		else
-		{
-			if(mProperties.getNumSamples() != target->getProperties().getNumSamples())
+			if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
 			{
-				LOGERR("When copying textures their multisample counts must match. Ignoring copy.");
-				return;
+				device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
 			}
-
-			device.getImmediateContext()->CopySubresourceRegion(other->getDX11Resource(), destResIdx, 0, 0, 0, mTex, srcResIdx, nullptr);
-
-			if (device.hasError())
+			else
 			{
-				String errorDescription = device.getErrorDescription();
-				BS_EXCEPT(RenderingAPIException, "D3D11 device cannot copy subresource\nError Description:" + errorDescription);
+				if (mProperties.getNumSamples() != target->getProperties().getNumSamples())
+				{
+					LOGERR("When copying textures their multisample counts must match. Ignoring copy.");
+					return;
+				}
+
+				device.getImmediateContext()->CopySubresourceRegion(other->getDX11Resource(), destResIdx, 0, 0, 0, mTex, srcResIdx, nullptr);
+
+				if (device.hasError())
+				{
+					String errorDescription = device.getErrorDescription();
+					BS_EXCEPT(RenderingAPIException, "D3D11 device cannot copy subresource\nError Description:" + errorDescription);
+				}
 			}
+		};
+
+		if (commandBuffer == nullptr)
+			executeRef(srcFace, srcMipLevel, destFace, destMipLevel, target);
+		else
+		{
+			auto execute = [=]() { executeRef(srcFace, srcMipLevel, destFace, destMipLevel, target); };
+
+			SPtr<D3D11CommandBuffer> cb = std::static_pointer_cast<D3D11CommandBuffer>(commandBuffer);
+			cb->queueCommand(execute);
 		}
 	}
 
@@ -754,4 +769,4 @@ namespace bs { namespace ct
 	{
 		return bs_shared_ptr<D3D11TextureView>(new (bs_alloc<D3D11TextureView>()) D3D11TextureView(this, desc));
 	}
-}}
+}}

+ 1 - 1
Source/BansheeGLRenderAPI/Include/BsGLTexture.h

@@ -56,7 +56,7 @@ namespace bs { namespace ct
 
 		/** @copydoc Texture::copyImpl */
 		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 dstFace, UINT32 dstMipLevel,
-					  const SPtr<Texture>& target, UINT32 queueIdx = 0) override;
+					  const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer) override;
 
 		/** @copydoc Texture::readData */
 		void readDataImpl(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,

+ 20 - 5
Source/BansheeGLRenderAPI/Source/BsGLTexture.cpp

@@ -11,6 +11,7 @@
 #include "BsGLRenderTexture.h"
 #include "BsGLTextureView.h"
 #include "BsRenderStats.h"
+#include "BsGLCommandBuffer.h"
 
 namespace bs { namespace ct
 {
@@ -256,12 +257,26 @@ namespace bs { namespace ct
 	}
 
 	void GLTexture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
-								 const SPtr<Texture>& target, UINT32 queueIdx)
+								 const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer)
 	{
-		GLTexture* destTex = static_cast<GLTexture*>(target.get());
-		GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());
+		auto executeRef = [this](UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel, 
+			const SPtr<Texture>& target)
+		{
+			GLTexture* destTex = static_cast<GLTexture*>(target.get());
+			GLTextureBuffer *src = static_cast<GLTextureBuffer*>(getBuffer(srcFace, srcMipLevel).get());
+
+			destTex->getBuffer(destFace, destMipLevel)->blitFromTexture(src);
+		};
+
+		if (commandBuffer == nullptr)
+			executeRef(srcFace, srcMipLevel, destFace, destMipLevel, target);
+		else
+		{
+			auto execute = [=]() { executeRef(srcFace, srcMipLevel, destFace, destMipLevel, target); };
 
-		destTex->getBuffer(destFace, destMipLevel)->blitFromTexture(src);
+			SPtr<GLCommandBuffer> cb = std::static_pointer_cast<GLCommandBuffer>(commandBuffer);
+			cb->queueCommand(execute);
+		}
 	}
 
 	void GLTexture::createSurfaceList()
@@ -307,4 +322,4 @@ namespace bs { namespace ct
 	{
 		return bs_shared_ptr<GLTextureView>(new (bs_alloc<GLTextureView>()) GLTextureView(this, desc));
 	}
-}}
+}}

+ 1 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h

@@ -211,7 +211,7 @@ namespace bs { namespace ct
 
 		/** @copydoc Texture::copyImpl */
 		void copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 dstFace, UINT32 dstMipLevel,
-					  const SPtr<Texture>& target, UINT32 queueIdx = 0) override;
+					  const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer) override;
 
 		/** @copydoc Texture::readData */
 		void readDataImpl(PixelData& dest, UINT32 mipLevel = 0, UINT32 face = 0, UINT32 deviceIdx = 0,

+ 55 - 87
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -380,6 +380,12 @@ namespace bs { namespace ct
 		case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
 			accessFlags = VK_ACCESS_SHADER_READ_BIT;
 			break;
+		case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+			accessFlags = VK_ACCESS_TRANSFER_READ_BIT;
+			break;
+		case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+			accessFlags = VK_ACCESS_TRANSFER_WRITE_BIT;
+			break;
 		case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
 			accessFlags = VK_ACCESS_MEMORY_READ_BIT;
 			break;
@@ -821,7 +827,7 @@ namespace bs { namespace ct
 	}
 
 	void VulkanTexture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
-									 const SPtr<Texture>& target, UINT32 queueIdx)
+									 const SPtr<Texture>& target, const SPtr<CommandBuffer>& commandBuffer)
 	{
 		VulkanTexture* other = static_cast<VulkanTexture*>(target.get());
 
@@ -848,21 +854,8 @@ namespace bs { namespace ct
 			}
 		}
 
-		VulkanCommandBufferManager& cbManager = gVulkanCBManager();
-		GpuQueueType queueType;
-		UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
-
-		VkImageLayout transferSrcLayout, transferDstLayout;
-		if (mDirectlyMappable)
-		{
-			transferSrcLayout = VK_IMAGE_LAYOUT_GENERAL;
-			transferDstLayout = VK_IMAGE_LAYOUT_GENERAL;
-		}
-		else
-		{
-			transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
-			transferDstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
-		}
+		VkImageLayout transferSrcLayout = mDirectlyMappable ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
+		VkImageLayout transferDstLayout = other->mDirectlyMappable ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
 		UINT32 mipWidth, mipHeight, mipDepth;
 		PixelUtil::getSizeForMipLevel(srcProps.getWidth(), srcProps.getHeight(), srcProps.getDepth(), srcMipLevel,
@@ -909,94 +902,69 @@ namespace bs { namespace ct
 		dstRange.levelCount = 1;
 
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
-		for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
-		{
-			VulkanImage* srcImage = mImages[i];
-			VulkanImage* dstImage = other->getResource(i);
-
-			if (srcImage == nullptr || dstImage == nullptr)
-				continue;
 
-			VulkanDevice& device = *rapi._getDevice(i);
-
-			VulkanImageSubresource* srcSubresource = srcImage->getSubresource(srcFace, srcMipLevel);
-			VulkanImageSubresource* dstSubresource = dstImage->getSubresource(destFace, destMipLevel);
-
-			VkImageLayout srcLayout = srcSubresource->getLayout();
-			VkImageLayout dstLayout = dstSubresource->getLayout();
-
-			VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(i, queueType, localQueueIdx);
-			VkCommandBuffer vkCmdBuf = transferCB->getCB()->getHandle();
+		VulkanCmdBuffer* vkCB;
+		if (commandBuffer != nullptr)
+			vkCB = static_cast<VulkanCommandBuffer*>(commandBuffer.get())->getInternal();
+		else
+			vkCB = rapi._getMainCommandBuffer()->getInternal();
 
-			// If destination subresource is queued for some operation on a CB (ignoring the ones we're waiting for), then 
-			// we need to make a copy of the image to avoid modifying its use in the previous operation
-			UINT32 useCount = dstImage->getUseCount();
-			UINT32 boundCount = dstImage->getBoundCount();
+		UINT32 deviceIdx = vkCB->getDeviceIdx();
 
-			bool isBoundWithoutUse = boundCount > useCount;
-			if (isBoundWithoutUse)
-			{
-				VulkanImage* newImage = other->createImage(device, other->mInternalFormats[i]);
+		VulkanImage* srcImage = mImages[deviceIdx];
+		VulkanImage* dstImage = other->getResource(deviceIdx);
 
-				// Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
-				if (dstProps.getNumMipmaps() > 0 || dstProps.getNumFaces() > 1)
-				{
-					VkImageLayout oldDstLayout = dstImage->getOptimalLayout();
+		if (srcImage == nullptr || dstImage == nullptr)
+			return;
 
-					dstLayout = newImage->getOptimalLayout();
-					other->copyImage(transferCB, dstImage, newImage, oldDstLayout, dstLayout);
-				}
+		VulkanImageSubresource* srcSubresource = srcImage->getSubresource(srcFace, srcMipLevel);
+		VulkanImageSubresource* dstSubresource = dstImage->getSubresource(destFace, destMipLevel);
 
-				dstImage->destroy();
-				dstImage = newImage;
-				other->mImages[i] = dstImage;
-			}
+		VkImageLayout srcLayout = srcSubresource->getLayout();
+		VkImageLayout dstLayout = dstSubresource->getLayout();
 
-			VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcLayout);
-			VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstLayout);
+		VkCommandBuffer vkCmdBuf = vkCB->getHandle();
 
-			// Transfer textures to a valid layout
-			transferCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcLayout,
-									transferSrcLayout, srcRange);
+		VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcLayout);
+		VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstLayout);
 
-			transferCB->setLayout(dstImage->getHandle(), dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
-									dstLayout, transferDstLayout, dstRange);
+		if (vkCB->isInRenderPass())
+			vkCB->endRenderPass();
 
-			if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
-			{
-				vkCmdResolveImage(vkCmdBuf, srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-								  dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolveRegion);
-			}
-			else // Just a normal copy
-			{
-				vkCmdCopyImage(vkCmdBuf, srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-							   dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageRegion);
-			}
+		// Transfer textures to a valid layout
+		vkCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcLayout,
+								transferSrcLayout, srcRange);
 
-			// Transfer back to optimal layouts
-			srcLayout = srcImage->getOptimalLayout();
+		vkCB->setLayout(dstImage->getHandle(), dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
+								dstLayout, transferDstLayout, dstRange);
 
-			srcAccessMask = srcImage->getAccessFlags(srcLayout);
-			transferCB->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
-									transferSrcLayout, srcLayout, srcRange);
+		if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
+		{
+			vkCmdResolveImage(vkCmdBuf, srcImage->getHandle(), transferSrcLayout, dstImage->getHandle(), transferDstLayout, 
+				1, &resolveRegion);
+		}
+		else // Just a normal copy
+		{
+			vkCmdCopyImage(vkCmdBuf, srcImage->getHandle(), transferSrcLayout, dstImage->getHandle(), transferDstLayout, 
+				1, &imageRegion);
+		}
 
-			dstLayout = dstImage->getOptimalLayout();
+		// Transfer back to optimal layouts
+		srcLayout = srcImage->getOptimalLayout();
 
-			dstAccessMask = dstImage->getAccessFlags(dstLayout);
-			transferCB->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
-									transferDstLayout, dstLayout, dstRange);
+		srcAccessMask = srcImage->getAccessFlags(srcLayout);
+		vkCB->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask, transferSrcLayout, 
+			srcLayout, srcRange);
 
-			// Notify the command buffer that these resources are being used on it
-			transferCB->getCB()->registerResource(srcImage, srcRange, VulkanUseFlag::Read);
-			transferCB->getCB()->registerResource(dstImage, dstRange, VulkanUseFlag::Write);
+		dstLayout = dstImage->getOptimalLayout();
 
-			// Need to wait if subresource we're reading from is being written, or if the subresource we're writing to is
-			// being accessed in any way
-			UINT32 srcUseFlags = srcSubresource->getUseInfo(VulkanUseFlag::Write);
-			UINT32 dstUseFlags = dstSubresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
+		dstAccessMask = dstImage->getAccessFlags(dstLayout);
+		vkCB->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask, transferDstLayout, 
+			dstLayout, dstRange);
 
-			transferCB->appendMask(srcUseFlags | dstUseFlags);
-		}
+		// Notify the command buffer that these resources are being used on it
+		vkCB->registerResource(srcImage, srcRange, VulkanUseFlag::Read);
+		vkCB->registerResource(dstImage, dstRange, VulkanUseFlag::Write);
 	}
 
 	PixelData VulkanTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,