Bladeren bron

Vulkan framebuffer now provides access to individual image resources

BearishSun 9 jaren geleden
bovenliggende
commit
896a17335d

+ 8 - 4
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -157,19 +157,23 @@ namespace bs
 
 
 		/** 
 		/** 
 		 * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
 		 * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
-		 * device when the command buffer is submitted. If a resource is an image or a buffer use the more specific
-		 * registerResource() overload.
+		 * device when the command buffer is submitted.
 		 */
 		 */
 		void registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout, 
 		void registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout, 
 			const VkImageSubresourceRange& range, VulkanUseFlags flags);
 			const VkImageSubresourceRange& range, VulkanUseFlags flags);
 
 
 		/** 
 		/** 
 		 * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
 		 * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
-		 * device when the command buffer is submitted. If a resource is an image or a buffer use the more specific
-		 * registerResource() overload.
+		 * device when the command buffer is submitted. 
 		 */
 		 */
 		void registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags);
 		void registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags);
 
 
+		/** 
+		 * Lets the command buffer know that the provided framebuffer resource has been queued on it, and will be used by
+		 * the device when the command buffer is submitted.
+		 */
+		void registerResource(VulkanFramebuffer* res, VulkanUseFlags flags);
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								COMMANDS	                     		*/
 		/* 								COMMANDS	                     		*/
 		/************************************************************************/
 		/************************************************************************/

+ 11 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanFramebuffer.h

