Forráskód Böngészése

Shadows: Use an atlas for all shadows

Panagiotis Christopoulos Charitos 8 éve
szülő
commit
f2f998114a
73 módosított fájl, 705 hozzáadás és 789 törlés
  1. 1 3
      programs/ExponentialShadowmappingResolve.ankiprog
  2. 3 4
      programs/LightShading.ankiprog
  3. 3 4
      programs/VolumetricFog.ankiprog
  4. 4 4
      shaders/ClusterLightCommon.glsl
  5. 3 5
      shaders/ForwardShadingCommonFrag.glsl
  6. 3 3
      shaders/Functions.glsl
  7. 12 3
      shaders/LightFunctions.glsl
  8. 1 0
      src/anki/collision/Frustum.cpp
  9. 1 0
      src/anki/collision/Frustum.h
  10. 2 2
      src/anki/core/App.cpp
  11. 1 1
      src/anki/core/App.h
  12. 2 2
      src/anki/core/Config.cpp
  13. 2 2
      src/anki/core/Timestamp.h
  14. 4 3
      src/anki/core/Trace.cpp
  15. 3 4
      src/anki/core/Trace.h
  16. 6 1
      src/anki/math/Vec4.h
  17. 1 1
      src/anki/physics/PhysicsWorld.cpp
  18. 3 3
      src/anki/physics/PhysicsWorld.h
  19. 2 4
      src/anki/renderer/ForwardShading.cpp
  20. 6 3
      src/anki/renderer/LightBin.cpp
  21. 6 7
      src/anki/renderer/LightShading.cpp
  22. 2 1
      src/anki/renderer/RenderQueue.h
  23. 2 1
      src/anki/renderer/Renderer.cpp
  24. 2 53
      src/anki/renderer/Renderer.h
  25. 427 489
      src/anki/renderer/ShadowMapping.cpp
  26. 76 62
      src/anki/renderer/ShadowMapping.h
  27. 1 2
      src/anki/renderer/Volumetric.cpp
  28. 1 1
      src/anki/scene/BodyComponent.h
  29. 1 1
      src/anki/scene/BodyNode.cpp
  30. 2 2
      src/anki/scene/Camera.cpp
  31. 1 1
      src/anki/scene/DecalComponent.h
  32. 2 2
      src/anki/scene/DecalNode.cpp
  33. 1 1
      src/anki/scene/FrustumComponent.cpp
  34. 1 1
      src/anki/scene/FrustumComponent.h
  35. 1 1
      src/anki/scene/LensFlareComponent.h
  36. 4 4
      src/anki/scene/Light.cpp
  37. 2 2
      src/anki/scene/Light.h
  38. 1 1
      src/anki/scene/LightComponent.cpp
  39. 1 1
      src/anki/scene/LightComponent.h
  40. 1 1
      src/anki/scene/ModelNode.cpp
  41. 1 1
      src/anki/scene/MoveComponent.cpp
  42. 3 3
      src/anki/scene/MoveComponent.h
  43. 1 1
      src/anki/scene/OccluderNode.cpp
  44. 6 6
      src/anki/scene/ParticleEmitter.cpp
  45. 16 16
      src/anki/scene/ParticleEmitter.h
  46. 1 1
      src/anki/scene/PlayerControllerComponent.h
  47. 2 2
      src/anki/scene/PlayerNode.cpp
  48. 2 2
      src/anki/scene/ReflectionProbe.cpp
  49. 1 1
      src/anki/scene/ReflectionProbe.h
  50. 1 1
      src/anki/scene/ReflectionProxy.cpp
  51. 1 1
      src/anki/scene/ReflectionProxyComponent.cpp
  52. 1 1
      src/anki/scene/ReflectionProxyComponent.h
  53. 1 1
      src/anki/scene/SceneComponent.cpp
  54. 4 4
      src/anki/scene/SceneComponent.h
  55. 4 4
      src/anki/scene/SceneGraph.cpp
  56. 4 4
      src/anki/scene/SceneGraph.h
  57. 0 14
      src/anki/scene/SceneNode.cpp
  58. 4 5
      src/anki/scene/SceneNode.h
  59. 2 2
      src/anki/scene/Sector.cpp
  60. 2 2
      src/anki/scene/Sector.h
  61. 1 1
      src/anki/scene/SkinComponent.cpp
  62. 1 1
      src/anki/scene/SkinComponent.h
  63. 1 1
      src/anki/scene/SpatialComponent.cpp
  64. 1 1
      src/anki/scene/SpatialComponent.h
  65. 2 1
      src/anki/scene/Visibility.cpp
  66. 20 1
      src/anki/util/DynamicArray.h
  67. 1 1
      src/anki/util/HighRezTimer.cpp
  68. 5 8
      src/anki/util/HighRezTimer.h
  69. 4 4
      src/anki/util/HighRezTimerPosix.cpp
  70. 4 4
      src/anki/util/HighRezTimerWindows.cpp
  71. 2 0
      src/anki/util/StdTypes.h
  72. 2 2
      tests/util/HashMap.cpp
  73. 6 6
      tests/util/SparseArray.cpp

+ 1 - 3
programs/ExponentialShadowmappingResolve.ankiprog

@@ -28,9 +28,7 @@ void main()
 	out_uv = vec2(gl_VertexID & 1, gl_VertexID >> 1) * 2.0;
 	vec2 pos = out_uv * 2.0 - 1.0;
 
-	out_uv *= u_uvScaleAndTranslation.xy;
-	out_uv += u_uvScaleAndTranslation.zw;
-
+	out_uv = fma(out_uv, u_uvScaleAndTranslation.zw, u_uvScaleAndTranslation.xy);
 	gl_Position = vec4(pos, 0.0, 1.0);
 }
 			]]></source>

+ 3 - 4
programs/LightShading.ankiprog

@@ -213,11 +213,10 @@ void main()
 
 		LIGHTING_COMMON_BRDF();
 
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(light.cubeFaceCoordinates[0].x >= 0.0)
 		{
 			float shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
+				frag2Light, light.specularColorRadius.w, u_invViewRotation, light.cubeFaceCoordinates, u_shadowTex);
 			lambert *= shadow;
 		}
 
@@ -238,7 +237,7 @@ void main()
 		if(shadowmapLayerIdx >= 0.0)
 		{
 			float shadow = computeShadowFactorSpot(
-				light.texProjectionMat, fragPos, light.specularColorRadius.w, u_spotMapArr);
+				light.texProjectionMat, fragPos, light.specularColorRadius.w, u_shadowTex);
 			lambert *= shadow;
 		}
 

+ 3 - 4
programs/VolumetricFog.ankiprog

@@ -73,11 +73,10 @@ vec3 computeLightColor(vec3 fragPos, uint plightCount, uint plightIdx, uint slig
 		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
 #if ENABLE_SHADOWS
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(light.cubeFaceCoordinates[0].x >= 0.0)
 		{
 			factor *= computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_invViewRotation, u_omniMapArr);
+				frag2Light, -1.0 / light.posRadius.w, u_invViewRotation, light.cubeFaceCoordinates, u_shadowTex);
 		}
 #endif
 
@@ -100,7 +99,7 @@ vec3 computeLightColor(vec3 fragPos, uint plightCount, uint plightIdx, uint slig
 		if(shadowmapLayerIdx >= 0.0)
 		{
 			factor *= computeShadowFactorSpot(
-				light.texProjectionMat, fragPos, light.specularColorRadius.w, u_spotMapArr);
+				light.texProjectionMat, fragPos, light.specularColorRadius.w, u_shadowTex);
 		}
 #endif
 

+ 4 - 4
shaders/ClusterLightCommon.glsl

@@ -25,8 +25,9 @@ struct LightingUniforms
 struct PointLight
 {
 	vec4 posRadius; // xyz: Light pos in view space. w: The -1/(radius^2)
-	vec4 diffuseColorShadowmapId; // xyz: diff color, w: shadowmap tex ID
+	vec4 diffuseColorShadowmapId; // xyz: diff color, w: unused
 	vec4 specularColorRadius; // xyz: spec color, w: radius
+	vec4 cubeFaceCoordinates[6]; // xy: uv offset, zw: uv scale
 };
 
 // Spot light
@@ -111,7 +112,7 @@ const uint _NEXT_UBO_BINDING = LIGHT_UBO_BINDING;
 //
 #if defined(LIGHT_LIGHTS)
 const uint _NEXT_UBO_BINDING_2 = _NEXT_UBO_BINDING + 2;
