Bläddra i källkod

More Vulkan fixes

BearishSun 9 år sedan
förälder
incheckning
1b4349927e

+ 1 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanQueue.h

@@ -46,6 +46,7 @@ namespace bs
 		VkQueue mQueue;
 		GpuQueueType mType;
 		UINT32 mIndex;
+		VkPipelineStageFlags mSubmitDstWaitMask[BS_MAX_UNIQUE_QUEUES];
 
 		VulkanCmdBuffer* mLastCommandBuffer;
 	};

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

@@ -343,7 +343,7 @@ namespace bs
 				continue;
 
 			UINT32 currentQueueFamily = resource->getQueueFamily();
-			if (currentQueueFamily != mQueueFamily)
+			if (currentQueueFamily != -1 && currentQueueFamily != mQueueFamily)
 			{
 				Vector<VkBufferMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].bufferBarriers;
 
@@ -367,7 +367,7 @@ namespace bs
 			ImageInfo& imageInfo = mImageInfos[entry.second];
 
 			UINT32 currentQueueFamily = resource->getQueueFamily();
-			bool queueMismatch = resource->isExclusive() && currentQueueFamily != mQueueFamily;
+			bool queueMismatch = resource->isExclusive() && currentQueueFamily != -1 && currentQueueFamily != mQueueFamily;
 
 			if (queueMismatch || imageInfo.currentLayout != imageInfo.requiredLayout)
 			{

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

@@ -10,7 +10,7 @@
 namespace bs
 {
 	VulkanLayoutKey::VulkanLayoutKey(VkDescriptorSetLayoutBinding* bindings, UINT32 numBindings)
-		:bindings(bindings), numBindings(numBindings)
+		:bindings(bindings), numBindings(numBindings), layout(nullptr)
 	{ }
 
 	bool VulkanLayoutKey::operator==(const VulkanLayoutKey& rhs) const

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

@@ -54,7 +54,7 @@ namespace bs
 		UINT32 numDevices = 0;
 		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
-			if (devices != nullptr)
+			if (devices[i] != nullptr)
 				numDevices++;
 		}
 

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

@@ -27,7 +27,7 @@ namespace bs
 		UINT32 numDevices = 0;
 		for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
 		{
-			if (devices != nullptr)
+			if (devices[i] != nullptr)
 				numDevices++;
 		}
 

+ 6 - 3
Source/BansheeVulkanRenderAPI/Source/BsVulkanGpuProgram.cpp

@@ -10,6 +10,8 @@
 #include "BsVertexDeclaration.h"
 #include "BsHardwareBufferManager.h"
 #include "BsRenderStats.h"
+#include "BsFileSystem.h"
+#include "BsDataStream.h"
 
 #include "glslang/Public/ShaderLang.h"
 #include "glslang/Include/Types.h"
@@ -598,12 +600,13 @@ namespace bs
 			goto cleanup;
 		}
 
+		program->mapIO();
+		program->buildReflection();
+
 		// Compile to SPIR-V
 		GlslangToSpv(*program->getIntermediate(glslType), spirv, &logger);
 
 		// Parse uniforms
-		program->buildReflection();
-
 		if(!parseUniforms(program, *mParametersDesc, mCompileError))
 		{
 			mIsCompiled = false;
@@ -629,7 +632,7 @@ namespace bs
 		moduleCI.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
 		moduleCI.pNext = nullptr;
 		moduleCI.flags = 0;
-		moduleCI.codeSize = spirv.size();
+		moduleCI.codeSize = spirv.size() * sizeof(UINT32);
 		moduleCI.pCode = spirv.data();
 
 		VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPICore::instance());

+ 9 - 12
Source/BansheeVulkanRenderAPI/Source/BsVulkanHardwareBuffer.cpp

@@ -293,14 +293,10 @@ namespace bs
 				return buffer->map(offset, length);
 			}
 
