Sfoglia il codice sorgente

Various Vulkan fixes and tweaks

BearishSun 9 anni fa
parent
commit
21eb8822cf

+ 2 - 2
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -159,8 +159,8 @@ namespace bs
 		 * 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.
 		 */
-		void registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout, 
-			VulkanUseFlags flags, bool isFBAttachment = false);
+		void registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout currentLayout,
+			VkImageLayout newLayout, VulkanUseFlags flags, bool isFBAttachment = false);
 
 		/** 
 		 * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the

+ 17 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanPrerequisites.h

@@ -18,6 +18,22 @@
 /** Maximum number of GPU queues that may exist at once. */
 #define BS_MAX_UNIQUE_QUEUES BS_MAX_QUEUES_PER_TYPE * bs::GQT_COUNT // Must fit within 4 bytes
 
+#if (BS_PLATFORM == BS_PLATFORM_WIN32) && !defined(__MINGW32__) && !defined(BS_STATIC_LIB)
+#	ifdef BS_VULKAN_EXPORTS
+#		define BS_VULKAN_EXPORT __declspec(dllexport)
+#	else
+#       if defined( __MINGW32__ )
+#           define BS_VULKAN_EXPORT
+#       else
+#    		define BS_VULKAN_EXPORT __declspec(dllimport)
+#       endif
+#	endif
+#elif defined (BS_GCC_VISIBILITY)
+#    define BS_VULKAN_EXPORT  __attribute__ ((visibility("default")))
+#else
+#    define BS_VULKAN_EXPORT
+#endif
+
 #include "vulkan/vulkan.h"
 
 /** @addtogroup Plugins
@@ -61,7 +77,7 @@ namespace bs
 	class VulkanQueryPool;
 	class VulkanVertexInput;
 
-	VkAllocationCallbacks* gVulkanAllocator = nullptr;
+	extern VkAllocationCallbacks* gVulkanAllocator;
 
 	/**	Vulkan specific types to track resource statistics for. */
 	enum VulkanRenderStatResourceType

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

@@ -214,7 +214,11 @@ namespace bs
 		 * are of the same size. The operation will be queued on the provided command buffer. The system assumes the 
 		 * provided image matches the current texture properties (i.e. num faces, mips, size).
 		 */
-		void copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage);
+		void copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage, 
+			VkImageLayout srcFinalLayout, VkImageLayout dstFinalLayout);
+
+		/** Returns the optimal layout this image should normally be in. */
+		VkImageLayout getOptimalLayout() const;
 
 		VulkanImage* mImages[BS_MAX_DEVICES];
 		GpuDeviceFlags mDeviceMask;

+ 15 - 14
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -63,7 +63,7 @@ namespace bs
 	VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(UINT32 queueFamily, bool secondary)
 	{
 		auto iterFind = mPools.find(queueFamily);
-		if (iterFind != mPools.end())
+		if (iterFind == mPools.end())
 			return nullptr;
 
 		VulkanCmdBuffer** buffers = iterFind->second.buffers;
@@ -93,7 +93,7 @@ namespace bs
 	VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(UINT32 queueFamily, bool secondary)
 	{
 		auto iterFind = mPools.find(queueFamily);
-		if (iterFind != mPools.end())
+		if (iterFind == mPools.end())
 			return nullptr;
 
 		const PoolInfo& poolInfo = iterFind->second;
@@ -387,8 +387,9 @@ namespace bs
 				barrier.subresourceRange = imageInfo.range;
 
 				imageInfo.currentLayout = imageInfo.requiredLayout;
-				resource->setLayout(imageInfo.finalLayout);
 			}
+
+			resource->setLayout(imageInfo.finalLayout);
 		}
 
 		VulkanDevice& device = queue->getDevice();
@@ -424,7 +425,8 @@ namespace bs
 			GpuQueueType otherQueueType = GQT_GRAPHICS;
 			for (UINT32 i = 0; i < GQT_COUNT; i++)
 			{
-				if (device.getQueueFamily((GpuQueueType)i) != entryQueueFamily)
+				otherQueueType = (GpuQueueType)i;
+				if (device.getQueueFamily(otherQueueType) != entryQueueFamily)
 					continue;
 
 				UINT32 numQueues = device.getNumQueues(otherQueueType);
@@ -446,7 +448,6 @@ namespace bs
 					otherQueueIdx = 0;
 				}
 
