Browse Source

[BUGFIX] Vulkan fixes. Fix render graph barrier merge

Panagiotis Christopoulos Charitos 8 năm trước cách đây
mục cha
commit
c7fe0542fd

+ 2 - 1
src/anki/gr/CommandBuffer.h

@@ -306,7 +306,8 @@ public:
 
 	void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
 
-	/// Generate mipmaps for non-3D textures.
+	/// Generate mipmaps for non-3D textures. You have to transition all the mip levels of this face and layer to
+	/// TextureUsageBit::GENERATE_MIPMAPS before calling this method.
 	/// @param tex The texture to generate mips.
 	/// @param face The face of a cube texture or zero.
 	/// @param layer The layer of an array texture or zero.

+ 5 - 0
src/anki/gr/Common.h

@@ -155,6 +155,11 @@ public:
 		return m_level == b.m_level && m_depth == b.m_depth && m_face == b.m_face && m_layer == b.m_layer;
 	}
 
+	Bool operator!=(const TextureSurfaceInfo& b) const
+	{
+		return !(*this == b);
+	}
+
 	U64 computeHash() const
 	{
 		return anki::computeHash(this, sizeof(*this), 0x1234567);

+ 3 - 3
src/anki/gr/GrObjectCache.cpp

@@ -11,10 +11,10 @@ namespace anki
 GrObjectCache::~GrObjectCache()
 {
 	// Some GrObjects may be in flight but someone destroys the cache. Do a manual destruction of the map
-	for(auto it : m_map)
+	while(!m_map.isEmpty())
 	{
-		GrObject* ptr = it;
-		unregisterObject(ptr);
+		auto it = m_map.getBegin();
+		unregisterObject(*it);
 	}
 }
 

+ 102 - 66
src/anki/gr/RenderGraph.cpp

@@ -688,6 +688,84 @@ void RenderGraph::initBatches()
 	}
 }
 
