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

Vulkan texture copy and resolve

BearishSun преди 9 години
родител
ревизия
84089250e9

+ 7 - 1
Source/BansheeD3D11RenderAPI/Source/BsD3D11Texture.cpp

@@ -72,12 +72,18 @@ namespace bs
 		bool srcHasMultisample = mProperties.getNumSamples() > 1;
 		bool srcHasMultisample = mProperties.getNumSamples() > 1;
 		bool destHasMultisample = target->getProperties().getNumSamples() > 1;
 		bool destHasMultisample = target->getProperties().getNumSamples() > 1;
 
 
-		if (srcHasMultisample && destHasMultisample && mProperties.getNumSamples() != target->getProperties().getNumSamples()) // Resolving from MS to non-MS texture
+		if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
 		{
 		{
 			device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
 			device.getImmediateContext()->ResolveSubresource(other->getDX11Resource(), destResIdx, mTex, srcResIdx, mDXGIFormat);
 		}
 		}
 		else
 		else
 		{
 		{
+			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);
 			device.getImmediateContext()->CopySubresourceRegion(other->getDX11Resource(), destResIdx, 0, 0, 0, mTex, srcResIdx, nullptr);
 
 
 			if (device.hasError())
 			if (device.hasError())

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

@@ -394,7 +394,7 @@ namespace bs
 
 
 	void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox)
 	void GLTextureBuffer::blitFromTexture(GLTextureBuffer* src, const PixelVolume& srcBox, const PixelVolume& dstBox)
 	{
 	{
-		if (src->mMultisampleCount > 0 && mMultisampleCount == 0) // Resolving MS texture
+		if (src->mMultisampleCount > 1 && mMultisampleCount <= 1) // Resolving MS texture
 		{
 		{
 			if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE)
 			if (mTarget != GL_TEXTURE_2D || mTarget != GL_TEXTURE_2D_MULTISAMPLE)
 				BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported.");
 				BS_EXCEPT(InvalidParametersException, "Non-2D multisampled texture not supported.");

+ 3 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanTexture.h

@@ -119,6 +119,9 @@ namespace bs
 		 */
 		 */
 		VkImageView getView(UINT32 deviceIdx, const TextureSurface& surface) const;
 		VkImageView getView(UINT32 deviceIdx, const TextureSurface& surface) const;
 
 
+		/** Returns the default set of access flags for this texture type. */
+		VkAccessFlags getAccessFlags() const { return mAccessFlags; }
+
 	protected:
 	protected:
 		friend class VulkanTextureCoreManager;
 		friend class VulkanTextureCoreManager;
 
 

+ 138 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -403,7 +403,144 @@ namespace bs
 	void VulkanTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
 	void VulkanTextureCore::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
 									 const SPtr<TextureCore>& target, UINT32 queueIdx)
 									 const SPtr<TextureCore>& target, UINT32 queueIdx)
 	{
 	{
-		// TODO - Handle resolve here as well
+		VulkanTextureCore* other = static_cast<VulkanTextureCore*>(target.get());
+
+		const TextureProperties& srcProps = mProperties;
+		const TextureProperties& dstProps = other->getProperties();
+
+		bool srcHasMultisample = srcProps.getNumSamples() > 1;
+		bool destHasMultisample = dstProps.getNumSamples() > 1;
+
+		if ((srcProps.getUsage() & TU_DEPTHSTENCIL) != 0 || (dstProps.getUsage() & TU_DEPTHSTENCIL) != 0)
+		{
+			LOGERR("Texture copy/resolve isn't supported for depth-stencil textures.");
+			return;
+		}
+
+		bool needsResolve = srcHasMultisample && !destHasMultisample;
+		bool isMSCopy = srcHasMultisample || destHasMultisample;
+		if (!needsResolve && isMSCopy)
+		{
+			if (srcProps.getNumSamples() != dstProps.getNumSamples())
+			{
+				LOGERR("When copying textures their multisample counts must match. Ignoring copy.");
+				return;
+			}
+		}
+
+		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;
+		}
+
+		UINT32 mipWidth, mipHeight, mipDepth;
+		PixelUtil::getSizeForMipLevel(srcProps.getWidth(), srcProps.getHeight(), srcProps.getDepth(), srcMipLevel,
+									  mipWidth, mipHeight, mipDepth);
+
+		VkImageResolve resolveRegion;
+		resolveRegion.srcOffset = { 0, 0, 0 };
+		resolveRegion.dstOffset = { 0, 0, 0 };
+		resolveRegion.extent = { mipWidth, mipHeight, mipDepth };
+		resolveRegion.srcSubresource.baseArrayLayer = srcFace;
+		resolveRegion.srcSubresource.layerCount = 1;
+		resolveRegion.srcSubresource.mipLevel = srcMipLevel;
+		resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+		resolveRegion.dstSubresource.baseArrayLayer = destFace;
+		resolveRegion.dstSubresource.layerCount = 1;
+		resolveRegion.dstSubresource.mipLevel = destMipLevel;
+		resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+
+		VkImageCopy imageRegion;
+		imageRegion.srcOffset = { 0, 0, 0 };
+		imageRegion.dstOffset = { 0, 0, 0 };
+		imageRegion.extent = { mipWidth, mipHeight, mipDepth };
+		imageRegion.srcSubresource.baseArrayLayer = srcFace;
+		imageRegion.srcSubresource.layerCount = 1;
+		imageRegion.srcSubresource.mipLevel = srcMipLevel;
+		imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+		imageRegion.dstSubresource.baseArrayLayer = destFace;
+		imageRegion.dstSubresource.layerCount = 1;
+		imageRegion.dstSubresource.mipLevel = destMipLevel;
+		imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+
+		VkImageSubresourceRange srcRange;
+		srcRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+		srcRange.baseArrayLayer = srcFace;
+		srcRange.layerCount = 1;
+		srcRange.baseMipLevel = srcMipLevel;
+		srcRange.levelCount = 1;
+
+		VkImageSubresourceRange dstRange;
+		dstRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+		dstRange.baseArrayLayer = destFace;
+		dstRange.layerCount = 1;
+		dstRange.baseMipLevel = destMipLevel;
+		dstRange.levelCount = 1;
+
+		for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
+		{
+			VulkanImage* srcImage = mImages[i];
+			VulkanImage* dstImage = other->getResource(i);
+
+			if (srcImage == nullptr || dstImage == nullptr)
+				continue;
+
+			VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(i, queueType, localQueueIdx);
+			VkCommandBuffer vkCmdBuf = transferCB->getCB()->getHandle();
+
+			// Transfer textures to a valid layout
+			transferCB->setLayout(srcImage->getHandle(), mAccessFlags, VK_ACCESS_TRANSFER_READ_BIT, srcImage->getLayout(),
+									transferSrcLayout, srcRange);
+
+			transferCB->setLayout(dstImage->getHandle(), other->getAccessFlags(), VK_ACCESS_TRANSFER_WRITE_BIT,
+									dstImage->getLayout(), transferDstLayout, dstRange);
+
+			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 back to original layouts
+			transferCB->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, mAccessFlags,
+									transferSrcLayout, srcImage->getLayout(), srcRange);
+
+			transferCB->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, other->getAccessFlags(),
+									transferDstLayout, dstImage->getLayout(), dstRange);
+
+			// Notify the command buffer that these resources are being used on it
+			transferCB->getCB()->registerResource(srcImage, mAccessFlags, srcImage->getLayout(), srcRange, 
+				VulkanUseFlag::Read);
+			transferCB->getCB()->registerResource(dstImage, other->getAccessFlags(), dstImage->getLayout(), dstRange,
+				VulkanUseFlag::Write);
+
+			// 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
+
+			VulkanImageSubresource* srcSubresource = srcImage->getSubresource(srcFace, srcMipLevel);
+			VulkanImageSubresource* dstSubresource = dstImage->getSubresource(srcFace, srcMipLevel);
+
+			UINT32 srcUseFlags = srcSubresource->getUseInfo(VulkanUseFlag::Write);
+			UINT32 dstUseFlags = dstSubresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
+
+			transferCB->appendMask(srcUseFlags | dstUseFlags);
+		}
 	}
 	}
 
 
 	PixelData VulkanTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
 	PixelData VulkanTextureCore::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,