-				otherQueueType = (GpuQueueType)i;
 				break;
 			}
 
@@ -1133,8 +1134,8 @@ namespace bs
 		}
 	}
 
-	void VulkanCmdBuffer::registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout, 
-		VulkanUseFlags flags, bool isFBAttachment)
+	void VulkanCmdBuffer::registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout currentLayout,
+			VkImageLayout newLayout, VulkanUseFlags flags, bool isFBAttachment)
 	{
 		// Note: I currently always perform pipeline barriers (layout transitions and similar), over the entire image.
 		//       In the case of render and storage images, the case is often that only a specific subresource requires
@@ -1153,9 +1154,9 @@ namespace bs
 
 			ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
 			imageInfo.accessFlags = accessFlags;
-			imageInfo.currentLayout = res->getLayout();
-			imageInfo.requiredLayout = layout;
-			imageInfo.finalLayout = layout;
+			imageInfo.currentLayout = currentLayout;
+			imageInfo.requiredLayout = newLayout;
+			imageInfo.finalLayout = newLayout;
 			imageInfo.range = range;
 			imageInfo.isFBAttachment = isFBAttachment;
 			imageInfo.isShaderInput = !isFBAttachment;
@@ -1180,7 +1181,7 @@ namespace bs
 
 			// Check if the same image is used with different layouts, in which case we need to transfer to the general
 			// layout
-			if (imageInfo.requiredLayout != layout)
+			if (imageInfo.requiredLayout != newLayout)
 				imageInfo.requiredLayout = VK_IMAGE_LAYOUT_GENERAL;
 
 			// If attached to FB, then the final layout is set by the FB (provided as layout param here), otherwise its
@@ -1190,7 +1191,7 @@ namespace bs
 			else
 			{
 				if (isFBAttachment)
-					imageInfo.finalLayout = layout;
+					imageInfo.finalLayout = newLayout;
 			}
 
 			if (imageInfo.currentLayout != imageInfo.requiredLayout)
@@ -1282,7 +1283,7 @@ namespace bs
 		{
 			const VulkanFramebufferAttachment& attachment = res->getColorAttachment(i);
 			registerResource(attachment.image, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
-							 attachment.finalLayout, VulkanUseFlag::Write, true);
+							 attachment.image->getLayout(), attachment.finalLayout, VulkanUseFlag::Write, true);
 		}
 
 		if(res->hasDepthAttachment())
@@ -1290,7 +1291,7 @@ namespace bs
 			const VulkanFramebufferAttachment& attachment = res->getDepthStencilAttachment();
 			registerResource(attachment.image,
 							 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
-							 attachment.finalLayout, VulkanUseFlag::Write, true);
+							 attachment.image->getLayout(), attachment.finalLayout, VulkanUseFlag::Write, true);
 		}
 	}
 

+ 1 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanDevice.cpp

@@ -148,7 +148,7 @@ namespace bs
 			return 0;
 
 		UINT32 idMask = 0;
-		UINT32 curIdx = queueIdx;
+		UINT32 curIdx = queueIdx % numQueues;
 		while (curIdx < BS_MAX_QUEUES_PER_TYPE)
 		{
 			idMask |= CommandSyncMask::getGlobalQueueMask(type, curIdx);
@@ -217,8 +217,6 @@ namespace bs
 				if ((mMemoryProperties.memoryTypes[i].propertyFlags & wantedFlags) == wantedFlags)
 					return i;
 			}
-
-			requirementBits >>= 1;
 		}
 
 		return -1;

+ 2 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuParams.cpp

@@ -372,7 +372,7 @@ namespace bs
 			VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
 			VulkanUseFlags useFlags = VulkanUseFlag::Read | VulkanUseFlag::Write;
 
-			buffer.registerResource(resource, accessFlags, VK_IMAGE_LAYOUT_GENERAL, useFlags);
+			buffer.registerResource(resource, accessFlags, resource->getLayout(), VK_IMAGE_LAYOUT_GENERAL, useFlags);
 		}
 
 		for (UINT32 i = 0; i < numTextures; i++)
@@ -396,7 +396,7 @@ namespace bs
 			else
 				layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