-const uint _NEXT_TEX_BINDING_2 = LIGHT_TEX_BINDING + 2;
+const uint _NEXT_TEX_BINDING_2 = LIGHT_TEX_BINDING + 1;
 
 layout(ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING), std140) uniform u1_
 {
@@ -123,8 +124,7 @@ layout(ANKI_UBO_BINDING(LIGHT_SET, _NEXT_UBO_BINDING + 1), std140, row_major) un
 	SpotLight u_spotLights[UBO_MAX_SIZE / (9 * 4 * 4)];
 };
 
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 0)) uniform highp sampler2D u_spotMapArr;
-layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 1)) uniform highp samplerCubeArray u_omniMapArr;
+layout(ANKI_TEX_BINDING(LIGHT_SET, LIGHT_TEX_BINDING + 0)) uniform highp sampler2D u_shadowTex;
 #else
 const uint _NEXT_UBO_BINDING_2 = _NEXT_UBO_BINDING;
 const uint _NEXT_TEX_BINDING_2 = LIGHT_TEX_BINDING;

+ 3 - 5
shaders/ForwardShadingCommonFrag.glsl

@@ -75,11 +75,10 @@ vec3 computeLightColor(vec3 diffCol)
 		const float shadow = 1.0;
 #else
 		float shadow = 1.0;
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(light.cubeFaceCoordinates[0].x >= 0.0)
 		{
 			shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
+				frag2Light, light.specularColorRadius.w, u_invViewRotation, light.cubeFaceCoordinates, u_shadowTex);
 		}
 #endif
 
@@ -108,8 +107,7 @@ vec3 computeLightColor(vec3 diffCol)
 		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
 		if(shadowmapLayerIdx >= 0.0)
 		{
-			shadow =
-				computeShadowFactorSpot(light.texProjectionMat, fragPos, light.specularColorRadius.w, u_spotMapArr);
+			shadow = computeShadowFactorSpot(light.texProjectionMat, fragPos, light.specularColorRadius.w, u_shadowTex);
 		}
 #endif
 

+ 3 - 3
shaders/Functions.glsl

@@ -185,12 +185,12 @@ vec3 getCubemapDirection(vec2 norm, uint faceIdx)
 	return normalize(norm.x * xDir + norm.y * yDir + zDir);
 }
 
-// Convert 3D cubemap coordinates to 2D plus face index. v needs to be normalized.
+// Convert 3D cubemap coordinates to 2D plus face index. v doesn't need to be normalized.
 vec2 convertCubeUvs(vec3 v, out float faceIndex)
 {
 	vec3 absV = abs(v);
 	float mag;
-	vec3 uv;
+	vec2 uv;
 
 	if(all(greaterThanEqual(absV.zz, absV.xy)))
 	{
@@ -211,7 +211,7 @@ vec2 convertCubeUvs(vec3 v, out float faceIndex)
 		mag = absV.x;
 	}
 
-	return uv * mag * 2.0 + 0.5;
+	return 0.5 / mag * uv + 0.5;
 }
 
 vec3 grayScale(vec3 col)

+ 12 - 3
shaders/LightFunctions.glsl

@@ -103,19 +103,28 @@ float computeShadowFactorSpot(mat4 lightProjectionMat, vec3 fragPos, float dista
 	return clamp(exp(ESM_CONSTANT * (textureLod(spotMapArr, texCoords3.xy, 0.0).r - linearDepth)), 0.0, 1.0);
 }
 
-float computeShadowFactorOmni(vec3 frag2Light, float layer, float radius, mat3 invViewMat, samplerCubeArray omniMapArr)
+float computeShadowFactorOmni(
+	vec3 frag2Light, float radius, mat3 invViewMat, vec4 cubeFaceCoords[6], sampler2D shadowMap)
 {
 	vec3 dir = invViewMat * -frag2Light;
 	vec3 dirabs = abs(dir);
 	float dist = max(dirabs.x, max(dirabs.y, dirabs.z));
-	dir = normalize(dir);
 
 	const float near = LIGHT_FRUSTUM_NEAR_PLANE;
 	const float far = radius;
 
 	float linearDepth = (dist - near) / (far - near);
 
-	return clamp(exp(ESM_CONSTANT * (texture(omniMapArr, vec4(dir, layer)).r - linearDepth)), 0.0, 1.0);
+	// Read tex
+	float shadowFactor;
+	{
+		float faceIdx;
+		vec2 uv = convertCubeUvs(dir, faceIdx);
+		uv = fma(uv, cubeFaceCoords[uint(faceIdx)].zw, cubeFaceCoords[uint(faceIdx)].xy);
+		shadowFactor = textureLod(shadowMap, uv, 0.0).r;
+	}
+
+	return clamp(exp(ESM_CONSTANT * (shadowFactor - linearDepth)), 0.0, 1.0);
 }
 
 // Compute the cubemap texture lookup vector given the reflection vector (r) the radius squared of the probe (R2) and

+ 1 - 0
src/anki/collision/Frustum.cpp