+void RenderGraph::setTextureBarrier(Batch& batch,
+	const RenderPassDescriptionBase& pass,
+	const RenderPassDependency& consumer,
+	BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64>& rtHasBarrierMask,
+	const RenderGraphDescription& descr,
+	BakeContext& ctx) const
+{
+	ANKI_ASSERT(consumer.m_isTexture);
+
+	const StackAllocator<U8>& alloc = ctx.m_alloc;
+
+	const U32 rtIdx = consumer.m_texture.m_handle.m_idx;
+	const TextureUsageBit consumerUsage = consumer.m_texture.m_usage;
+	const Bool consumerWholeTex = consumer.m_texture.m_wholeTex;
+
+	Bool anySurfaceFound = false;
+	for(RT::Usage& u : ctx.m_rts[rtIdx].m_surfUsages)
+	{
+		if(!consumerWholeTex && u.m_surface != consumer.m_texture.m_surface)
+		{
+			// Not the right surface, continue
+			continue;
+		}
+
+		anySurfaceFound = true;
+
+		if(u.m_usage == consumerUsage)
+		{
+			// Surface in the correct usage, continue
+			continue;
+		}
+
+		// Check if we can merge barriers
+		const Bool rtHasBarrier = rtHasBarrierMask.get(rtIdx);
+		Barrier* barrierToMergeTo = nullptr;
+		if(rtHasBarrier)
+		{
+			for(Barrier& b : batch.m_barriersBefore)
+			{
+				if(b.m_isTexture && b.m_texture.m_idx == rtIdx && b.m_texture.m_surface == u.m_surface)
+				{
+					barrierToMergeTo = &b;
+					break;
+				}
+			}
+		}
+
+		if(barrierToMergeTo == nullptr)
+		{
+			// RT hasn't had a barrier in this batch, add a new one
+			batch.m_barriersBefore.emplaceBack(
+				alloc, consumer.m_texture.m_handle.m_idx, u.m_usage, consumerUsage, u.m_surface);
+
+			u.m_usage = consumer.m_texture.m_usage;
+			rtHasBarrierMask.set(rtIdx);
+		}
+		else
+		{
+			// RT already in a barrier, merge the 2 barriers
+
+			ANKI_ASSERT(!!barrierToMergeTo->m_texture.m_usageAfter);
+			ANKI_ASSERT(!!u.m_usage);
+			barrierToMergeTo->m_texture.m_usageAfter |= consumerUsage;
+			u.m_usage |= consumerUsage;
+		}
+	} // end for
+
+	// Create the transition from the initial state
+	if(!anySurfaceFound && descr.m_renderTargets[rtIdx].m_usage != consumerUsage)
+	{
+		batch.m_barriersBefore.emplaceBack(
+			alloc, rtIdx, descr.m_renderTargets[rtIdx].m_usage, consumerUsage, consumer.m_texture.m_surface);
+
+		RT::Usage usage{consumerUsage, consumer.m_texture.m_surface};
+		ctx.m_rts[rtIdx].m_surfUsages.emplaceBack(alloc, usage);
+	}
+}
+
 void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr, BakeContext& ctx) const
 {
 	const StackAllocator<U8>& alloc = ctx.m_alloc;
@@ -708,71 +786,7 @@ void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr, BakeCont
 			{
 				if(consumer.m_isTexture)
 				{
-					const U32 rtIdx = consumer.m_texture.m_handle.m_idx;
-					const TextureUsageBit consumerUsage = consumer.m_texture.m_usage;
-
-					Bool anySurfaceFound = false;
-					const Bool consumerWholeTex = consumer.m_texture.m_wholeTex;
-					for(RT::Usage& u : ctx.m_rts[rtIdx].m_surfUsages)
-					{
-						if(consumerWholeTex || u.m_surface == consumer.m_texture.m_surface)
-						{
-							anySurfaceFound = true;
-
-							// Check if we might need a new barrier
-							if(u.m_usage != consumerUsage)
-							{
-								const Bool rtHasBarrier = rtHasBarrierMask.get(rtIdx);
-
-								if(!rtHasBarrier)
-								{
-									// RT hasn't had a barrier in this batch, add a new barrier
-
-									batch.m_barriersBefore.emplaceBack(alloc,
-										consumer.m_texture.m_handle.m_idx,
-										u.m_usage,
-										consumerUsage,
-										u.m_surface);
-
-									u.m_usage = consumer.m_texture.m_usage;
-									rtHasBarrierMask.set(rtIdx);
-								}
-								else
-								{
-									// RT already in a barrier, merge the 2 barriers
-
-									Barrier* barrierToMergeTo = nullptr;
-									for(Barrier& b : batch.m_barriersBefore)
-									{
-										if(b.m_isTexture && b.m_texture.m_idx == rtIdx)
-										{
-											barrierToMergeTo = &b;
-											break;
-										}
-									}
-
-									ANKI_ASSERT(barrierToMergeTo);
-									ANKI_ASSERT(!!barrierToMergeTo->m_texture.m_usageAfter);
-									ANKI_ASSERT(!!u.m_usage);
-									barrierToMergeTo->m_texture.m_usageAfter |= consumerUsage;
-									u.m_usage |= consumerUsage;
-								}
-							}
-						}
-					}
-
-					// Create the transition from the initial state
-					if(!anySurfaceFound && descr.m_renderTargets[rtIdx].m_usage != consumerUsage)
-					{
-						batch.m_barriersBefore.emplaceBack(alloc,
-							rtIdx,
-							descr.m_renderTargets[rtIdx].m_usage,
-							consumerUsage,
-							consumer.m_texture.m_surface);
-
-						RT::Usage usage{consumerUsage, consumer.m_texture.m_surface};
-						ctx.m_rts[rtIdx].m_surfUsages.emplaceBack(alloc, usage);
-					}
+					setTextureBarrier(batch, pass, consumer, rtHasBarrierMask, descr, ctx);
 				}
 				else
 				{
@@ -825,7 +839,29 @@ void RenderGraph::setBatchBarriers(const RenderGraphDescription& descr, BakeCont
 				const U aidx = (a.m_isTexture) ? a.m_texture.m_idx : a.m_buffer.m_idx;
 				const U bidx = (b.m_isTexture) ? b.m_texture.m_idx : b.m_buffer.m_idx;
 
-				return aidx < bidx;
+				if(aidx == bidx && a.m_isTexture && b.m_isTexture)
+				{
+					if(a.m_texture.m_surface.m_level != b.m_texture.m_surface.m_level)
+					{
+						return a.m_texture.m_surface.m_level < b.m_texture.m_surface.m_level;
+					}
+					else if(a.m_texture.m_surface.m_face != b.m_texture.m_surface.m_face)
+					{
+						return a.m_texture.m_surface.m_face < b.m_texture.m_surface.m_face;
+					}
+					else if(a.m_texture.m_surface.m_layer != b.m_texture.m_surface.m_layer)
+					{
+						return a.m_texture.m_surface.m_layer < b.m_texture.m_surface.m_layer;
+					}
+					else
+					{
+						return false;
+					}
+				}
+				else
+				{
+					return aidx < bidx;
+				}
 			});
 #endif
 	} // For all batches

+ 7 - 0
src/anki/gr/RenderGraph.h

@@ -686,6 +686,13 @@ private:
 
 	static Bool passHasUnmetDependencies(const BakeContext& ctx, U32 passIdx);
 
+	void setTextureBarrier(Batch& batch,
+		const RenderPassDescriptionBase& pass,
+		const RenderPassDependency& consumer,
+		BitSet<MAX_RENDER_GRAPH_RENDER_TARGETS, U64>& rtHasBarrierMask,
+		const RenderGraphDescription& descr,
+		BakeContext& ctx) const;
+
 	void getCrntUsageAndAspect(
 		RenderTargetHandle handle, U32 passIdx, TextureUsageBit& usage, DepthStencilAspectBit& aspect) const;
 	void getCrntUsageAndAspect(RenderTargetHandle handle,

+ 3 - 3
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -151,10 +151,10 @@ inline void CommandBufferImpl::setTextureBarrierRange(
 inline void CommandBufferImpl::setTextureSurfaceBarrier(
 	TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage, const TextureSurfaceInfo& surf)
 {
-	if(surf.m_level > 0)
+	if(ANKI_UNLIKELY(surf.m_level > 0 && nextUsage == TextureUsageBit::GENERATE_MIPMAPS))
 	{
-		ANKI_ASSERT(!(nextUsage & TextureUsageBit::GENERATE_MIPMAPS)
-			&& "This transition happens inside CommandBufferImpl::generateMipmapsX");
+		// This transition happens inside CommandBufferImpl::generateMipmapsX. No need to do something
+		return;
 	}
 
 	const TextureImpl& impl = *tex->m_impl;

+ 62 - 33
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -17,31 +17,6 @@
 namespace anki
 {
 
-static VkBool32 debugReportCallbackEXT(VkDebugReportFlagsEXT flags,
-	VkDebugReportObjectTypeEXT objectType,
-	uint64_t object,
-	size_t location,
-	int32_t messageCode,
-	const char* pLayerPrefix,
-	const char* pMessage,
-	void* pUserData)
-{
-	if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
-	{
-		ANKI_VK_LOGE("%s", pMessage);
-	}
-	else if(flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT))
-	{
-		ANKI_VK_LOGW("%s", pMessage);
-	}
-	else
-	{
-		ANKI_VK_LOGI("%s", pMessage);
-	}
-
-	return false;
-}
-
 GrManagerImpl::~GrManagerImpl()
 {
 	// FIRST THING: wait for the GPU
@@ -122,6 +97,8 @@ GrManagerImpl::~GrManagerImpl()
 
 		vkDestroyInstance(m_instance, pallocCbs);
 	}
+
+	m_vkHandleToName.destroy(getAllocator());
 }
 
 GrAllocator<U8> GrManagerImpl::getAllocator() const
@@ -396,6 +373,7 @@ Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
 		ci.pfnCallback = debugReportCallbackEXT;
 		ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT
 			| VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+		ci.pUserData = this;
 
 		PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT =
 			reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
@@ -696,7 +674,11 @@ Error GrManagerImpl::initSwapchain(const GrManagerInitInfo& init)
 		return Error::FUNCTION_FAILED;
 	}
 
-	ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u", count, presentMode);
+	ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u, size %ux%u",
+		count,
+		presentMode,
+		m_surfaceWidth,
+		m_surfaceHeight);
 
 	Array<VkImage, MAX_FRAMES_IN_FLIGHT> images;
 	ANKI_VK_CHECK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &count, &images[0]));
