소스 검색

Small refactoring

Panagiotis Christopoulos Charitos 2 년 전
부모
커밋
9881e1a519

+ 2 - 1
AnKi/Core/StatsSet.h

@@ -38,12 +38,13 @@ enum class StatCategory : U8
 	kCpuMem,
 	kGpuMem,
 	kGpuMisc,
+	kRenderer,
 	kMisc,
 
 	kCount,
 };
 
-inline constexpr Array<CString, U32(StatCategory::kCount)> kStatCategoryTexts = {"Time", "CPU memory", "GPU memory", "GPU misc", "Misc"};
+inline constexpr Array<CString, U32(StatCategory::kCount)> kStatCategoryTexts = {"Time", "CPU memory", "GPU memory", "GPU misc", "Renderer", "Misc"};
 
 /// A stats counter.
 class StatCounter

+ 2 - 2
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -24,8 +24,8 @@ static NumericCVar<U32> g_indirectDiffuseProbeTileResolutionCVar(CVarSubsystem::
 static NumericCVar<U32> g_indirectDiffuseProbeShadowMapResolutionCVar(CVarSubsystem::kRenderer, "IndirectDiffuseProbeShadowMapResolution", 128, 4,
 																	  2048, "GI shadowmap resolution");
 
-static StatCounter g_giProbeRenderCountStatVar(StatCategory::kMisc, "GI probes rendered");
-static StatCounter g_giProbeCellsRenderCountStatVar(StatCategory::kMisc, "GI probes cells rendered");
+static StatCounter g_giProbeRenderCountStatVar(StatCategory::kRenderer, "GI probes rendered");
+static StatCounter g_giProbeCellsRenderCountStatVar(StatCategory::kRenderer, "GI probes cells rendered");
 
 static Vec3 computeCellCenter(U32 cellIdx, const GlobalIlluminationProbeComponent& probe)
 {

+ 1 - 1
AnKi/Renderer/ProbeReflections.cpp

@@ -26,7 +26,7 @@ static NumericCVar<U32> g_probeReflectionIrradianceResolutionCVar(CVarSubsystem:
 																  "Reflection probe irradiance resolution");
 static NumericCVar<U32> g_probeReflectionShadowMapResolutionCVar(CVarSubsystem::kRenderer, "ProbeReflectionShadowMapResolution", 64, 4, 2048,
 																 "Reflection probe shadow resolution");
-static StatCounter g_probeReflectionCountStatVar(StatCategory::kMisc, "Reflection probes rendered");
+static StatCounter g_probeReflectionCountStatVar(StatCategory::kRenderer, "Reflection probes rendered");
 
 Error ProbeReflections::init()
 {

+ 44 - 32
AnKi/Renderer/ShadowMapping.cpp

@@ -8,6 +8,7 @@
 #include <AnKi/Renderer/GBuffer.h>
 #include <AnKi/Renderer/PrimaryNonRenderableVisibility.h>
 #include <AnKi/Core/App.h>
+#include <AnKi/Core/StatsSet.h>
 #include <AnKi/Util/ThreadHive.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Scene/Components/LightComponent.h>
@@ -22,6 +23,8 @@ static NumericCVar<U32> g_shadowMappingTileCountPerRowOrColumnCVar(CVarSubsystem
 NumericCVar<U32> g_shadowMappingPcfCVar(CVarSubsystem::kRenderer, "ShadowMappingPcf", (ANKI_PLATFORM_MOBILE) ? 0 : 1, 0, 1,
 										"Shadow PCF (CVarSubsystem::kRenderer, 0: off, 1: on)");
 
+static StatCounter g_tilesAllocatedStatVar(StatCategory::kRenderer, "Shadow tiles (re)allocated");
+
 class LightHash
 {
 public:
@@ -175,10 +178,10 @@ void ShadowMapping::populateRenderGraph(RenderingContext& ctx)
 		// Will have to create render passes
 
 		// Compute render area
-		const U32 minx = m_runCtx.m_fullViewport[0];
-		const U32 miny = m_runCtx.m_fullViewport[1];
-		const U32 width = m_runCtx.m_fullViewport[2] - m_runCtx.m_fullViewport[0];
-		const U32 height = m_runCtx.m_fullViewport[3] - m_runCtx.m_fullViewport[1];
+		const U32 minx = m_runCtx.m_renderAreaMin.x();
+		const U32 miny = m_runCtx.m_renderAreaMin.y();
+		const U32 width = m_runCtx.m_renderAreaMax.x() - m_runCtx.m_renderAreaMin.x();
+		const U32 height = m_runCtx.m_renderAreaMax.y() - m_runCtx.m_renderAreaMin.y();
 
 		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("Shadowmapping");
 
@@ -244,20 +247,22 @@ void ShadowMapping::chooseDetail(const Vec3& cameraOrigin, const LightComponent&
 	}
 }
 
-Bool ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies, UVec4* atlasTileViewports,
-									   TileAllocatorResult2* subResults)
+TileAllocatorResult2 ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies,
+													   UVec4* atlasTileViewports)
 {
 	ANKI_ASSERT(lightUuid > 0);
 	ANKI_ASSERT(faceCount > 0);
 	ANKI_ASSERT(hierarchies);
 
+	TileAllocatorResult2 goodResult = TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached;
+
 	for(U i = 0; i < faceCount; ++i)
 	{
 		TileAllocator2::ArrayOfLightUuids kickedOutLights(&getRenderer().getFrameMemoryPool());
 
 		Array<U32, 4> tileViewport;
-		subResults[i] = m_tileAlloc.allocate(GlobalFrameIndex::getSingleton().m_value, encodeTileHash(lightUuid, componentIndex, i), 0,
-											 hierarchies[i], tileViewport, kickedOutLights);
+		const TileAllocatorResult2 result = m_tileAlloc.allocate(
+			GlobalFrameIndex::getSingleton().m_value, encodeTileHash(lightUuid, componentIndex, i), hierarchies[i], tileViewport, kickedOutLights);
 
 		for(U64 kickedLightHash : kickedOutLights)
 		{
@@ -273,7 +278,7 @@ Bool ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 fa
 			}
 		}
 
-		if(!!(subResults[i] & TileAllocatorResult2::kAllocationFailed))
+		if(!!(result & TileAllocatorResult2::kAllocationFailed))
 		{
 			ANKI_R_LOGW("There is not enough space in the shadow atlas for more shadow maps. Increase the %s or decrease the scene's shadow casters",
 						g_shadowMappingTileCountPerRowOrColumnCVar.getFullName().cstr());
@@ -281,23 +286,28 @@ Bool ShadowMapping::allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 fa
 			// Invalidate cache entries for what we already allocated
 			for(U j = 0; j < i; ++j)
 			{
-				m_tileAlloc.invalidateCache(lightUuid);
+				m_tileAlloc.invalidateCache(encodeTileHash(lightUuid, componentIndex, j));
 			}
 
-			return false;
+			return TileAllocatorResult2::kAllocationFailed;
+		}
+
+		if(!(result & TileAllocatorResult2::kTileCached))
+		{
+			g_tilesAllocatedStatVar.increment(1);
 		}
 
+		goodResult &= result;
+
 		// Set viewport
 		const UVec4 viewport = UVec4(tileViewport) * m_tileResolution;
 		atlasTileViewports[i] = viewport;
 
-		m_runCtx.m_fullViewport[0] = min(m_runCtx.m_fullViewport[0], viewport[0]);
-		m_runCtx.m_fullViewport[1] = min(m_runCtx.m_fullViewport[1], viewport[1]);
-		m_runCtx.m_fullViewport[2] = max(m_runCtx.m_fullViewport[2], viewport[0] + viewport[2]);
-		m_runCtx.m_fullViewport[3] = max(m_runCtx.m_fullViewport[3], viewport[1] + viewport[3]);
+		m_runCtx.m_renderAreaMin = m_runCtx.m_renderAreaMin.min(UVec2(viewport[0], viewport[1]));
+		m_runCtx.m_renderAreaMax = m_runCtx.m_renderAreaMax.max(UVec2(viewport[0] + viewport[2], viewport[1] + viewport[3]));
 	}
 
-	return true;
+	return goodResult;
 }
 
 template<typename TMemoryPool>
@@ -326,7 +336,8 @@ void ShadowMapping::newWorkItem(const UVec4& atlasViewport, const RenderQueue& q
 
 void ShadowMapping::processLights(RenderingContext& ctx)
 {
-	m_runCtx.m_fullViewport = UVec4(kMaxU32, kMaxU32, kMinU32, kMinU32);
+	m_runCtx.m_renderAreaMin = UVec2(kMaxU32, kMaxU32);
+	m_runCtx.m_renderAreaMax = UVec2(kMinU32, kMinU32);
 
 	// Vars
 	const Vec3 cameraOrigin = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
@@ -351,11 +362,9 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 		}
 
 		Array<UVec4, kMaxShadowCascades> atlasViewports;
-		Array<TileAllocatorResult2, kMaxShadowCascades> subResults;
-		[[maybe_unused]] const Bool allocationFailed =
-			!allocateAtlasTiles(kMaxU32, 0, cascadeCount, &hierarchies[0], &atlasViewports[0], &subResults[0]);
+		[[maybe_unused]] const TileAllocatorResult2 res = allocateAtlasTiles(kMaxU32, 0, cascadeCount, &hierarchies[0], &atlasViewports[0]);
 
-		ANKI_ASSERT(!allocationFailed && "Dir light should never fail");
+		ANKI_ASSERT(!!(res & TileAllocatorResult2::kAllocationSucceded) && "Dir light should never fail");
 
 		// Compute the view projection matrices
 		Array<F32, kMaxShadowCascades> cascadeDistances;
@@ -426,11 +435,9 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 		hierarchies.fill(hierarchy);
 
 		Array<UVec4, 6> atlasViewports;
-		Array<TileAllocatorResult2, 6> subResults;
-		const Bool allocationFailed =
-			!allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 6, &hierarchies[0], &atlasViewports[0], &subResults[0]);
+		const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 6, &hierarchies[0], &atlasViewports[0]);
 