-			// No GPU writes are are supported and we're only reading, so no need to wait on anything
-			if (options == GBL_READ_ONLY && !mSupportsGPUWrites)
-				return buffer->map(offset, length);
-
-			// We need to read the buffer contents with GPU writes potentially enabled
+			// We need to read the buffer contents
 			if(options == GBL_READ_ONLY || options == GBL_READ_WRITE)
 			{
-				// We need to wait until (potential) GPU read/write completes
+				// We need to wait until (potential) read/write operations complete
 				VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
 
 				// Ensure flush() will wait for all queues currently using to the buffer (if any) to finish
@@ -330,9 +326,9 @@ namespace bs
 				// Submit the command buffer and wait until it finishes
 				transferCB->flush(true);
 
-				// If some CB has an operation queued that will be using the current contents of the buffer, create a new 
-				// buffer so we don't modify the previous use of the buffer
-				if (buffer->isBound())
+				// If writing and some CB has an operation queued that will be using the current contents of the buffer, 
+				// create a new  buffer so we don't modify the previous use of the buffer
+				if (options == GBL_READ_WRITE && buffer->isBound())
 				{
 					VulkanBuffer* newBuffer = createBuffer(device, mSize, false, true);
 
@@ -380,11 +376,12 @@ namespace bs
 		{
 			VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
 				
-			// Similar to above, if buffer supports GPU writes, we need to wait on any potential writes to complete
-			if(mSupportsGPUWrites)
+			// Similar to above, if buffer supports GPU writes or is currently being written to, we need to wait on any
+			// potential writes to complete
+			UINT32 writeUseMask = buffer->getUseInfo(VulkanUseFlag::Write);
+			if(mSupportsGPUWrites || writeUseMask != 0)
 			{
 				// Ensure flush() will wait for all queues currently writing to the buffer (if any) to finish
-				UINT32 writeUseMask = buffer->getUseInfo(VulkanUseFlag::Write);
 				transferCB->appendMask(writeUseMask);
 			}
 

+ 11 - 2
Source/BansheeVulkanRenderAPI/Source/BsVulkanQueue.cpp

@@ -7,7 +7,10 @@ namespace bs
 {
 	VulkanQueue::VulkanQueue(VulkanDevice& device, VkQueue queue, GpuQueueType type, UINT32 index)
 		:mDevice(device), mQueue(queue), mType(type), mIndex(index), mLastCommandBuffer(nullptr)
-	{ }
+	{
+		for (UINT32 i = 0; i < BS_MAX_UNIQUE_QUEUES; i++)
+			mSubmitDstWaitMask[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+	}
 
 	bool VulkanQueue::isExecuting() const
 	{
@@ -25,16 +28,22 @@ namespace bs
 		VkSubmitInfo submitInfo;
 		submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
 		submitInfo.pNext = nullptr;
-		submitInfo.pWaitDstStageMask = 0;
 		submitInfo.commandBufferCount = 1;
 		submitInfo.pCommandBuffers = &vkCmdBuffer;
 		submitInfo.signalSemaphoreCount = 1;
 		submitInfo.pSignalSemaphores = &semaphore;
+		submitInfo.waitSemaphoreCount = semaphoresCount;
 
 		if (semaphoresCount > 0)
+		{
 			submitInfo.pWaitSemaphores = waitSemaphores;
+			submitInfo.pWaitDstStageMask = mSubmitDstWaitMask;
+		}
 		else
+		{
 			submitInfo.pWaitSemaphores = nullptr;
+			submitInfo.pWaitDstStageMask = nullptr;
+		}
 
 		VkResult result = vkQueueSubmit(mQueue, 1, &submitInfo, cmdBuffer->getFence());
 		assert(result == VK_SUCCESS);

+ 39 - 22
Source/BansheeVulkanRenderAPI/Source/BsVulkanResource.cpp

@@ -39,7 +39,6 @@ namespace bs
 	void VulkanResource::notifyUsed(UINT32 globalQueueIdx, UINT32 queueFamily, VulkanUseFlags useFlags)
 	{
 		Lock lock(mMutex);
-		assert(mState != State::Destroyed);
 		assert(useFlags != VulkanUseFlag::None);
 
 		if(isUsed() && mState == State::Normal) // Used without support for concurrency
@@ -68,32 +67,44 @@ namespace bs
 
 	void VulkanResource::notifyDone(UINT32 globalQueueIdx, VulkanUseFlags useFlags)
 	{
-		Lock lock(mMutex);
-		mNumUsedHandles--;
-		mNumBoundHandles--;
-
-		if (useFlags.isSet(VulkanUseFlag::Read))
+		bool destroy;
 		{
-			assert(mReadUses[globalQueueIdx] > 0);
-			mReadUses[globalQueueIdx]--;
-		}
+			Lock lock(mMutex);
+			mNumUsedHandles--;
+			mNumBoundHandles--;
 
-		if (useFlags.isSet(VulkanUseFlag::Write))
-		{
-			assert(mWriteUses[globalQueueIdx] > 0);
-			mWriteUses[globalQueueIdx]--;
+			if (useFlags.isSet(VulkanUseFlag::Read))
+			{
+				assert(mReadUses[globalQueueIdx] > 0);
+				mReadUses[globalQueueIdx]--;
+			}
+
+			if (useFlags.isSet(VulkanUseFlag::Write))
+			{
+				assert(mWriteUses[globalQueueIdx] > 0);
+				mWriteUses[globalQueueIdx]--;
+			}
+
+			destroy = !isBound() && mState == State::Destroyed; // Queued for destruction
 		}
 
-		if (!isBound() && mState == State::Destroyed) // Queued for destruction
+		// (Safe to check outside of mutex as we guarantee that once queued for destruction, state cannot be changed)
+		if (destroy)
 			mOwner->destroy(this);
 	}
 
 	void VulkanResource::notifyUnbound()
 	{
-		Lock lock(mMutex);
-		mNumBoundHandles--;
+		bool destroy;
+		{
+			Lock lock(mMutex);
+			mNumBoundHandles--;
+
+			destroy = !isBound() && mState == State::Destroyed; // Queued for destruction
+		}
 
-		if (!isBound() && mState == State::Destroyed) // Queued for destruction
+		// (Safe to check outside of mutex as we guarantee that once queued for destruction, state cannot be changed)
+		if (destroy)
 			mOwner->destroy(this);
 	}
 
@@ -124,13 +135,19 @@ namespace bs
 
 	void VulkanResource::destroy()
 	{
-		Lock lock(mMutex);
-		assert(mState != State::Destroyed && "Vulkan resource destroy() called more than once.");
+		bool destroy;
+		{
+			Lock lock(mMutex);
+			assert(mState != State::Destroyed && "Vulkan resource destroy() called more than once.");
+
+			mState = State::Destroyed;
 
-		mState = State::Destroyed;
+			// If not bound anyhwere, destroy right away, otherwise check when it is reported as finished on the device
+			destroy = !isBound();
+		}
 
-		// If not bound anyhwere, destroy right away, otherwise check when it is reported as finished on the device
-		if (!isBound())
+		// (Safe to check outside of mutex as we guarantee that once queued for destruction, state cannot be changed)
+		if (destroy)
 			mOwner->destroy(this);
 	}
 

+ 18 - 17
Source/BansheeVulkanRenderAPI/Source/BsVulkanTexture.cpp

@@ -867,13 +867,6 @@ namespace bs
 				return lockedArea;
 			}
 
-			// No GPU writes are are supported and we're only reading, so no need to wait on anything
-			if (options == GBL_READ_ONLY)
-			{
-				image->map(face, mipLevel, lockedArea);
-				return lockedArea;
-			}
-
 			// Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
 			if (options == GBL_WRITE_ONLY_DISCARD)
 			{
@@ -887,20 +880,26 @@ namespace bs
 				return lockedArea;
 			}
 
-			// We need to both read and write, meaning we need to wait until existing reads complete before we return
-			if (options == GBL_READ_WRITE)
+			// We need to read the buffer contents
+			if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
 			{
 				VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
 
-				// Ensure flush() will wait for all queues currently reading from the texture to finish
+				// Ensure flush() will wait for all queues currently using to the texture (if any) to finish
+				// If only reading, wait for all writes to complete, otherwise wait on both writes and reads
+				if (options == GBL_READ_ONLY)
+					useMask = subresource->getUseInfo(VulkanUseFlag::Write);
+				else
+					useMask = subresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
+
 				transferCB->appendMask(useMask);
 
 				// Submit the command buffer and wait until it finishes
 				transferCB->flush(true);
 
-				// If some CB has an operation queued that will be using the current contents of the image, create a new 
-				// image so we don't modify the previous use of the image
-				if (subresource->isBound())
+				// If writing and some CB has an operation queued that will be using the current contents of the image, 
+				// create a new image so we don't modify the previous use of the image
+				if (options == GBL_READ_WRITE && subresource->isBound())
 				{
 					VulkanImage* newImage = createImage(device);
 
@@ -944,11 +943,13 @@ namespace bs
 		{
 			VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
 
-			// Similar to above, if image supports GPU writes, we need to wait on any potential writes to complete
-			if (mSupportsGPUWrites)
+			// Similar to above, if image supports GPU writes or is currently being written to, we need to wait on any
+			// potential writes to complete
+			UINT32 writeUseMask = subresource->getUseInfo(VulkanUseFlag::Write);
+
+			if (mSupportsGPUWrites || writeUseMask != 0)
 			{
 				// Ensure flush() will wait for all queues currently writing to the image (if any) to finish
-				UINT32 writeUseMask = subresource->getUseInfo(VulkanUseFlag::Write);
 				transferCB->appendMask(writeUseMask);
 			}
 
@@ -989,8 +990,8 @@ namespace bs
 			VkImageLayout dstLayout = image->getLayout();
 			if (dstLayout == VK_IMAGE_LAYOUT_UNDEFINED || dstLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
 			{
-				currentAccessMask = image->getAccessFlags(dstLayout);
 				dstLayout = getOptimalLayout();
+				currentAccessMask = image->getAccessFlags(dstLayout);
 			}
 
 			transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, currentAccessMask,

+ 3 - 0
Source/BansheeVulkanRenderAPI/Source/BsVulkanUtility.cpp

@@ -237,6 +237,9 @@ namespace bs
 		case GPT_COMPUTE_PROGRAM:
 			return VK_SHADER_STAGE_COMPUTE_BIT;
 		}
+
+		// Unsupported type
+		return VK_SHADER_STAGE_VERTEX_BIT;
 	}
 
 	VkSamplerAddressMode VulkanUtility::getAddressingMode(TextureAddressingMode mode)

+ 5 - 5
Source/ExampleProject/Source/Main.cpp

@@ -148,7 +148,7 @@ namespace bs
 		HMaterial exampleMaterial = createMaterial(exampleTexture, exampleShader);
 
 		setUp3DScene(exampleModel, exampleMaterial);
-		setUpGUI();
+		//setUpGUI();
 		setUpInput();
 	}
 
@@ -261,9 +261,9 @@ namespace bs
 		
 		// Attach the Renderable component and hook up the mesh we imported earlier,
 		// and the material we created in the previous section.
-		HRenderable renderable = dragonSO->addComponent<CRenderable>();
-		renderable->setMesh(mesh);
-		renderable->setMaterial(material);
+		//HRenderable renderable = dragonSO->addComponent<CRenderable>();
+		//renderable->setMesh(mesh);
+		//renderable->setMaterial(material);
 
 		/************************************************************************/
 		/* 									CAMERA	                     		*/
@@ -415,7 +415,7 @@ namespace bs
 		elemLayout->addElement(toggleFullscreenButton);
 
 		// Add a profiler overlay object that is responsible for displaying CPU and GPU profiling GUI
-		profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->_getCamera());
+		//profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->_getCamera());
 
 		// Set up video mode list box
 		// First get a list of output devices