@@ -920,16 +902,63 @@ void GrManagerImpl::flushCommandBuffer(CommandBufferPtr cmdb, FencePtr* outFence
 
 void GrManagerImpl::trySetVulkanHandleName(CString name, VkDebugReportObjectTypeEXT type, U64 handle) const
 {
-	if(m_pfnDebugMarkerSetObjectNameEXT && name)
+	if(name)
+	{
+		if(m_pfnDebugMarkerSetObjectNameEXT)
+		{
+			VkDebugMarkerObjectNameInfoEXT inf = {};
+			inf.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
+			inf.objectType = type;
+			inf.pObjectName = name.get();
+			inf.object = handle;
+
+			m_pfnDebugMarkerSetObjectNameEXT(m_device, &inf);
+		}
+
+		LockGuard<SpinLock> lock(m_vkHandleToNameLock);
+		StringAuto newName(getAllocator());
+		newName.create(name);
+		m_vkHandleToName.emplace(getAllocator(), computeHash(&handle, sizeof(handle)), std::move(newName));
+	}
+}
+
+VkBool32 GrManagerImpl::debugReportCallbackEXT(VkDebugReportFlagsEXT flags,
+	VkDebugReportObjectTypeEXT objectType,
+	uint64_t object,
+	size_t location,
+	int32_t messageCode,
+	const char* pLayerPrefix,
+	const char* pMessage,
+	void* pUserData)
+{
+	// Get the object name
+	GrManagerImpl* self = static_cast<GrManagerImpl*>(pUserData);
+	LockGuard<SpinLock> lock(self->m_vkHandleToNameLock);
+	auto it = self->m_vkHandleToName.find(computeHash(&object, sizeof(object)));
+	CString objName;
+	if(it != self->m_vkHandleToName.getEnd())
+	{
+		objName = it->toCString();
+	}
+	else
 	{
-		VkDebugMarkerObjectNameInfoEXT inf = {};
-		inf.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
-		inf.objectType = type;
-		inf.pObjectName = name.get();
-		inf.object = handle;
+		objName = "Unnamed";
+	}
 
-		m_pfnDebugMarkerSetObjectNameEXT(m_device, &inf);
+	if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
+	{
+		ANKI_VK_LOGE("%s (handle: %s)", pMessage, objName.cstr());
 	}
+	else if(flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT))
+	{
+		ANKI_VK_LOGW("%s (handle: %s)", pMessage, objName.cstr());
+	}
+	else
+	{
+		ANKI_VK_LOGI("%s (handle: %s)", pMessage, objName.cstr());
+	}
+
+	return false;
 }
 
 } // end namespace anki