@@ -92,6 +92,7 @@ void Frustum::resetTransform(const Transform& trf)
 void Frustum::update() const
 {
 	Frustum& self = *const_cast<Frustum*>(this);
+	LockGuard<SpinLock> lock(self.m_lock);
 	if(self.m_frustumDirty)
 	{
 		self.updateInternal();

+ 1 - 0
src/anki/collision/Frustum.h

@@ -142,6 +142,7 @@ protected:
 
 private:
 	FrustumType m_type;
+	SpinLock m_lock;
 };
 
 /// Frustum shape for perspective cameras

+ 2 - 2
src/anki/core/App.cpp

@@ -375,8 +375,8 @@ Error App::mainLoop()
 	ANKI_CORE_LOGI("Entering main loop");
 	Bool quit = false;
 
-	HighRezTimer::Scalar prevUpdateTime = HighRezTimer::getCurrentTime();
-	HighRezTimer::Scalar crntTime = prevUpdateTime;
+	Second prevUpdateTime = HighRezTimer::getCurrentTime();
+	Second crntTime = prevUpdateTime;
 
 	while(!quit)
 	{

+ 1 - 1
src/anki/core/App.h

@@ -159,7 +159,7 @@ private:
 	ScriptManager* m_script = nullptr;
 
 	// Misc
-	Timestamp m_globalTimestamp = 0;
+	Timestamp m_globalTimestamp = 1;
 	ThreadPool* m_threadpool = nullptr;
 	ThreadHive* m_threadHive = nullptr;
 	String m_settingsDir; ///< The path that holds the configuration

+ 2 - 2
src/anki/core/Config.cpp

@@ -22,8 +22,8 @@ Config::Config()
 
 	newOption("r.shadowMapping.enabled", true);
 	newOption("r.shadowMapping.resolution", 512);
-	newOption("r.shadowMapping.maxLights", 16);
-	newOption("r.shadowMapping.batchCount", 6);
+	newOption("r.shadowMapping.tileCountPerRowOrColumn", 8);
+	newOption("r.shadowMapping.scratchTileCount", 8);
 
 	newOption("r.lensFlare.maxSpritesPerFlare", 8);
 	newOption("r.lensFlare.maxFlares", 16);

+ 2 - 2
src/anki/core/Timestamp.h

@@ -11,8 +11,8 @@ namespace anki
 {
 
 /// Timestamp type
-using Timestamp = U32;
+using Timestamp = U64;
 
-const U MAX_TIMESTAMP = MAX_U32;
+const U64 MAX_TIMESTAMP = MAX_U64;
 
 } // end namespace anki

+ 4 - 3
src/anki/core/Trace.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/core/Trace.h>
+#include <anki/util/HighRezTimer.h>
 #include <cstdlib>
 
 #if ANKI_ENABLE_TRACE
@@ -74,7 +75,7 @@ static Array<const char*, U(TraceCounterType::COUNT)> counterNames = {{"GR_DRAWC
 	}
 
 const U MAX_EVENTS_DEPTH = 20;
-thread_local HighRezTimer::Scalar g_traceEventStartTime[MAX_EVENTS_DEPTH];
+thread_local Second g_traceEventStartTime[MAX_EVENTS_DEPTH];
 thread_local I g_traceEventsInFlight = 0;
 
 TraceManager::~TraceManager()
@@ -171,8 +172,8 @@ Error TraceManager::flushCounters()
 	}
 
 	// Write the FPS counter
-	HighRezTimer::Scalar now = HighRezTimer::getCurrentTime();
-	HighRezTimer::Scalar time = now - m_startFrameTime;
+	Second now = HighRezTimer::getCurrentTime();
+	Second time = now - m_startFrameTime;
 	F32 fps = 1.0 / time;
 	ANKI_CHECK(m_traceFile.writeText("{\"name\": \"FPS\", \"cat\": \"PERF\", \"ph\": \"C\", "
 									 "\"pid\": 1, \"ts\": %llu, \"args\": {\"val\": %f}},\n",

+ 3 - 4
src/anki/core/Trace.h

@@ -9,7 +9,6 @@
 #include <anki/util/StdTypes.h>
 #include <anki/util/Singleton.h>
 #include <anki/util/Array.h>
-#include <anki/util/HighRezTimer.h>
 #include <anki/util/Thread.h>
 #include <anki/util/Atomic.h>
 #include <anki/util/Logger.h>
@@ -122,8 +121,8 @@ private:
 	{
 	public:
 		TraceEventType m_event;
-		HighRezTimer::Scalar m_timestamp; ///< When it started.
-		HighRezTimer::Scalar m_duration;
+		Second m_timestamp; ///< When it started.
+		Second m_duration;
 		ThreadId m_tid;
 	};
 
@@ -133,7 +132,7 @@ private:
 	File m_traceFile;
 	File m_perFrameFile;
 	File m_perRunFile;
-	HighRezTimer::Scalar m_startFrameTime;
+	Second m_startFrameTime;
 
 	Array<Atomic<U64>, U(TraceEventType::COUNT) + U(TraceCounterType::COUNT)> m_perFrameCounters = {{}};
 	Array<Atomic<U64>, U(TraceEventType::COUNT) + U(TraceCounterType::COUNT)> m_perRunCounters = {{}};

+ 6 - 1
src/anki/math/Vec4.h

@@ -58,10 +58,10 @@ class alignas(16) TVec4 : public TVec<T, 4, typename TVec4Simd<T>::Type, TVec4<T
 public:
 	using Base = TVec<T, 4, typename TVec4Simd<T>::Type, TVec4<T>>;
 
+	using Base::w;
 	using Base::x;
 	using Base::y;
 	using Base::z;
-	using Base::w;
 	using Base::operator*;
 
 	/// @name Constructors
@@ -101,6 +101,11 @@ public:
 	{
 	}
 
+	TVec4(const TVec2<T>& v, const TVec2<T>& v2)
+		: Base(v.x(), v.y(), v2.x(), v2.y())
+	{
+	}
+
 	TVec4(const TVec3<T>& v, const T w_)
 		: Base(v.x(), v.y(), v.z(), w_)
 	{

+ 1 - 1
src/anki/physics/PhysicsWorld.cpp

@@ -96,7 +96,7 @@ Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData)
 	return err;
 }
 
-Error PhysicsWorld::updateAsync(F32 dt)
+Error PhysicsWorld::updateAsync(Second dt)
 {
 	m_dt = dt;
 

+ 3 - 3
src/anki/physics/PhysicsWorld.h

@@ -30,7 +30,7 @@ public:
 	PhysicsPtr<T> newInstance(TArgs&&... args);
 
 	/// Start asynchronous update.
-	Error updateAsync(F32 dt);
+	Error updateAsync(Second dt);
 
 	/// End asynchronous update.
 	void waitUpdate();
@@ -53,7 +53,7 @@ anki_internal:
 		return m_sceneCollision;
 	}
 
-	F32 getDeltaTime() const
+	Second getDeltaTime() const
 	{
 		return m_dt;
 	}
@@ -76,7 +76,7 @@ private:
 	NewtonCollision* m_sceneCollision = nullptr;
 	NewtonBody* m_sceneBody = nullptr;
 	Vec4 m_gravity = Vec4(0.0, -9.8, 0.0, 0.0);
-	F32 m_dt = 0.0;
+	Second m_dt = 0.0;
 
 	/// @note Don't delete it. Newton will
 	CharacterControllerManager* m_playerManager = nullptr;

+ 2 - 4
src/anki/renderer/ForwardShading.cpp

@@ -135,12 +135,10 @@ void ForwardShading::buildCommandBuffers(RenderingContext& ctx, U threadId, U th
 		TextureSurfaceInfo(0, 0, 0, 0),
 		TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ);
 	cmdb->informTextureCurrentUsage(m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE);
-	cmdb->informTextureCurrentUsage(m_r->getShadowMapping().m_omniTexArray, TextureUsageBit::SAMPLED_FRAGMENT);
-	cmdb->informTextureCurrentUsage(m_r->getShadowMapping().m_spotTex, TextureUsageBit::SAMPLED_FRAGMENT);
+	cmdb->informTextureCurrentUsage(m_r->getShadowMapping().m_shadowAtlas, TextureUsageBit::SAMPLED_FRAGMENT);
 
 	cmdb->bindTexture(0, 0, m_r->getDepthDownscale().m_qd.m_colorRt);
-	cmdb->bindTexture(0, 1, m_r->getShadowMapping().m_spotTex);
-	cmdb->bindTexture(0, 2, m_r->getShadowMapping().m_omniTexArray);
+	cmdb->bindTexture(0, 1, m_r->getShadowMapping().m_shadowAtlas);
 	bindUniforms(cmdb, 0, 0, ctx.m_lightShading.m_commonToken);
 	bindUniforms(cmdb, 0, 1, ctx.m_lightShading.m_pointLightsToken);
 	bindUniforms(cmdb, 0, 2, ctx.m_lightShading.m_spotLightsToken);

+ 6 - 3
src/anki/renderer/LightBin.cpp

@@ -35,6 +35,8 @@ public:
 
 class ShaderPointLight : public ShaderLight
 {
+public:
+	Array<Vec4, 6> m_cubeFaceCoordinates;
 };
 
 class ShaderSpotLight : public ShaderLight
@@ -671,11 +673,12 @@ void LightBin::writeAndBinPointLight(
 
 	if(lightEl.m_shadowRenderQueues[0] == nullptr || !ctx.m_shadowsEnabled)
 	{
-		slight.m_diffuseColorShadowmapId.w() = INVALID_TEXTURE_INDEX;
+		slight.m_cubeFaceCoordinates[0].x() = INVALID_TEXTURE_INDEX;
 	}
 	else
 	{
-		slight.m_diffuseColorShadowmapId.w() = lightEl.m_textureArrayIndex;
+		memcpy(
+			&slight.m_cubeFaceCoordinates[0][0], &lightEl.m_textureAtlasUvs[0][0], sizeof(lightEl.m_textureAtlasUvs));
 	}
 
 	slight.m_specularColorRadius = Vec4(lightEl.m_specularColor, lightEl.m_radius);
@@ -711,7 +714,7 @@ void LightBin::writeAndBinSpotLight(
 	ShaderSpotLight& light = ctx.m_spotLights[idx];
 	F32 shadowmapIndex = INVALID_TEXTURE_INDEX;
 
-	if(lightEl.m_shadowRenderQueue != nullptr && ctx.m_shadowsEnabled)
+	if(lightEl.hasShadow() && ctx.m_shadowsEnabled)
 	{
 		// bias * proj_l * view_l * world_c
 		light.m_texProjectionMat = lightEl.m_textureMatrix * ctx.m_camTrf;

+ 6 - 7
src/anki/renderer/LightShading.cpp

@@ -163,16 +163,15 @@ void LightShading::run(RenderingContext& ctx)
 	cmdb->informTextureCurrentUsage(m_r->getSsao().getRt(), TextureUsageBit::SAMPLED_FRAGMENT);
 	cmdb->bindTexture(1, 4, m_r->getSsao().getRt());
 
-	cmdb->bindTexture(0, 0, m_r->getShadowMapping().m_spotTex);
-	cmdb->bindTexture(0, 1, m_r->getShadowMapping().m_omniTexArray);
-	cmdb->bindTexture(0, 2, m_r->getIndirect().getReflectionTexture());
-	cmdb->bindTexture(0, 3, m_r->getIndirect().getIrradianceTexture());
+	cmdb->bindTexture(0, 0, m_r->getShadowMapping().m_shadowAtlas);
+	cmdb->bindTexture(0, 1, m_r->getIndirect().getReflectionTexture());
+	cmdb->bindTexture(0, 2, m_r->getIndirect().getIrradianceTexture());
 	cmdb->bindTextureAndSampler(
-		0, 4, m_r->getIndirect().getIntegrationLut(), m_r->getIndirect().getIntegrationLutSampler());
+		0, 3, m_r->getIndirect().getIntegrationLut(), m_r->getIndirect().getIntegrationLutSampler());
 	cmdb->bindTexture(
-		0, 5, (ctx.m_lightShading.m_diffDecalTex) ? ctx.m_lightShading.m_diffDecalTex : m_r->getDummyTexture());
+		0, 4, (ctx.m_lightShading.m_diffDecalTex) ? ctx.m_lightShading.m_diffDecalTex : m_r->getDummyTexture());
 	cmdb->bindTexture(0,
-		6,
+		5,
 		(ctx.m_lightShading.m_normRoughnessDecalTex) ? ctx.m_lightShading.m_normRoughnessDecalTex
 													 : m_r->getDummyTexture());
 

+ 2 - 1
src/anki/renderer/RenderQueue.h

@@ -60,10 +60,11 @@ public:
 	Vec3 m_diffuseColor;
 	Vec3 m_specularColor;
 	Array<RenderQueue*, 6> m_shadowRenderQueues;
-	U32 m_textureArrayIndex; ///< Renderer internal.
 	const void* m_userData;
 	RenderQueueDrawCallback m_drawCallback;
 
+	Array<Vec4, 6> m_textureAtlasUvs; ///< Renderer internal.
+
 	Bool hasShadow() const
 	{
 		return m_shadowRenderQueues[0] != nullptr;

+ 2 - 1
src/anki/renderer/Renderer.cpp

@@ -437,7 +437,7 @@ TextureInitInfo Renderer::create2DRenderTargetInitInfo(
 	return init;
 }
 
-TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf)
+TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf, const ClearValue& clearVal)
 {
 	ANKI_ASSERT(!!(inf.m_usage & TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
 
@@ -480,6 +480,7 @@ TexturePtr Renderer::createAndClearRenderTarget(const TextureInitInfo& inf)
 					fbInit.m_colorAttachments[0].m_surface = surf;
 					fbInit.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
 					fbInit.m_colorAttachments[0].m_stencilLoadOperation = AttachmentLoadOperation::CLEAR;
+					fbInit.m_colorAttachments[0].m_clearValue = clearVal;
 				}
 				FramebufferPtr fb = m_gr->newInstance<Framebuffer>(fbInit);
 

+ 2 - 53
src/anki/renderer/Renderer.h

@@ -79,57 +79,6 @@ public:
 		TexturePtr m_normRoughnessDecalTex;
 	} m_lightShading;
 
-	class ShadowMapping
-	{
-	public:
-		class SpotCasterInfo
-		{
-		public:
-			SpotLightQueueElement* m_light = nullptr;
-			WeakArray<CommandBufferPtr> m_cmdbs; ///< One per thread.
-			Array<U32, 4> m_renderArea;
-			U8 m_batchIdx = MAX_U8;
-		};
-
-		class OmniCasterInfo
-		{
-		public:
-			PointLightQueueElement* m_light = nullptr;
-			WeakArray<CommandBufferPtr> m_cmdbs; ///< Dimensions are [threadId][faceIdx]
-			U32 m_cacheEntry = MAX_U32;
-			U8 m_firstBatchIdx = MAX_U8;
-		};
-
-		WeakArray<SpotCasterInfo> m_spotCasters;
-		WeakArray<OmniCasterInfo> m_omniCasters;
-
-		StackAllocator<U8> m_alloc;
-
-		ShadowMapping(const StackAllocator<U8>& alloc)
-			: m_alloc(alloc)
-		{
-		}
-
-		~ShadowMapping()
-		{
-			for(SpotCasterInfo& inf : m_spotCasters)
-			{
-				for(U i = 0; i < inf.m_cmdbs.getSize(); ++i)
-				{
-					inf.m_cmdbs[i].reset(nullptr);
-				}
-			}
-
-			for(OmniCasterInfo& inf : m_omniCasters)
-			{
-				for(U i = 0; i < inf.m_cmdbs.getSize(); ++i)
-				{
-					inf.m_cmdbs[i].reset(nullptr);
-				}
-			}
-		}
-	} m_shadowMapping;
-
 	class ForwardShading
 	{
 	public:
@@ -144,7 +93,6 @@ public:
 	RenderingContext(const StackAllocator<U8>& alloc)
 		: m_tempAllocator(alloc)
 		, m_lensFlare(alloc)
-		, m_shadowMapping(alloc)
 	{
 	}
 };
@@ -325,7 +273,8 @@ anki_internal:
 		U mipsCount = 1,
 		CString name = {});
 
-	ANKI_USE_RESULT TexturePtr createAndClearRenderTarget(const TextureInitInfo& inf);
+	ANKI_USE_RESULT TexturePtr createAndClearRenderTarget(
+		const TextureInitInfo& inf, const ClearValue& clearVal = ClearValue());
 
 	GrManager& getGrManager()
 	{

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 427 - 489
src/anki/renderer/ShadowMapping.cpp


+ 76 - 62
src/anki/renderer/ShadowMapping.h

@@ -20,8 +20,7 @@ namespace anki
 class ShadowMapping : public RenderingPass
 {
 anki_internal:
-	TexturePtr m_spotTex; ///< ESM map.
-	TexturePtr m_omniTexArray; ///< ESM map.
+	TexturePtr m_shadowAtlas; ///< ESM texture atlas.
 
 	ShadowMapping(Renderer* r)
 		: RenderingPass(r)
@@ -34,8 +33,6 @@ anki_internal:
 
 	void prepareBuildCommandBuffers(RenderingContext& ctx);
 
-	void prepareBuildCommandBuffers2(RenderingContext& ctx);
-
 	void buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount);
 
 	void setPreRunBarriers(RenderingContext& ctx);
@@ -45,65 +42,27 @@ anki_internal:
 	void setPostRunBarriers(RenderingContext& ctx);
 
 private:
-	class CacheEntry
-	{
-	public:
-		U32 m_timestamp = 0; ///< Timestamp of last render or light change
-		U64 m_lightUuid = 0;
-	};
-
-	class SpotCacheEntry : public CacheEntry
-	{
-	public:
-		Array<U32, 4> m_renderArea;
-		Array<F32, 4> m_uv;
-	};
-
-	class OmniCacheEntry : public CacheEntry
-	{
-	public:
-		U32 m_layerId;
-		Array<FramebufferPtr, 6> m_fbs;
-	};
-
-	U32 m_tileResolution; ///< Shadowmap resolution
-	U32 m_atlasResolution;
+	/// @name ESM stuff
+	/// @{
 
-	DynamicArray<SpotCacheEntry> m_spots;
-	DynamicArray<OmniCacheEntry> m_omnis;
-
-	FramebufferPtr m_spotsFb;
-
-	struct
-	{
-		TexturePtr m_rt; ///< Shadowmap that will be resolved to ESM maps.
-		FramebufferPtr m_fb;
-		U32 m_batchSize = 0;
-	} m_scratchSm;
-
-	ShaderProgramResourcePtr m_esmResolveProg;
-	ShaderProgramPtr m_esmResolveGrProg;
-
-#if 1
+	/// The ESM map consists of tiles.
 	class Tile
 	{
 	public:
 		U64 m_timestamp = 0;
 		U64 m_lightUuid = 0;
 		U8 m_face = 0;
+		Bool8 m_pinned = false; ///< If true we cannot allocate from it.
 
-		Array<F32, 4> m_uv;
-		Array<U32, 2> m_viewportXY;
+		Vec4 m_uv;
+		Array<U32, 4> m_viewport;
 	};
 
-	DynamicArray<Tile> m_tiles;
-	U32 m_tileCountPerRowOrColumn = 0;
-
 	class TileKey
 	{
 	public:
 		U64 m_lightUuid;
-		U8 m_face;
+		U64 m_face;
 
 		U64 computeHash() const
 		{
@@ -111,27 +70,82 @@ private:
 		}
 	};
 
+	FramebufferPtr m_esmFb;
+	U32 m_tileResolution = 0; ///< Tile resolution.
+	U32 m_atlasResolution = 0; ///< Atlas size is (m_atlasResolution, m_atlasResolution)
+	U32 m_tileCountPerRowOrColumn = 0;
+	DynamicArray<Tile> m_tiles;
+
+	ShaderProgramResourcePtr m_esmResolveProg;
+	ShaderProgramPtr m_esmResolveGrProg;
+
 	HashMap<TileKey, U32> m_lightUuidToTileIdx;
 
-	Bool allocateTile(U64 lightTimestamp, U64 lightUuid, U32 face, U32& tileAllocated);
+	Bool allocateTile(U64 lightTimestamp, U64 lightUuid, U32 face, U32& tileAllocated, Bool& inTheCache);
 	static Bool shouldRenderTile(U64 lightTimestamp, U64 lightUuid, U32 face, const Tile& tileIdx);
-#endif
 
-	ANKI_USE_RESULT Error initInternal(const ConfigSet& initializer);
+	class EsmResolveWorkItem
+	{
+	public:
+		Vec4 m_uvIn; ///< UV + size that point to the scratch buffer.
+		Array<U32, 4> m_viewportOut; ///< Viewport in the ESM RT.
+		F32 m_cameraNear;
+		F32 m_cameraFar;
+	};
+	WeakArray<EsmResolveWorkItem> m_esmResolveWorkItems;
+
+	ANKI_USE_RESULT Error initEsm(const ConfigSet& cfg);
+
+	static Mat4 createSpotLightTextureMatrix(const Tile& tile);
+	/// @}
+
+	/// @name Scratch buffer stuff
+	/// @{
+	TexturePtr m_scratchRt; ///< Size of the RT is (m_scratchTileSize * m_scratchTileCount, m_scratchTileSize).
+	FramebufferPtr m_scratchFb;
+	U32 m_scratchTileCount = 0;
+	U32 m_scratchTileResolution = 0;
+	U32 m_freeScratchTiles = 0;
+
+	class ScratchBufferWorkItem
+	{
+	public:
+		Array<U32, 4> m_viewport;
+		RenderQueue* m_renderQueue;
+		U32 m_firstRenderableElement;
+		U32 m_renderableElementCount;
+		U32 m_threadPoolTaskIdx;
+	};
+
+	struct LightToRenderToScratchInfo;
+
+	WeakArray<ScratchBufferWorkItem> m_scratchWorkItems;
+	WeakArray<CommandBufferPtr> m_scratchSecondLevelCmdbs;
+
+	ANKI_USE_RESULT Error initScratch(const ConfigSet& cfg);
+	/// @}
 
-	/// Find the best shadowmap for that light
-	template<typename TLightElement, typename TShadowmap, typename TContainer>
-	void bestCandidate(const TLightElement& light, TContainer& arr, TShadowmap*& out);
+	/// @name Misc & common
+	/// @{
 
-	/// Check if a shadow pass can be skipped.
-	Bool skip(PointLightQueueElement& light, OmniCacheEntry& sm);
-	Bool skip(SpotLightQueueElement& light, SpotCacheEntry& sm);
+	/// Try to allocate a number of scratch tiles and regular tiles.
+	Bool allocateTilesAndScratchTiles(U64 lightUuid,
+		U32 faceCount,
+		const U64* faceTimestamps,
+		const U32* faceIndices,
+		U32* tileIndices,
+		U32* scratchTileIndices);
 
-	void doSpotLight(
-		const SpotLightQueueElement& light, CommandBufferPtr& cmdBuff, U threadId, U threadCount, U tileIdx) const;
+	/// Add new work to render to scratch buffer and ESM buffer.
+	void newScratchAndEsmResloveRenderWorkItems(U32 tileIdx,
+		U32 scratchTileIdx,
+		RenderQueue* lightRenderQueue,
+		DynamicArrayAuto<LightToRenderToScratchInfo>& scratchWorkItem,
+		DynamicArrayAuto<EsmResolveWorkItem>& esmResolveWorkItem,
+		U32& drawcallCount) const;
 
-	void doOmniLight(
-		const PointLightQueueElement& light, CommandBufferPtr cmdbs[], U threadId, U threadCount, U firstTileIdx) const;
+	ANKI_USE_RESULT Error initInternal(const ConfigSet& config);
+	/// @}
 };
 /// @}
 

+ 1 - 2
src/anki/renderer/Volumetric.cpp

@@ -88,8 +88,7 @@ void VolumetricMain::run(RenderingContext& ctx)
 	TexturePtr& history = m_rt[(m_r->getFrameCount() + 1) & 1];
 	cmdb->informTextureCurrentUsage(history, TextureUsageBit::SAMPLED_FRAGMENT);
 	cmdb->bindTexture(0, 2, history);
-	cmdb->bindTexture(0, 3, m_r->getShadowMapping().m_spotTex);
-	cmdb->bindTexture(0, 4, m_r->getShadowMapping().m_omniTexArray);
+	cmdb->bindTexture(0, 3, m_r->getShadowMapping().m_shadowAtlas);
 
 	bindUniforms(cmdb, 0, 0, ctx.m_lightShading.m_commonToken);
 	bindUniforms(cmdb, 0, 1, ctx.m_lightShading.m_pointLightsToken);

+ 1 - 1
src/anki/scene/BodyComponent.h

@@ -43,7 +43,7 @@ public:
 		return m_body;
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override
 	{
 		m_trf = m_body->getTransform(updated);
 		return Error::NONE;

+ 1 - 1
src/anki/scene/BodyNode.cpp

@@ -22,7 +22,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 2 - 2
src/anki/scene/Camera.cpp

@@ -17,7 +17,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 
@@ -41,7 +41,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 1 - 1
src/anki/scene/DecalComponent.h

@@ -74,7 +74,7 @@ public:
 	}
 
 	/// Implements SceneComponent::update.
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override
 	{
 		updated = m_markedForUpdate;
 

+ 2 - 2
src/anki/scene/DecalNode.cpp

@@ -20,7 +20,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 
@@ -44,7 +44,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 1 - 1
src/anki/scene/FrustumComponent.cpp

@@ -22,7 +22,7 @@ FrustumComponent::FrustumComponent(SceneNode* node, Frustum* frustum)
 	setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
 }
 
-Error FrustumComponent::update(SceneNode& node, F32, F32, Bool& updated)
+Error FrustumComponent::update(SceneNode& node, Second, Second, Bool& updated)
 {
 	updated = false;
 

+ 1 - 1
src/anki/scene/FrustumComponent.h

@@ -111,7 +111,7 @@ public:
 
 	/// @name SceneComponent overrides
 	/// @{
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override;
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override;
 	/// @}
 
 	void setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag bits)

+ 1 - 1
src/anki/scene/LensFlareComponent.h

@@ -74,7 +74,7 @@ public:
 	}
 
 	/// Implements SceneComponent::update.
-	Error update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated) override
+	Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
 	{
 		updated = false;
 		return Error::NONE;

+ 4 - 4
src/anki/scene/Light.cpp

@@ -21,7 +21,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) override
+	Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 		Light& lnode = static_cast<Light&>(node);
@@ -46,7 +46,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) override
+	Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 		Light& lnode = static_cast<Light&>(node);
@@ -210,7 +210,7 @@ void PointLight::onShapeUpdate(LightComponent& light)
 	onShapeUpdateCommon(light);
 }
 
