Browse Source

Add pipeline stats query support in GR

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
20d828f280

+ 1 - 0
AnKi/Gr.h

@@ -15,6 +15,7 @@
 #include <AnKi/Gr/CommandBuffer.h>
 #include <AnKi/Gr/OcclusionQuery.h>
 #include <AnKi/Gr/TimestampQuery.h>
+#include <AnKi/Gr/PipelineQuery.h>
 #include <AnKi/Gr/Fence.h>
 #include <AnKi/Gr/AccelerationStructure.h>
 #include <AnKi/Gr/GrManager.h>

+ 4 - 0
AnKi/Gr/CMakeLists.txt

@@ -27,6 +27,7 @@ set(common_headers
 	Texture.h
 	TextureView.h
 	TimestampQuery.h
+	PipelineQuery.h
 	GrUpscaler.h
 	Utils/StackGpuMemoryPool.h
 	Utils/Functions.h
@@ -71,6 +72,8 @@ if(VULKAN)
 		Vulkan/TextureViewImpl.cpp
 		Vulkan/TimestampQuery.cpp
 		Vulkan/TimestampQueryImpl.cpp
+		Vulkan/PipelineQueryImpl.cpp
+		Vulkan/PipelineQuery.cpp
 		Vulkan/FrameGarbageCollector.cpp
 		Vulkan/GrUpscaler.cpp
 		Vulkan/GrUpscalerImpl.cpp)
@@ -108,6 +111,7 @@ if(VULKAN)
 		Vulkan/TextureImpl.h
 		Vulkan/TextureViewImpl.h
 		Vulkan/TimestampQueryImpl.h
+		Vulkan/PipelineQueryImpl.h
 		Vulkan/GrUpscalerImpl.h)
 
 	if(ANKI_HEADLESS)

+ 17 - 0
AnKi/Gr/Common.h

@@ -94,6 +94,7 @@ ANKI_GR_CLASS(Shader)
 ANKI_GR_CLASS(Framebuffer)
 ANKI_GR_CLASS(OcclusionQuery)
 ANKI_GR_CLASS(TimestampQuery)
+ANKI_GR_CLASS(PipelineQuery)
 ANKI_GR_CLASS(ShaderProgram)
 ANKI_GR_CLASS(Fence)
 ANKI_GR_CLASS(RenderGraph)
@@ -220,6 +221,9 @@ public:
 
 	/// Mesh shaders.
 	Bool m_meshShaders = false;
+
+	/// Can create PipelineQuery objects.
+	Bool m_pipelineQuery = false;
 };
 ANKI_END_PACKED_STRUCT
 
@@ -654,6 +658,19 @@ enum class TimestampQueryResult : U8
 	kAvailable
 };
 