-			buffer.registerResource(resource, VK_ACCESS_SHADER_READ_BIT, layout, VulkanUseFlag::Read);
+			buffer.registerResource(resource, VK_ACCESS_SHADER_READ_BIT, resource->getLayout(), layout, VulkanUseFlag::Read);
 		}
 
 		// Acquire sets as needed, and updated their contents if dirty

+ 12 - 5
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuProgram.cpp

@@ -256,11 +256,18 @@ namespace bs
 		{ }
 
 		/**
-		* Return true if attribute name matches the specified name and returns optional semantic index if it exists. Start
-		* of the two compared strings must match, and the remaining non-matching bit will be assumed to be the semantic
-		* index. Returns -1 if no match is made.
-		*/
-		INT32 matchesName(const String& name);
+		 * Return true if attribute name matches the specified name and returns optional semantic index if it exists. Start
+		 * of the two compared strings must match, and the remaining non-matching bit will be assumed to be the semantic
+		 * index. Returns -1 if no match is made.
+		 */
+		INT32 matchesName(const String& name) const
+		{
+			if (!StringUtil::startsWith(name, mName, false))
+				return -1;
+
+			UINT32 length = (UINT32)mName.size();
+			return parseINT32(name.substr(length));
+		}
 
 		/**	Returns the semantic of this attribute. */
 		VertexElementSemantic getSemantic() const { return mSemantic; }

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

@@ -465,6 +465,8 @@ namespace bs
 						isNormalWrite = true;
 					}
 				}
+				else
+					isNormalWrite = true;
 
 				// Check if the buffer will still be bound somewhere after the CBs using it finish
 				if (isNormalWrite)

+ 1 - 1
Source/BansheeVulkanRenderAPI/Source/BsVulkanPlugin.cpp

@@ -5,7 +5,7 @@
 
 namespace bs
 {
-	extern "C" const char* getPluginName()
+	extern "C" BS_VULKAN_EXPORT const char* getPluginName()
 	{
 		return SystemName;
 	}

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

@@ -26,6 +26,8 @@
 
 namespace bs
 {
+	VkAllocationCallbacks* gVulkanAllocator = nullptr;
+
 	PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = nullptr;
 	PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = nullptr;
 
@@ -175,22 +177,20 @@ namespace bs
 #endif
 
 		// Enumerate all devices
-		uint32_t numDevices;
-
-		result = vkEnumeratePhysicalDevices(mInstance, &numDevices, nullptr);
+		result = vkEnumeratePhysicalDevices(mInstance, &mNumDevices, nullptr);
 		assert(result == VK_SUCCESS);
 
-		Vector<VkPhysicalDevice> physicalDevices(numDevices);
-		result = vkEnumeratePhysicalDevices(mInstance, &numDevices, physicalDevices.data());
+		Vector<VkPhysicalDevice> physicalDevices(mNumDevices);
+		result = vkEnumeratePhysicalDevices(mInstance, &mNumDevices, physicalDevices.data());
 		assert(result == VK_SUCCESS);
 
-		mDevices.resize(numDevices);
-		for(uint32_t i = 0; i < numDevices; i++)
+		mDevices.resize(mNumDevices);
+		for(uint32_t i = 0; i < mNumDevices; i++)
 			mDevices[i] = bs_shared_ptr_new<VulkanDevice>(physicalDevices[i], i);
 
 		// Find primary device
 		// Note: MULTIGPU - Detect multiple similar devices here if supporting multi-GPU
-		for (uint32_t i = 0; i < numDevices; i++)
+		for (uint32_t i = 0; i < mNumDevices; i++)
 		{
 			bool isPrimary = mDevices[i]->getDeviceProperties().deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
 

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

@@ -464,7 +464,8 @@ namespace bs
 			pixelData.getRowPitch(), pixelData.getSlicePitch());
 	}
 
-	void VulkanTextureCore::copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage)
+	void VulkanTextureCore::copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage, 
+									  VkImageLayout srcFinalLayout, VkImageLayout dstFinalLayout)
 	{
 		UINT32 numFaces = mProperties.getNumFaces();
 		UINT32 numMipmaps = mProperties.getNumMipmaps() + 1;
@@ -528,16 +529,33 @@ namespace bs
 		vkCmdCopyImage(cb->getCB()->getHandle(), srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
 						dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, numMipmaps, imageRegions);
 
-		// Transfer back to original layouts
+		// Transfer back to final layouts
+		srcAccessMask = srcImage->getAccessFlags(srcFinalLayout);
 		cb->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
-							  transferSrcLayout, srcImage->getLayout(), range);
+							  transferSrcLayout, srcFinalLayout, range);
 