-Error PointLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error PointLight::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	if(getComponent<LightComponent>().getShadowEnabled() && m_shadowData.isEmpty())
 	{
@@ -290,7 +290,7 @@ void SpotLight::onShapeUpdate(LightComponent& light)
 		light.getOuterAngle(), light.getOuterAngle(), LightComponent::FRUSTUM_NEAR_PLANE, light.getDistance());
 }
 
-Error SpotLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error SpotLight::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	frameUpdateCommon();
 	return Error::NONE;

+ 2 - 2
src/anki/scene/Light.h

@@ -56,7 +56,7 @@ public:
 
 	ANKI_USE_RESULT Error init();
 
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 private:
 	class ShadowCombo
@@ -81,7 +81,7 @@ public:
 
 	ANKI_USE_RESULT Error init();
 
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 private:
 	PerspectiveFrustum m_frustum;

+ 1 - 1
src/anki/scene/LightComponent.cpp

@@ -17,7 +17,7 @@ LightComponent::LightComponent(SceneNode* node, LightComponentType type)
 	m_radius = 1.0;
 }
 
-Error LightComponent::update(SceneNode&, F32, F32, Bool& updated)
+Error LightComponent::update(SceneNode&, Second, Second, Bool& updated)
 {
 	updated = false;
 

+ 1 - 1
src/anki/scene/LightComponent.h

@@ -131,7 +131,7 @@ public:
 		m_flags.set(SHADOW, x);
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override;
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override;
 
 	void setupPointLightQueueElement(PointLightQueueElement& el) const
 	{

+ 1 - 1
src/anki/scene/ModelNode.cpp

@@ -134,7 +134,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated)
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 1 - 1
src/anki/scene/MoveComponent.cpp

@@ -20,7 +20,7 @@ MoveComponent::~MoveComponent()
 {
 }
 
-Error MoveComponent::update(SceneNode& node, F32, F32, Bool& updated)
+Error MoveComponent::update(SceneNode& node, Second, Second, Bool& updated)
 {
 	updated = updateWorldTransform(node);
 	return Error::NONE;

+ 3 - 3
src/anki/scene/MoveComponent.h

@@ -100,7 +100,7 @@ public:
 	}
 
 	/// Called when there is an update in the world transformation.
-	virtual ANKI_USE_RESULT Error onMoveComponentUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
+	virtual ANKI_USE_RESULT Error onMoveComponentUpdate(SceneNode& node, Second prevTime, Second crntTime)
 	{
 		return Error::NONE;
 	}
@@ -111,9 +111,9 @@ public:
 	/// Update self and children world transform recursively, if root node. Need to call this at every frame.
 	/// @note Don't update if child because we start from roots and go to children and we don't want a child to be
 	///       updated before the parent
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override;
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override;
 
-	ANKI_USE_RESULT Error onUpdate(SceneNode& node, F32 prevTime, F32 crntTime) final
+	ANKI_USE_RESULT Error onUpdate(SceneNode& node, Second prevTime, Second crntTime) final
 	{
 		return onMoveComponentUpdate(node, prevTime, crntTime);
 	}

+ 1 - 1
src/anki/scene/OccluderNode.cpp

@@ -21,7 +21,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated) override
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 6 - 6
src/anki/scene/ParticleEmitter.cpp

