فهرست منبع

Vulkan queries can now be interrupted by command buffer submission, in order to match the behaviour of DX11 and OpenGL queries and make them more intuitive to use

BearishSun 8 سال پیش
والد
کامیت
dd43fd4a65

+ 14 - 0
Source/BansheeVulkanRenderAPI/Include/BsVulkanCommandBuffer.h

@@ -10,7 +10,10 @@
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
+	class VulkanOcclusionQuery;
+	class VulkanTimerQuery;
 	class VulkanImage;
 	class VulkanImage;
+
 	/** @addtogroup Vulkan
 	/** @addtogroup Vulkan
 	 *  @{
 	 *  @{
 	 */
 	 */
@@ -235,6 +238,12 @@ namespace bs { namespace ct
 		 */
 		 */
 		void registerResource(VulkanFramebuffer* res, RenderSurfaceMask loadMask, VulkanUseFlags flags);
 		void registerResource(VulkanFramebuffer* res, RenderSurfaceMask loadMask, VulkanUseFlags flags);
 
 
+		/** Notifies the command buffer that the provided query has been queued on it. */
+		void registerQuery(VulkanOcclusionQuery* query) { mOcclusionQueries.insert(query); }
+
+		/** Notifies the command buffer that the provided query has been queued on it. */
+		void registerQuery(VulkanTimerQuery* query) { mTimerQueries.insert(query); }
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								COMMANDS	                     		*/
 		/* 								COMMANDS	                     		*/
 		/************************************************************************/
 		/************************************************************************/
@@ -431,6 +440,9 @@ namespace bs { namespace ct
 		/** Finds a subresource info structure containing the specified face and mip level of the provided image. */
 		/** Finds a subresource info structure containing the specified face and mip level of the provided image. */
 		ImageSubresourceInfo& findSubresourceInfo(VulkanImage* image, UINT32 face, UINT32 mip);
 		ImageSubresourceInfo& findSubresourceInfo(VulkanImage* image, UINT32 face, UINT32 mip);
 
 
+		/** Gets all queries registered on this command buffer that haven't been ended. */
+		void getInProgressQueries(Vector<VulkanTimerQuery*>& timer, Vector<VulkanOcclusionQuery*>& occlusion) const;
+
 		UINT32 mId;
 		UINT32 mId;
 		UINT32 mQueueFamily;
 		UINT32 mQueueFamily;
 		State mState;
 		State mState;
@@ -452,6 +464,8 @@ namespace bs { namespace ct
 		UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
 		UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
 		UnorderedMap<VulkanResource*, UINT32> mImages;
 		UnorderedMap<VulkanResource*, UINT32> mImages;
 		UnorderedMap<VulkanResource*, BufferInfo> mBuffers;
 		UnorderedMap<VulkanResource*, BufferInfo> mBuffers;
+		UnorderedSet<VulkanOcclusionQuery*> mOcclusionQueries;
+		UnorderedSet<VulkanTimerQuery*> mTimerQueries;
 		Vector<ImageInfo> mImageInfos;
 		Vector<ImageInfo> mImageInfos;
 		Vector<ImageSubresourceInfo> mSubresourceInfos;
 		Vector<ImageSubresourceInfo> mSubresourceInfos;
 		UINT32 mGlobalQueueIdx;
 		UINT32 mGlobalQueueIdx;

+ 14 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanOcclusionQuery.h

@@ -30,15 +30,28 @@ namespace bs { namespace ct
 		/** @copydoc OcclusionQuery::getNumSamples */
 		/** @copydoc OcclusionQuery::getNumSamples */
 		UINT32 getNumSamples() override;
 		UINT32 getNumSamples() override;
 
 
+		/** Returns true if the query begin() was called, but not end(). */
+		bool _isInProgress() const;
+
+		/**
+		 * Interrupts an in-progress query, allowing the command buffer to submitted. Interrupted queries must be resumed
+		 * using _resume().
+		 */
+		void _interrupt(VulkanCmdBuffer& cb);
+
+		/** Resumes an interrupted query, restoring it back to its original in-progress state. */
+		void _resume(VulkanCmdBuffer& cb);
+
 	private:
 	private:
 		friend class QueryManager;
 		friend class QueryManager;
 
 
 		VulkanDevice& mDevice;
 		VulkanDevice& mDevice;
-		VulkanQuery* mQuery;
+		Vector<VulkanQuery*> mQueries;
 
 
 		UINT64 mNumSamples;
 		UINT64 mNumSamples;
 		bool mQueryEndCalled : 1;
 		bool mQueryEndCalled : 1;
 		bool mQueryFinalized : 1;
 		bool mQueryFinalized : 1;
+		bool mQueryInterrupted : 1;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 14 - 2
Source/BansheeVulkanRenderAPI/Include/BsVulkanTimerQuery.h

@@ -30,14 +30,26 @@ namespace bs { namespace ct
 		/** @copydoc TimerQuery::getTimeMs */
 		/** @copydoc TimerQuery::getTimeMs */
 		float getTimeMs() override;
 		float getTimeMs() override;
 
 
+		/** Returns true if the query begin() was called, but not end(). */
+		bool _isInProgress() const;
+
+		/**
+		* Interrupts an in-progress query, allowing the command buffer to submitted. Interrupted queries must be resumed
+		* using _resume().
+		*/
+		void _interrupt(VulkanCmdBuffer& cb);
+
+		/** Resumes an interrupted query, restoring it back to its original in-progress state. */
+		void _resume(VulkanCmdBuffer& cb);
+
 	private:
 	private:
 		VulkanDevice& mDevice;
 		VulkanDevice& mDevice;
-		VulkanQuery* mBeginQuery;
-		VulkanQuery* mEndQuery;
+		Vector < std::pair<VulkanQuery*, VulkanQuery*>> mQueries;
 
 
 		float mTimeDelta;
 		float mTimeDelta;
 		bool mQueryEndCalled : 1;
 		bool mQueryEndCalled : 1;
 		bool mQueryFinalized : 1;
 		bool mQueryFinalized : 1;
+		bool mQueryInterrupted : 1;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 42 - 5
Source/BansheeVulkanRenderAPI/Source/BsVulkanCommandBuffer.cpp

@@ -15,6 +15,8 @@
 #include "BsVulkanEventQuery.h"
 #include "BsVulkanEventQuery.h"
 #include "BsVulkanQueryManager.h"
 #include "BsVulkanQueryManager.h"
 #include "BsVulkanSwapChain.h"
 #include "BsVulkanSwapChain.h"
+#include "BsVulkanTimerQuery.h"
+#include "BsVulkanOcclusionQuery.h"
 
 
 #if BS_PLATFORM == BS_PLATFORM_WIN32
 #if BS_PLATFORM == BS_PLATFORM_WIN32
 #include "Win32/BsWin32RenderWindow.h"
 #include "Win32/BsWin32RenderWindow.h"
@@ -766,6 +768,8 @@ namespace bs { namespace ct
 		mResources.clear();
 		mResources.clear();
 		mImages.clear();
 		mImages.clear();
 		mBuffers.clear();
 		mBuffers.clear();
+		mOcclusionQueries.clear();
+		mTimerQueries.clear();
 		mImageInfos.clear();
 		mImageInfos.clear();
 		mSubresourceInfos.clear();
 		mSubresourceInfos.clear();
 	}
 	}
@@ -2030,6 +2034,21 @@ namespace bs { namespace ct
 		return subresourceInfos[0];
 		return subresourceInfos[0];
 	}
 	}
 
 
+	void VulkanCmdBuffer::getInProgressQueries(Vector<VulkanTimerQuery*>& timer, Vector<VulkanOcclusionQuery*>& occlusion) const
+	{
+		for(auto& query : mTimerQueries)
+		{
+			if (query->_isInProgress())
+				timer.push_back(query);
+		}
+
+		for (auto& query : mOcclusionQueries)
+		{
+			if (query->_isInProgress())
+				occlusion.push_back(query);
+		}
+	}
+
 	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)
@@ -2075,15 +2094,33 @@ namespace bs { namespace ct
 		// Execute any queued layout transitions that weren't already handled by the render pass
 		// Execute any queued layout transitions that weren't already handled by the render pass
 		mBuffer->executeLayoutTransitions();
 		mBuffer->executeLayoutTransitions();
 
 
+		// Interrupt any in-progress queries (no in-progress queries allowed during command buffer submit)
+		Vector<VulkanTimerQuery*> timerQueries;
+		Vector<VulkanOcclusionQuery*> occlusionQueries;
+		mBuffer->getInProgressQueries(timerQueries, occlusionQueries);
+
+		for (auto& query : timerQueries)
+			query->_interrupt(*mBuffer);
+
+		for (auto& query : occlusionQueries)
+			query->_interrupt(*mBuffer);
+
 		if (mBuffer->isRecording())
 		if (mBuffer->isRecording())
 			mBuffer->end();
 			mBuffer->end();
 
 
-		if (!mBuffer->isReadyForSubmit()) // Possibly nothing was recorded in the buffer
-			return;
+		if (mBuffer->isReadyForSubmit()) // Possibly nothing was recorded in the buffer
+		{
+			mBuffer->submit(mQueue, mQueueIdx, syncMask);
+			acquireNewBuffer();
 
 
-		mBuffer->submit(mQueue, mQueueIdx, syncMask);
-		acquireNewBuffer();
+			gVulkanCBManager().refreshStates(mDeviceIdx);
+		}
+
+		// Resume interrupted queries on the new command buffer
+		for (auto& query : timerQueries)
+			query->_resume(*mBuffer);
 
 
-		gVulkanCBManager().refreshStates(mDeviceIdx);
+		for (auto& query : occlusionQueries)
+			query->_resume(*mBuffer);
 	}
 	}
 }}
 }}