+		dstAccessMask = dstImage->getAccessFlags(dstFinalLayout);
 		cb->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
-							  transferDstLayout, dstImage->getLayout(), range);
+							  transferDstLayout, dstFinalLayout, range);
 
 		bs_stack_free(imageRegions);
 	}
 
+	VkImageLayout VulkanTextureCore::getOptimalLayout() const
+	{
+		int usage = getProperties().getUsage();
+		if ((usage & TU_RENDERTARGET) != 0)
+			return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+		else if ((usage & TU_DEPTHSTENCIL) != 0)
+			return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+		else if ((usage & TU_LOADSTORE) != 0)
+			return VK_IMAGE_LAYOUT_GENERAL;
+		else if ((usage & TU_DYNAMIC) != 0)
+			return VK_IMAGE_LAYOUT_GENERAL;
+		else
+			return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+	}
+
 	VkImageView VulkanTextureCore::getView(UINT32 deviceIdx) const
 	{
 		if (mImages[deviceIdx] == nullptr)
@@ -653,6 +671,9 @@ namespace bs
 			if (srcImage == nullptr || dstImage == nullptr)
 				continue;
 
+			VkImageLayout srcLayout = srcImage->getLayout();
+			VkImageLayout dstLayout = dstImage->getLayout();
+
 			VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(i, queueType, localQueueIdx);
 			VkCommandBuffer vkCmdBuf = transferCB->getCB()->getHandle();
 
@@ -669,10 +690,16 @@ namespace bs
 				// Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
 				if (dstProps.getNumMipmaps() > 0 || dstProps.getNumFaces() > 1)
 				{
-					copyImage(transferCB, dstImage, newImage);
+					VkImageLayout oldDstLayout = dstLayout;
+					if (oldDstLayout == VK_IMAGE_LAYOUT_UNDEFINED || oldDstLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+						oldDstLayout = getOptimalLayout();
+
+					dstLayout = getOptimalLayout();
+					copyImage(transferCB, dstImage, newImage, oldDstLayout, dstLayout);
 
-					VkAccessFlags accessMask = dstImage->getAccessFlags(dstImage->getLayout());
-					transferCB->getCB()->registerResource(dstImage, accessMask, dstImage->getLayout(), VulkanUseFlag::Read);
+					VkAccessFlags accessMask = dstImage->getAccessFlags(oldDstLayout);
+					transferCB->getCB()->registerResource(dstImage, accessMask, oldDstLayout, oldDstLayout,
+						VulkanUseFlag::Read);
 				}
 
 				dstImage->destroy();
@@ -680,15 +707,15 @@ namespace bs
 				mImages[i] = dstImage;
 			}
 
-			VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcImage->getLayout());
-			VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstImage->getLayout());
+			VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcLayout);
+			VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstLayout);
 
 			// Transfer textures to a valid layout
-			transferCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcImage->getLayout(),
+			transferCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcLayout,
 									transferSrcLayout, srcRange);
 
 			transferCB->setLayout(dstImage->getHandle(), dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
-									dstImage->getLayout(), transferDstLayout, dstRange);
+									dstLayout, transferDstLayout, dstRange);
 
 			if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
 			{
@@ -702,15 +729,23 @@ namespace bs
 			}
 
 			// Transfer back to original layouts
+			if (srcLayout == VK_IMAGE_LAYOUT_UNDEFINED || srcLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+				srcLayout = getOptimalLayout();
+
+			srcAccessMask = srcImage->getAccessFlags(srcLayout);
 			transferCB->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
-									transferSrcLayout, srcImage->getLayout(), srcRange);
+									transferSrcLayout, srcLayout, srcRange);
+
+			if (dstLayout == VK_IMAGE_LAYOUT_UNDEFINED || dstLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+				dstLayout = other->getOptimalLayout();
 
+			dstAccessMask = dstImage->getAccessFlags(dstLayout);
 			transferCB->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
-									transferDstLayout, dstImage->getLayout(), dstRange);
+									transferDstLayout, dstLayout, dstRange);
 
 			// Notify the command buffer that these resources are being used on it