+/// Pipeline query result.
+enum class PipelineQueryResult : U8
+{
+	kNotAvailable,
+	kAvailable
+};
+
+enum class PipelineQueryType : U8
+{
+	kPrimitivesPassedClipping,
+	kCount
+};
+
 /// Attachment load operation.
 enum class AttachmentLoadOperation : U8
 {

+ 1 - 0
AnKi/Gr/GrManager.h

@@ -68,6 +68,7 @@ public:
 	[[nodiscard]] FramebufferPtr newFramebuffer(const FramebufferInitInfo& init);
 	[[nodiscard]] OcclusionQueryPtr newOcclusionQuery();
 	[[nodiscard]] TimestampQueryPtr newTimestampQuery();
+	[[nodiscard]] PipelineQueryPtr newPipelineQuery(PipelineQueryType type);
 	[[nodiscard]] RenderGraphPtr newRenderGraph();
 	[[nodiscard]] GrUpscalerPtr newGrUpscaler(const GrUpscalerInitInfo& init);
 	[[nodiscard]] AccelerationStructurePtr newAccelerationStructure(const AccelerationStructureInitInfo& init);

+ 1 - 0
AnKi/Gr/GrObject.h

@@ -21,6 +21,7 @@ enum class GrObjectType : U8
 	kFramebuffer,
 	kOcclusionQuery,
 	kTimstampQuery,
+	kPipelineQuery,
 	kSampler,
 	kShader,
 	kTexture,

+ 44 - 0
AnKi/Gr/PipelineQuery.h

@@ -0,0 +1,44 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Gr/GrObject.h>
+
+namespace anki {
+
+/// @addtogroup graphics
+/// @{
+
+/// Query of various pipeline statistics.
+class PipelineQuery : public GrObject
+{
+	ANKI_GR_OBJECT
+
+public:
+	static constexpr GrObjectType kClassType = GrObjectType::kPipelineQuery;
+
+	/// Get the occlusion query result. It won't block.
+	PipelineQueryResult getResult(U64& value) const;
+
+protected:
+	/// Construct.
+	PipelineQuery(CString name)
+		: GrObject(kClassType, name)
+	{
+	}
+
+	/// Destroy.
+	~PipelineQuery()
+	{
+	}
+
+private:
+	/// Allocate and initialize a new instance.
+	[[nodiscard]] static PipelineQuery* newInstance(PipelineQueryType type);
+};
+/// @}
+
+} // end namespace anki

+ 11 - 0
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -175,6 +175,11 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 
 	m_occlusionQueryFactory.init(VK_QUERY_TYPE_OCCLUSION);
 	m_timestampQueryFactory.init(VK_QUERY_TYPE_TIMESTAMP);
+	if(m_capabilities.m_pipelineQuery)
+	{
+		m_pipelineQueryFactories[PipelineQueryType::kPrimitivesPassedClipping].init(VK_QUERY_TYPE_PIPELINE_STATISTICS,
+																					VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT);
+	}
 
 	// See if unaligned formats are supported
 	{
@@ -830,6 +835,12 @@ Error GrManagerImpl::initDevice()
 		devFeatures.robustBufferAccess = (g_validationCVar.get() && devFeatures.robustBufferAccess) ? true : false;
 		ANKI_VK_LOGI("Robust buffer access is %s", (devFeatures.robustBufferAccess) ? "enabled" : "disabled");
 
+		if(devFeatures.pipelineStatisticsQuery)
+		{
+			m_capabilities.m_pipelineQuery = true;
+			ANKI_VK_LOGV("GPU supports pipeline statistics queries");
+		}
+
 		ci.pEnabledFeatures = &devFeatures;
 	}
 

+ 7 - 0
AnKi/Gr/Vulkan/GrManagerImpl.h

@@ -136,6 +136,12 @@ public:
 		return m_timestampQueryFactory;
 	}
 