+ 67 - 19
Source/BansheeVulkanRenderAPI/Source/BsVulkanOcclusionQuery.cpp

@@ -10,16 +10,18 @@
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	VulkanOcclusionQuery::VulkanOcclusionQuery(VulkanDevice& device, bool binary)
 	VulkanOcclusionQuery::VulkanOcclusionQuery(VulkanDevice& device, bool binary)
-		: OcclusionQuery(binary), mDevice(device), mQuery(nullptr), mNumSamples(0), mQueryEndCalled(false)
-		, mQueryFinalized(false)
+		: OcclusionQuery(binary), mDevice(device), mNumSamples(0), mQueryEndCalled(false), mQueryFinalized(false)
+		, mQueryInterrupted(false)
 	{
 	{
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 	}
 
 
 	VulkanOcclusionQuery::~VulkanOcclusionQuery()
 	VulkanOcclusionQuery::~VulkanOcclusionQuery()
 	{
 	{
-		if (mQuery != nullptr)
-			mDevice.getQueryPool().releaseQuery(mQuery);
+		for(auto& query : mQueries)
+			mDevice.getQueryPool().releaseQuery(query);
+
+		mQueries.clear();
 
 
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 	}
@@ -28,12 +30,11 @@ namespace bs { namespace ct
 	{
 	{
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 
 
-		// Clear any existing query
-		if (mQuery != nullptr)
-		{
-			queryPool.releaseQuery(mQuery);
-			mQuery = nullptr;
-		}
+		// Clear any existing queries
+		for (auto& query : mQueries)
+			mDevice.getQueryPool().releaseQuery(query);
+
+		mQueries.clear();
 
 
 		mQueryEndCalled = false;
 		mQueryEndCalled = false;
 		mNumSamples = 0;
 		mNumSamples = 0;
@@ -46,14 +47,17 @@ namespace bs { namespace ct
 			vulkanCB = static_cast<VulkanCommandBuffer*>(gVulkanRenderAPI()._getMainCommandBuffer());
 			vulkanCB = static_cast<VulkanCommandBuffer*>(gVulkanRenderAPI()._getMainCommandBuffer());
 
 
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
-		mQuery = queryPool.beginOcclusionQuery(internalCB, !mBinary);
+		mQueries.push_back(queryPool.beginOcclusionQuery(internalCB, !mBinary));
+		internalCB->registerQuery(this);
 
 
 		setActive(true);
 		setActive(true);
 	}
 	}
 
 
 	void VulkanOcclusionQuery::end(const SPtr<CommandBuffer>& cb)
 	void VulkanOcclusionQuery::end(const SPtr<CommandBuffer>& cb)
 	{
 	{
-		if(mQuery == nullptr)
+		assert(!mQueryInterrupted);
+
+		if(mQueries.size() == 0)
 		{
 		{
 			LOGERR("end() called but query was never started.");
 			LOGERR("end() called but query was never started.");
 			return;
 			return;
@@ -70,7 +74,33 @@ namespace bs { namespace ct
 
 
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
-		queryPool.endOcclusionQuery(mQuery, internalCB);
+		queryPool.endOcclusionQuery(mQueries.back(), internalCB);
+	}
+
+	bool VulkanOcclusionQuery::_isInProgress() const
+	{
+		return !mQueries.empty() && !mQueryEndCalled;
+	}
+
+	void VulkanOcclusionQuery::_interrupt(VulkanCmdBuffer& cb)
+	{
+		assert(mQueries.size() != 0 && !mQueryEndCalled);
+
+		VulkanQueryPool& queryPool = mDevice.getQueryPool();
+		queryPool.endOcclusionQuery(mQueries.back(), &cb);
+
+		mQueryInterrupted = true;
+	}
+
+	void VulkanOcclusionQuery::_resume(VulkanCmdBuffer& cb)
+	{
+		assert(mQueryInterrupted);
+
+		VulkanQueryPool& queryPool = mDevice.getQueryPool();
+		mQueries.push_back(queryPool.beginOcclusionQuery(&cb, !mBinary));
+		cb.registerQuery(this);
+
+		mQueryInterrupted = false;
 	}
 	}
 
 
 	bool VulkanOcclusionQuery::isReady() const
 	bool VulkanOcclusionQuery::isReady() const
@@ -82,25 +112,43 @@ namespace bs { namespace ct
 			return true;
 			return true;
 
 
 		UINT64 numSamples;
 		UINT64 numSamples;
-		return !mQuery->isBound() && mQuery->getResult(numSamples);
+		bool ready = true;
+		for (auto& query : mQueries)
+			ready &= !query->isBound() && query->getResult(numSamples);
+
+		return ready;
 	}
 	}
 
 
 	UINT32 VulkanOcclusionQuery::getNumSamples()
 	UINT32 VulkanOcclusionQuery::getNumSamples()
 	{
 	{
 		if(!mQueryFinalized)
 		if(!mQueryFinalized)
 		{
 		{
-			UINT64 numSamples;
-			if(!mQuery->isBound() && mQuery->getResult(numSamples))
+			UINT64 totalNumSamples = 0;
+			bool ready = true;
+			for (auto& query : mQueries)
+			{
+				UINT64 numSamples;
+				ready &= !query->isBound() && query->getResult(numSamples);
+
+				totalNumSamples += numSamples;
+			}
+
+			if(ready)
 			{
 			{
 				mQueryFinalized = true;
 				mQueryFinalized = true;
-				mNumSamples = numSamples;
+				mNumSamples = totalNumSamples;
 
 
 				VulkanQueryPool& queryPool = mDevice.getQueryPool();
 				VulkanQueryPool& queryPool = mDevice.getQueryPool();
-				queryPool.releaseQuery(mQuery);
-				mQuery = nullptr;
+				for (auto& query : mQueries)
+					queryPool.releaseQuery(query);
+
+				mQueries.clear();
 			}
 			}
 		}
 		}
 
 
+		if (mBinary)
+			return mNumSamples == 0 ? 0 : 1;
+
 		return (UINT32)mNumSamples;
 		return (UINT32)mNumSamples;
 	}
 	}
 }}
 }}

+ 85 - 35
Source/BansheeVulkanRenderAPI/Source/BsVulkanTimerQuery.cpp

@@ -10,19 +10,23 @@
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	VulkanTimerQuery::VulkanTimerQuery(VulkanDevice& device)
 	VulkanTimerQuery::VulkanTimerQuery(VulkanDevice& device)
-		: mDevice(device), mBeginQuery(nullptr), mEndQuery(nullptr), mTimeDelta(0.0f), mQueryEndCalled(false)
-		, mQueryFinalized(false)
+		: mDevice(device), mTimeDelta(0.0f), mQueryEndCalled(false), mQueryFinalized(false), mQueryInterrupted(false)
 	{
 	{
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 	}
 
 
 	VulkanTimerQuery::~VulkanTimerQuery()
 	VulkanTimerQuery::~VulkanTimerQuery()
 	{
 	{
-		if (mBeginQuery != nullptr)
-			mDevice.getQueryPool().releaseQuery(mBeginQuery);
+		for (auto& query : mQueries)
+		{
+			if(query.first != nullptr)
+				mDevice.getQueryPool().releaseQuery(query.first);
+
+			if (query.second != nullptr)
+				mDevice.getQueryPool().releaseQuery(query.second);
+		}
 
 
-		if (mEndQuery != nullptr)
-			mDevice.getQueryPool().releaseQuery(mEndQuery);
+		mQueries.clear();
 
 
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 	}
@@ -32,18 +36,17 @@ namespace bs { namespace ct
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 
 
 		// Clear any existing queries
 		// Clear any existing queries
-		if (mBeginQuery != nullptr)
+		for (auto& query : mQueries)
 		{
 		{
-			queryPool.releaseQuery(mBeginQuery);
-			mBeginQuery = nullptr;
-		}
+			if (query.first != nullptr)
+				queryPool.releaseQuery(query.first);
 
 
-		if (mEndQuery != nullptr)
-		{
-			queryPool.releaseQuery(mEndQuery);
-			mEndQuery = nullptr;
+			if (query.second != nullptr)
+				queryPool.releaseQuery(query.second);
 		}
 		}
 
 
+		mQueries.clear();
+
 		mQueryEndCalled = false;
 		mQueryEndCalled = false;
 		mTimeDelta = 0.0f;
 		mTimeDelta = 0.0f;
 
 
@@ -55,14 +58,19 @@ namespace bs { namespace ct
 			vulkanCB = static_cast<VulkanCommandBuffer*>(gVulkanRenderAPI()._getMainCommandBuffer());
 			vulkanCB = static_cast<VulkanCommandBuffer*>(gVulkanRenderAPI()._getMainCommandBuffer());
 
 
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
-		mBeginQuery = queryPool.beginTimerQuery(internalCB);
+		VulkanQuery* beginQuery = queryPool.beginTimerQuery(internalCB);
+		internalCB->registerQuery(this);
+
+		mQueries.push_back(std::make_pair(beginQuery, nullptr));
 
 
 		setActive(true);
 		setActive(true);
 	}
 	}
 
 
 	void VulkanTimerQuery::end(const SPtr<CommandBuffer>& cb)
 	void VulkanTimerQuery::end(const SPtr<CommandBuffer>& cb)
 	{
 	{
-		if (mBeginQuery == nullptr)
+		assert(!mQueryInterrupted);
+
+		if (mQueries.empty())
 		{
 		{
 			LOGERR("end() called but query was never started.");
 			LOGERR("end() called but query was never started.");
 			return;
 			return;
@@ -79,7 +87,39 @@ namespace bs { namespace ct
 
 
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanQueryPool& queryPool = mDevice.getQueryPool();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
 		VulkanCmdBuffer* internalCB = vulkanCB->getInternal();
-		mEndQuery = queryPool.beginTimerQuery(internalCB);
+		VulkanQuery* endQuery = queryPool.beginTimerQuery(internalCB);
+		internalCB->registerQuery(this);
+
+		mQueries.back().second = endQuery;
+	}
+
+	bool VulkanTimerQuery::_isInProgress() const
+	{
+		return !mQueries.empty() && !mQueryEndCalled;
+	}
+
+	void VulkanTimerQuery::_interrupt(VulkanCmdBuffer& cb)
+	{
+		assert(mQueries.size() != 0 && !mQueryEndCalled);
+
+		VulkanQueryPool& queryPool = mDevice.getQueryPool();
+		VulkanQuery* endQuery = queryPool.beginTimerQuery(&cb);
+		cb.registerQuery(this);
+
+		mQueries.back().second = endQuery;
+		mQueryInterrupted = true;
+	}
+
+	void VulkanTimerQuery::_resume(VulkanCmdBuffer& cb)
+	{
+		assert(mQueryInterrupted);
+
+		VulkanQueryPool& queryPool = mDevice.getQueryPool();
+		VulkanQuery* beginQuery = queryPool.beginTimerQuery(&cb);
+		cb.registerQuery(this);
+
+		mQueries.push_back(std::make_pair(beginQuery, nullptr));
+		mQueryInterrupted = false;
 	}
 	}
 
 
 	bool VulkanTimerQuery::isReady() const
 	bool VulkanTimerQuery::isReady() const
@@ -90,40 +130,50 @@ namespace bs { namespace ct
 		if (mQueryFinalized)
 		if (mQueryFinalized)
 			return true;
 			return true;
 
 
-		UINT64 timeBegin;
-		bool beginReady = !mBeginQuery->isBound() && mBeginQuery->getResult(timeBegin);
-
-		UINT64 timeEnd;
-		bool endReady = !mEndQuery->isBound() && mEndQuery->getResult(timeEnd);
+		UINT64 timeBegin, timeEnd;
+		bool ready = true;
+		for (auto& entry : mQueries)
+		{
+			ready &= !entry.first->isBound() && entry.first->getResult(timeBegin);
+			ready &= !entry.second->isBound() && entry.second->getResult(timeEnd);
+		}
 
 
-		return beginReady && endReady;
+		return ready;
 	}
 	}
 
 
 	float VulkanTimerQuery::getTimeMs()
 	float VulkanTimerQuery::getTimeMs()
 	{
 	{
 		if (!mQueryFinalized)
 		if (!mQueryFinalized)
 		{
 		{
-			UINT64 timeBegin;
-			bool beginReady = !mBeginQuery->isBound() && mBeginQuery->getResult(timeBegin);
+			UINT64 totalTimeDiff = 0;
+			bool ready = true;
+			for (auto& entry : mQueries)
+			{
+				UINT64 timeBegin, timeEnd;
+				ready &= !entry.first->isBound() && entry.first->getResult(timeBegin);
+				ready &= !entry.second->isBound() && entry.second->getResult(timeEnd);
 
 
-			UINT64 timeEnd;
-			bool endReady = !mEndQuery->isBound() && mEndQuery->getResult(timeEnd);
+				totalTimeDiff += (timeEnd - timeBegin);
+			}
 
 
-			if (beginReady && endReady)
+			if (ready)
 			{
 			{
 				mQueryFinalized = true;
 				mQueryFinalized = true;
 
 
-				UINT64 timeDiff = timeEnd - timeBegin;
 				double timestampToMs = (double)mDevice.getDeviceProperties().limits.timestampPeriod / 1e6; // Nano to milli
 				double timestampToMs = (double)mDevice.getDeviceProperties().limits.timestampPeriod / 1e6; // Nano to milli
-
-				mTimeDelta = (float)((double)timeDiff * timestampToMs);
+				mTimeDelta = (float)((double)totalTimeDiff * timestampToMs);
 
 
 				VulkanQueryPool& queryPool = mDevice.getQueryPool();
 				VulkanQueryPool& queryPool = mDevice.getQueryPool();
-				queryPool.releaseQuery(mBeginQuery);
-				mBeginQuery = nullptr;
+				for (auto& query : mQueries)
+				{
+					if (query.first != nullptr)
+						queryPool.releaseQuery(query.first);
+
+					if (query.second != nullptr)
+						queryPool.releaseQuery(query.second);
+				}
 
 
-				queryPool.releaseQuery(mEndQuery);
-				mEndQuery = nullptr;
+				mQueries.clear();
 			}
 			}
 		}
 		}