@@ -14,6 +14,9 @@ namespace bs
 	/** Represents a single attachment in a Vulkan frame-buffer. */
 	/** Represents a single attachment in a Vulkan frame-buffer. */
 	struct VULKAN_ATTACHMENT_DESC
 	struct VULKAN_ATTACHMENT_DESC
 	{
 	{
+		/** Image to attach or null if none. */
+		VulkanImage* image;
+
 		/** View of the image to attach or VK_NULL_HANDLE if none. */
 		/** View of the image to attach or VK_NULL_HANDLE if none. */
 		VkImageView view;
 		VkImageView view;
 
 
@@ -88,6 +91,12 @@ namespace bs
 		 */
 		 */
 		UINT32 getNumLayers() const { return mNumLayers; }
 		UINT32 getNumLayers() const { return mNumLayers; }
 
 
+		/** Returns the image representing the color attachment at the provided index. */
+		VulkanImage* getColorImage(UINT32 colorIdx) const { return mColorImages[colorIdx]; }
+
+		/** Returns the image representing the depth/stencil attachment, if one exists. */
+		VulkanImage* getDepthStencilImage() const { return mDepthStencilImage; }
+
 		/** Returns the initial layer of the color texture surface in which to start rendering. */
 		/** Returns the initial layer of the color texture surface in which to start rendering. */
 		UINT32 getColorBaseLayer(UINT32 colorIdx) const { return mColorBaseLayers[colorIdx]; }
 		UINT32 getColorBaseLayer(UINT32 colorIdx) const { return mColorBaseLayers[colorIdx]; }
 
 
@@ -116,6 +125,8 @@ namespace bs
 		UINT32 mNumAttachments;
 		UINT32 mNumAttachments;
 		UINT32 mNumColorAttachments;
 		UINT32 mNumColorAttachments;
 		UINT32 mNumLayers;
 		UINT32 mNumLayers;
+		VulkanImage* mColorImages[BS_MAX_MULTIPLE_RENDER_TARGETS];
+		VulkanImage* mDepthStencilImage;
 		UINT32 mColorBaseLayers[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		UINT32 mColorBaseLayers[BS_MAX_MULTIPLE_RENDER_TARGETS];
 		UINT32 mDepthBaseLayer;
 		UINT32 mDepthBaseLayer;
 		bool mHasDepth;
 		bool mHasDepth;

+ 2 - 3
Source/BansheeVulkanRenderAPI/Include/BsVulkanSwapChain.h

@@ -14,7 +14,7 @@ namespace bs
 	/** Description of a single swap chain surface. */
 	/** Description of a single swap chain surface. */
 	struct SwapChainSurface
 	struct SwapChainSurface
 	{
 	{
-		VkImage image;
+		VulkanImage* image;
 		VkImageView view;
 		VkImageView view;
 		VkSemaphore sync;
 		VkSemaphore sync;
 		bool acquired;
 		bool acquired;
@@ -87,9 +87,8 @@ namespace bs
 		UINT32 mHeight = 0;
 		UINT32 mHeight = 0;
 		Vector<SwapChainSurface> mSurfaces;
 		Vector<SwapChainSurface> mSurfaces;
 
 
-		VkImage mDepthStencilImage = VK_NULL_HANDLE;
+		VulkanImage* mDepthStencilImage = nullptr;
 		VkImageView mDepthStencilView = VK_NULL_HANDLE;
 		VkImageView mDepthStencilView = VK_NULL_HANDLE;
-		VkDeviceMemory mDepthStencilMemory = nullptr;
 
 
 		UINT32 mCurrentSemaphoreIdx = 0;
 		UINT32 mCurrentSemaphoreIdx = 0;
 		UINT32 mCurrentBackBufferIdx = 0;
 		UINT32 mCurrentBackBufferIdx = 0;

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

@@ -14,12 +14,42 @@ namespace bs
 
 
 	class VulkanImageSubresource;
 	class VulkanImageSubresource;
 
 
+	/** Descriptor used for initializing a VulkanImage. */
+	struct VULKAN_IMAGE_DESC
+	{
+		VkImage image; /**< Internal Vulkan image object */
+		VkDeviceMemory memory; /**< Memory bound to the image. */
+		VkImageLayout layout; /**< Initial layout of the image. */
+		TextureType type; /**< Type of the image. */
+		VkFormat format; /**< Pixel format of the image. */
+		UINT32 numFaces; /**< Number of faces (array slices, or cube-map faces). */
+		UINT32 numMipLevels; /**< Number of mipmap levels per face. */
+		bool isDepthStencil; /**< True if the image represents a depth-stencil surface. */
+	};
+
 	/** 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
 	{
 	{
 	public:
 	public:
+		/**
+		 * @param[in]	owner		Resource manager that keeps track of lifetime of this resource.
+		 * @param[in]	image		Internal image Vulkan object.
+		 * @param[in]	memory		Memory bound to the image.
+		 * @param[in]	layout		Initial layout of the image.
+		 * @param[in]	props		Properties describing the image.
+		 * @param[in]	ownsImage	If true, this object will take care of releasing the image and its memory, otherwise
+		 *							it is expected they will be released externally.
+		 */
 		VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout,
 		VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout,
-					const TextureProperties& props);
+					const TextureProperties& props, bool ownsImage = true);
+
+		/**
+		 * @param[in]	owner		Resource manager that keeps track of lifetime of this resource.
+		 * @param[in]	desc		Describes the image to assign.
+		 * @param[in]	ownsImage	If true, this object will take care of releasing the image and its memory, otherwise
+		 *							it is expected they will be released externally.
+		 */
+		VulkanImage(VulkanResourceManager* owner, const VULKAN_IMAGE_DESC& desc, bool ownsImage = true);
 		~VulkanImage();
 		~VulkanImage();
 
 
 		/** Returns the internal handle to the Vulkan object. */
 		/** Returns the internal handle to the Vulkan object. */
@@ -79,6 +109,7 @@ namespace bs
 		VkDeviceMemory mMemory;
 		VkDeviceMemory mMemory;
 		VkImageLayout mLayout;
 		VkImageLayout mLayout;
 		VkImageView mMainView;
 		VkImageView mMainView;
+		bool mOwnsImage;
 
 
 		UINT32 mNumFaces;
 		UINT32 mNumFaces;
 		UINT32 mNumMipLevels;
 		UINT32 mNumMipLevels;

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

@@ -242,12 +242,8 @@ namespace bs
 		renderPassBeginInfo.renderArea.offset.y = 0;
 		renderPassBeginInfo.renderArea.offset.y = 0;
 		renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
 		renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
 		renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
 		renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
-
-		// TODO: Handle clears (if provided) here. See VulkanRenderAPI::clearRenderTarget.
-		//  - Potential problem is that we might need different framebuffers depending on whether we use load or clear
-		//    ops during render pass start.
-		renderPassBeginInfo.clearValueCount = 0; // TODO
-		renderPassBeginInfo.pClearValues = nullptr; // TODO
+		renderPassBeginInfo.clearValueCount = 0;
+		renderPassBeginInfo.pClearValues = nullptr;
 
 
 		vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
 		vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
 
 
@@ -331,7 +327,7 @@ namespace bs
 
 
 			UINT32 entryQueueFamily = entry.first;
 			UINT32 entryQueueFamily = entry.first;
 
 
-			// No queue transition needed for entries on this queue (this entry is most likely an in image layout transition)
+			// No queue transition needed for entries on this queue (this entry is most likely an image layout transition)
 			if (entryQueueFamily == mQueueFamily)
 			if (entryQueueFamily == mQueueFamily)
 				continue;
 				continue;
 
 
@@ -479,6 +475,7 @@ namespace bs
 		mComputePipeline = nullptr;
 		mComputePipeline = nullptr;
 		mGfxPipelineRequiresBind = true;
 		mGfxPipelineRequiresBind = true;
 		mCmpPipelineRequiresBind = true;
 		mCmpPipelineRequiresBind = true;
+		mFramebuffer = nullptr;
 		mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
 		mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
 	}
 	}
 
 
@@ -539,6 +536,8 @@ namespace bs
 	{
 	{
 		assert(mState != State::RecordingRenderPass && mState != State::Submitted);
 		assert(mState != State::RecordingRenderPass && mState != State::Submitted);
 
 
+		VulkanFramebuffer* oldFramebuffer = mFramebuffer;
+
 		if(rt == nullptr)
 		if(rt == nullptr)
 		{
 		{
 			mFramebuffer = nullptr;
 			mFramebuffer = nullptr;
@@ -565,7 +564,14 @@ namespace bs
 			registerResource(mFramebuffer, VulkanUseFlag::Write);
 			registerResource(mFramebuffer, VulkanUseFlag::Write);
 		}
 		}
 
 
-		mGfxPipelineRequiresBind = true;
+		// If anything changed
+		if(oldFramebuffer != mFramebuffer)
+		{
+			if (isInRenderPass())
+				endRenderPass();
+
+			mGfxPipelineRequiresBind = true;
+		}
 	}
 	}
 
 
 	void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
 	void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
@@ -1067,6 +1073,41 @@ namespace bs
 		}
 		}
 	}
 	}
 
 
+	void VulkanCmdBuffer::registerResource(VulkanFramebuffer* res, VulkanUseFlags flags)
+	{
+		auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
+		if (insertResult.second) // New element
+		{
+			ResourceUseHandle& useHandle = insertResult.first->second;
+			useHandle.used = false;
+			useHandle.flags = flags;
+
+			res->notifyBound();
+		}
+		else // Existing element
+		{
+			ResourceUseHandle& useHandle = insertResult.first->second;
+
+			assert(!useHandle.used);
+			useHandle.flags |= flags;
+		}
+
+		// Register any sub-resources
+		// (Purposely don't register them as images, as we will handle any layout transitions manually)
+		UINT32 numColorAttachments = res->getNumColorAttachments();
+		for (UINT32 i = 0; i < numColorAttachments; i++)
+		{
+			VulkanImage* image = res->getColorImage(i);
+			registerResource(image, VulkanUseFlag::Write);
+		}
+
+		if(res->hasDepthAttachment())
+		{
+			VulkanImage* image = res->getDepthStencilImage();
+			registerResource(image, VulkanUseFlag::Write);
+		}
+	}
+
 	VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
 	VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
 		UINT32 queueIdx, bool secondary)
 		UINT32 queueIdx, bool secondary)
 		: CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)
 		: CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)