-		if(!allocationFailed)
+		if(!!(result & TileAllocatorResult2::kAllocationSucceded))
 		{
 			// All good, update the light
 
@@ -458,7 +465,10 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 				uvViewports[face] = Vec4(uvViewportXY, Vec2(superTileSize / atlasResolution));
 			}
 
-			lightc->setShadowAtlasUvViewports(uvViewports);
+			if(!(result & TileAllocatorResult2::kTileCached))
+			{
+				lightc->setShadowAtlasUvViewports(uvViewports);
+			}
 
 			// Vis testing
 			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};
@@ -508,17 +518,19 @@ void ShadowMapping::processLights(RenderingContext& ctx)
 		// Allocate tile
 		U32 hierarchy;
 		chooseDetail(cameraOrigin, *lightc, hierarchy);
-		TileAllocatorResult2 subResult;
 		UVec4 atlasViewport;
-		const Bool allocationFailed = !allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport, &subResult);
+		const TileAllocatorResult2 result = allocateAtlasTiles(lightc->getUuid(), lightc->getArrayIndex(), 1, &hierarchy, &atlasViewport);
 
-		if(!allocationFailed)
+		if(!!(result & TileAllocatorResult2::kAllocationSucceded))
 		{
 			// All good, update the light
 
-			const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
-			const Vec4 uvViewport = Vec4(atlasViewport) / atlasResolution;
-			lightc->setShadowAtlasUvViewports({&uvViewport, 1});
+			if(!(result & TileAllocatorResult2::kTileCached))
+			{
+				const F32 atlasResolution = F32(m_tileResolution * m_tileCountBothAxis);
+				const Vec4 uvViewport = Vec4(atlasViewport) / atlasResolution;
+				lightc->setShadowAtlasUvViewports({&uvViewport, 1});
+			}
 
 			// Vis testing
 			const Array<F32, kMaxLodCount - 1> lodDistances = {g_lod0MaxDistanceCVar.get(), g_lod1MaxDistanceCVar.get()};

+ 4 - 3
AnKi/Renderer/ShadowMapping.h

@@ -58,15 +58,16 @@ private:
 	public:
 		RenderTargetHandle m_rt;
 		WeakArray<ViewportWorkItem> m_workItems;
-		UVec4 m_fullViewport; ///< Calculate the viewport that contains all of the work items. Mobile optimization.
+
+		UVec2 m_renderAreaMin; ///< Calculate the viewport that contains all of the work items. Mobile optimization.
+		UVec2 m_renderAreaMax;
 	} m_runCtx;
 
 	Error initInternal();
 
 	void processLights(RenderingContext& ctx);
 
-	Bool allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies, UVec4* atlasTileViewports,
-							TileAllocatorResult2* subResults);
+	TileAllocatorResult2 allocateAtlasTiles(U32 lightUuid, U32 componentIndex, U32 faceCount, const U32* hierarchies, UVec4* atlasTileViewports);
 
 	Mat4 createSpotLightTextureMatrix(const UVec4& viewport) const;
 

+ 2 - 2
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -16,8 +16,8 @@
 
 namespace anki {
 
-static StatCounter g_visibleObjects(StatCategory::kMisc, "Visible objects", StatFlag::kZeroEveryFrame);
-static StatCounter g_testedObjects(StatCategory::kMisc, "Visbility tested objects", StatFlag::kZeroEveryFrame);
+static StatCounter g_visibleObjects(StatCategory::kRenderer, "Visible objects", StatFlag::kZeroEveryFrame);
+static StatCounter g_testedObjects(StatCategory::kRenderer, "Visbility tested objects", StatFlag::kZeroEveryFrame);
 
 Error GpuVisibility::init()
 {

+ 0 - 360
AnKi/Renderer/Utils/TileAllocator.cpp

@@ -1,360 +0,0 @@
-// 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/Renderer/Utils/TileAllocator.h>
-
-namespace anki {
-
-class TileAllocator::Tile
-{
-public:
-	Timestamp m_lightTimestamp = 0; ///< The last timestamp the light got updated.
-	Timestamp m_lastUsedTimestamp = 0; ///< The last timestamp this tile was used.
-	U64 m_lightUuid = 0;
-	U32 m_lightDrawcallCount = 0;
-	Array<U32, 4> m_viewport = {};
-	Array<U32, 4> m_subTiles = {kMaxU32, kMaxU32, kMaxU32, kMaxU32};
-	U32 m_superTile = kMaxU32; ///< The parent.
-	U8 m_lightHierarchy = 0;
-	U8 m_lightFace = 0;
-};
-
-class TileAllocator::HashMapKey
-{
-public:
-	U64 m_lightUuid;
-	U64 m_face;
-
-	U64 computeHash() const
-	{
-		return anki::computeHash(this, sizeof(*this), 693);
-	}
-};
-
-TileAllocator::TileAllocator()
-{
-}
-
-TileAllocator::~TileAllocator()
-{
-}
-
-void TileAllocator::init(U32 tileCountX, U32 tileCountY, U32 hierarchyCount, Bool enableCaching)
-{
-	// Preconditions
-	ANKI_ASSERT(tileCountX > 0);
-	ANKI_ASSERT(tileCountY > 0);
-	ANKI_ASSERT(hierarchyCount > 0);
-
-	// Store some stuff
-	m_tileCountX = U16(tileCountX);
-	m_tileCountY = U16(tileCountY);
-	m_hierarchyCount = U8(hierarchyCount);
-	m_cachingEnabled = enableCaching;
-	m_firstTileIdxOfHierarchy.resize(hierarchyCount + 1);
-
-	// Create the tile array & index ranges
-	U32 tileCount = 0;
-	for(U32 hierarchy = 0; hierarchy < hierarchyCount; ++hierarchy)
-	{
-		const U32 hierarchyTileCountX = tileCountX >> hierarchy;
-		const U32 hierarchyTileCountY = tileCountY >> hierarchy;
-		ANKI_ASSERT((hierarchyTileCountX << hierarchy) == tileCountX && "Every hierarchy should be power of 2 of its parent hierarchy");
-		ANKI_ASSERT((hierarchyTileCountY << hierarchy) == tileCountY && "Every hierarchy should be power of 2 of its parent hierarchy");
-
-		m_firstTileIdxOfHierarchy[hierarchy] = tileCount;
-
-		tileCount += hierarchyTileCountX * hierarchyTileCountY;
-	}
-	ANKI_ASSERT(tileCount >= tileCountX * tileCountY);
-	m_allTiles.resize(tileCount);
-	m_firstTileIdxOfHierarchy[hierarchyCount] = tileCount - 1;
-
-	// Init the tiles
-	U32 tileIdx = 0;
-	for(U32 hierarchy = 0; hierarchy < hierarchyCount; ++hierarchy)
-	{
-		const U32 hierarchyTileCountX = tileCountX >> hierarchy;
-		const U32 hierarchyTileCountY = tileCountY >> hierarchy;
-
-		for(U32 y = 0; y < hierarchyTileCountY; ++y)
-		{
-			for(U32 x = 0; x < hierarchyTileCountX; ++x)
-			{
-				ANKI_ASSERT(tileIdx >= m_firstTileIdxOfHierarchy[hierarchy] && tileIdx <= m_firstTileIdxOfHierarchy[hierarchy + 1]);
-				Tile& tile = m_allTiles[tileIdx];
-
-				tile.m_viewport[0] = x << hierarchy;
-				tile.m_viewport[1] = y << hierarchy;
-				tile.m_viewport[2] = 1 << hierarchy;
-				tile.m_viewport[3] = 1 << hierarchy;
-
-				if(hierarchy > 0)
-				{
-					// Has sub tiles
-					for(U32 j = 0; j < 2; ++j)
-					{
-						for(U32 i = 0; i < 2; ++i)
-						{
-							const U32 subTileIdx = translateTileIdx((x << 1) + i, (y << 1) + j, hierarchy - 1);
-							m_allTiles[subTileIdx].m_superTile = tileIdx;
-
-							tile.m_subTiles[j * 2 + i] = subTileIdx;
-						}
-					}
-				}
-				else
-				{
-					// No sub-tiles
-				}
-
-				++tileIdx;
-			}
-		}
-	}
-}
-
-void TileAllocator::updateSubTiles(const Tile& updateFrom)
-{
-	if(updateFrom.m_subTiles[0] == kMaxU32)
-	{
-		return;
-	}
-
-	for(U32 idx : updateFrom.m_subTiles)
-	{
-		m_allTiles[idx].m_lightTimestamp = updateFrom.m_lightTimestamp;
-		m_allTiles[idx].m_lastUsedTimestamp = updateFrom.m_lastUsedTimestamp;
-		m_allTiles[idx].m_lightUuid = updateFrom.m_lightUuid;
-		m_allTiles[idx].m_lightDrawcallCount = updateFrom.m_lightDrawcallCount;
-		m_allTiles[idx].m_lightHierarchy = updateFrom.m_lightHierarchy;
-		m_allTiles[idx].m_lightFace = updateFrom.m_lightFace;
-
-		updateSubTiles(m_allTiles[idx]);
-	}
-}
-
-void TileAllocator::updateSuperTiles(const Tile& updateFrom)
-{
-	if(updateFrom.m_superTile != kMaxU32)
-	{
-		m_allTiles[updateFrom.m_superTile].m_lightUuid = 0;
-		m_allTiles[updateFrom.m_superTile].m_lastUsedTimestamp = updateFrom.m_lastUsedTimestamp;
-		updateSuperTiles(m_allTiles[updateFrom.m_superTile]);
-	}
-}
-
-Bool TileAllocator::searchTileRecursively(U32 crntTileIdx, U32 crntTileHierarchy, U32 allocationHierarchy, Timestamp crntTimestamp, U32& emptyTileIdx,
-										  U32& toKickTileIdx, Timestamp& tileToKickMinTimestamp) const
-{
-	const Tile& tile = m_allTiles[crntTileIdx];
-
-	if(crntTileHierarchy == allocationHierarchy)
-	{
-		// We may have a candidate
-
-		const Bool done = evaluateCandidate(crntTileIdx, crntTimestamp, emptyTileIdx, toKickTileIdx, tileToKickMinTimestamp);
-
-		if(done)
-		{
-			return true;
-		}
-	}
-	else if(tile.m_subTiles[0] != kMaxU32)
-	{
-		// Move down the hierarchy
-
-		ANKI_ASSERT(allocationHierarchy < crntTileHierarchy);
-
-		for(const U32 idx : tile.m_subTiles)
-		{
-			const Bool done = searchTileRecursively(idx, crntTileHierarchy - 1, allocationHierarchy, crntTimestamp, emptyTileIdx, toKickTileIdx,
-													tileToKickMinTimestamp);
-
-			if(done)
-			{
-				return true;
-			}
-		}
-	}
-
-	return false;
-}
-
-Bool TileAllocator::evaluateCandidate(U32 tileIdx, Timestamp crntTimestamp, U32& emptyTileIdx, U32& toKickTileIdx,
-									  Timestamp& tileToKickMinTimestamp) const
-{
-	const Tile& tile = m_allTiles[tileIdx];
-
-	if(m_cachingEnabled)
-	{
-		if(tile.m_lastUsedTimestamp == 0)
-		{
-			// Found empty
-			emptyTileIdx = tileIdx;
-			return true;
-		}
-		else if(tile.m_lastUsedTimestamp != crntTimestamp && tile.m_lastUsedTimestamp < tileToKickMinTimestamp)
-		{
-			// Found one with low timestamp
-			toKickTileIdx = tileIdx;
-			tileToKickMinTimestamp = tile.m_lightTimestamp;
-		}
-	}
-	else
-	{
-		if(tile.m_lastUsedTimestamp != crntTimestamp)
-		{
-			emptyTileIdx = tileIdx;
-			return true;
-		}
-	}
-
-	return false;
-}
-
-TileAllocatorResult TileAllocator::allocate(Timestamp crntTimestamp, Timestamp lightTimestamp, U64 lightUuid, U32 lightFace, U32 drawcallCount,
-											U32 hierarchy, Array<U32, 4>& tileViewport)
-{
-	// Preconditions
-	ANKI_ASSERT(crntTimestamp > 0);
-	ANKI_ASSERT(lightTimestamp > 0);
-	ANKI_ASSERT(lightTimestamp <= crntTimestamp);
-	ANKI_ASSERT(lightUuid != 0);
-	ANKI_ASSERT(lightFace < 6);
-	ANKI_ASSERT(hierarchy < m_hierarchyCount);
-
-	// 1) Search if it's already cached
-	HashMapKey key;
-	if(m_cachingEnabled)
-	{
-		key.m_lightUuid = lightUuid;
-		key.m_face = lightFace;
-		auto it = m_lightInfoToTileIdx.find(key);
-		if(it != m_lightInfoToTileIdx.getEnd())
-		{
-			Tile& tile = m_allTiles[*it];
-
-			if(tile.m_lightUuid != lightUuid || tile.m_lightHierarchy != hierarchy || tile.m_lightFace != lightFace)
-			{
-				// Cache entry is wrong, remove it
-				m_lightInfoToTileIdx.erase(it);
-			}
-			else
-			{
-				// Same light & hierarchy & face, found the cache entry.
-
-				ANKI_ASSERT(tile.m_lastUsedTimestamp != crntTimestamp && "Trying to allocate the same thing twice in this timestamp?");
-
-				ANKI_ASSERT(tile.m_lightUuid == lightUuid && tile.m_lightHierarchy == hierarchy && tile.m_lightFace == lightFace);
-
-				tileViewport = {tile.m_viewport[0], tile.m_viewport[1], tile.m_viewport[2], tile.m_viewport[3]};
-
-				const Bool needsReRendering = tile.m_lightDrawcallCount != drawcallCount || tile.m_lightTimestamp < lightTimestamp;
-
-				tile.m_lightTimestamp = lightTimestamp;
-				tile.m_lastUsedTimestamp = crntTimestamp;
-				tile.m_lightDrawcallCount = drawcallCount;
-
-				updateTileHierarchy(tile);
-
-				return (needsReRendering) ? TileAllocatorResult::kAllocationSucceded : TileAllocatorResult::kCached;
-			}
-		}
-	}
-
-	// Start searching for a suitable tile. Do a hieratchical search to end up with better locality and not better
-	// utilization of the atlas' space
-	U32 emptyTileIdx = kMaxU32;
-	U32 toKickTileIdx = kMaxU32;
-	Timestamp tileToKickMinTimestamp = kMaxTimestamp;
-	const U32 maxHierarchy = m_hierarchyCount - 1;
-	if(hierarchy == maxHierarchy)
-	{
-		// This search is simple, iterate the tiles of the max hierarchy
-
-		for(U32 tileIdx = m_firstTileIdxOfHierarchy[maxHierarchy]; tileIdx <= m_firstTileIdxOfHierarchy[maxHierarchy + 1]; ++tileIdx)
-		{
-			const Bool done = evaluateCandidate(tileIdx, crntTimestamp, emptyTileIdx, toKickTileIdx, tileToKickMinTimestamp);
-
-			if(done)
-			{
-				break;
-			}
-		}
-	}
-	else
-	{
-		// Need to do a recursive search
-
-		for(U32 tileIdx = m_firstTileIdxOfHierarchy[maxHierarchy]; tileIdx <= m_firstTileIdxOfHierarchy[maxHierarchy + 1]; ++tileIdx)
-		{
-			const Bool done =
-				searchTileRecursively(tileIdx, maxHierarchy, hierarchy, crntTimestamp, emptyTileIdx, toKickTileIdx, tileToKickMinTimestamp);
-
-			if(done)
-			{
-				break;
-			}
-		}
-	}
-
-	U32 allocatedTileIdx;
-	if(emptyTileIdx != kMaxU32)
-	{
-		allocatedTileIdx = emptyTileIdx;
-	}
-	else if(toKickTileIdx != kMaxU32)
-	{
-		allocatedTileIdx = toKickTileIdx;
-	}
-	else
-	{
-		// Out of tiles
-		return TileAllocatorResult::kAllocationFailed;
-	}
-
-	// Allocation succedded, need to do some bookkeeping
-
-	// Mark the allocated tile
-	Tile& allocatedTile = m_allTiles[allocatedTileIdx];
-	allocatedTile.m_lightTimestamp = lightTimestamp;
-	allocatedTile.m_lastUsedTimestamp = crntTimestamp;
-	allocatedTile.m_lightUuid = lightUuid;
-	allocatedTile.m_lightDrawcallCount = drawcallCount;
-	allocatedTile.m_lightHierarchy = U8(hierarchy);
-	allocatedTile.m_lightFace = U8(lightFace);
-
-	updateTileHierarchy(allocatedTile);
-
-	// Update the cache
-	if(m_cachingEnabled)
-	{
-		m_lightInfoToTileIdx.emplace(key, allocatedTileIdx);
-	}
-
-	// Return
-	tileViewport = {allocatedTile.m_viewport[0], allocatedTile.m_viewport[1], allocatedTile.m_viewport[2], allocatedTile.m_viewport[3]};
-
-	return TileAllocatorResult::kAllocationSucceded;
-}
-
-void TileAllocator::invalidateCache(U64 lightUuid, U32 lightFace)
-{
-	ANKI_ASSERT(m_cachingEnabled);
-	ANKI_ASSERT(lightUuid > 0);
-
-	HashMapKey key;
-	key.m_lightUuid = lightUuid;
-	key.m_face = lightFace;
-
-	auto it = m_lightInfoToTileIdx.find(key);
-	if(it != m_lightInfoToTileIdx.getEnd())
-	{
-		m_lightInfoToTileIdx.erase(it);
-	}
-}
-
-} // end namespace anki

+ 0 - 89
AnKi/Renderer/Utils/TileAllocator.h

@@ -1,89 +0,0 @@
-// 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/Renderer/Common.h>
-
-namespace anki {
-
-/// @addtogroup renderer
-/// @{
-
-/// The result of a tile allocation.
-enum class TileAllocatorResult : U32
-{
-	kCached, ///< The tile is cached. No need to re-render it.
-	kAllocationFailed, ///< No more available tiles.
-	kAllocationSucceded ///< Allocation succeded but the tile needs update.
-};
-
-/// Allocates tiles out of a tilemap suitable for shadow mapping.
-class TileAllocator
-{
-public:
-	TileAllocator();
-
-	TileAllocator(const TileAllocator&) = delete; // Non-copyable
-
-	~TileAllocator();
-
-	TileAllocator& operator=(const TileAllocator&) = delete; // Non-copyable
-
-	/// Initialize the allocator.
-	void init(U32 tileCountX, U32 tileCountY, U32 hierarchyCount, Bool enableCaching);
-
-	/// Allocate some tiles.
-	/// @param hierarchy If it's 0 it chooses the smallest tile.
-	[[nodiscard]] TileAllocatorResult allocate(Timestamp crntTimestamp, Timestamp lightTimestamp, U64 lightUuid, U32 lightFace, U32 drawcallCount,
-											   U32 hierarchy, Array<U32, 4>& tileViewport);
-
-	/// Remove an light from the cache.
-	void invalidateCache(U64 lightUuid, U32 lightFace);
-
-private:
-	class Tile;
-
-	/// A HashMap key.
-	class HashMapKey;
-
-	RendererDynamicArray<Tile> m_allTiles;
-	RendererDynamicArray<U32> m_firstTileIdxOfHierarchy;
-
-	RendererHashMap<HashMapKey, U32> m_lightInfoToTileIdx;
-
-	U16 m_tileCountX = 0; ///< Tile count for hierarchy 0
-	U16 m_tileCountY = 0; ///< Tile count for hierarchy 0
-	U8 m_hierarchyCount = 0;
-	Bool m_cachingEnabled = false;
-
-	U32 translateTileIdx(U32 x, U32 y, U32 hierarchy) const
-	{
-		const U32 hierarchyWidth = m_tileCountX >> hierarchy;
-		const U32 idx = y * hierarchyWidth + x + m_firstTileIdxOfHierarchy[hierarchy];
-		ANKI_ASSERT(idx < m_allTiles.getSize());
-		return idx;
-	}
-
-	void updateSubTiles(const Tile& updateFrom);
-
-	void updateSuperTiles(const Tile& updateFrom);
-
-	/// Given a tile move the hierarchy up and down to update the hierarchy this tile belongs to.
-	void updateTileHierarchy(const Tile& updateFrom)
-	{
-		updateSubTiles(updateFrom);
-		updateSuperTiles(updateFrom);
-	}
-
-	/// Search for a tile recursively.
-	Bool searchTileRecursively(U32 crntTileIdx, U32 crntTileHierarchy, U32 allocationHierarchy, Timestamp crntTimestamp, U32& emptyTileIdx,
-							   U32& toKickTileIdx, Timestamp& tileToKickMinTimestamp) const;
-
-	Bool evaluateCandidate(U32 tileIdx, Timestamp crntTimestamp, U32& emptyTileIdx, U32& toKickTileIdx, Timestamp& tileToKickMinTimestamp) const;
-};
-/// @}
-
-} // end namespace anki

+ 4 - 23
AnKi/Renderer/Utils/TileAllocator2.cpp

@@ -12,7 +12,6 @@ class TileAllocator2::Tile
 public:
 	Timestamp m_lastUsedTimestamp = 0; ///< The last timestamp this tile was used.
 	U64 m_lightUuid = 0;
-	U64 m_lightAdditionalIdendification = 0;
 	Array<U32, 4> m_viewport = {};
 	Array<U32, 4> m_subTiles = {kMaxU32, kMaxU32, kMaxU32, kMaxU32};
 	U32 m_superTile = kMaxU32; ///< The parent.
@@ -118,7 +117,6 @@ void TileAllocator2::updateSubTiles(const Tile& updateFrom, U64 crntLightUuid, A
 
 		m_allTiles[idx].m_lastUsedTimestamp = updateFrom.m_lastUsedTimestamp;
 		m_allTiles[idx].m_lightUuid = updateFrom.m_lightUuid;
-		m_allTiles[idx].m_lightAdditionalIdendification = updateFrom.m_lightAdditionalIdendification;
 		m_allTiles[idx].m_lightHierarchy = updateFrom.m_lightHierarchy;
 
 		updateSubTiles(m_allTiles[idx], crntLightUuid, kickedOutLights);
@@ -209,8 +207,8 @@ Bool TileAllocator2::evaluateCandidate(U32 tileIdx, Timestamp crntTimestamp, U32
 	return false;
 }
 
-TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 lightUuid, U64 lightAdditionalIdentification, U32 hierarchy,
-											  Array<U32, 4>& tileViewport, ArrayOfLightUuids& kickedOutLightUuids)
+TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 lightUuid, U32 hierarchy, Array<U32, 4>& tileViewport,
+											  ArrayOfLightUuids& kickedOutLightUuids)
 {
 	// Preconditions
 	ANKI_ASSERT(crntTimestamp > 0);
@@ -242,21 +240,12 @@ TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 light
 
 				tileViewport = {tile.m_viewport[0], tile.m_viewport[1], tile.m_viewport[2], tile.m_viewport[3]};
 
-				const Bool needsReRendering = tile.m_lightAdditionalIdendification != lightAdditionalIdentification;
-
 				tile.m_lastUsedTimestamp = crntTimestamp;
-				tile.m_lightAdditionalIdendification = lightAdditionalIdentification;
 
 				updateTileHierarchy(tile, lightUuid, kickedOutLightUuids);
 				ANKI_ASSERT(kickedOutLightUuids.getSize() == 0);
 
-				TileAllocatorResult2 result = TileAllocatorResult2::kAllocationSucceded;
-				if(needsReRendering)
-				{
-					result |= TileAllocatorResult2::kNeedsRefresh;
-				}
-
-				return result;
+				return TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached;
 			}
 		}
 	}