@@ -37,7 +37,7 @@ static Vec3 getRandom(const Vec3& initial, const Vec3& deviation)
 	}
 }
 
-void ParticleBase::revive(const ParticleEmitter& pe, const Transform& trf, F32 /*prevUpdateTime*/, F32 crntTime)
+void ParticleBase::revive(const ParticleEmitter& pe, const Transform& trf, Second /*prevUpdateTime*/, Second crntTime)
 {
 	ANKI_ASSERT(isDead());
 	const ParticleEmitterProperties& props = pe;
@@ -47,9 +47,9 @@ void ParticleBase::revive(const ParticleEmitter& pe, const Transform& trf, F32 /
 	m_timeOfBirth = crntTime;
 }
 
-void ParticleSimple::simulate(const ParticleEmitter& pe, F32 prevUpdateTime, F32 crntTime)
+void ParticleSimple::simulate(const ParticleEmitter& pe, Second prevUpdateTime, Second crntTime)
 {
-	F32 dt = crntTime - prevUpdateTime;
+	Second dt = crntTime - prevUpdateTime;
 
 	Vec4 xp = m_position;
 	Vec4 xc = m_acceleration * (dt * dt) + m_velocity * dt + xp;
@@ -59,7 +59,7 @@ void ParticleSimple::simulate(const ParticleEmitter& pe, F32 prevUpdateTime, F32
 	m_velocity += m_acceleration * dt;
 }
 
-void ParticleSimple::revive(const ParticleEmitter& pe, const Transform& trf, F32 prevUpdateTime, F32 crntTime)
+void ParticleSimple::revive(const ParticleEmitter& pe, const Transform& trf, Second prevUpdateTime, Second crntTime)
 {
 	ParticleBase::revive(pe, trf, prevUpdateTime, crntTime);
 	m_velocity = Vec4(0.0);
@@ -189,7 +189,7 @@ public:
 	{
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32, F32, Bool& updated) override
+	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false; // Don't care about updates for this component
 
@@ -366,7 +366,7 @@ void ParticleEmitter::createParticlesSimpleSimulation()
 	}
 }
 
-Error ParticleEmitter::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error ParticleEmitter::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	// - Deactivate the dead particles
 	// - Calc the AABB

+ 16 - 16
src/anki/scene/ParticleEmitter.h

@@ -33,32 +33,32 @@ public:
 	{
 	}
 
-	F32 getTimeOfBirth() const
+	Second getTimeOfBirth() const
 	{
 		return m_timeOfBirth;
 	}
 
-	F32& getTimeOfBirth()
+	Second& getTimeOfBirth()
 	{
 		return m_timeOfBirth;
 	}
 
-	void setTimeOfBirth(const F32 x)
+	void setTimeOfBirth(const Second x)
 	{
 		m_timeOfBirth = x;
 	}
 
-	F32 getTimeOfDeath() const
+	Second getTimeOfDeath() const
 	{
 		return m_timeOfDeath;
 	}
 
-	F32& getTimeOfDeath()
+	Second& getTimeOfDeath()
 	{
 		return m_timeOfDeath;
 	}
 
-	void setTimeOfDeath(const F32 x)
+	void setTimeOfDeath(const Second x)
 	{
 		m_timeOfDeath = x;
 	}
@@ -76,10 +76,10 @@ public:
 	}
 
 	/// Revive the particle