-			transferCB->getCB()->registerResource(srcImage, srcAccessMask, srcImage->getLayout(), VulkanUseFlag::Read);
-			transferCB->getCB()->registerResource(dstImage, dstAccessMask, dstImage->getLayout(), VulkanUseFlag::Write);
+			transferCB->getCB()->registerResource(srcImage, srcAccessMask, srcLayout, srcLayout, VulkanUseFlag::Read);
+			transferCB->getCB()->registerResource(dstImage, dstAccessMask, dstLayout, dstLayout, 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
@@ -806,8 +841,8 @@ namespace bs
 						VkMemoryRequirements memReqs;
 						vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
 
-						UINT8* src = image->map(0, memReqs.size);
-						UINT8* dst = newImage->map(0, memReqs.size);
+						UINT8* src = image->map(0, (UINT32)memReqs.size);
+						UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
 
 						memcpy(dst, src, memReqs.size);
 
@@ -872,8 +907,8 @@ namespace bs
 					VkMemoryRequirements memReqs;
 					vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
 
-					UINT8* src = image->map(0, memReqs.size);
-					UINT8* dst = newImage->map(0, memReqs.size);
+					UINT8* src = image->map(0, (UINT32)memReqs.size);
+					UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
 
 					memcpy(dst, src, memReqs.size);
 
@@ -951,8 +986,16 @@ namespace bs
 			image->copy(transferCB, mStagingBuffer, extent, rangeLayers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
 
 			// Transfer back to original layout
+			VkImageLayout dstLayout = image->getLayout();
+			if (dstLayout == VK_IMAGE_LAYOUT_UNDEFINED || dstLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+			{
+				currentAccessMask = image->getAccessFlags(dstLayout);
+				dstLayout = getOptimalLayout();
+			}
+
 			transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, currentAccessMask,
-								  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image->getLayout(), range);
+								  VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstLayout, range);
+			transferCB->getCB()->registerResource(image, currentAccessMask, dstLayout, dstLayout, VulkanUseFlag::Read);
 
 			// Ensure data written to the staging buffer is visible
 			VkAccessFlags stagingAccessFlags;
@@ -1005,6 +1048,7 @@ namespace bs
 				UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(mMappedGlobalQueueIdx, queueType);
 
 				VulkanImage* image = mImages[mMappedDeviceIdx];
+				VkImageLayout curLayout = image->getLayout();
 				VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(mMappedDeviceIdx, queueType, localQueueIdx);
 
 				VulkanImageSubresource* subresource = image->getSubresource(mMappedFace, mMappedMip);
@@ -1018,12 +1062,12 @@ namespace bs
 					// Try to avoid the wait by checking for special write conditions
 
 					// Caller guarantees he won't touch the same data as the GPU, so just copy
-					if (mMappedLockOptions == GBL_WRITE_ONLY_NO_OVERWRITE) 
+					if (mMappedLockOptions == GBL_WRITE_ONLY_NO_OVERWRITE)
 					{
 						// Fall through to copy()
 					}
 					// 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)
 					{
 						// We need to discard the entire image, even though we're only writing to a single sub-resource
 						image->destroy();
@@ -1039,6 +1083,8 @@ namespace bs
 						isNormalWrite = true;
 					}
 				}
+				else
+					isNormalWrite = true;
 
 				const TextureProperties& props = getProperties();
 
@@ -1059,10 +1105,16 @@ namespace bs
 						// Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
 						if (props.getNumMipmaps() > 0 || props.getNumFaces() > 1)
 						{
-							copyImage(transferCB, image, newImage);
+							VkImageLayout oldImgLayout = image->getLayout();
+							if (oldImgLayout == VK_IMAGE_LAYOUT_UNDEFINED || oldImgLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+								oldImgLayout = getOptimalLayout();
 
-							VkAccessFlags accessMask = image->getAccessFlags(image->getLayout());
-							transferCB->getCB()->registerResource(image, accessMask, image->getLayout(), VulkanUseFlag::Read);
+							curLayout = getOptimalLayout();
+							copyImage(transferCB, image, newImage, oldImgLayout, curLayout);
+
+							VkAccessFlags accessMask = image->getAccessFlags(oldImgLayout);
+							transferCB->getCB()->registerResource(image, accessMask, oldImgLayout, oldImgLayout,
+								VulkanUseFlag::Read);
 						}
 
 						image->destroy();
@@ -1099,20 +1151,25 @@ namespace bs
 					transferLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
 
 				// Transfer texture to a valid layout
-				VkAccessFlags currentAccessMask = image->getAccessFlags(image->getLayout());
+				VkAccessFlags currentAccessMask = image->getAccessFlags(curLayout);
 				transferCB->setLayout(image->getHandle(), currentAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
-									  image->getLayout(), transferLayout, range);
+									  curLayout, transferLayout, range);
 
 				// Queue copy command
 				mStagingBuffer->copy(transferCB, image, extent, rangeLayers, transferLayout);
 
-				// Transfer back to original layout
+				// Transfer back to original  (or optimal if initial layout was undefined/preinitialized)
+				VkImageLayout dstLayout = curLayout;
+				if(dstLayout == VK_IMAGE_LAYOUT_UNDEFINED || dstLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
+					dstLayout = getOptimalLayout();
+
+				currentAccessMask = image->getAccessFlags(dstLayout);
 				transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, currentAccessMask,
-									  transferLayout, image->getLayout(), range);
+									  transferLayout, dstLayout, range);
 
 				// Notify the command buffer that these resources are being used on it
 				transferCB->getCB()->registerResource(mStagingBuffer, VK_ACCESS_TRANSFER_READ_BIT, VulkanUseFlag::Read);
-				transferCB->getCB()->registerResource(image, currentAccessMask, image->getLayout(), VulkanUseFlag::Write);
+				transferCB->getCB()->registerResource(image, currentAccessMask, dstLayout, dstLayout, VulkanUseFlag::Write);
 
 				// We don't actually flush the transfer buffer here since it's an expensive operation, but it's instead
 				// done automatically before next "normal" command buffer submission.

+ 7 - 3
Source/CMake/Modules/FindVulkan.cmake

@@ -7,7 +7,7 @@
 
 # TODO: Set default install paths for mac/unix
 # TODO: Don't hardcode the version (instead use regex or GLOB to match latest)
-set(Vulkan_INSTALL_DIRS "C:/VulkanSDK/1.0.30.0" CACHE PATH "")
+set(Vulkan_INSTALL_DIRS "C:/VulkanSDK/1.0.33.0" CACHE PATH "")
 set(Vulkan_INCLUDE_SEARCH_DIRS "${Vulkan_INSTALL_DIRS}/Include")
 
 if(BS_64BIT)
@@ -40,9 +40,13 @@ if(Vulkan_FOUND)
 	add_library(Vulkan STATIC IMPORTED)
 	set_target_properties(Vulkan PROPERTIES IMPORTED_LOCATION_DEBUG "${Vulkan_LIBRARY_DEBUG}")
 	set_target_properties(Vulkan PROPERTIES IMPORTED_LOCATION_OPTIMIZEDDEBUG "${Vulkan_LIBRARY_DEBUG}")
-	set_target_properties(Vulkan PROPERTIES IMPORTED_LOCATION_RELEASE "${Vulkan_LIBRARY_OPTIMIZED}")	
+	set_target_properties(Vulkan PROPERTIES IMPORTED_LOCATION_RELEASE "${Vulkan_LIBRARY_OPTIMIZED}")
 endif()
 
-mark_as_advanced(Vulkan_INSTALL_DIRS Vulkan_INCLUDE_DIR Vulkan_LIBRARY_OPTIMIZED Vulkan_LIBRARY_DEBUG)
+mark_as_advanced(
+	Vulkan_INSTALL_DIRS 
+	Vulkan_INCLUDE_DIR 
+	Vulkan_LIBRARY_OPTIMIZED 
+	Vulkan_LIBRARY_DEBUG)
 set(Vulkan_INCLUDE_DIRS ${Vulkan_INCLUDE_DIR})
 set(Vulkan_LIBRARIES Vulkan)