@@ -296,8 +285,6 @@ TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 light
 		}
 	}
 
-	TileAllocatorResult2 result = TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh;
-
 	U32 allocatedTileIdx;
 	if(emptyTileIdx != kMaxU32)
 	{
@@ -319,16 +306,10 @@ TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 light
 	Tile& allocatedTile = m_allTiles[allocatedTileIdx];
 	allocatedTile.m_lastUsedTimestamp = crntTimestamp;
 	allocatedTile.m_lightUuid = lightUuid;
-	allocatedTile.m_lightAdditionalIdendification = lightAdditionalIdentification;
 	allocatedTile.m_lightHierarchy = U8(hierarchy);
 
 	updateTileHierarchy(allocatedTile, lightUuid, kickedOutLightUuids);
 
-	if(kickedOutLightUuids.getSize())
-	{
-		result |= TileAllocatorResult2::kOtherTileKicked;
-	}
-
 	// Update the cache
 	if(m_cachingEnabled)
 	{
@@ -338,7 +319,7 @@ TileAllocatorResult2 TileAllocator2::allocate(Timestamp crntTimestamp, U64 light
 	// Return
 	tileViewport = {allocatedTile.m_viewport[0], allocatedTile.m_viewport[1], allocatedTile.m_viewport[2], allocatedTile.m_viewport[3]};
 
-	return result;
+	return TileAllocatorResult2::kAllocationSucceded;
 }
 
 void TileAllocator2::invalidateCache(U64 lightUuid)

+ 5 - 6
AnKi/Renderer/Utils/TileAllocator2.h

@@ -13,12 +13,11 @@ namespace anki {
 /// @{
 
 /// The result of a tile allocation.
-enum class TileAllocatorResult2 : U32
+enum class TileAllocatorResult2 : U8
 {
 	kAllocationFailed = 0,
-	kAllocationSucceded = 1 << 0, ///< Allocation succedded or out of tile space.
-	kOtherTileKicked = 1 << 1, ///< Another tile was kicked.
-	kNeedsRefresh = 1 << 2, ///< Additional identification or hierarchy missmatch. Needs to be re-rendered.
+	kAllocationSucceded = 1 << 0, ///< Allocation succedded.
+	kTileCached = 1 << 1, ///< The tile was in the cache already. Goes only with kAllocationSucceded.
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TileAllocatorResult2)
 
@@ -42,8 +41,8 @@ public:
 
 	/// Allocate some tiles.
 	/// @param hierarchy If it's 0 it chooses the smallest tile.
-	[[nodiscard]] TileAllocatorResult2 allocate(Timestamp crntTimestamp, U64 lightUuid, U64 lightAdditionalIdentification, U32 hierarchy,
-												Array<U32, 4>& tileViewport, ArrayOfLightUuids& kickedOutLightUuids);
+	[[nodiscard]] TileAllocatorResult2 allocate(Timestamp crntTimestamp, U64 lightUuid, U32 hierarchy, Array<U32, 4>& tileViewport,
+												ArrayOfLightUuids& kickedOutLightUuids);
 
 	/// Remove an light from the cache.
 	void invalidateCache(U64 lightUuid);

+ 34 - 25
Tests/Renderer/TileAllocator.cpp

@@ -23,7 +23,6 @@ ANKI_TEST(Renderer, TileAllocator)
 		TileAllocatorResult2 res;
 
 		const U64 lightUuid = 1000;
-		const U64 dcCount = 666;
 		Timestamp crntTimestamp = 1;
 
 		constexpr U kSmallTile = 0;
@@ -31,43 +30,53 @@ ANKI_TEST(Renderer, TileAllocator)
 		constexpr U kBigTile = 2;
 
 		// Allocate 1 med
-		res = talloc.allocate(crntTimestamp, lightUuid + 1, dcCount, kMedTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
+		res = talloc.allocate(crntTimestamp, lightUuid + 1, kMedTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
 
 		// Allocate 3 big
-		res = talloc.allocate(crntTimestamp, lightUuid + 2, dcCount, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
-		res = talloc.allocate(crntTimestamp, lightUuid + 3, dcCount, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
-		res = talloc.allocate(crntTimestamp, lightUuid + 4, dcCount, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
+		res = talloc.allocate(crntTimestamp, lightUuid + 2, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 3, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 4, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
 
 		// Fail to allocate 1 big
-		res = talloc.allocate(crntTimestamp, lightUuid + 5, dcCount, kBigTile, viewport, kickedOutUuids);
+		res = talloc.allocate(crntTimestamp, lightUuid + 5, kBigTile, viewport, kickedOutUuids);
 		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationFailed);
 
 		// Allocate 3 med
-		res = talloc.allocate(crntTimestamp, lightUuid + 6, dcCount, kMedTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
-		res = talloc.allocate(crntTimestamp, lightUuid + 7, dcCount, kMedTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
-		res = talloc.allocate(crntTimestamp, lightUuid + 8, dcCount, kMedTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
+		res = talloc.allocate(crntTimestamp, lightUuid + 6, kMedTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 7, kMedTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 8, kMedTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
 
 		// Fail to allocate a small
-		res = talloc.allocate(crntTimestamp, lightUuid + 9, dcCount, kSmallTile, viewport, kickedOutUuids);
+		res = talloc.allocate(crntTimestamp, lightUuid + 9, kSmallTile, viewport, kickedOutUuids);
 		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationFailed);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
 
 		// New frame
 		++crntTimestamp;
 
 		// Allocate the same 3 big again
-		res = talloc.allocate(crntTimestamp, lightUuid + 2, dcCount + 1, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
-		res = talloc.allocate(crntTimestamp, lightUuid + 3, dcCount, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
-		res = talloc.allocate(crntTimestamp, lightUuid + 4, dcCount + 1, kBigTile, viewport, kickedOutUuids);
-		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh);
+		res = talloc.allocate(crntTimestamp, lightUuid + 2, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 3, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
+		res = talloc.allocate(crntTimestamp, lightUuid + 4, kBigTile, viewport, kickedOutUuids);
+		ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kTileCached);
+		ANKI_TEST_EXPECT_EQ(kickedOutUuids.getSize(), 0);
 
 		// New frame
 		++crntTimestamp;
@@ -76,8 +85,8 @@ ANKI_TEST(Renderer, TileAllocator)
 		TileAllocator2::ArrayOfLightUuids allKicked(&pool);
 		for(U i = 0; i < 16; ++i)
 		{
-			res = talloc.allocate(crntTimestamp, lightUuid + 10 + i, dcCount, 0, viewport, kickedOutUuids);
-			ANKI_TEST_EXPECT_EQ(!!(res & (TileAllocatorResult2::kAllocationSucceded | TileAllocatorResult2::kNeedsRefresh)), true);
+			res = talloc.allocate(crntTimestamp, lightUuid + 10 + i, kSmallTile, viewport, kickedOutUuids);
+			ANKI_TEST_EXPECT_EQ(res, TileAllocatorResult2::kAllocationSucceded);
 
 			for(U64 uuid : kickedOutUuids)
 			{