+	QueryFactory& getPipelineQueryFactory(PipelineQueryType type)
+	{
+		ANKI_ASSERT(m_capabilities.m_pipelineQuery);
+		return m_pipelineQueryFactories[type];
+	}
+
 	DescriptorSetFactory& getDescriptorSetFactory()
 	{
 		return m_descrFactory;
@@ -283,6 +289,7 @@ private:
 
 	QueryFactory m_occlusionQueryFactory;
 	QueryFactory m_timestampQueryFactory;
+	Array<QueryFactory, U32(PipelineQueryType::kCount)> m_pipelineQueryFactories;
 
 	PipelineCache m_pplineCache;
 

+ 29 - 0
AnKi/Gr/Vulkan/PipelineQuery.cpp

@@ -0,0 +1,29 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Gr/PipelineQuery.h>
+#include <AnKi/Gr/Vulkan/PipelineQueryImpl.h>
+#include <AnKi/Gr/GrManager.h>
+
+namespace anki {
+
+PipelineQuery* PipelineQuery::newInstance(PipelineQueryType type)
+{
+	PipelineQueryImpl* impl = anki::newInstance<PipelineQueryImpl>(GrMemoryPool::getSingleton(), "N/A");
+	const Error err = impl->init(type);
+	if(err)
+	{
+		deleteInstance(GrMemoryPool::getSingleton(), impl);
+		impl = nullptr;
+	}
+	return impl;
+}
+
+PipelineQueryResult PipelineQuery::getResult(U64& value) const
+{
+	return static_cast<const PipelineQueryImpl*>(this)->getResultInternal(value);
+}
+
+} // end namespace anki

+ 54 - 0
AnKi/Gr/Vulkan/PipelineQueryImpl.cpp

@@ -0,0 +1,54 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Gr/Vulkan/PipelineQueryImpl.h>
+#include <AnKi/Gr/Vulkan/GrManagerImpl.h>
+
+namespace anki {
+
+PipelineQueryImpl::~PipelineQueryImpl()
+{
+	if(m_handle)
+	{
+		getGrManagerImpl().getPipelineQueryFactory(m_type).deleteQuery(m_handle);
+	}
+}
+
+Error PipelineQueryImpl::init(PipelineQueryType type)
+{
+	ANKI_ASSERT(type < PipelineQueryType::kCount);
+	m_type = type;
+	ANKI_CHECK(getGrManagerImpl().getPipelineQueryFactory(type).newQuery(m_handle));
+	return Error::kNone;
+}
+
+PipelineQueryResult PipelineQueryImpl::getResultInternal(U64& value) const
+{
+	ANKI_ASSERT(m_handle);
+	value = kMaxU64;
+
+	VkResult res;
+	ANKI_VK_CHECKF(res = vkGetQueryPoolResults(getVkDevice(), m_handle.getQueryPool(), m_handle.getQueryIndex(), 1, sizeof(value), &value,
+											   sizeof(value), VK_QUERY_RESULT_64_BIT));
+
+	PipelineQueryResult qout = PipelineQueryResult::kNotAvailable;
+	if(res == VK_SUCCESS)
+	{
+		qout = PipelineQueryResult::kAvailable;
+	}
+	else if(res == VK_NOT_READY)
+	{
+		value = kMaxU64;
+		qout = PipelineQueryResult::kNotAvailable;
+	}
+	else
+	{
+		ANKI_ASSERT(0);
+	}
+
+	return qout;
+}
+
+} // end namespace anki

+ 39 - 0
AnKi/Gr/Vulkan/PipelineQueryImpl.h

@@ -0,0 +1,39 @@
+// Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Gr/PipelineQuery.h>
+#include <AnKi/Gr/Vulkan/QueryFactory.h>
+
+namespace anki {
+
+/// @addtogroup vulkan
+/// @{
+
+/// Pipeline query.
+class PipelineQueryImpl final : public PipelineQuery
+{
+public:
+	MicroQuery m_handle = {};
+
+	PipelineQueryType m_type = PipelineQueryType::kCount;
+
+	PipelineQueryImpl(CString name)
+		: PipelineQuery(name)
+	{
+	}
+
+	~PipelineQueryImpl();
+
+	/// Create the query.
+	Error init(PipelineQueryType type);
+
+	/// Get query result.
+	PipelineQueryResult getResultInternal(U64& value) const;
+};
+/// @}
+
+} // end namespace anki

+ 1 - 0
AnKi/Gr/Vulkan/QueryFactory.cpp

@@ -50,6 +50,7 @@ Error QueryFactory::newQuery(MicroQuery& handle)
 		ci.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
 		ci.queryType = m_poolType;
 		ci.queryCount = kMaxSuballocationsPerQueryChunk;
+		ci.pipelineStatistics = m_pplineStatisticsFlags;
 
 		ANKI_VK_CHECK(vkCreateQueryPool(getVkDevice(), &ci, nullptr, &chunk->m_pool));
 		m_chunks.pushBack(chunk);

+ 3 - 1
AnKi/Gr/Vulkan/QueryFactory.h

@@ -74,9 +74,10 @@ public:
 
 	QueryFactory& operator=(const QueryFactory&) = delete; // Non-copyable
 
-	void init(VkQueryType poolType)
+	void init(VkQueryType poolType, VkQueryPipelineStatisticFlags pplineStatisticsFlags = 0)
 	{
 		m_poolType = poolType;
+		m_pplineStatisticsFlags = pplineStatisticsFlags;
 	}
 
 	/// @note It's thread-safe.
@@ -91,6 +92,7 @@ private:
 	IntrusiveList<Chunk> m_chunks;
 	Mutex m_mtx;
 	VkQueryType m_poolType = VK_QUERY_TYPE_MAX_ENUM;
+	VkQueryPipelineStatisticFlags m_pplineStatisticsFlags = 0;
 };
 /// @}