-	virtual void revive(const ParticleEmitter& pe, const Transform& trf, F32 prevUpdateTime, F32 crntTime);
+	virtual void revive(const ParticleEmitter& pe, const Transform& trf, Second prevUpdateTime, Second crntTime);
 
 	/// Only relevant for non-bullet simulations
-	virtual void simulate(const ParticleEmitter& pe, F32 prevUpdateTime, F32 crntTime)
+	virtual void simulate(const ParticleEmitter& pe, Second prevUpdateTime, Second crntTime)
 	{
 		(void)pe;
 		(void)prevUpdateTime;
@@ -89,10 +89,10 @@ public:
 	virtual const Vec4& getPosition() const = 0;
 
 protected:
-	F32 m_timeOfBirth; ///< Keep the time of birth for nice effects
-	F32 m_timeOfDeath = -1.0; ///< Time of death. If < 0.0 then dead
-	F32 m_size = 1.0;
-	F32 m_alpha = 1.0;
+	Second m_timeOfBirth; ///< Keep the time of birth for nice effects
+	Second m_timeOfDeath = -1.0; ///< Time of death. If < 0.0 then dead
+	Second m_size = 1.0;
+	Second m_alpha = 1.0;
 };
 
 /// Simple particle for simple simulation
@@ -103,9 +103,9 @@ public:
 	{
 	}
 
-	void revive(const ParticleEmitter& pe, const Transform& trf, F32 prevUpdateTime, F32 crntTime) override;
+	void revive(const ParticleEmitter& pe, const Transform& trf, Second prevUpdateTime, Second crntTime) override;
 
-	void simulate(const ParticleEmitter& pe, F32 prevUpdateTime, F32 crntTime) override;
+	void simulate(const ParticleEmitter& pe, Second prevUpdateTime, Second crntTime) override;
 
 	const Vec4& getPosition() const override
 	{
@@ -163,7 +163,7 @@ public:
 
 	/// @name SceneNode virtuals
 	/// @{
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 	/// @}
 
 private:
@@ -179,7 +179,7 @@ private:
 
 	ParticleEmitterResourcePtr m_particleEmitterResource;
 	DynamicArray<ParticleBase*> m_particles;
-	F32 m_timeLeftForNextEmission = 0.0;
+	Second m_timeLeftForNextEmission = 0.0;
 	Obb m_obb;
 
 	// Opt: We dont have to make extra calculations if the ParticleEmitter's rotation is the identity

+ 1 - 1
src/anki/scene/PlayerControllerComponent.h

@@ -43,7 +43,7 @@ public:
 		m_player->setVelocity(forwardSpeed, strafeSpeed, jumpSpeed, forwardDir);
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override
 	{
 		m_trf = m_player->getTransform(updated);
 		return Error::NONE;

+ 2 - 2
src/anki/scene/PlayerNode.cpp

@@ -23,7 +23,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) override
+	Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 
@@ -69,7 +69,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) override
+	Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 

+ 2 - 2
src/anki/scene/ReflectionProbe.cpp

@@ -26,7 +26,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) override
+	Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
 		updated = false;
 
@@ -127,7 +127,7 @@ void ReflectionProbe::onMoveUpdate(MoveComponent& move)
 	reflc.setPosition(move.getWorldTransform().getOrigin());
 }
 
-Error ReflectionProbe::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error ReflectionProbe::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	// Check the reflection probe component and if it's marked for rendering enable the frustum components
 	const ReflectionProbeComponent& reflc = getComponent<ReflectionProbeComponent>();

+ 1 - 1
src/anki/scene/ReflectionProbe.h

@@ -46,7 +46,7 @@ public:
 		m_cubemapArrayIdx = cubemapArrayIdx;
 	}
 
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 private:
 	class CubeSide

+ 1 - 1
src/anki/scene/ReflectionProxy.cpp

@@ -21,7 +21,7 @@ public:
 	{
 	}
 
-	Error update(SceneNode& node, F32, F32, Bool& updated) final
+	Error update(SceneNode& node, Second, Second, Bool& updated) final
 	{
 		updated = false;
 

+ 1 - 1
src/anki/scene/ReflectionProxyComponent.cpp

@@ -18,7 +18,7 @@ void ReflectionProxyComponent::setQuad(U index, const Vec4& a, const Vec4& b, co
 	m_faces[index].m_vertices[3] = d;
 }
 
-Error ReflectionProxyComponent::update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated)
+Error ReflectionProxyComponent::update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated)
 {
 	if(m_dirty)
 	{

+ 1 - 1
src/anki/scene/ReflectionProxyComponent.h

@@ -48,7 +48,7 @@ public:
 		return m_faces;
 	}
 
-	ANKI_USE_RESULT Error update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated) final;
+	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) final;
 
 private:
 	DynamicArray<Face> m_faces; ///< Quads.

+ 1 - 1
src/anki/scene/SceneComponent.cpp

@@ -35,7 +35,7 @@ Timestamp SceneComponent::getGlobalTimestamp() const
 	return m_node->getGlobalTimestamp();
 }
 
-Error SceneComponent::updateReal(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated)
+Error SceneComponent::updateReal(SceneNode& node, Second prevTime, Second crntTime, Bool& updated)
 {
 	Error err = update(node, prevTime, crntTime, updated);
 	if(!err && updated)

+ 4 - 4
src/anki/scene/SceneComponent.h

@@ -67,20 +67,20 @@ public:
 	/// @param prevTime Previous update time.
 	/// @param crntTime Current update time.
 	/// @param[out] updated true if an update happened.
-	virtual ANKI_USE_RESULT Error update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated)
+	virtual ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated)
 	{
 		updated = false;
 		return Error::NONE;
 	}
 
 	/// Called if SceneComponent::update returned true.
-	virtual ANKI_USE_RESULT Error onUpdate(SceneNode& node, F32 prevTime, F32 crntTime)
+	virtual ANKI_USE_RESULT Error onUpdate(SceneNode& node, Second prevTime, Second crntTime)
 	{
 		return Error::NONE;
 	}
 
 	/// Called only by the SceneGraph