+ 7 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanFramebuffer.cpp

@@ -1,6 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanFramebuffer.h"
 #include "BsVulkanFramebuffer.h"
+#include "BsVulkanTexture.h"
 #include "BsVulkanUtility.h"
 #include "BsVulkanUtility.h"
 #include "BsVulkanDevice.h"
 #include "BsVulkanDevice.h"
 
 
@@ -10,7 +11,8 @@ namespace bs
 
 
 	VulkanFramebuffer::VulkanFramebuffer(VulkanResourceManager* owner, const VULKAN_FRAMEBUFFER_DESC& desc)
 	VulkanFramebuffer::VulkanFramebuffer(VulkanResourceManager* owner, const VULKAN_FRAMEBUFFER_DESC& desc)
 		: VulkanResource(owner, false), mNumAttachments(0), mNumColorAttachments(0), mNumLayers(desc.layers)
 		: VulkanResource(owner, false), mNumAttachments(0), mNumColorAttachments(0), mNumLayers(desc.layers)
-		, mColorBaseLayers(), mDepthBaseLayer(0), mHasDepth(false), mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
+		, mColorImages(), mDepthStencilImage(nullptr), mColorBaseLayers(), mDepthBaseLayer(0), mHasDepth(false)
+		, mSampleFlags(VK_SAMPLE_COUNT_1_BIT)
 	{
 	{
 		mId = sNextValidId++;
 		mId = sNextValidId++;
 
 
@@ -25,7 +27,7 @@ namespace bs
 		UINT32 attachmentIdx = 0;
 		UINT32 attachmentIdx = 0;
 		for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
 		for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
 		{
 		{
-			if (desc.color[i].view == VK_NULL_HANDLE)
+			if (desc.color[i].image == nullptr)
 				continue;
 				continue;
 
 
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
 			VkAttachmentDescription& attachmentDesc = attachments[attachmentIdx];
@@ -44,7 +46,8 @@ namespace bs
 			else
 			else
 				attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 				attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
 
 
-			mColorBaseLayers[i] = desc.color[i].baseLayer;
+			mColorBaseLayers[attachmentIdx] = desc.color[i].baseLayer;
+			mColorImages[attachmentIdx] = desc.color[i].image;
 
 
 			VkAttachmentReference& ref = colorReferences[attachmentIdx];
 			VkAttachmentReference& ref = colorReferences[attachmentIdx];
 			ref.attachment = attachmentIdx;
 			ref.attachment = attachmentIdx;
@@ -71,6 +74,7 @@ namespace bs
 			attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 			attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
 
 
 			mDepthBaseLayer = desc.depth.baseLayer;
 			mDepthBaseLayer = desc.depth.baseLayer;
+			mDepthStencilImage = desc.depth.image;
 
 
 			VkAttachmentReference& ref = depthReference;
 			VkAttachmentReference& ref = depthReference;
 			ref.attachment = attachmentIdx;
 			ref.attachment = attachmentIdx;

+ 20 - 10
Source/BansheeVulkanRenderAPI/Source/BsVulkanRenderTexture.cpp

@@ -39,13 +39,18 @@ namespace bs
 			const SPtr<TextureView>& view = mColorSurfaces[i];
 			const SPtr<TextureView>& view = mColorSurfaces[i];
 			VulkanTextureCore* texture = static_cast<VulkanTextureCore*>(view->getTexture().get());
 			VulkanTextureCore* texture = static_cast<VulkanTextureCore*>(view->getTexture().get());
 
 
+			VulkanImage* image = texture->getResource(mDeviceIdx);
+			if (image == nullptr)
+				continue;
+
 			TextureSurface surface;
 			TextureSurface surface;
 			surface.arraySlice = view->getFirstArraySlice();
 			surface.arraySlice = view->getFirstArraySlice();
 			surface.numArraySlices = view->getNumArraySlices();
 			surface.numArraySlices = view->getNumArraySlices();
 			surface.mipLevel = view->getMostDetailedMip();
 			surface.mipLevel = view->getMostDetailedMip();
 			surface.numMipLevels = view->getNumMips();
 			surface.numMipLevels = view->getNumMips();
 
 
-			fbDesc.color[i].view = texture->getView(mDeviceIdx, surface);
+			fbDesc.color[i].image = image;
+			fbDesc.color[i].view = image->getView(surface);
 			fbDesc.color[i].format = VulkanUtility::getPixelFormat(texture->getProperties().getFormat());
 			fbDesc.color[i].format = VulkanUtility::getPixelFormat(texture->getProperties().getFormat());
 			fbDesc.color[i].baseLayer = view->getFirstArraySlice();
 			fbDesc.color[i].baseLayer = view->getFirstArraySlice();
 		}
 		}
@@ -55,15 +60,20 @@ namespace bs
 			const SPtr<TextureView>& view = mDepthStencilSurface;
 			const SPtr<TextureView>& view = mDepthStencilSurface;
 			VulkanTextureCore* texture = static_cast<VulkanTextureCore*>(view->getTexture().get());
 			VulkanTextureCore* texture = static_cast<VulkanTextureCore*>(view->getTexture().get());
 
 
-			TextureSurface surface;
-			surface.arraySlice = view->getFirstArraySlice();
-			surface.numArraySlices = view->getNumArraySlices();
-			surface.mipLevel = view->getMostDetailedMip();
-			surface.numMipLevels = view->getNumMips();
-
-			fbDesc.depth.view = texture->getView(mDeviceIdx, surface);
-			fbDesc.depth.format = VulkanUtility::getPixelFormat(texture->getProperties().getFormat());
-			fbDesc.depth.baseLayer = view->getFirstArraySlice();
+			VulkanImage* image = texture->getResource(mDeviceIdx);
+			if (image != nullptr)
+			{
+				TextureSurface surface;
+				surface.arraySlice = view->getFirstArraySlice();
+				surface.numArraySlices = view->getNumArraySlices();
+				surface.mipLevel = view->getMostDetailedMip();
+				surface.numMipLevels = view->getNumMips();
+
+				fbDesc.depth.image = image;
+				fbDesc.depth.view = image->getView(surface);
+				fbDesc.depth.format = VulkanUtility::getPixelFormat(texture->getProperties().getFormat());
+				fbDesc.depth.baseLayer = view->getFirstArraySlice();
+			}
 		}
 		}
 
 
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());

+ 34 - 57
Source/BansheeVulkanRenderAPI/Source/BsVulkanSwapChain.cpp

@@ -1,6 +1,7 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsVulkanSwapChain.h"
 #include "BsVulkanSwapChain.h"
+#include "BsVulkanTexture.h"
 #include "BsVulkanRenderAPI.h"
 #include "BsVulkanRenderAPI.h"
 #include "BsVulkanDevice.h"
 #include "BsVulkanDevice.h"
 
 
@@ -119,32 +120,25 @@ namespace bs
 		result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images);
 		result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images);
 		assert(result == VK_SUCCESS);
 		assert(result == VK_SUCCESS);
 
 
+		VulkanResourceManager& resManager = device->getResourceManager();
+
+		VULKAN_IMAGE_DESC imageDesc;
+		imageDesc.isDepthStencil = false;
+		imageDesc.format = colorFormat;
+		imageDesc.type = TEX_TYPE_2D;
+		imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED;
+		imageDesc.numFaces = 1;
+		imageDesc.numMipLevels = 1;
+		imageDesc.memory = VK_NULL_HANDLE;
+
 		mSurfaces.resize(numImages);
 		mSurfaces.resize(numImages);
 		for (UINT32 i = 0; i < numImages; i++)
 		for (UINT32 i = 0; i < numImages; i++)
 		{
 		{
-			VkImageViewCreateInfo colorViewCI;
-			colorViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-			colorViewCI.pNext = nullptr;
-			colorViewCI.flags = 0;
-			colorViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
-			colorViewCI.image = images[i];
-			colorViewCI.format = colorFormat;
-			colorViewCI.components = {
-				VK_COMPONENT_SWIZZLE_R,
-				VK_COMPONENT_SWIZZLE_G,
-				VK_COMPONENT_SWIZZLE_B,
-				VK_COMPONENT_SWIZZLE_A
-			};
-			colorViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-			colorViewCI.subresourceRange.baseMipLevel = 0;
-			colorViewCI.subresourceRange.levelCount = 1;
-			colorViewCI.subresourceRange.baseArrayLayer = 0;
-			colorViewCI.subresourceRange.layerCount = 1;
-			
+			imageDesc.image = images[i];
+
 			mSurfaces[i].acquired = false;
 			mSurfaces[i].acquired = false;
-			mSurfaces[i].image = images[i];
-			result = vkCreateImageView(logicalDevice, &colorViewCI, gVulkanAllocator, &mSurfaces[i].view);
-			assert(result == VK_SUCCESS);
+			mSurfaces[i].image = resManager.create<VulkanImage>(imageDesc, false);
+			mSurfaces[i].view = mSurfaces[i].image->getView();
 
 
 			VkSemaphoreCreateInfo semaphoreCI;
 			VkSemaphoreCreateInfo semaphoreCI;
 			semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
 			semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -177,42 +171,24 @@ namespace bs
 			depthStencilImageCI.pQueueFamilyIndices = nullptr;
 			depthStencilImageCI.pQueueFamilyIndices = nullptr;
 			depthStencilImageCI.queueFamilyIndexCount = 0;
 			depthStencilImageCI.queueFamilyIndexCount = 0;
 
 
-			result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &mDepthStencilImage);
+			VkImage depthStencilImage;
+			result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &depthStencilImage);
 			assert(result == VK_SUCCESS);
 			assert(result == VK_SUCCESS);
 
 
-			mDepthStencilMemory = mDevice->allocateMemory(mDepthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
-			VkImageViewCreateInfo depthStencilViewCI;
-			depthStencilViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-			depthStencilViewCI.pNext = nullptr;
-			depthStencilViewCI.flags = 0;
-			depthStencilViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
-			depthStencilViewCI.image = mDepthStencilImage;
-			depthStencilViewCI.format = depthFormat;
-			depthStencilViewCI.components = {
-				VK_COMPONENT_SWIZZLE_R,
-				VK_COMPONENT_SWIZZLE_G,
-				VK_COMPONENT_SWIZZLE_B,
-				VK_COMPONENT_SWIZZLE_A
-			};
-			depthStencilViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
-			depthStencilViewCI.subresourceRange.baseMipLevel = 0;
-			depthStencilViewCI.subresourceRange.levelCount = 1;
-			depthStencilViewCI.subresourceRange.baseArrayLayer = 0;
-			depthStencilViewCI.subresourceRange.layerCount = 1;
-
-			result = vkCreateImageView(logicalDevice, &depthStencilViewCI, gVulkanAllocator, &mDepthStencilView);
-			assert(result == VK_SUCCESS);
+			imageDesc.image = depthStencilImage;
+			imageDesc.isDepthStencil = true;
+			imageDesc.format = depthFormat;
+			imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+			mDepthStencilImage = resManager.create<VulkanImage>(imageDesc, true);
+			mDepthStencilView = mDepthStencilImage->getView();
 		}
 		}
 		else
 		else
 		{
 		{
-			mDepthStencilImage = VK_NULL_HANDLE;
+			mDepthStencilImage = nullptr;
 			mDepthStencilView = VK_NULL_HANDLE;
 			mDepthStencilView = VK_NULL_HANDLE;
-			mDepthStencilMemory = VK_NULL_HANDLE;
 		}
 		}
 
 
-		VulkanResourceManager& resManager = device->getResourceManager();
-
 		// Create a framebuffer for each swap chain buffer
 		// Create a framebuffer for each swap chain buffer
 		UINT32 numFramebuffers = (UINT32)mSurfaces.size();
 		UINT32 numFramebuffers = (UINT32)mSurfaces.size();
 		for (UINT32 i = 0; i < numFramebuffers; i++)
 		for (UINT32 i = 0; i < numFramebuffers; i++)
@@ -225,9 +201,11 @@ namespace bs
 			desc.numSamples = 1;
 			desc.numSamples = 1;
 			desc.offscreen = false;
 			desc.offscreen = false;
 			desc.color[0].format = colorFormat;
 			desc.color[0].format = colorFormat;
+			desc.color[0].image = mSurfaces[i].image;
 			desc.color[0].view = mSurfaces[i].view;
 			desc.color[0].view = mSurfaces[i].view;
 			desc.color[0].baseLayer = 0;
 			desc.color[0].baseLayer = 0;
 			desc.depth.format = depthFormat;
 			desc.depth.format = depthFormat;
+			desc.depth.image = mDepthStencilImage;
 			desc.depth.view = mDepthStencilView;
 			desc.depth.view = mDepthStencilView;
 			desc.depth.baseLayer = 0;
 			desc.depth.baseLayer = 0;
 
 
@@ -295,20 +273,19 @@ namespace bs
 				surface.framebuffer->destroy();
 				surface.framebuffer->destroy();
 				surface.framebuffer = nullptr;
 				surface.framebuffer = nullptr;
 
 
+				surface.image->destroy();
+				surface.image = nullptr;
+
 				vkDestroySemaphore(logicalDevice, surface.sync, gVulkanAllocator);
 				vkDestroySemaphore(logicalDevice, surface.sync, gVulkanAllocator);
-				vkDestroyImageView(logicalDevice, surface.view, gVulkanAllocator);
 			}
 			}
 
 
 			vkDestroySwapchainKHR(logicalDevice, swapChain, gVulkanAllocator);
 			vkDestroySwapchainKHR(logicalDevice, swapChain, gVulkanAllocator);
 		}
 		}
 
 
-		if (mDepthStencilImage != VK_NULL_HANDLE)
+		if (mDepthStencilImage != nullptr)
 		{
 		{
-			vkDestroyImageView(logicalDevice, mDepthStencilView, gVulkanAllocator);
-			vkDestroyImage(logicalDevice, mDepthStencilImage, gVulkanAllocator);
-
-			mDevice->freeMemory(mDepthStencilMemory);
-			mDepthStencilImage = VK_NULL_HANDLE;
+			mDepthStencilImage->destroy();
+			mDepthStencilImage = nullptr;
 		}
 		}
 	}
 	}
 }
 }

