Browse Source

Adding subresources for Vulkan images, for more precise usage tracking
Handling Vulkan texture discard on write

BearishSun 9 years ago
parent
commit
9c52e15fe4

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

@@ -12,6 +12,8 @@ namespace bs
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	class VulkanImageSubresource;
+
 	/** Wrapper around a Vulkan image object that manages its usage and lifetime. */
 	/** Wrapper around a Vulkan image object that manages its usage and lifetime. */
 	class VulkanImage : public VulkanResource
 	class VulkanImage : public VulkanResource
 	{
 	{
@@ -35,6 +37,12 @@ namespace bs
 		/** Returns an image view that covers the specified faces and mip maps of the texture. */
 		/** Returns an image view that covers the specified faces and mip maps of the texture. */
 		VkImageView getView(const TextureSurface& surface) const;
 		VkImageView getView(const TextureSurface& surface) const;
 
 
+		/** 
+		 * Retrieves a separate resource for a specific image face & mip level. This allows the caller to track subresource
+		 * usage individually, instead for the entire image. 
+		 */
+		VulkanImageSubresource* getSubresource(UINT32 face, UINT32 mipLevel);
+
 		/** 
 		/** 
 		 * Returns a pointer to internal image memory for the specified sub-resource. Must be followed by unmap(). Caller
 		 * Returns a pointer to internal image memory for the specified sub-resource. Must be followed by unmap(). Caller
 		 * must ensure the image was created in CPU readable memory, and that image isn't currently being written to by the
 		 * must ensure the image was created in CPU readable memory, and that image isn't currently being written to by the
@@ -72,10 +80,21 @@ namespace bs
 		VkImageLayout mLayout;
 		VkImageLayout mLayout;
 		VkImageView mMainView;
 		VkImageView mMainView;
 
 
+		UINT32 mNumFaces;
+		UINT32 mNumMipLevels;
+		VulkanImageSubresource** mSubresources;
+
 		mutable VkImageViewCreateInfo mImageViewCI;
 		mutable VkImageViewCreateInfo mImageViewCI;
 		mutable Vector<ImageViewInfo> mImageInfos;
 		mutable Vector<ImageViewInfo> mImageInfos;
 	};
 	};
 
 
+	/** Represents a single sub-resource (face & mip level) of a larger image object. */
+	class VulkanImageSubresource : public VulkanResource
+	{
+	public:
+		VulkanImageSubresource(VulkanResourceManager* owner);
+	};
+
 	/**	Vulkan implementation of a texture. */
 	/**	Vulkan implementation of a texture. */
 	class VulkanTextureCore : public TextureCore
 	class VulkanTextureCore : public TextureCore
 	{
 	{

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

@@ -1030,6 +1030,18 @@ namespace bs
 			imageInfo.accessFlags |= accessFlags;
 			imageInfo.accessFlags |= accessFlags;
 			imageInfo.range = range;
 			imageInfo.range = range;
 		}
 		}
+
+		// Register any sub-resources
+		for(UINT32 i = 0; i < range.layerCount; i++)
+		{
+			for(UINT32 j = 0; j < range.levelCount; j++)
+			{
+				UINT32 layer = range.baseArrayLayer + i;
+				UINT32 mipLevel = range.baseMipLevel + j;
+
+				registerResource(res->getSubresource(layer, mipLevel), flags);
+			}
+		}
 	}
 	}
 
 
 	void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)
 	void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)

+ 4 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanResource.cpp

@@ -149,8 +149,10 @@ namespace bs
 	void VulkanResourceManager::destroy(VulkanResource* resource)
 	void VulkanResourceManager::destroy(VulkanResource* resource)
 	{
 	{
 #if BS_DEBUG_MODE
 #if BS_DEBUG_MODE
-		Lock lock(mMutex);
-		mResources.erase(resource);
+		{
+			Lock lock(mMutex);
+			mResources.erase(resource);
+		}
 #endif
 #endif
 
 
 		bs_delete(resource);
 		bs_delete(resource);

+ 39 - 13
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -52,6 +52,14 @@ namespace bs
 
 
 		TextureSurface completeSurface(0, props.getNumMipmaps() + 1, 0, props.getNumArraySlices());
 		TextureSurface completeSurface(0, props.getNumMipmaps() + 1, 0, props.getNumArraySlices());
 		mMainView = createView(completeSurface);
 		mMainView = createView(completeSurface);
+
+		mNumFaces = props.getNumFaces();
+		mNumMipLevels = props.getNumMipmaps();
+
+		UINT32 numSubresources = mNumFaces * mNumMipLevels;
+		mSubresources = (VulkanImageSubresource**)bs_alloc<VulkanImageSubresource*>(numSubresources);
+		for (UINT32 i = 0; i < numSubresources; i++)
+			mSubresources[i] = owner->create<VulkanImageSubresource>();
 	}
 	}
 
 
 	VulkanImage::~VulkanImage()
 	VulkanImage::~VulkanImage()
@@ -59,6 +67,14 @@ namespace bs
 		VulkanDevice& device = mOwner->getDevice();
 		VulkanDevice& device = mOwner->getDevice();
 		VkDevice vkDevice = device.getLogical();
 		VkDevice vkDevice = device.getLogical();
 
 
+		UINT32 numSubresources = mNumFaces * mNumMipLevels;
+		for (UINT32 i = 0; i < numSubresources; i++)
+		{
+			assert(!mSubresources[i]->isBound()); // Image beeing freed but its subresources are still bound somewhere
+
+			mSubresources[i]->destroy();
+		}
+
 		vkDestroyImageView(vkDevice, mMainView, gVulkanAllocator);
 		vkDestroyImageView(vkDevice, mMainView, gVulkanAllocator);
 
 
 		for(auto& entry : mImageInfos)
 		for(auto& entry : mImageInfos)
@@ -125,6 +141,11 @@ namespace bs
 		return view;
 		return view;
 	}
 	}
 
 
+	VulkanImageSubresource* VulkanImage::getSubresource(UINT32 face, UINT32 mipLevel)
+	{
+		return mSubresources[face * mNumMipLevels + mipLevel];
+	}
+
 	void VulkanImage::map(UINT32 face, UINT32 mipLevel, PixelData& output) const
 	void VulkanImage::map(UINT32 face, UINT32 mipLevel, PixelData& output) const
 	{
 	{
 		VulkanDevice& device = mOwner->getDevice();
 		VulkanDevice& device = mOwner->getDevice();
@@ -175,6 +196,10 @@ namespace bs
 		vkCmdCopyImageToBuffer(cb->getCB()->getHandle(), mImage, layout, destination->getHandle(), 1, &region);
 		vkCmdCopyImageToBuffer(cb->getCB()->getHandle(), mImage, layout, destination->getHandle(), 1, &region);
 	}
 	}
 
 
+	VulkanImageSubresource::VulkanImageSubresource(VulkanResourceManager* owner)
+		:VulkanResource(owner, false)
+	{ }
+
 	VulkanTextureCore::VulkanTextureCore(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
 	VulkanTextureCore::VulkanTextureCore(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
 		GpuDeviceFlags deviceMask)
 		GpuDeviceFlags deviceMask)
 		: TextureCore(desc, initialData, deviceMask), mImages(), mDeviceMask(deviceMask), mAccessFlags(0)
 		: TextureCore(desc, initialData, deviceMask), mImages(), mDeviceMask(deviceMask), mAccessFlags(0)
@@ -429,7 +454,7 @@ namespace bs
 		GpuQueueType queueType;
 		GpuQueueType queueType;
 		UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
 		UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
 
 
-		VulkanImage* subresource = image->getSubresource(face, mipLevel);
+		VulkanImageSubresource* subresource = image->getSubresource(face, mipLevel);
 
 
 		// If memory is host visible try mapping it directly
 		// If memory is host visible try mapping it directly
 		if (mDirectlyMappable)
 		if (mDirectlyMappable)
@@ -471,14 +496,14 @@ namespace bs
 			// Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
 			// Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
 			if (options == GBL_WRITE_ONLY_DISCARD)
 			if (options == GBL_WRITE_ONLY_DISCARD)
 			{
 			{
-				// TODO - Since I'm only writing to a single subresource, how will discard work? Discard every subresource?
+				// We need to discard the entire image, even though we're only writing to a single sub-resource
+				image->destroy();
 
 
-				//buffer->destroy();
+				image = createImage(device);
+				mImages[deviceIdx] = image;
 
 
-				//buffer = createBuffer(device, false, mReadable);
-				//mBuffers[deviceIdx] = buffer;
-
-				//return buffer->map(offset, length);
+				image->map(face, mipLevel, lockedArea);
+				return lockedArea;
 			}
 			}
 
 
 			// We need to both read and write, meaning we need to wait until existing reads complete before we return
 			// We need to both read and write, meaning we need to wait until existing reads complete before we return
@@ -604,7 +629,7 @@ namespace bs
 				VulkanImage* image = mImages[mMappedDeviceIdx];
 				VulkanImage* image = mImages[mMappedDeviceIdx];
 				VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(mMappedDeviceIdx, queueType, localQueueIdx);
 				VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(mMappedDeviceIdx, queueType, localQueueIdx);
 
 
-				VulkanImage* subresource = image->getSubresource(mMappedFace, mMappedMip);
+				VulkanImageSubresource* subresource = image->getSubresource(mMappedFace, mMappedMip);
 
 
 				// If the subresource is used in any way on the GPU, we need to wait for that use to finish before
 				// If the subresource is used in any way on the GPU, we need to wait for that use to finish before
 				// we issue our copy
 				// we issue our copy
@@ -618,15 +643,16 @@ namespace bs
 					{
 					{
 						// Fall through to copy()
 						// Fall through to copy()
 					}
 					}
-					// Caller doesn't care about buffer contents, so just discard the  existing buffer and create a new one
+					// Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
 					else if (mMappedLockOptions == GBL_WRITE_ONLY_DISCARD) 
 					else if (mMappedLockOptions == GBL_WRITE_ONLY_DISCARD) 
 					{
 					{
-						// TODO - Handle discard
+						// We need to discard the entire image, even though we're only writing to a single sub-resource
+						image->destroy();
 
 
-						//buffer->destroy();
+						image = createImage(device);
+						mImages[mMappedDeviceIdx] = image;
 
 
-						//buffer = createBuffer(device, false, mReadable);
-						//mBuffers[mMappedDeviceIdx] = buffer;
+						subresource = image->getSubresource(mMappedFace, mMappedMip);
 					}
 					}
 					else // Otherwise we have no choice but to issue a dependency between the queues
 					else // Otherwise we have no choice but to issue a dependency between the queues
 						transferCB->appendMask(useMask);
 						transferCB->appendMask(useMask);