-	ANKI_USE_RESULT Error updateReal(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated);
+	ANKI_USE_RESULT Error updateReal(SceneNode& node, Second prevTime, Second crntTime, Bool& updated);
 
 	U64 getUuid() const
 	{
@@ -113,7 +113,7 @@ public:
 
 protected:
 	SceneNode* m_node = nullptr;
-	Timestamp m_timestamp = 0; ///< Indicates when an update happened
+	Timestamp m_timestamp = 1; ///< Indicates when an update happened
 
 private:
 	SceneComponentType m_type;

+ 4 - 4
src/anki/scene/SceneGraph.cpp

@@ -27,8 +27,8 @@ public:
 	IntrusiveList<SceneNode>::Iterator m_crntNode;
 	SpinLock m_crntNodeLock;
 
-	F32 m_prevUpdateTime;
-	F32 m_crntTime;
+	Second m_prevUpdateTime;
+	Second m_crntTime;
 };
 
 class UpdateSceneNodesTask : public ThreadPoolTask
@@ -187,7 +187,7 @@ void SceneGraph::deleteNodesMarkedForDeletion()
 	}
 }
 
-Error SceneGraph::update(F32 prevUpdateTime, F32 crntTime)
+Error SceneGraph::update(Second prevUpdateTime, Second crntTime)
 {
 	ANKI_ASSERT(m_mainCam);
 	ANKI_TRACE_SCOPED_EVENT(SCENE_UPDATE);
@@ -241,7 +241,7 @@ void SceneGraph::doVisibilityTests(RenderQueue& rqueue)
 	anki::doVisibilityTests(*m_mainCam, *this, rqueue);
 }
 
-Error SceneGraph::updateNode(F32 prevTime, F32 crntTime, SceneNode& node)
+Error SceneGraph::updateNode(Second prevTime, Second crntTime, SceneNode& node)
 {
 	ANKI_TRACE_INC_COUNTER(SCENE_NODES_UPDATED, 1);
 

+ 4 - 4
src/anki/scene/SceneGraph.h

@@ -84,7 +84,7 @@ public:
 		m_mainCam = cam;
 		m_activeCameraChangeTimestamp = getGlobalTimestamp();
 	}
-	U32 getActiveCameraChangeTimestamp() const
+	Timestamp getActiveCameraChangeTimestamp() const
 	{
 		return m_activeCameraChangeTimestamp;
 	}
@@ -120,7 +120,7 @@ public:
 		return *m_stagingAlloc;
 	}
 
-	ANKI_USE_RESULT Error update(F32 prevUpdateTime, F32 crntTime);
+	ANKI_USE_RESULT Error update(Second prevUpdateTime, Second crntTime);
 
 	void doVisibilityTests(RenderQueue& rqueue);
 
@@ -237,7 +237,7 @@ private:
 	HashMap<CString, SceneNode*, CStringHasher> m_nodesDict;
 
 	SceneNode* m_mainCam = nullptr;
-	Timestamp m_activeCameraChangeTimestamp = getGlobalTimestamp();
+	Timestamp m_activeCameraChangeTimestamp = 0;
 	PerspectiveCamera* m_defaultMainCam = nullptr;
 
 	EventManager m_events;
@@ -261,7 +261,7 @@ private:
 	void deleteNodesMarkedForDeletion();
 
 	ANKI_USE_RESULT Error updateNodes(UpdateSceneNodesCtx& ctx) const;
-	ANKI_USE_RESULT static Error updateNode(F32 prevTime, F32 crntTime, SceneNode& node);
+	ANKI_USE_RESULT static Error updateNode(Second prevTime, Second crntTime, SceneNode& node);
 };
 
 template<typename Node, typename... Args>

+ 0 - 14
src/anki/scene/SceneNode.cpp

@@ -70,20 +70,6 @@ SceneFrameAllocator<U8> SceneNode::getFrameAllocator() const
 	return m_scene->getFrameAllocator();
 }
 
-U32 SceneNode::getLastUpdateFrame() const
-{
-	U32 max = 0;
-
-	Error err = iterateComponents([&max](const SceneComponent& comp) -> Error {
-		max = std::max(max, comp.getTimestamp());
-		return Error::NONE;
-	});
-
-	(void)err;
-
-	return max;
-}
-
 ResourceManager& SceneNode::getResourceManager()
 {
 	return m_scene->getResourceManager();

+ 4 - 5
src/anki/scene/SceneNode.h

@@ -68,6 +68,7 @@ public:
 
 	Timestamp getComponentMaxTimestamp() const
 	{
+		ANKI_ASSERT(m_maxComponentTimestamp > 0);
 		return m_maxComponentTimestamp;
 	}
 
@@ -83,23 +84,21 @@ public:
 	/// This is called by the scene every frame after logic and before rendering. By default it does nothing.
 	/// @param prevUpdateTime Timestamp of the previous update
 	/// @param crntTime Timestamp of this update
-	virtual ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime)
+	virtual ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime)
 	{
 		(void)prevUpdateTime;
 		(void)crntTime;
 		return Error::NONE;
 	}
 
-	ANKI_USE_RESULT Error frameUpdateComplete(F32 prevUpdateTime, F32 crntTime, Timestamp maxComponentTimestamp)
+	ANKI_USE_RESULT Error frameUpdateComplete(Second prevUpdateTime, Second crntTime, Timestamp maxComponentTimestamp)
 	{
 		m_sectorVisitedBitset.unsetAll();
 		m_maxComponentTimestamp = maxComponentTimestamp;
+		ANKI_ASSERT(maxComponentTimestamp > 0);
 		return frameUpdate(prevUpdateTime, crntTime);
 	}
 
-	/// Return the last frame the node was updated. It checks all components
-	U32 getLastUpdateFrame() const;
-
 	/// Inform if a sector has visited this node.
 	/// @return The previous value.
 	Bool fetchSetSectorVisited(U testId, Bool visited)

+ 2 - 2
src/anki/scene/Sector.cpp

@@ -138,7 +138,7 @@ Error Portal::init(const CString& meshFname)
 	return Error::NONE;
 }
 
-Error Portal::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error Portal::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	MoveComponent& move = getComponent<MoveComponent>();
 	if(move.getTimestamp() == getGlobalTimestamp())
@@ -346,7 +346,7 @@ List<SpatialComponent*>::Iterator Sector::findSpatialComponent(SpatialComponent*
 	return it;
 }
 
-Error Sector::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+Error Sector::frameUpdate(Second prevUpdateTime, Second crntTime)
 {
 	MoveComponent& move = getComponent<MoveComponent>();
 	if(move.getTimestamp() == getGlobalTimestamp())

+ 2 - 2
src/anki/scene/Sector.h

@@ -107,7 +107,7 @@ public:
 
 	ANKI_USE_RESULT Error init(const CString& modelFname);
 
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 	/// Add reference to sector.
 	void tryAddSector(Sector* sector);
@@ -145,7 +145,7 @@ public:
 	void tryAddSpatialComponent(SpatialComponent* sp);
 	void tryRemoveSpatialComponent(SpatialComponent* sp);
 
-	ANKI_USE_RESULT Error frameUpdate(F32 prevUpdateTime, F32 crntTime) override;
+	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 	void deferredUpdate();
 

+ 1 - 1
src/anki/scene/SkinComponent.cpp

@@ -34,7 +34,7 @@ void SkinComponent::playAnimation(U track, AnimationResourcePtr anim, F64 startT
 	m_tracks[track].m_repeat = repeat;
 }
 
-Error SkinComponent::update(SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated)
+Error SkinComponent::update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated)
 {
 	updated = false;
 	const F64 timeDiff = crntTime - prevTime;

+ 1 - 1
src/anki/scene/SkinComponent.h

@@ -27,7 +27,7 @@ public:
 
 	~SkinComponent();
 
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override;
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override;
 
 	void playAnimation(U track, AnimationResourcePtr anim, F64 startTime, Bool repeat);
 

+ 1 - 1
src/anki/scene/SpatialComponent.cpp

@@ -24,7 +24,7 @@ SpatialComponent::~SpatialComponent()
 	getSceneGraph().getSectorGroup().spatialDeleted(this);
 }
 