+ 32 - 12
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -12,15 +12,35 @@
 
 
 namespace bs
 namespace bs
 {
 {
+	VULKAN_IMAGE_DESC createDesc(VkImage image, VkDeviceMemory memory, VkImageLayout layout, const TextureProperties& props)
+	{
+		VULKAN_IMAGE_DESC desc;
+		desc.image = image;
+		desc.memory = memory;
+		desc.type = props.getTextureType();
+		desc.format = VulkanUtility::getPixelFormat(props.getFormat());
+		desc.numFaces = props.getNumFaces();
+		desc.numMipLevels = props.getNumMipmaps() + 1;
+		desc.isDepthStencil = (props.getUsage() & TU_DEPTHSTENCIL) != 0;
+		desc.layout = layout;
+
+		return desc;
+	}
+
 	VulkanImage::VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout,
 	VulkanImage::VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout,
-							 const TextureProperties& props)
-		: VulkanResource(owner, false), mImage(image), mMemory(memory), mLayout(layout)
+							 const TextureProperties& props, bool ownsImage)
+		: VulkanImage(owner, createDesc(image, memory, layout, props), ownsImage)
+	{ }
+
+	VulkanImage::VulkanImage(VulkanResourceManager* owner, const VULKAN_IMAGE_DESC& desc, bool ownsImage)
+		: VulkanResource(owner, false), mImage(desc.image), mMemory(desc.memory), mLayout(desc.layout)
+		, mOwnsImage(ownsImage), mNumFaces(desc.numFaces), mNumMipLevels(desc.numMipLevels)
 	{
 	{
 		mImageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 		mImageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
 		mImageViewCI.pNext = nullptr;
 		mImageViewCI.pNext = nullptr;
 		mImageViewCI.flags = 0;
 		mImageViewCI.flags = 0;
-		mImageViewCI.image = image;
-		mImageViewCI.format = VulkanUtility::getPixelFormat(props.getFormat());
+		mImageViewCI.image = desc.image;
+		mImageViewCI.format = desc.format;
 		mImageViewCI.components = {
 		mImageViewCI.components = {
 			VK_COMPONENT_SWIZZLE_R,
 			VK_COMPONENT_SWIZZLE_R,
 			VK_COMPONENT_SWIZZLE_G,
 			VK_COMPONENT_SWIZZLE_G,
@@ -28,7 +48,7 @@ namespace bs
 			VK_COMPONENT_SWIZZLE_A
 			VK_COMPONENT_SWIZZLE_A
 		};
 		};
 
 
-		switch (props.getTextureType())
+		switch (desc.type)
 		{
 		{
 		case TEX_TYPE_1D:
 		case TEX_TYPE_1D:
 			mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D;
 			mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D;
@@ -45,17 +65,14 @@ namespace bs
 			break;
 			break;
 		}
 		}
 
 
-		if ((props.getUsage() & TU_DEPTHSTENCIL) != 0)
+		if (desc.isDepthStencil)
 			mImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
 			mImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
 		else
 		else
 			mImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 			mImageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 
 
-		TextureSurface completeSurface(0, props.getNumMipmaps() + 1, 0, props.getNumArraySlices());
+		TextureSurface completeSurface(0, desc.numMipLevels, 0, desc.numFaces);
 		mMainView = createView(completeSurface);
 		mMainView = createView(completeSurface);
 
 
-		mNumFaces = props.getNumFaces();
-		mNumMipLevels = props.getNumMipmaps();
-
 		UINT32 numSubresources = mNumFaces * mNumMipLevels;
 		UINT32 numSubresources = mNumFaces * mNumMipLevels;
 		mSubresources = (VulkanImageSubresource**)bs_alloc<VulkanImageSubresource*>(numSubresources);
 		mSubresources = (VulkanImageSubresource**)bs_alloc<VulkanImageSubresource*>(numSubresources);
 		for (UINT32 i = 0; i < numSubresources; i++)
 		for (UINT32 i = 0; i < numSubresources; i++)
@@ -80,8 +97,11 @@ namespace bs
 		for(auto& entry : mImageInfos)
 		for(auto& entry : mImageInfos)
 			vkDestroyImageView(vkDevice, entry.view, gVulkanAllocator);
 			vkDestroyImageView(vkDevice, entry.view, gVulkanAllocator);
 
 
-		vkDestroyImage(vkDevice, mImage, gVulkanAllocator);
-		device.freeMemory(mMemory);
+		if (mOwnsImage)
+		{
+			vkDestroyImage(vkDevice, mImage, gVulkanAllocator);
+			device.freeMemory(mMemory);
+		}
 	}
 	}
 
 
 	VkImageView VulkanImage::getView(const TextureSurface& surface) const
 	VkImageView VulkanImage::getView(const TextureSurface& surface) const