+ 12 - 0
src/anki/gr/vulkan/GrManagerImpl.h

@@ -282,6 +282,9 @@ private:
 
 	GrObjectCache* m_samplerCache = nullptr;
 
+	mutable HashMap<U64, StringAuto> m_vkHandleToName;
+	mutable SpinLock m_vkHandleToNameLock;
+
 	ANKI_USE_RESULT Error initInternal(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initInstance(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initSurface(const GrManagerInitInfo& init);
@@ -301,6 +304,15 @@ private:
 #endif
 
 	void resetFrame(PerFrame& frame);
+
+	static VkBool32 debugReportCallbackEXT(VkDebugReportFlagsEXT flags,
+		VkDebugReportObjectTypeEXT objectType,
+		uint64_t object,
+		size_t location,
+		int32_t messageCode,
+		const char* pLayerPrefix,
+		const char* pMessage,
+		void* pUserData);
 };
 /// @}
 

+ 2 - 4
src/anki/gr/vulkan/TextureImpl.cpp

@@ -131,10 +131,6 @@ Error TextureImpl::init(const TextureInitInfo& init_, Texture* tex)
 		getGrManagerImpl().flushCommandBuffer(cmdb, nullptr);
 	}
 
-#if 0
-	printf("image %s handle %p\n", (init.getName()) ? init.getName().cstr() : "-", m_imageHandle);
-#endif
-
 	return Error::NONE;
 }
 
@@ -365,6 +361,8 @@ Error TextureImpl::initImage(const TextureInitInfo& init_)
 		memAllocCi.memoryTypeIndex = memIdx;
 
 		ANKI_VK_CHECK(vkAllocateMemory(getDevice(), &memAllocCi, nullptr, &m_dedicatedMem));
+		getGrManagerImpl().trySetVulkanHandleName(
+			init.getName(), VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT, ptrToNumber(m_dedicatedMem));
 
 		ANKI_TRACE_START_EVENT(VK_BIND_OBJECT);
 		ANKI_VK_CHECK(vkBindImageMemory(getDevice(), m_imageHandle, m_dedicatedMem, 0));

+ 1 - 1
src/anki/resource/TransferGpuAllocator.h

@@ -127,7 +127,7 @@ private:
 	ConditionVariable m_condVar;
 	Array<Frame, FRAME_COUNT> m_frames;
 	U8 m_frameCount = 0;
-	PtrSize m_crntFrameAllocatedSize;
+	PtrSize m_crntFrameAllocatedSize = 0;
 };
 /// @}