-Error SpatialComponent::update(SceneNode&, F32, F32, Bool& updated)
+Error SpatialComponent::update(SceneNode&, Second, Second, Bool& updated)
 {
 	m_flags.unset(Flag::VISIBLE_ANY);
 

+ 1 - 1
src/anki/scene/SpatialComponent.h

@@ -111,7 +111,7 @@ public:
 
 	/// @name SceneComponent overrides
 	/// @{
-	ANKI_USE_RESULT Error update(SceneNode&, F32, F32, Bool& updated) override;
+	ANKI_USE_RESULT Error update(SceneNode&, Second, Second, Bool& updated) override;
 	/// @}
 
 private:

+ 2 - 1
src/anki/scene/Visibility.cpp

@@ -393,7 +393,7 @@ void VisibilityTestTask::test(ThreadHive& hive)
 			{
 				PointLightQueueElement* el = m_result.m_pointLights.newElement(alloc);
 				lc->setupPointLightQueueElement(*el);
-				el->m_textureArrayIndex = MAX_U32;
+				zeroMemory(el->m_textureAtlasUvs);
 
 				if(lc->getShadowEnabled())
 				{
@@ -511,6 +511,7 @@ void CombineResultsTask::combine()
 		m_results->m_shadowRenderablesLastUpdateTimestamp =
 			max(m_results->m_shadowRenderablesLastUpdateTimestamp, m_tests[i].m_timestamp);
 	}
+	ANKI_ASSERT(m_results->m_shadowRenderablesLastUpdateTimestamp);
 
 #define ANKI_VIS_COMBINE(t_, member_)                                                      \
 	{                                                                                      \

+ 20 - 1
src/anki/util/DynamicArray.h

@@ -265,6 +265,18 @@ public:
 		}
 	}
 
+	/// Move the data from this object. It's like moving (operator or constructor) but instead of moving to another
+	/// object of the same type it moves to 3 values.
+	void moveAndReset(Value*& data, PtrSize& size, PtrSize& storageSize)
+	{
+		data = m_data;
+		size = m_size;
+		storageSize = m_capacity;
+		m_data = nullptr;
+		m_size = 0;
+		m_capacity = 0;
+	}
+
 protected:
 	PtrSize m_capacity = 0;
 
@@ -281,9 +293,9 @@ class DynamicArrayAuto : public DynamicArray<T>
 {
 public:
 	using Base = DynamicArray<T>;
+	using Base::m_capacity;
 	using Base::m_data;
 	using Base::m_size;
-	using Base::m_capacity;
 	using typename Base::Value;
 
 	template<typename TAllocator>
@@ -352,6 +364,13 @@ public:
 		Base::resize(m_alloc, size);
 	}
 
+	/// @copydoc DynamicArray::moveAndReset
+	void moveAndReset(Value*& data, PtrSize& size, PtrSize& storageSize)
+	{
+		Base::moveAndReset(data, size, storageSize);
+		// Don't touch the m_alloc
+	}
+
 private:
 	GenericMemoryPoolAllocator<T> m_alloc;
 };

+ 1 - 1
src/anki/util/HighRezTimer.cpp

@@ -22,7 +22,7 @@ void HighRezTimer::stop()
 	m_stopTime = getCurrentTime();
 }
 
-HighRezTimer::Scalar HighRezTimer::getElapsedTime() const
+Second HighRezTimer::getElapsedTime() const
 {
 	if(m_stopTime == 0.0)
 	{

+ 5 - 8
src/anki/util/HighRezTimer.h

@@ -17,9 +17,6 @@ namespace anki
 class HighRezTimer
 {
 public:
-	/// The type that the timer manipulates the results
-	using Scalar = F64;
-
 	/// Start the timer
 	void start();
 
@@ -27,17 +24,17 @@ public:
 	void stop();
 
 	/// Get the time elapsed between start and stop (if its stopped) or between start and the current time.
-	Scalar getElapsedTime() const;
+	Second getElapsedTime() const;
 
 	/// Get the current date's seconds
-	static Scalar getCurrentTime();
+	static Second getCurrentTime();
 
 	/// Micro sleep. The resolution is in nanoseconds.
-	static void sleep(Scalar seconds);
+	static void sleep(Second seconds);
 
 private:
-	Scalar m_startTime = 0.0;
-	Scalar m_stopTime = 0.0;
+	Second m_startTime = 0.0;
+	Second m_stopTime = 0.0;
 };
 /// @}
 

+ 4 - 4
src/anki/util/HighRezTimerPosix.cpp

@@ -45,7 +45,7 @@ static U64 getNs()
 	return ticks;
 }
 
-void HighRezTimer::sleep(Scalar sec)
+void HighRezTimer::sleep(Second sec)
 {
 	ANKI_ASSERT(sec >= 0.0);
 	int wasError;
@@ -65,10 +65,10 @@ void HighRezTimer::sleep(Scalar sec)
 	} while(wasError && (errno == EINTR));
 }
 
-HighRezTimer::Scalar HighRezTimer::getCurrentTime()
+Second HighRezTimer::getCurrentTime()
 {
-	// Scalar(ticks) / 1000.0
-	return static_cast<Scalar>(getNs()) * 1e-9;
+	// Second(ticks) / 1000.0
+	return static_cast<Second>(getNs()) * 1e-9;
 }
 
 } // end namespace anki

+ 4 - 4
src/anki/util/HighRezTimerWindows.cpp

@@ -35,16 +35,16 @@ static U32 getMs()
 	return now - init.m_start;
 }
 
-void HighRezTimer::sleep(Scalar sec)
+void HighRezTimer::sleep(Second sec)
 {
 	U32 ms = static_cast<U32>(sec * 1000.0);
 	Sleep(ms);
 }
 
-HighRezTimer::Scalar HighRezTimer::getCurrentTime()
+Second HighRezTimer::getCurrentTime()
 {
-	// Scalar(ticks) / 1000.0
-	return static_cast<Scalar>(getMs()) * 0.001;
+	// Second(ticks) / 1000.0
+	return static_cast<Second>(getMs()) * 0.001;
 }
 
 } // end namespace anki

+ 2 - 0
src/anki/util/StdTypes.h

@@ -74,6 +74,8 @@ using Bool = int; ///< Fast boolean type
 using Bool8 = I8; ///< Small 8bit boolean type
 using Bool32 = I32; ///< A 32bit boolean
 
+using Second = F64; ///< The base time unit is second.
+
 /// Representation of error and a wrapper on top of error codes.
 class Error
 {

+ 2 - 2
tests/util/HashMap.cpp

@@ -178,7 +178,7 @@ ANKI_TEST(Util, HashMap)
 			akMap.pushBack(alloc, vals[i], vals[i]);
 		}
 		timer.stop();
-		HighRezTimer::Scalar akTime = timer.getElapsedTime();
+		Second akTime = timer.getElapsedTime();
 
 		// Put the vals STL
 		timer.start();
@@ -187,7 +187,7 @@ ANKI_TEST(Util, HashMap)
 			stdMap[vals[i]] = vals[i];
 		}
 		timer.stop();
-		HighRezTimer::Scalar stlTime = timer.getElapsedTime();
+		Second stlTime = timer.getElapsedTime();
 
 		printf("Inserting bench: STL %f AnKi %f | %f%%\n", stlTime, akTime, stlTime / akTime * 100.0);
 

+ 6 - 6
tests/util/SparseArray.cpp

@@ -355,7 +355,7 @@ ANKI_TEST(Util, SparseArrayBench)
 			akMap.emplace(allocAk, vals[i], vals[i]);
 		}
 		timer.stop();
-		HighRezTimer::Scalar akTime = timer.getElapsedTime();
+		Second akTime = timer.getElapsedTime();
 
 		// STL
 		timer.start();
@@ -364,7 +364,7 @@ ANKI_TEST(Util, SparseArrayBench)
 			stdMap[vals[i]] = vals[i];
 		}
 		timer.stop();
-		HighRezTimer::Scalar stlTime = timer.getElapsedTime();
+		Second stlTime = timer.getElapsedTime();
 
 		ANKI_TEST_LOGI("Inserting bench: STL %f AnKi %f | %f%%", stlTime, akTime, stlTime / akTime * 100.0);
 	}
@@ -384,7 +384,7 @@ ANKI_TEST(Util, SparseArrayBench)
 			count += *it;
 		}
 		timer.stop();
-		HighRezTimer::Scalar akTime = timer.getElapsedTime();
+		Second akTime = timer.getElapsedTime();
 
 		// Find values STL
 		timer.start();
@@ -393,7 +393,7 @@ ANKI_TEST(Util, SparseArrayBench)
 			count += stdMap[vals[i]];
 		}
 		timer.stop();
-		HighRezTimer::Scalar stlTime = timer.getElapsedTime();
+		Second stlTime = timer.getElapsedTime();
 
 		// Print the "count" so that the compiler won't optimize it
 		ANKI_TEST_LOGI("Find bench: STL %f AnKi %f | %f%% (r:%d)", stlTime, akTime, stlTime / akTime * 100.0, count);
@@ -413,7 +413,7 @@ ANKI_TEST(Util, SparseArrayBench)
 		std::random_shuffle(vals.begin(), vals.end());
 
 		// Random delete AnKi
-		HighRezTimer::Scalar akTime = 0.0;
+		Second akTime = 0.0;
 		for(U i = 0; i < vals.size(); ++i)
 		{
 			auto it = akMap.find(vals[i]);
@@ -425,7 +425,7 @@ ANKI_TEST(Util, SparseArrayBench)
 		}
 
 		// Random delete STL
-		HighRezTimer::Scalar stlTime = 0.0;
+		Second stlTime = 0.0;
 		for(U i = 0; i < vals.size(); ++i)
 		{
 			auto it = stdMap.find(vals[i]);

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott