Browse Source

Make NativeWindow and Input singletons

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
38795390e9
55 changed files with 546 additions and 532 deletions
  1. 1 1
      AnKi/AnKi.h
  2. 1 1
      AnKi/CMakeLists.txt
  3. 0 1
      AnKi/Core.h
  4. 22 23
      AnKi/Core/App.cpp
  5. 2 16
      AnKi/Core/App.h
  6. 1 15
      AnKi/Core/CMakeLists.txt
  7. 17 0
      AnKi/Core/Common.h
  8. 0 109
      AnKi/Core/NativeWindowAndroid.cpp
  9. 0 41
      AnKi/Core/NativeWindowHeadless.cpp
  10. 1 1
      AnKi/Gr/Gl/GrManagerImpl.cpp
  11. 2 2
      AnKi/Gr/Gl/GrManagerImplSdl.cpp
  12. 0 2
      AnKi/Gr/GrManager.h
  13. 3 3
      AnKi/Gr/Vulkan/GrManagerImpl.cpp
  14. 2 2
      AnKi/Gr/Vulkan/GrManagerImpl.h
  15. 3 3
      AnKi/Gr/Vulkan/GrManagerImplAndroid.cpp
  16. 4 4
      AnKi/Gr/Vulkan/GrManagerImplHeadless.cpp
  17. 5 4
      AnKi/Gr/Vulkan/GrManagerImplSdl.cpp
  18. 0 13
      AnKi/Input/CMakeLists.txt
  19. 0 64
      AnKi/Input/InputDummy.cpp
  20. 1 1
      AnKi/Renderer/ConfigVars.defs.h
  21. 0 1
      AnKi/Scene/Common.h
  22. 6 4
      AnKi/Scene/Components/ModelComponent.cpp
  23. 2 2
      AnKi/Ui/Canvas.cpp
  24. 0 1
      AnKi/Ui/Common.h
  25. 1 1
      AnKi/Util/Logger.cpp
  26. 9 8
      AnKi/Util/Singleton.h
  27. 1 1
      AnKi/Util/String.h
  28. 2 1
      AnKi/Window.h
  29. 16 0
      AnKi/Window/CMakeLists.txt
  30. 34 0
      AnKi/Window/Common.h
  31. 13 15
      AnKi/Window/Input.h
  32. 28 35
      AnKi/Window/InputAndroid.cpp
  33. 3 3
      AnKi/Window/InputAndroid.h
  34. 70 0
      AnKi/Window/InputDummy.cpp
  35. 31 42
      AnKi/Window/InputSdl.cpp
  36. 2 3
      AnKi/Window/InputSdl.h
  37. 0 0
      AnKi/Window/KeyCode.defs.h
  38. 1 1
      AnKi/Window/KeyCode.h
  39. 13 11
      AnKi/Window/NativeWindow.h
  40. 105 0
      AnKi/Window/NativeWindowAndroid.cpp
  41. 3 3
      AnKi/Window/NativeWindowAndroid.h
  42. 46 0
      AnKi/Window/NativeWindowHeadless.cpp
  43. 1 1
      AnKi/Window/NativeWindowHeadless.h
  44. 35 40
      AnKi/Window/NativeWindowSdl.cpp
  45. 3 3
      AnKi/Window/NativeWindowSdl.h
  46. 9 5
      Samples/Common/SampleApp.cpp
  47. 18 18
      Samples/PhysicsPlayground/Main.cpp
  48. 1 1
      Samples/SkeletalAnimation/Main.cpp
  49. 10 6
      Sandbox/Main.cpp
  50. 3 4
      Tests/Framework/Framework.cpp
  51. 1 0
      Tests/Framework/Framework.h
  52. 5 5
      Tests/Gr/Gr.cpp
  53. 1 1
      Tests/Gr/GrTextureBuffer.cpp
  54. 6 8
      Tests/Ui/Ui.cpp
  55. 2 2
      Tools/Image/ImageViewerMain.cpp

+ 1 - 1
AnKi/AnKi.h

@@ -11,7 +11,7 @@
 #include <AnKi/Scene.h>
 #include <AnKi/Renderer.h>
 #include <AnKi/Script.h>
-#include <AnKi/Input.h>
+#include <AnKi/Window.h>
 #include <AnKi/Resource.h>
 #include <AnKi/Physics.h>
 #include <AnKi/Gr.h>

+ 1 - 1
AnKi/CMakeLists.txt

@@ -1,4 +1,4 @@
-set(ANKI_SUB_DIRS Importer Core Script Renderer Scene Ui Input Physics Resource Gr Collision Math Util ShaderCompiler
+set(ANKI_SUB_DIRS Importer Core Script Renderer Scene Ui Window Physics Resource Gr Collision Math Util ShaderCompiler
 	Shaders)
 foreach(TMP ${ANKI_SUB_DIRS})
 	add_subdirectory(${TMP})

+ 0 - 1
AnKi/Core.h

@@ -7,5 +7,4 @@
 
 #include <AnKi/Core/App.h>
 #include <AnKi/Core/ConfigSet.h>
-#include <AnKi/Core/NativeWindow.h>
 #include <AnKi/Core/CoreTracer.h>

+ 22 - 23
AnKi/Core/App.cpp

@@ -16,9 +16,9 @@
 #include <AnKi/Core/CoreTracer.h>
 #include <AnKi/Core/DeveloperConsole.h>
 #include <AnKi/Core/StatsUi.h>
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 #include <AnKi/Core/MaliHwCounters.h>
-#include <AnKi/Input/Input.h>
+#include <AnKi/Window/Input.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Resource/ResourceManager.h>
@@ -145,10 +145,8 @@ void App::cleanup()
 	m_maliHwCounters = nullptr;
 	GrManager::deleteInstance(m_gr);
 	m_gr = nullptr;
-	Input::deleteInstance(m_input);
-	m_input = nullptr;
-	NativeWindow::deleteInstance(m_window);
-	m_window = nullptr;
+	Input::freeSingleton();
+	NativeWindow::freeSingleton();
 
 #if ANKI_ENABLE_TRACE
 	deleteInstance(m_mainPool, m_coreTracer);
@@ -157,8 +155,10 @@ void App::cleanup()
 
 	ConfigSet::freeSingleton();
 
-	m_settingsDir.destroy(m_mainPool);
-	m_cacheDir.destroy(m_mainPool);
+	m_settingsDir.destroy();
+	m_cacheDir.destroy();
+
+	CoreMemoryPool::freeSingleton();
 }
 
 Error App::init(AllocAlignedCallback allocCb, void* allocCbUserData)
@@ -180,6 +180,8 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	setSignalHandlers();
 
 	initMemoryCallbacks(allocCb, allocCbUserData);
+	CoreMemoryPool::allocateSingleton(allocCb, allocCbUserData);
+
 	m_mainPool.init(allocCb, allocCbUserData, "Core");
 
 	ANKI_CHECK(initDirs());
@@ -244,8 +246,6 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	// Window
 	//
 	NativeWindowInitInfo nwinit;
-	nwinit.m_allocCallback = m_mainPool.getAllocationCallback();
-	nwinit.m_allocCallbackUserData = m_mainPool.getAllocationCallbackUserData();
 	nwinit.m_width = ConfigSet::getSingleton().getWidth();
 	nwinit.m_height = ConfigSet::getSingleton().getHeight();
 	nwinit.m_depthBits = 0;
@@ -253,13 +253,14 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	nwinit.m_fullscreenDesktopRez = ConfigSet::getSingleton().getWindowFullscreen() > 0;
 	nwinit.m_exclusiveFullscreen = ConfigSet::getSingleton().getWindowFullscreen() == 2;
 	nwinit.m_targetFps = ConfigSet::getSingleton().getCoreTargetFps();
-	ANKI_CHECK(NativeWindow::newInstance(nwinit, m_window));
+	NativeWindow::allocateSingleton();
+	ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
 
 	//
 	// Input
 	//
-	ANKI_CHECK(Input::newInstance(m_mainPool.getAllocationCallback(), m_mainPool.getAllocationCallbackUserData(),
-								  m_window, m_input));
+	Input::allocateSingleton();
+	ANKI_CHECK(Input::getSingleton().init());
 
 	//
 	// ThreadPool
@@ -275,7 +276,6 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	grInit.m_allocCallback = m_mainPool.getAllocationCallback();
 	grInit.m_allocCallbackUserData = m_mainPool.getAllocationCallbackUserData();
 	grInit.m_cacheDirectory = m_cacheDir.toCString();
-	grInit.m_window = m_window;
 
 	ANKI_CHECK(GrManager::newInstance(grInit, m_gr));
 
@@ -345,7 +345,6 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	uiInitInfo.m_allocCallback = m_mainPool.getAllocationCallback();
 	uiInitInfo.m_allocCallbackUserData = m_mainPool.getAllocationCallbackUserData();
 	uiInitInfo.m_grManager = m_gr;
-	uiInitInfo.m_input = m_input;
 	uiInitInfo.m_resourceFilesystem = m_resourceFs;
 	uiInitInfo.m_resourceManager = m_resources;
 	uiInitInfo.m_rebarPool = m_rebarPool;
@@ -362,7 +361,8 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	// Renderer
 	//
 	MainRendererInitInfo renderInit;
-	renderInit.m_swapchainSize = UVec2(m_window->getWidth(), m_window->getHeight());
+	renderInit.m_swapchainSize =
+		UVec2(NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
 	renderInit.m_allocCallback = m_mainPool.getAllocationCallback();
 	renderInit.m_allocCallbackUserData = m_mainPool.getAllocationCallbackUserData();
 	renderInit.m_threadHive = m_threadHive;
@@ -394,7 +394,6 @@ Error App::initInternal(AllocAlignedCallback allocCb, void* allocCbUserData)
 	sceneInit.m_globalTimestamp = &m_globalTimestamp;
 	sceneInit.m_gpuSceneMemoryPool = m_gpuSceneMemPool;
 	sceneInit.m_gpuSceneMicroPatcher = m_gpuSceneMicroPatcher;
-	sceneInit.m_input = m_input;
 	sceneInit.m_resourceManager = m_resources;
 	sceneInit.m_scriptManager = m_script;
 	sceneInit.m_threadHive = m_threadHive;
@@ -425,9 +424,9 @@ Error App::initDirs()
 	StringRaii home(&m_mainPool);
 	ANKI_CHECK(getHomeDirectory(home));
 
-	m_settingsDir.sprintf(m_mainPool, "%s/.anki", &home[0]);
+	m_settingsDir.sprintf("%s/.anki", &home[0]);
 #else
-	m_settingsDir.sprintf(m_mainPool, "%s/.anki", g_androidApp->activity->internalDataPath);
+	m_settingsDir.sprintf("%s/.anki", g_androidApp->activity->internalDataPath);
 #endif
 
 	if(!directoryExists(m_settingsDir.toCString()))
@@ -441,18 +440,18 @@ Error App::initDirs()
 	}
 
 	// Cache
-	m_cacheDir.sprintf(m_mainPool, "%s/cache", &m_settingsDir[0]);
+	m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
 
 	const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
 	if(ConfigSet::getSingleton().getCoreClearCaches() && cacheDirExists)
 	{
-		ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", &m_cacheDir[0]);
+		ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
 		ANKI_CHECK(removeDirectory(m_cacheDir.toCString(), m_mainPool));
 		ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
 	}
 	else if(!cacheDirExists)
 	{
-		ANKI_CORE_LOGI("Will create cache dir: %s", &m_cacheDir[0]);
+		ANKI_CORE_LOGI("Will create cache dir: %s", m_cacheDir.cstr());
 		ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
 	}
 
@@ -492,7 +491,7 @@ Error App::mainLoop()
 			crntTime = (!benchmarkMode) ? HighRezTimer::getCurrentTime() : (prevUpdateTime + 1.0_sec / 60.0_sec);
 
 			// Update
-			ANKI_CHECK(m_input->handleEvents());
+			ANKI_CHECK(Input::getSingleton().handleEvents());
 
 			// User update
 			ANKI_CHECK(userMainLoop(quit, crntTime - prevUpdateTime));

+ 2 - 16
AnKi/Core/App.h

@@ -15,8 +15,6 @@ namespace anki {
 // Forward
 class CoreTracer;
 class ThreadHive;
-class NativeWindow;
-class Input;
 class GrManager;
 class MainRenderer;
 class SceneGraph;
@@ -77,11 +75,6 @@ public:
 		return Error::kNone;
 	}
 
-	Input& getInput()
-	{
-		return *m_input;
-	}
-
 	SceneGraph& getSceneGraph()
 	{
 		return *m_scene;
@@ -102,11 +95,6 @@ public:
 		return *m_script;
 	}
 
-	NativeWindow& getWindow()
-	{
-		return *m_window;
-	}
-
 	void setDisplayDeveloperConsole(Bool display)
 	{
 		m_consoleEnabled = display;
@@ -124,8 +112,6 @@ private:
 #if ANKI_ENABLE_TRACE
 	CoreTracer* m_coreTracer = nullptr;
 #endif
-	NativeWindow* m_window = nullptr;
-	Input* m_input = nullptr;
 	ThreadHive* m_threadHive = nullptr;
 	GrManager* m_gr = nullptr;
 	MaliHwCounters* m_maliHwCounters = nullptr;
@@ -145,8 +131,8 @@ private:
 	UiImmediateModeBuilderPtr m_console;
 	Bool m_consoleEnabled = false;
 	Timestamp m_globalTimestamp = 1;
-	String m_settingsDir; ///< The path that holds the configuration
-	String m_cacheDir; ///< This is used as a cache
+	CoreString m_settingsDir; ///< The path that holds the configuration
+	CoreString m_cacheDir; ///< This is used as a cache
 	U64 m_resourceCompletedAsyncTaskCount = 0;
 
 	class MemStats

+ 1 - 15
AnKi/Core/CMakeLists.txt

@@ -17,24 +17,10 @@ set(headers
 	DeveloperConsole.h
 	GpuMemoryPools.h
 	MaliHwCounters.h
-	NativeWindow.h
 	StatsUi.h
 	StatsUi.defs.h
 	StdinListener.h)
 
-if(ANKI_HEADLESS)
-	set(sources ${sources} NativeWindowHeadless.cpp)
-	set(headers ${headers} NativeWindowHeadless.h)
-elseif(SDL)
-	set(sources ${sources} NativeWindowSdl.cpp)
-	set(headers ${headers} NativeWindowSdl.h)
-elseif(ANDROID)
-	set(sources ${sources} NativeWindowAndroid.cpp)
-	set(headers ${headers} NativeWindowAndroid.h)
-else()
-	message(FATAL_ERROR "Not implemented")
-endif()
-
 add_library(AnKiCore ${sources} ${headers})
 
 if(SDL)
@@ -50,4 +36,4 @@ elseif(WINDOWS)
 endif()
 
 target_compile_definitions(AnKiCore PRIVATE -DANKI_SOURCE_FILE)
-target_link_libraries(AnKiCore AnKiGr AnKiResource AnKiUi AnKiRenderer AnKiUtil AnKiPhysics AnKiScript AnKiInput ${extra_libs})
+target_link_libraries(AnKiCore AnKiGr AnKiResource AnKiUi AnKiRenderer AnKiUtil AnKiPhysics AnKiScript AnKiWindow ${extra_libs})

+ 17 - 0
AnKi/Core/Common.h

@@ -7,6 +7,7 @@
 
 #include <AnKi/Config.h>
 #include <AnKi/Util/StdTypes.h>
+#include <AnKi/Util/MemoryPool.h>
 
 namespace anki {
 
@@ -15,4 +16,20 @@ namespace anki {
 #define ANKI_CORE_LOGW(...) ANKI_LOG("CORE", kWarning, __VA_ARGS__)
 #define ANKI_CORE_LOGF(...) ANKI_LOG("CORE", kFatal, __VA_ARGS__)
 
+class CoreMemoryPool : public HeapMemoryPool, public MakeSingleton<CoreMemoryPool>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+private:
+	CoreMemoryPool(AllocAlignedCallback allocCb, void* allocCbUserData)
+		: HeapMemoryPool(allocCb, allocCbUserData, "CoreMemPool")
+	{
+	}
+
+	~CoreMemoryPool() = default;
+};
+
+using CoreString = BaseStringRaii<SingletonMemoryPoolWrapper<CoreMemoryPool>>;
+
 } // end namespace anki

+ 0 - 109
AnKi/Core/NativeWindowAndroid.cpp

@@ -1,109 +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/Core/NativeWindowAndroid.h>
-
-namespace anki {
-
-Error NativeWindow::newInstance(const NativeWindowInitInfo& initInfo, NativeWindow*& nativeWindow)
-{
-	NativeWindowAndroid* andwin = static_cast<NativeWindowAndroid*>(initInfo.m_allocCallback(
-		initInfo.m_allocCallbackUserData, nullptr, sizeof(NativeWindowAndroid), alignof(NativeWindowAndroid)));
-	callConstructor(*andwin);
-
-	const Error err = andwin->init(initInfo);
-	if(err)
-	{
-		callDestructor(*andwin);
-		initInfo.m_allocCallback(initInfo.m_allocCallbackUserData, andwin, 0, 0);
-		nativeWindow = nullptr;
-		return err;
-	}
-	else
-	{
-		nativeWindow = andwin;
-		return Error::kNone;
-	}
-}
-
-void NativeWindow::deleteInstance(NativeWindow* window)
-{
-	if(window)
-	{
-		NativeWindowAndroid* self = static_cast<NativeWindowAndroid*>(window);
-		AllocAlignedCallback callback = self->m_pool.getAllocationCallback();
-		void* userData = self->m_pool.getAllocationCallbackUserData();
-		callDestructor(*self);
-		callback(userData, self, 0, 0);
-	}
-}
-
-void NativeWindow::setWindowTitle([[maybe_unused]] CString title)
-{
-	// Nothing
-}
-
-NativeWindowAndroid::~NativeWindowAndroid()
-{
-	ANKI_CORE_LOGI("Destroying Android window");
-	ANativeActivity_finish(g_androidApp->activity);
-
-	// Loop until destroyRequested is set
-	while(!g_androidApp->destroyRequested)
-	{
-		int ident;
-		int events;
-		android_poll_source* source;
-
-		while((ident = ALooper_pollAll(0, nullptr, &events, reinterpret_cast<void**>(&source))) >= 0)
-		{
-			if(source != nullptr)
-			{
-				source->process(g_androidApp, source);
-			}
-		}
-	}
-
-	m_nativeWindow = nullptr;
-}
-
-Error NativeWindowAndroid::init([[maybe_unused]] const NativeWindowInitInfo& init)
-{
-	ANKI_CORE_LOGI("Initializing Android window");
-
-	m_pool.init(init.m_allocCallback, init.m_allocCallbackUserData);
-
-	// Loop until the window is ready
-	while(g_androidApp->window == nullptr)
-	{
-		int ident;
-		int events;
-		android_poll_source* source;
-
-		const int timeoutMs = 5;
-		while((ident = ALooper_pollAll(timeoutMs, nullptr, &events, reinterpret_cast<void**>(&source))) >= 0)
-		{
-			if(source != nullptr)
-			{
-				source->process(g_androidApp, source);
-			}
-		}
-	}
-
-	m_nativeWindow = g_androidApp->window;
-
-	if(init.m_targetFps)
-	{
-		ANativeWindow_setFrameRate(m_nativeWindow, init.m_targetFps, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
-	}
-
-	// Set some stuff
-	m_width = ANativeWindow_getWidth(g_androidApp->window);
-	m_height = ANativeWindow_getHeight(g_androidApp->window);
-
-	return Error::kNone;
-}
-
-} // end namespace anki

+ 0 - 41
AnKi/Core/NativeWindowHeadless.cpp

@@ -1,41 +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/Core/NativeWindowHeadless.h>
-
-namespace anki {
-
-Error NativeWindow::newInstance(const NativeWindowInitInfo& initInfo, NativeWindow*& nativeWindow)
-{
-	NativeWindowHeadless* hwin = static_cast<NativeWindowHeadless*>(initInfo.m_allocCallback(
-		initInfo.m_allocCallbackUserData, nullptr, sizeof(NativeWindowHeadless), alignof(NativeWindowHeadless)));
-	callConstructor(*hwin);
-
-	hwin->m_pool.init(initInfo.m_allocCallback, initInfo.m_allocCallbackUserData);
-	hwin->m_width = initInfo.m_width;
-	hwin->m_height = initInfo.m_height;
-
-	nativeWindow = hwin;
-	return Error::kNone;
-}
-
-void NativeWindow::deleteInstance(NativeWindow* window)
-{
-	if(window)
-	{
-		NativeWindowHeadless* self = static_cast<NativeWindowHeadless*>(window);
-		AllocAlignedCallback callback = self->m_pool.getAllocationCallback();
-		void* userData = self->m_pool.getAllocationCallbackUserData();
-		callDestructor(*self);
-		callback(userData, self, 0, 0);
-	}
-}
-
-void NativeWindow::setWindowTitle([[maybe_unused]] CString title)
-{
-	// Nothing
-}
-
-} // end namespace anki

+ 1 - 1
AnKi/Gr/Gl/GrManagerImpl.cpp

@@ -8,7 +8,7 @@
 #include <AnKi/Gr/gl/RenderingThread.h>
 #include <AnKi/Gr/gl/GlState.h>
 #include <AnKi/Core/Config.h>
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 
 namespace anki {
 

+ 2 - 2
AnKi/Gr/Gl/GrManagerImplSdl.cpp

@@ -7,8 +7,8 @@
 
 #include <AnKi/Gr/gl/GrManagerImpl.h>
 #include <AnKi/Gr/GrManager.h>
-#include <AnKi/Core/NativeWindow.h>
-#include <AnKi/Core/NativeWindowSdl.h>
+#include <AnKi/Window/NativeWindow.h>
+#include <AnKi/Window/NativeWindowSdl.h>
 #include <AnKi/Core/Config.h>
 #include <SDL.h>
 #include <GL/glew.h>

+ 0 - 2
AnKi/Gr/GrManager.h

@@ -25,8 +25,6 @@ public:
 	void* m_allocCallbackUserData = nullptr;
 
 	CString m_cacheDirectory;
-
-	NativeWindow* m_window = nullptr;
 };
 
 /// Graphics statistics.

+ 3 - 3
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -120,8 +120,8 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	ANKI_VK_LOGI("Initializing Vulkan backend");
 
 	ANKI_CHECK(initInstance());
-	ANKI_CHECK(initSurface(init));
-	ANKI_CHECK(initDevice(init));
+	ANKI_CHECK(initSurface());
+	ANKI_CHECK(initDevice());
 
 	for(VulkanQueueType qtype : EnumIterable<VulkanQueueType>())
 	{
@@ -564,7 +564,7 @@ Error GrManagerImpl::initInstance()
 	return Error::kNone;
 }
 
-Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
+Error GrManagerImpl::initDevice()
 {
 	uint32_t count = 0;
 	vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, nullptr);

+ 2 - 2
AnKi/Gr/Vulkan/GrManagerImpl.h

@@ -333,8 +333,8 @@ private:
 
 	Error initInternal(const GrManagerInitInfo& init);
 	Error initInstance();
-	Error initSurface(const GrManagerInitInfo& init);
-	Error initDevice(const GrManagerInitInfo& init);
+	Error initSurface();
+	Error initDevice();
 	Error initMemory();
 
 #if ANKI_GR_MANAGER_DEBUG_MEMMORY

+ 3 - 3
AnKi/Gr/Vulkan/GrManagerImplAndroid.cpp

@@ -5,15 +5,15 @@
 
 #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
 #include <AnKi/Gr/GrManager.h>
-#include <AnKi/Core/NativeWindowAndroid.h>
+#include <AnKi/Window/NativeWindowAndroid.h>
 
 namespace anki {
 
-Error GrManagerImpl::initSurface(const GrManagerInitInfo& init)
+Error GrManagerImpl::initSurface()
 {
 	VkAndroidSurfaceCreateInfoKHR createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
-	createInfo.window = static_cast<NativeWindowAndroid*>(init.m_window)->m_nativeWindow;
+	createInfo.window = static_cast<NativeWindowAndroid&>(NativeWindow::getSingleton()).m_nativeWindowAndroid;
 
 	ANKI_VK_CHECK(vkCreateAndroidSurfaceKHR(m_instance, &createInfo, nullptr, &m_surface));
 

+ 4 - 4
AnKi/Gr/Vulkan/GrManagerImplHeadless.cpp

@@ -4,19 +4,19 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 
 namespace anki {
 
-Error GrManagerImpl::initSurface(const GrManagerInitInfo& init)
+Error GrManagerImpl::initSurface()
 {
 	VkHeadlessSurfaceCreateInfoEXT createInfo = {};
 	createInfo.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
 
 	ANKI_VK_CHECK(vkCreateHeadlessSurfaceEXT(m_instance, &createInfo, nullptr, &m_surface));
 
-	m_nativeWindowWidth = init.m_window->getWidth();
-	m_nativeWindowHeight = init.m_window->getHeight();
+	m_nativeWindowWidth = NativeWindow::getSingleton().getWidth();
+	m_nativeWindowHeight = NativeWindow::getSingleton().getHeight();
 
 	return Error::kNone;
 }

+ 5 - 4
AnKi/Gr/Vulkan/GrManagerImplSdl.cpp

@@ -5,8 +5,8 @@
 
 #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
 #include <AnKi/Gr/GrManager.h>
-#include <AnKi/Core/NativeWindow.h>
-#include <AnKi/Core/NativeWindowSdl.h>
+#include <AnKi/Window/NativeWindow.h>
+#include <AnKi/Window/NativeWindowSdl.h>
 #include <SDL_syswm.h>
 #include <SDL_vulkan.h>
 
@@ -17,9 +17,10 @@
 
 namespace anki {
 
-Error GrManagerImpl::initSurface(const GrManagerInitInfo& init)
+Error GrManagerImpl::initSurface()
 {
-	if(!SDL_Vulkan_CreateSurface(static_cast<NativeWindowSdl*>(init.m_window)->m_window, m_instance, &m_surface))
+	if(!SDL_Vulkan_CreateSurface(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow, m_instance,
+								 &m_surface))
 	{
 		ANKI_VK_LOGE("SDL_Vulkan_CreateSurface() failed: %s", SDL_GetError());
 		return Error::kFunctionFailed;

+ 0 - 13
AnKi/Input/CMakeLists.txt

@@ -1,13 +0,0 @@
-file(GLOB_RECURSE headers *.h)
-
-if(ANKI_HEADLESS)
-	set(sources InputDummy.cpp)
-elseif(SDL)
-	set(sources InputSdl.cpp)
-elseif(ANDROID)
-	set(sources InputAndroid.cpp)
-endif()
-
-add_library(AnKiInput ${sources} ${headers})
-target_compile_definitions(AnKiInput PRIVATE -DANKI_SOURCE_FILE)
-target_link_libraries(AnKiInput AnKiCore AnKiImGui)

+ 0 - 64
AnKi/Input/InputDummy.cpp

@@ -1,64 +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/Input/Input.h>
-#include <AnKi/Core/NativeWindow.h>
-
-namespace anki {
-
-Error Input::newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData, NativeWindow* nativeWindow,
-						 Input*& input)
-{
-	ANKI_ASSERT(allocCallback && nativeWindow);
-
-	Input* ainput = static_cast<Input*>(allocCallback(allocCallbackUserData, nullptr, sizeof(Input), alignof(Input)));
-	callConstructor(*ainput);
-
-	ainput->m_pool.init(allocCallback, allocCallbackUserData);
-	ainput->m_nativeWindow = nativeWindow;
-
-	input = ainput;
-	return Error::kNone;
-}
-
-void Input::deleteInstance(Input* input)
-{
-	if(input)
-	{
-		AllocAlignedCallback callback = input->m_pool.getAllocationCallback();
-		void* userData = input->m_pool.getAllocationCallbackUserData();
-		callDestructor(*input);
-		callback(userData, input, 0, 0);
-	}
-}
-
-Error Input::handleEvents()
-{
-	if(m_lockCurs)
-	{
-		moveCursor(Vec2(0.0f));
-	}
-
-	return Error::kNone;
-}
-
-void Input::moveCursor(const Vec2& posNdc)
-{
-	m_mousePosNdc = posNdc;
-	m_mousePosWin.x() = U32(F32(m_nativeWindow->getWidth()) * (posNdc.x() * 0.5f + 0.5f));
-	m_mousePosWin.y() = U32(F32(m_nativeWindow->getHeight()) * (-posNdc.y() * 0.5f + 0.5f));
-}
-
-void Input::hideCursor([[maybe_unused]] Bool hide)
-{
-	// Nothing
-}
-
-Bool Input::hasTouchDevice() const
-{
-	return false;
-}
-
-} // end namespace anki

+ 1 - 1
AnKi/Renderer/ConfigVars.defs.h

@@ -58,7 +58,7 @@ ANKI_CONFIG_VAR_F32(RIndirectDiffuseVrsDistanceThreshold, 0.01f, 0.00001f, 10.0f
 					"The meters that control the VRS SRI generation")
 
 // Shadows
-ANKI_CONFIG_VAR_U32(RShadowMappingTileResolution, ((ANKI_PLATFORM_MOBILE) ? 64 : 256), 16, 2048,
+ANKI_CONFIG_VAR_U32(RShadowMappingTileResolution, ((ANKI_PLATFORM_MOBILE) ? 128 : 256), 16, 2048,
 					"Shadowmapping tile resolution")
 ANKI_CONFIG_VAR_U32(RShadowMappingTileCountPerRowOrColumn, 32, 1, 256,
 					"Shadowmapping atlas will have this number squared number of tiles")

+ 0 - 1
AnKi/Scene/Common.h

@@ -47,7 +47,6 @@ class SceneGraphExternalSubsystems
 public:
 	ThreadHive* m_threadHive = nullptr;
 	ResourceManager* m_resourceManager = nullptr;
-	Input* m_input = nullptr;
 	ScriptManager* m_scriptManager = nullptr;
 	UiManager* m_uiManager = nullptr;
 	GrManager* m_grManager = nullptr;

+ 6 - 4
AnKi/Scene/Components/ModelComponent.cpp

@@ -305,8 +305,9 @@ void ModelComponent::setupRenderableQueueElements(U32 lod, RenderingTechnique te
 		queueElem.m_worldTransformsOffset = U32(m_gpuSceneTransformsIndex * sizeof(Mat3x4) * 2
 												+ gpuArrays.getArrayBase(GpuSceneContiguousArrayType::kTransformPairs));
 		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
-		queueElem.m_geometryOffset = m_patchInfos[i].m_gpuSceneMeshLodsIndex * sizeof(GpuSceneMeshLod) * kMaxLodCount
-									 + lod * sizeof(GpuSceneMeshLod);
+		queueElem.m_geometryOffset =
+			U32(m_patchInfos[i].m_gpuSceneMeshLodsIndex * sizeof(GpuSceneMeshLod) * kMaxLodCount
+				+ lod * sizeof(GpuSceneMeshLod));
 		queueElem.m_geometryOffset += U32(gpuArrays.getArrayBase(GpuSceneContiguousArrayType::kMeshLods));
 		queueElem.m_boneTransformsOffset = (hasSkin) ? m_skinComponent->getBoneTransformsGpuSceneOffset() : 0;
 		queueElem.m_indexCount = modelInf.m_indexCount;
@@ -380,8 +381,9 @@ void ModelComponent::setupRayTracingInstanceQueueElements(U32 lod, RenderingTech
 		queueElem.m_worldTransformsOffset = U32(m_gpuSceneTransformsIndex * sizeof(Mat3x4) * 2
 												+ gpuArrays.getArrayBase(GpuSceneContiguousArrayType::kTransformPairs));
 		queueElem.m_uniformsOffset = m_patchInfos[i].m_gpuSceneUniformsOffset;
-		queueElem.m_geometryOffset = m_patchInfos[i].m_gpuSceneMeshLodsIndex * sizeof(GpuSceneMeshLod) * kMaxLodCount
-									 + lod * sizeof(GpuSceneMeshLod);
+		queueElem.m_geometryOffset =
+			U32(m_patchInfos[i].m_gpuSceneMeshLodsIndex * sizeof(GpuSceneMeshLod) * kMaxLodCount
+				+ lod * sizeof(GpuSceneMeshLod));
 		queueElem.m_geometryOffset += U32(gpuArrays.getArrayBase(GpuSceneContiguousArrayType::kMeshLods));
 		queueElem.m_indexBufferOffset = U32(modelInf.m_indexBufferOffset);
 

+ 2 - 2
AnKi/Ui/Canvas.cpp

@@ -8,7 +8,7 @@
 #include <AnKi/Ui/UiManager.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Core/GpuMemoryPools.h>
-#include <AnKi/Input/Input.h>
+#include <AnKi/Window/Input.h>
 #include <AnKi/Gr/Sampler.h>
 #include <AnKi/Gr/GrManager.h>
 
@@ -104,7 +104,7 @@ Error Canvas::init(FontPtr font, U32 fontHeight, U32 width, U32 height)
 
 void Canvas::handleInput()
 {
-	const Input& in = *getExternalSubsystems().m_input;
+	const Input& in = Input::getSingleton();
 
 	// Begin
 	setImAllocator();

+ 0 - 1
AnKi/Ui/Common.h

@@ -46,7 +46,6 @@ public:
 	ResourceFilesystem* m_resourceFilesystem = nullptr;
 	GrManager* m_grManager = nullptr;
 	RebarStagingGpuMemoryPool* m_rebarPool = nullptr;
-	Input* m_input = nullptr;
 };
 
 inline Vec2 toAnki(const ImVec2& v)

+ 1 - 1
AnKi/Util/Logger.cpp

@@ -39,7 +39,7 @@ Logger::~Logger()
 void Logger::addMessageHandler(void* data, LoggerMessageHandlerCallback callback)
 {
 	LockGuard<Mutex> lock(m_mutex);
-	m_handlers[m_handlersCount++] = Handler(data, callback);
+	m_handlers[m_handlersCount++] = Handler{data, callback};
 }
 
 void Logger::removeMessageHandler(void* data, LoggerMessageHandlerCallback callback)

+ 9 - 8
AnKi/Util/Singleton.h

@@ -23,16 +23,16 @@ template<typename T>
 class MakeSingleton
 {
 public:
-	static T& getSingleton()
+	ANKI_PURE static T& getSingleton()
 	{
 		return *m_global;
 	}
 
 	template<typename... TArgs>
-	static T& allocateSingleton(TArgs&&... args)
+	static T& allocateSingleton(TArgs... args)
 	{
 		ANKI_ASSERT(m_global == nullptr);
-		m_global = new T(std::forward<TArgs>(args)...);
+		m_global = new T(args...);
 
 #if ANKI_ENABLE_ASSERTIONS
 		++g_singletonsAllocated;
@@ -43,13 +43,14 @@ public:
 
 	static void freeSingleton()
 	{
-		ANKI_ASSERT(m_global);
-
-		delete m_global;
-		m_global = nullptr;
+		if(m_global)
+		{
+			delete m_global;
+			m_global = nullptr;
 #if ANKI_ENABLE_ASSERTIONS
-		--g_singletonsAllocated;
+			--g_singletonsAllocated;
 #endif
+		}
 	}
 
 	static Bool isAllocated()

+ 1 - 1
AnKi/Util/String.h

@@ -833,7 +833,7 @@ public:
 	using MemoryPool = TMemPool;
 
 	/// Create with pool.
-	BaseStringRaii(const MemoryPool& pool)
+	BaseStringRaii(const MemoryPool& pool = MemoryPool())
 		: Base()
 		, m_pool(pool)
 	{

+ 2 - 1
AnKi/Input.h → AnKi/Window.h

@@ -5,4 +5,5 @@
 
 #pragma once
 
-#include <AnKi/Input/Input.h>
+#include <AnKi/Window/Input.h>
+#include <AnKi/Window/NativeWindow.h>

+ 16 - 0
AnKi/Window/CMakeLists.txt

@@ -0,0 +1,16 @@
+file(GLOB_RECURSE headers *.h)
+
+if(ANKI_HEADLESS)
+	set(sources InputDummy.cpp)
+	set(sources ${sources} NativeWindowHeadless.cpp)
+elseif(SDL)
+	set(sources InputSdl.cpp)
+	set(sources ${sources} NativeWindowSdl.cpp)
+elseif(ANDROID)
+	set(sources InputAndroid.cpp)
+	set(sources ${sources} NativeWindowAndroid.cpp)
+endif()
+
+add_library(AnKiWindow ${sources} ${headers})
+target_compile_definitions(AnKiWindow PRIVATE -DANKI_SOURCE_FILE)
+target_link_libraries(AnKiWindow AnKiCore AnKiImGui)

+ 34 - 0
AnKi/Window/Common.h

@@ -0,0 +1,34 @@
+// 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/Util/StdTypes.h>
+#include <AnKi/Util/MemoryPool.h>
+
+namespace anki {
+
+#define ANKI_WIND_LOGI(...) ANKI_LOG("WIND", kNormal, __VA_ARGS__)
+#define ANKI_WIND_LOGE(...) ANKI_LOG("WIND", kError, __VA_ARGS__)
+#define ANKI_WIND_LOGW(...) ANKI_LOG("WIND", kWarning, __VA_ARGS__)
+#define ANKI_WIND_LOGF(...) ANKI_LOG("WIND", kFatal, __VA_ARGS__)
+
+class WindowMemoryPool : public HeapMemoryPool, public MakeSingleton<WindowMemoryPool>
+{
+	template<typename>
+	friend class MakeSingleton;
+
+private:
+	WindowMemoryPool(AllocAlignedCallback allocCb, void* allocCbUserData)
+		: HeapMemoryPool(allocCb, allocCbUserData, "WindowMemPool")
+	{
+	}
+
+	~WindowMemoryPool() = default;
+};
+
+using WindowString = BaseStringRaii<SingletonMemoryPoolWrapper<WindowMemoryPool>>;
+
+} // end namespace anki

+ 13 - 15
AnKi/Input/Input.h → AnKi/Window/Input.h

@@ -9,14 +9,10 @@
 #include <AnKi/Util/Singleton.h>
 #include <AnKi/Util/Array.h>
 #include <AnKi/Util/String.h>
-#include <AnKi/Input/KeyCode.h>
+#include <AnKi/Window/KeyCode.h>
 
 namespace anki {
 
-// Forward
-class InputImpl;
-class NativeWindow;
-
 enum class InputEvent : U8
 {
 	kWindowFocusLost,
@@ -27,15 +23,13 @@ enum class InputEvent : U8
 
 /// Handle the input and other events
 /// @note All positions are in NDC space
-class Input
+class Input : public MakeSingleton<Input>
 {
-	ANKI_FRIEND_CALL_CONSTRUCTOR_AND_DESTRUCTOR
+	template<typename>
+	friend class MakeSingleton;
 
 public:
-	static Error newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData,
-							 NativeWindow* nativeWindow, Input*& input);
-
-	static void deleteInstance(Input* input);
+	Error init();
 
 	U32 getKey(KeyCode i) const
 	{
@@ -135,9 +129,6 @@ public:
 	Bool hasTouchDevice() const;
 
 protected:
-	NativeWindow* m_nativeWindow = nullptr;
-	HeapMemoryPool m_pool;
-
 	/// Shows the current key state
 	/// - 0 times: unpressed
 	/// - 1 times: pressed once
@@ -165,9 +156,16 @@ protected:
 		reset();
 	}
 
-	~Input()
+	virtual ~Input()
 	{
 	}
 };
 
+template<>
+template<>
+Input& MakeSingleton<Input>::allocateSingleton<>();
+
+template<>
+void MakeSingleton<Input>::freeSingleton();
+
 } // end namespace anki

+ 28 - 35
AnKi/Input/InputAndroid.cpp → AnKi/Window/InputAndroid.cpp

@@ -3,49 +3,42 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Input/InputAndroid.h>
-#include <AnKi/Core/NativeWindowAndroid.h>
+#include <AnKi/Window/InputAndroid.h>
+#include <AnKi/Window/NativeWindowAndroid.h>
 #include <AnKi/Util/Logger.h>
 
 namespace anki {
 
-Error Input::newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData, NativeWindow* nativeWindow,
-						 Input*& input)
+template<>
+template<>
+Input& MakeSingleton<Input>::allocateSingleton<>()
 {
-	ANKI_ASSERT(allocCallback && nativeWindow);
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new InputAndroid;
 
-	InputAndroid* ainput = static_cast<InputAndroid*>(
-		allocCallback(allocCallbackUserData, nullptr, sizeof(InputAndroid), alignof(InputAndroid)));
-	callConstructor(*ainput);
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
 
-	ainput->m_pool.init(allocCallback, allocCallbackUserData);
-	ainput->m_nativeWindow = nativeWindow;
+	return *m_global;
+}
 
-	const Error err = ainput->init();
-	if(err)
-	{
-		callDestructor(*ainput);
-		allocCallback(allocCallbackUserData, ainput, 0, 0);
-		input = nullptr;
-		return err;
-	}
-	else
+template<>
+void MakeSingleton<Input>::freeSingleton()
+{
+	if(m_global)
 	{
-		input = ainput;
-		return Error::kNone;
+		delete static_cast<InputAndroid*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
 	}
 }
 
-void Input::deleteInstance(Input* input)
+Error Input::init()
 {
-	if(input)
-	{
-		InputAndroid* self = static_cast<InputAndroid*>(input);
-		AllocAlignedCallback callback = self->m_pool.getAllocationCallback();
-		void* userData = self->m_pool.getAllocationCallbackUserData();
-		callDestructor(*self);
-		callback(userData, self, 0, 0);
-	}
+	return static_cast<InputAndroid*>(this)->initInternal();
 }
 
 Error Input::handleEvents()
@@ -77,7 +70,8 @@ void Input::moveCursor(const Vec2& posNdc)
 {
 	m_mousePosNdc = posNdc;
 	m_mousePosWin =
-		UVec2((posNdc * 0.5f + 0.5f) * Vec2(F32(m_nativeWindow->getWidth()), F32(m_nativeWindow->getHeight())));
+		UVec2((posNdc * 0.5f + 0.5f)
+			  * Vec2(F32(NativeWindow::getSingleton().getWidth()), F32(NativeWindow::getSingleton().getHeight())));
 }
 
 void Input::hideCursor(Bool hide)
@@ -90,9 +84,8 @@ Bool Input::hasTouchDevice() const
 	return true;
 }
 
-Error InputAndroid::init()
+Error InputAndroid::initInternal()
 {
-	ANKI_ASSERT(m_nativeWindow);
 	g_androidApp->userData = this;
 
 	g_androidApp->onAppCmd = [](android_app* app, int32_t cmd) {
@@ -151,8 +144,8 @@ int InputAndroid::handleAndroidInput(android_app* app, AInputEvent* event)
 
 				m_touchPointerPosWin[id] = UVec2(U32(x), U32(y));
 
-				m_touchPointerPosNdc[id].x() = F32(x) / F32(m_nativeWindow->getWidth()) * 2.0f - 1.0f;
-				m_touchPointerPosNdc[id].y() = -(F32(y) / F32(m_nativeWindow->getHeight()) * 2.0f - 1.0f);
+				m_touchPointerPosNdc[id].x() = F32(x) / F32(NativeWindow::getSingleton().getWidth()) * 2.0f - 1.0f;
+				m_touchPointerPosNdc[id].y() = -(F32(y) / F32(NativeWindow::getSingleton().getHeight()) * 2.0f - 1.0f);
 
 				if(pressValue == 0 || pressValue == 1)
 				{

+ 3 - 3
AnKi/Input/InputAndroid.h → AnKi/Window/InputAndroid.h

@@ -5,8 +5,8 @@
 
 #pragma once
 
-#include <AnKi/Input.h>
-#include <AnKi/Input/KeyCode.h>
+#include <AnKi/Window/Input.h>
+#include <AnKi/Window/KeyCode.h>
 #include <android_native_app_glue.h>
 
 namespace anki {
@@ -15,7 +15,7 @@ namespace anki {
 class InputAndroid : public Input
 {
 public:
-	Error init();
+	Error initInternal();
 
 	void handleAndroidEvents(android_app* app, int32_t cmd);
 	int handleAndroidInput(android_app* app, AInputEvent* event);

+ 70 - 0
AnKi/Window/InputDummy.cpp

@@ -0,0 +1,70 @@
+// 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/Window/Input.h>
+#include <AnKi/Window/NativeWindow.h>
+
+namespace anki {
+
+template<>
+template<>
+Input& MakeSingleton<Input>::allocateSingleton<>()
+{
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new Input;
+
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
+
+	return *m_global;
+}
+
+template<>
+void MakeSingleton<Input>::freeSingleton()
+{
+	if(m_global)
+	{
+		delete static_cast<Input*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
+	}
+}
+
+Error Input::init()
+{
+	return Error::kNone;
+}
+
+Error Input::handleEvents()
+{
+	if(m_lockCurs)
+	{
+		moveCursor(Vec2(0.0f));
+	}
+
+	return Error::kNone;
+}
+
+void Input::moveCursor(const Vec2& posNdc)
+{
+	m_mousePosNdc = posNdc;
+	m_mousePosWin.x() = U32(F32(NativeWindow::getSingleton().getWidth()) * (posNdc.x() * 0.5f + 0.5f));
+	m_mousePosWin.y() = U32(F32(NativeWindow::getSingleton().getHeight()) * (-posNdc.y() * 0.5f + 0.5f));
+}
+
+void Input::hideCursor([[maybe_unused]] Bool hide)
+{
+	// Nothing
+}
+
+Bool Input::hasTouchDevice() const
+{
+	return false;
+}
+
+} // end namespace anki

+ 31 - 42
AnKi/Input/InputSdl.cpp → AnKi/Window/InputSdl.cpp

@@ -3,9 +3,9 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Input/Input.h>
-#include <AnKi/Input/InputSdl.h>
-#include <AnKi/Core/NativeWindowSdl.h>
+#include <AnKi/Window/Input.h>
+#include <AnKi/Window/InputSdl.h>
+#include <AnKi/Window/NativeWindowSdl.h>
 #include <AnKi/Util/Logger.h>
 #include <SDL.h>
 
@@ -40,7 +40,7 @@ static KeyCode sdlKeytoAnKi(SDL_Keycode sdlk)
 	case SDLK_##sdl: \
 		akk = KeyCode::k##ak; \
 		break;
-#include <AnKi/Input/KeyCode.defs.h>
+#include <AnKi/Window/KeyCode.defs.h>
 #undef ANKI_KEY_CODE
 	}
 
@@ -48,43 +48,36 @@ static KeyCode sdlKeytoAnKi(SDL_Keycode sdlk)
 	return akk;
 }
 
-Error Input::newInstance(AllocAlignedCallback allocCallback, void* allocCallbackUserData, NativeWindow* nativeWindow,
-						 Input*& input)
+template<>
+template<>
+Input& MakeSingleton<Input>::allocateSingleton<>()
 {
-	ANKI_ASSERT(allocCallback && nativeWindow);
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new InputSdl;
 
-	InputSdl* sdlinput =
-		static_cast<InputSdl*>(allocCallback(allocCallbackUserData, nullptr, sizeof(InputSdl), alignof(InputSdl)));
-	callConstructor(*sdlinput);
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
 
-	sdlinput->m_pool.init(allocCallback, allocCallbackUserData);
-	sdlinput->m_nativeWindow = nativeWindow;
+	return *m_global;
+}
 
-	const Error err = sdlinput->init();
-	if(err)
-	{
-		callDestructor(*sdlinput);
-		allocCallback(allocCallbackUserData, sdlinput, 0, 0);
-		input = nullptr;
-		return err;
-	}
-	else
+template<>
+void MakeSingleton<Input>::freeSingleton()
+{
+	if(m_global)
 	{
-		input = sdlinput;
-		return Error::kNone;
+		delete static_cast<InputSdl*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
 	}
 }
 
-void Input::deleteInstance(Input* input)
+Error Input::init()
 {
-	if(input)
-	{
-		InputSdl* self = static_cast<InputSdl*>(input);
-		AllocAlignedCallback callback = self->m_pool.getAllocationCallback();
-		void* userData = self->m_pool.getAllocationCallbackUserData();
-		callDestructor(*self);
-		callback(userData, self, 0, 0);
-	}
+	return static_cast<InputSdl*>(this)->initInternal();
 }
 
 Error Input::handleEvents()
@@ -97,10 +90,10 @@ void Input::moveCursor(const Vec2& pos)
 {
 	if(pos != m_mousePosNdc)
 	{
-		const I32 x = I32(F32(m_nativeWindow->getWidth()) * (pos.x() * 0.5f + 0.5f));
-		const I32 y = I32(F32(m_nativeWindow->getHeight()) * (-pos.y() * 0.5f + 0.5f));
+		const I32 x = I32(F32(NativeWindow::getSingleton().getWidth()) * (pos.x() * 0.5f + 0.5f));
+		const I32 y = I32(F32(NativeWindow::getSingleton().getHeight()) * (-pos.y() * 0.5f + 0.5f));
 
-		SDL_WarpMouseInWindow(static_cast<NativeWindowSdl*>(m_nativeWindow)->m_window, x, y);
+		SDL_WarpMouseInWindow(static_cast<NativeWindowSdl&>(NativeWindow::getSingleton()).m_sdlWindow, x, y);
 
 		// SDL doesn't generate a SDL_MOUSEMOTION event if the cursor is outside the window. Push that event
 		SDL_Event event;
@@ -122,18 +115,14 @@ Bool Input::hasTouchDevice() const
 	return false;
 }
 
-Error InputSdl::init()
+Error InputSdl::initInternal()
 {
-	ANKI_ASSERT(m_nativeWindow);
-
 	// Call once to clear first events
 	return handleEvents();
 }
 
 Error InputSdl::handleEventsInternal()
 {
-	ANKI_ASSERT(m_nativeWindow != nullptr);
-
 	m_textInput[0] = '\0';
 
 	// add the times a key is being pressed
@@ -192,8 +181,8 @@ Error InputSdl::handleEventsInternal()
 		case SDL_MOUSEMOTION:
 			m_mousePosWin.x() = event.button.x;
 			m_mousePosWin.y() = event.button.y;
-			m_mousePosNdc.x() = F32(event.button.x) / F32(m_nativeWindow->getWidth()) * 2.0f - 1.0f;
-			m_mousePosNdc.y() = -(F32(event.button.y) / F32(m_nativeWindow->getHeight()) * 2.0f - 1.0f);
+			m_mousePosNdc.x() = F32(event.button.x) / F32(NativeWindow::getSingleton().getWidth()) * 2.0f - 1.0f;
+			m_mousePosNdc.y() = -(F32(event.button.y) / F32(NativeWindow::getSingleton().getHeight()) * 2.0f - 1.0f);
 			break;
 		case SDL_QUIT:
 			addEvent(InputEvent::kWindowClosed);

+ 2 - 3
AnKi/Input/InputSdl.h → AnKi/Window/InputSdl.h

@@ -5,8 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Input.h>
-#include <AnKi/Input/KeyCode.h>
+#include <AnKi/Window/Input.h>
 #include <SDL_keycode.h>
 #include <unordered_map>
 
@@ -16,7 +15,7 @@ namespace anki {
 class InputSdl : public Input
 {
 public:
-	Error init();
+	Error initInternal();
 	Error handleEventsInternal();
 };
 

+ 0 - 0
AnKi/Input/KeyCode.defs.h → AnKi/Window/KeyCode.defs.h


+ 1 - 1
AnKi/Input/KeyCode.h → AnKi/Window/KeyCode.h

@@ -15,7 +15,7 @@ enum class KeyCode
 	kUnknown = 0,
 
 #define ANKI_KEY_CODE(ak, sdl) k##ak,
-#include <AnKi/Input/KeyCode.defs.h>
+#include <AnKi/Window/KeyCode.defs.h>
 #undef ANKI_KEY_CODE
 
 	kCount,

+ 13 - 11
AnKi/Core/NativeWindow.h → AnKi/Window/NativeWindow.h

@@ -5,8 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Core/Common.h>
-#include <AnKi/Util/StdTypes.h>
+#include <AnKi/Window/Common.h>
 #include <AnKi/Util/Array.h>
 #include <AnKi/Util/String.h>
 
@@ -16,9 +15,6 @@ namespace anki {
 class NativeWindowInitInfo
 {
 public:
-	AllocAlignedCallback m_allocCallback = nullptr;
-	void* m_allocCallbackUserData = nullptr;
-
 	U32 m_width = 1920;
 	U32 m_height = 1080;
 	Array<U32, 4> m_rgbaBits = {8, 8, 8, 0};
@@ -35,12 +31,13 @@ public:
 };
 
 /// Native window.
-class NativeWindow
+class NativeWindow : public MakeSingleton<NativeWindow>
 {
-public:
-	static Error newInstance(const NativeWindowInitInfo& initInfo, NativeWindow*& nativeWindow);
+	template<typename>
+	friend class MakeSingleton;
 
-	static void deleteInstance(NativeWindow* nativeWindow);
+public:
+	Error init(const NativeWindowInitInfo& inf);
 
 	U32 getWidth() const
 	{
@@ -63,8 +60,6 @@ protected:
 	U32 m_width = 0;
 	U32 m_height = 0;
 
-	HeapMemoryPool m_pool;
-
 	NativeWindow()
 	{
 	}
@@ -74,4 +69,11 @@ protected:
 	}
 };
 
+template<>
+template<>
+NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>();
+
+template<>
+void MakeSingleton<NativeWindow>::freeSingleton();
+
 } // end namespace anki

+ 105 - 0
AnKi/Window/NativeWindowAndroid.cpp

@@ -0,0 +1,105 @@
+// 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/Window/NativeWindowAndroid.h>
+
+namespace anki {
+
+template<>
+template<>
+NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
+{
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new NativeWindowAndroid();
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
+	return *m_global;
+}
+
+template<>
+void MakeSingleton<NativeWindow>::freeSingleton()
+{
+	if(m_global)
+	{
+		delete static_cast<NativeWindowAndroid*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
+	}
+}
+
+Error NativeWindow::init(const NativeWindowInitInfo& inf)
+{
+	return static_cast<NativeWindowAndroid*>(this)->initInternal(inf);
+}
+
+void NativeWindow::setWindowTitle([[maybe_unused]] CString title)
+{
+	// Nothing
+}
+
+NativeWindowAndroid::~NativeWindowAndroid()
+{
+	ANKI_WIND_LOGI("Destroying Android window");
+	ANativeActivity_finish(g_androidApp->activity);
+
+	// Loop until destroyRequested is set
+	while(!g_androidApp->destroyRequested)
+	{
+		int ident;
+		int events;
+		android_poll_source* source;
+
+		while((ident = ALooper_pollAll(0, nullptr, &events, reinterpret_cast<void**>(&source))) >= 0)
+		{
+			if(source != nullptr)
+			{
+				source->process(g_androidApp, source);
+			}
+		}
+	}
+
+	m_nativeWindowAndroid = nullptr;
+}
+
+Error NativeWindowAndroid::initInternal([[maybe_unused]] const NativeWindowInitInfo& init)
+{
+	ANKI_WIND_LOGI("Initializing Android window");
+
+	// Loop until the window is ready
+	while(g_androidApp->window == nullptr)
+	{
+		int ident;
+		int events;
+		android_poll_source* source;
+
+		const int timeoutMs = 5;
+		while((ident = ALooper_pollAll(timeoutMs, nullptr, &events, reinterpret_cast<void**>(&source))) >= 0)
+		{
+			if(source != nullptr)
+			{
+				source->process(g_androidApp, source);
+			}
+		}
+	}
+
+	m_nativeWindowAndroid = g_androidApp->window;
+
+	if(init.m_targetFps)
+	{
+		ANativeWindow_setFrameRate(m_nativeWindowAndroid, init.m_targetFps,
+								   ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+	}
+
+	// Set some stuff
+	m_width = ANativeWindow_getWidth(g_androidApp->window);
+	m_height = ANativeWindow_getHeight(g_androidApp->window);
+
+	return Error::kNone;
+}
+
+} // end namespace anki

+ 3 - 3
AnKi/Core/NativeWindowAndroid.h → AnKi/Window/NativeWindowAndroid.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 #include <android_native_app_glue.h>
 
 namespace anki {
@@ -14,11 +14,11 @@ namespace anki {
 class NativeWindowAndroid : public NativeWindow
 {
 public:
-	ANativeWindow* m_nativeWindow = nullptr;
+	ANativeWindow* m_nativeWindowAndroid = nullptr;
 
 	~NativeWindowAndroid();
 
-	Error init(const NativeWindowInitInfo& init);
+	Error initInternal(const NativeWindowInitInfo& init);
 };
 
 } // end namespace anki

+ 46 - 0
AnKi/Window/NativeWindowHeadless.cpp

@@ -0,0 +1,46 @@
+// 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/Window/NativeWindowHeadless.h>
+
+namespace anki {
+
+template<>
+template<>
+NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
+{
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new NativeWindowHeadless();
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
+	return *m_global;
+}
+
+template<>
+void MakeSingleton<NativeWindow>::freeSingleton()
+{
+	if(m_global)
+	{
+		delete static_cast<NativeWindowHeadless*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
+	}
+}
+
+Error NativeWindow::init([[maybe_unused]] const NativeWindowInitInfo& inf)
+{
+	// Nothing
+	return Error::kNone;
+}
+
+void NativeWindow::setWindowTitle([[maybe_unused]] CString title)
+{
+	// Nothing
+}
+
+} // end namespace anki

+ 1 - 1
AnKi/Core/NativeWindowHeadless.h → AnKi/Window/NativeWindowHeadless.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 
 namespace anki {
 

+ 35 - 40
AnKi/Core/NativeWindowSdl.cpp → AnKi/Window/NativeWindowSdl.cpp

@@ -3,7 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Core/NativeWindowSdl.h>
+#include <AnKi/Window/NativeWindowSdl.h>
 #include <AnKi/Util/Logger.h>
 #if ANKI_GR_BACKEND_VULKAN
 #	include <SDL_vulkan.h>
@@ -11,70 +11,65 @@
 
 namespace anki {
 
-Error NativeWindow::newInstance(const NativeWindowInitInfo& initInfo, NativeWindow*& nativeWindow)
+template<>
+template<>
+NativeWindow& MakeSingleton<NativeWindow>::allocateSingleton<>()
 {
-	NativeWindowSdl* sdlwin = static_cast<NativeWindowSdl*>(initInfo.m_allocCallback(
-		initInfo.m_allocCallbackUserData, nullptr, sizeof(NativeWindowSdl), alignof(NativeWindowSdl)));
-	callConstructor(*sdlwin);
+	ANKI_ASSERT(m_global == nullptr);
+	m_global = new NativeWindowSdl();
+#if ANKI_ENABLE_ASSERTIONS
+	++g_singletonsAllocated;
+#endif
+	return *m_global;
+}
 
-	const Error err = sdlwin->init(initInfo);
-	if(err)
-	{
-		callDestructor(*sdlwin);
-		initInfo.m_allocCallback(initInfo.m_allocCallbackUserData, sdlwin, 0, 0);
-		nativeWindow = nullptr;
-		return err;
-	}
-	else
+template<>
+void MakeSingleton<NativeWindow>::freeSingleton()
+{
+	if(m_global)
 	{
-		nativeWindow = sdlwin;
-		return Error::kNone;
+		delete static_cast<NativeWindowSdl*>(m_global);
+		m_global = nullptr;
+#if ANKI_ENABLE_ASSERTIONS
+		--g_singletonsAllocated;
+#endif
 	}
 }
 
-void NativeWindow::deleteInstance(NativeWindow* window)
+Error NativeWindow::init(const NativeWindowInitInfo& inf)
 {
-	if(window)
-	{
-		NativeWindowSdl* self = static_cast<NativeWindowSdl*>(window);
-		AllocAlignedCallback callback = self->m_pool.getAllocationCallback();
-		void* userData = self->m_pool.getAllocationCallbackUserData();
-		callDestructor(*self);
-		callback(userData, self, 0, 0);
-	}
+	return static_cast<NativeWindowSdl*>(this)->initSdl(inf);
 }
 
 void NativeWindow::setWindowTitle(CString title)
 {
 	NativeWindowSdl* self = static_cast<NativeWindowSdl*>(this);
-	SDL_SetWindowTitle(self->m_window, title.cstr());
+	SDL_SetWindowTitle(self->m_sdlWindow, title.cstr());
 }
 
 NativeWindowSdl::~NativeWindowSdl()
 {
-	if(m_window)
+	if(m_sdlWindow)
 	{
-		SDL_DestroyWindow(m_window);
+		SDL_DestroyWindow(m_sdlWindow);
 	}
 
 	SDL_QuitSubSystem(kInitSubsystems);
 	SDL_Quit();
 }
 
-Error NativeWindowSdl::init(const NativeWindowInitInfo& init)
+Error NativeWindowSdl::initSdl(const NativeWindowInitInfo& init)
 {
-	m_pool.init(init.m_allocCallback, init.m_allocCallbackUserData);
-
 	if(SDL_Init(kInitSubsystems) != 0)
 	{
-		ANKI_CORE_LOGE("SDL_Init() failed: %s", SDL_GetError());
+		ANKI_WIND_LOGE("SDL_Init() failed: %s", SDL_GetError());
 		return Error::kFunctionFailed;
 	}
 
 #if ANKI_GR_BACKEND_VULKAN
 	if(SDL_Vulkan_LoadLibrary(nullptr))
 	{
-		ANKI_CORE_LOGE("SDL_Vulkan_LoadLibrary() failed: %s", SDL_GetError());
+		ANKI_WIND_LOGE("SDL_Vulkan_LoadLibrary() failed: %s", SDL_GetError());
 		return Error::kFunctionFailed;
 	}
 #endif
@@ -82,7 +77,7 @@ Error NativeWindowSdl::init(const NativeWindowInitInfo& init)
 	//
 	// Set GL attributes
 	//
-	ANKI_CORE_LOGI("Creating SDL window. SDL version %u.%u", SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+	ANKI_WIND_LOGI("Creating SDL window. SDL version %u.%u", SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
 
 	//
 	// Create window
@@ -113,7 +108,7 @@ Error NativeWindowSdl::init(const NativeWindowInitInfo& init)
 		SDL_DisplayMode mode;
 		if(SDL_GetDesktopDisplayMode(0, &mode))
 		{
-			ANKI_CORE_LOGE("SDL_GetDesktopDisplayMode() failed: %s", SDL_GetError());
+			ANKI_WIND_LOGE("SDL_GetDesktopDisplayMode() failed: %s", SDL_GetError());
 			return Error::kFunctionFailed;
 		}
 
@@ -126,23 +121,23 @@ Error NativeWindowSdl::init(const NativeWindowInitInfo& init)
 		m_height = init.m_height;
 	}
 
-	m_window =
+	m_sdlWindow =
 		SDL_CreateWindow(&init.m_title[0], SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_width, m_height, flags);
 
-	if(m_window == nullptr)
+	if(m_sdlWindow == nullptr)
 	{
-		ANKI_CORE_LOGE("SDL_CreateWindow() failed");
+		ANKI_WIND_LOGE("SDL_CreateWindow() failed");
 		return Error::kFunctionFailed;
 	}
 
 	// Final check
 	{
 		int w, h;
-		SDL_GetWindowSize(m_window, &w, &h);
+		SDL_GetWindowSize(m_sdlWindow, &w, &h);
 		ANKI_ASSERT(m_width == U32(w) && m_height == U32(h));
 	}
 
-	ANKI_CORE_LOGI("SDL window created");
+	ANKI_WIND_LOGI("SDL window created");
 	return Error::kNone;
 }
 

+ 3 - 3
AnKi/Core/NativeWindowSdl.h → AnKi/Window/NativeWindowSdl.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <AnKi/Core/NativeWindow.h>
+#include <AnKi/Window/NativeWindow.h>
 #include <SDL.h>
 
 namespace anki {
@@ -14,11 +14,11 @@ namespace anki {
 class NativeWindowSdl : public NativeWindow
 {
 public:
-	SDL_Window* m_window = nullptr;
+	SDL_Window* m_sdlWindow = nullptr;
 
 	~NativeWindowSdl();
 
-	Error init(const NativeWindowInitInfo& init);
+	Error initSdl(const NativeWindowInitInfo& init);
 
 private:
 	static constexpr U32 kInitSubsystems =

+ 9 - 5
Samples/Common/SampleApp.cpp

@@ -48,7 +48,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	SceneGraph& scene = getSceneGraph();
 	Renderer& renderer = getMainRenderer().getOffscreenRenderer();
-	Input& in = getInput();
+	Input& in = Input::getSingleton();
 
 	if(in.getKey(KeyCode::kEscape))
 	{
@@ -270,7 +270,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 			   && in.getTouchPointerNdcPosition(touch).x() > 0.1f)
 			{
 				rotateCameraTouch = touch;
-				rotateEventInitialPos = in.getTouchPointerNdcPosition(touch) * getWindow().getAspectRatio();
+				rotateEventInitialPos =
+					in.getTouchPointerNdcPosition(touch) * NativeWindow::getSingleton().getAspectRatio();
 				break;
 			}
 		}
@@ -283,7 +284,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		if(rotateCameraTouch != TouchPointer::kCount && in.getTouchPointer(rotateCameraTouch) > 1)
 		{
 			Vec2 velocity =
-				in.getTouchPointerNdcPosition(rotateCameraTouch) * getWindow().getAspectRatio() - rotateEventInitialPos;
+				in.getTouchPointerNdcPosition(rotateCameraTouch) * NativeWindow::getSingleton().getAspectRatio()
+				- rotateEventInitialPos;
 			velocity *= 0.3f;
 
 			Euler angles(mover->getLocalRotation().getRotationPart());
@@ -302,7 +304,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 			   && in.getTouchPointerNdcPosition(touch).x() < -0.1f)
 			{
 				moveCameraTouch = touch;
-				moveEventInitialPos = in.getTouchPointerNdcPosition(touch) * getWindow().getAspectRatio();
+				moveEventInitialPos =
+					in.getTouchPointerNdcPosition(touch) * NativeWindow::getSingleton().getAspectRatio();
 				break;
 			}
 		}
@@ -315,7 +318,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		if(moveCameraTouch != TouchPointer::kCount && in.getTouchPointer(moveCameraTouch) > 0)
 		{
 			Vec2 velocity =
-				in.getTouchPointerNdcPosition(moveCameraTouch) * getWindow().getAspectRatio() - moveEventInitialPos;
+				in.getTouchPointerNdcPosition(moveCameraTouch) * NativeWindow::getSingleton().getAspectRatio()
+				- moveEventInitialPos;
 			velocity *= 2.0f;
 
 			mover->moveLocalX(moveDistance * velocity.x());

+ 18 - 18
Samples/PhysicsPlayground/Main.cpp

@@ -192,9 +192,9 @@ Error MyApp::sampleExtraInit()
 		node->setLocalTransform(Transform(Vec4(1.0f, 0.5f, 0.0f, 0.0f), Mat3x4::getIdentity(), 1.0f));
 	}
 
-	getInput().lockCursor(true);
-	getInput().hideCursor(true);
-	getInput().moveCursor(Vec2(0.0f));
+	Input::getSingleton().lockCursor(true);
+	Input::getSingleton().hideCursor(true);
+	Input::getSingleton().moveCursor(Vec2(0.0f));
 
 	return Error::kNone;
 }
@@ -204,18 +204,18 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 	// ANKI_CHECK(SampleApp::userMainLoop(quit));
 	Renderer& renderer = getMainRenderer().getOffscreenRenderer();
 
-	if(getInput().getKey(KeyCode::kEscape))
+	if(Input::getSingleton().getKey(KeyCode::kEscape))
 	{
 		quit = true;
 	}
 
-	if(getInput().getKey(KeyCode::kH) == 1)
+	if(Input::getSingleton().getKey(KeyCode::kH) == 1)
 	{
 		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "RtShadows") ? ""
 																									 : "RtShadows");
 	}
 
-	if(getInput().getKey(KeyCode::kP) == 1)
+	if(Input::getSingleton().getKey(KeyCode::kP) == 1)
 	{
 		static U32 idx = 3;
 		++idx;
@@ -238,17 +238,17 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		}
 	}
 
-	if(getInput().getKey(KeyCode::kL) == 1)
+	if(Input::getSingleton().getKey(KeyCode::kL) == 1)
 	{
 		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "Bloom") ? "" : "Bloom");
 	}
 
-	if(getInput().getKey(KeyCode::kJ) == 1)
+	if(Input::getSingleton().getKey(KeyCode::kJ) == 1)
 	{
 		ConfigSet::getSingleton().setRVrs(!ConfigSet::getSingleton().getRVrs());
 	}
 
-	if(getInput().getKey(KeyCode::kF1) == 1)
+	if(Input::getSingleton().getKey(KeyCode::kF1) == 1)
 	{
 		static U mode = 0;
 		mode = (mode + 1) % 3;
@@ -275,15 +275,15 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		SceneNode& player = getSceneGraph().findSceneNode("player");
 		PlayerControllerComponent& playerc = player.getFirstComponentOfType<PlayerControllerComponent>();
 
-		if(getInput().getKey(KeyCode::kR))
+		if(Input::getSingleton().getKey(KeyCode::kR))
 		{
 			player.getFirstComponentOfType<PlayerControllerComponent>().moveToPosition(Vec3(0.0f, 2.0f, 0.0f));
 		}
 
 		constexpr F32 ang = toRad(7.0f);
 
-		F32 y = getInput().getMousePosition().y();
-		F32 x = getInput().getMousePosition().x();
+		F32 y = Input::getSingleton().getMousePosition().y();
+		F32 x = Input::getSingleton().getMousePosition().x();
 		if(y != 0.0 || x != 0.0)
 		{
 			// Set origin
@@ -307,22 +307,22 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 
 		const F32 speed = 0.5;
 		Vec4 moveVec(0.0);
-		if(getInput().getKey(KeyCode::kW))
+		if(Input::getSingleton().getKey(KeyCode::kW))
 		{
 			moveVec.z() += 1.0f;
 		}
 
-		if(getInput().getKey(KeyCode::kA))
+		if(Input::getSingleton().getKey(KeyCode::kA))
 		{
 			moveVec.x() -= 1.0f;
 		}
 
-		if(getInput().getKey(KeyCode::kS))
+		if(Input::getSingleton().getKey(KeyCode::kS))
 		{
 			moveVec.z() -= 1.0f;
 		}
 
-		if(getInput().getKey(KeyCode::kD))
+		if(Input::getSingleton().getKey(KeyCode::kD))
 		{
 			moveVec.x() += 1.0f;
 		}
@@ -334,7 +334,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		playerc.setVelocity(moveVec.z() * speed, moveVec.x() * speed, 0.0, dir);
 	}
 
-	if(getInput().getMouseButton(MouseButton::kLeft) == 1)
+	if(Input::getSingleton().getMouseButton(MouseButton::kLeft) == 1)
 	{
 		ANKI_LOGI("Firing a monkey");
 
@@ -361,7 +361,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		ANKI_CHECK(createDestructionEvent(monkey));
 	}
 
-	if(getInput().getMouseButton(MouseButton::kRight) == 1)
+	if(Input::getSingleton().getMouseButton(MouseButton::kRight) == 1)
 	{
 		Transform camTrf = getSceneGraph().getActiveCameraNode().getWorldTransform();
 		Vec3 from = camTrf.getOrigin().xyz();

+ 1 - 1
Samples/SkeletalAnimation/Main.cpp

@@ -37,7 +37,7 @@ public:
 
 	Error userMainLoop(Bool& quit, Second elapsedTime) override
 	{
-		if(getInput().getKey(KeyCode::kZ) == 1)
+		if(Input::getSingleton().getKey(KeyCode::kZ) == 1)
 		{
 			AnimationPlayInfo animInfo;
 			animInfo.m_startTime = 0.5;

+ 10 - 6
Sandbox/Main.cpp

@@ -36,7 +36,7 @@ Error MyApp::init(int argc, char* argv[])
 
 	// Config
 #if ANKI_OS_ANDROID
-	ANKI_CHECK(m_config.setFromCommandLineArguments(argc - 1, argv + 1));
+	ANKI_CHECK(ConfigSet::getSingleton().setFromCommandLineArguments(argc - 1, argv + 1));
 #else
 	ANKI_CHECK(ConfigSet::getSingleton().setFromCommandLineArguments(argc - 2, argv + 2));
 #endif
@@ -88,7 +88,7 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 	quit = false;
 
 	SceneGraph& scene = getSceneGraph();
-	Input& in = getInput();
+	Input& in = Input::getSingleton();
 	Renderer& renderer = getMainRenderer().getOffscreenRenderer();
 
 	if(in.getKey(KeyCode::kEscape))
@@ -294,7 +294,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 			   && in.getTouchPointerNdcPosition(touch).x() > 0.1f)
 			{
 				rotateCameraTouch = touch;
-				rotateEventInitialPos = in.getTouchPointerNdcPosition(touch) * getWindow().getAspectRatio();
+				rotateEventInitialPos =
+					in.getTouchPointerNdcPosition(touch) * NativeWindow::getSingleton().getAspectRatio();
 				break;
 			}
 		}
@@ -307,7 +308,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		if(rotateCameraTouch != TouchPointer::kCount && in.getTouchPointer(rotateCameraTouch) > 1)
 		{
 			Vec2 velocity =
-				in.getTouchPointerNdcPosition(rotateCameraTouch) * getWindow().getAspectRatio() - rotateEventInitialPos;
+				in.getTouchPointerNdcPosition(rotateCameraTouch) * NativeWindow::getSingleton().getAspectRatio()
+				- rotateEventInitialPos;
 			velocity *= 0.3f;
 
 			Euler angles(mover->getLocalRotation().getRotationPart());
@@ -326,7 +328,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 			   && in.getTouchPointerNdcPosition(touch).x() < -0.1f)
 			{
 				moveCameraTouch = touch;
-				moveEventInitialPos = in.getTouchPointerNdcPosition(touch) * getWindow().getAspectRatio();
+				moveEventInitialPos =
+					in.getTouchPointerNdcPosition(touch) * NativeWindow::getSingleton().getAspectRatio();
 				break;
 			}
 		}
@@ -339,7 +342,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		if(moveCameraTouch != TouchPointer::kCount && in.getTouchPointer(moveCameraTouch) > 0)
 		{
 			Vec2 velocity =
-				in.getTouchPointerNdcPosition(moveCameraTouch) * getWindow().getAspectRatio() - moveEventInitialPos;
+				in.getTouchPointerNdcPosition(moveCameraTouch) * NativeWindow::getSingleton().getAspectRatio()
+				- moveEventInitialPos;
 			velocity *= 2.0f;
 
 			mover->moveLocalX(moveDistance * velocity.x());

+ 3 - 4
Tests/Framework/Framework.cpp

@@ -245,14 +245,14 @@ void initConfig(ConfigSet& cfg)
 NativeWindow* createWindow(ConfigSet& cfg)
 {
 	NativeWindowInitInfo inf;
-	inf.m_allocCallback = allocAligned;
 	inf.m_width = cfg.getWidth();
 	inf.m_height = cfg.getHeight();
 	inf.m_title = "AnKi unit tests";
-	NativeWindow* win;
-	const Error err = NativeWindow::newInstance(inf, win);
+	NativeWindow* win = &NativeWindow::allocateSingleton();
+	const Error err = NativeWindow::getSingleton().init(inf);
 	if(err)
 	{
+		NativeWindow::freeSingleton();
 		return nullptr;
 	}
 
@@ -271,7 +271,6 @@ GrManager* createGrManager(NativeWindow* win)
 		return nullptr;
 	}
 	inf.m_cacheDirectory = home;
-	inf.m_window = win;
 	GrManager* gr;
 	ANKI_TEST_EXPECT_NO_ERR(GrManager::newInstance(inf, gr));
 

+ 1 - 0
Tests/Framework/Framework.h

@@ -9,6 +9,7 @@
 #include <AnKi/Math.h>
 #include <AnKi/Util/Logger.h>
 #include <AnKi/Core.h>
+#include <AnKi/Window.h>
 #include <AnKi/Gr.h>
 #include <AnKi/Resource.h>
 #include <AnKi/Physics.h>

+ 5 - 5
Tests/Gr/Gr.cpp

@@ -7,8 +7,8 @@
 #include <Tests/Framework/Framework.h>
 #include <Tests/Gr/GrCommon.h>
 #include <AnKi/Gr.h>
-#include <AnKi/Core/NativeWindow.h>
-#include <AnKi/Input/Input.h>
+#include <AnKi/Window/NativeWindow.h>
+#include <AnKi/Window/Input.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Core/GpuMemoryPools.h>
@@ -244,7 +244,7 @@ static Input* input = nullptr;
 	cfg.setGrDebugMarkers(true); \
 	stagingMem = new RebarStagingGpuMemoryPool(); \
 	g_win = createWindow(cfg); \
-	ANKI_TEST_EXPECT_NO_ERR(Input::newInstance(allocAligned, nullptr, g_win, input)); \
+	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init()); \
 	g_gr = createGrManager(g_win); \
 	ANKI_TEST_EXPECT_NO_ERR(stagingMem->init(g_gr)); \
 	TransferGpuAllocator* transfAlloc = new TransferGpuAllocator(); \
@@ -259,8 +259,8 @@ static Input* input = nullptr;
 	delete transfAlloc; \
 	delete stagingMem; \
 	GrManager::deleteInstance(g_gr); \
-	Input::deleteInstance(input); \
-	NativeWindow::deleteInstance(g_win); \
+	Input::freeSingleton(); \
+	NativeWindow::freeSingleton(); \
 	ConfigSet::freeSingleton(); \
 	g_win = nullptr; \
 	g_gr = nullptr; \

+ 1 - 1
Tests/Gr/GrTextureBuffer.cpp

@@ -76,5 +76,5 @@ void main()
 	}
 
 	GrManager::deleteInstance(gr);
-	NativeWindow::deleteInstance(win);
+	NativeWindow::freeSingleton();
 }

+ 6 - 8
Tests/Ui/Ui.cpp

@@ -7,7 +7,7 @@
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Util/HighRezTimer.h>
 #include <AnKi/Ui.h>
-#include <AnKi/Input.h>
+#include <AnKi/Window.h>
 #include <AnKi/Core/GpuMemoryPools.h>
 
 using namespace anki;
@@ -66,8 +66,7 @@ ANKI_TEST(Ui, Ui)
 	cfg.setRsrcDataPaths("EngineAssets");
 
 	NativeWindow* win = createWindow(cfg);
-	Input* in;
-	ANKI_TEST_EXPECT_NO_ERR(Input::newInstance(allocAligned, nullptr, win, in));
+	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init());
 	GrManager* gr = createGrManager(win);
 	ResourceFilesystem* fs;
 	ResourceManager* resource = createResourceManager(gr, fs);
@@ -81,7 +80,6 @@ ANKI_TEST(Ui, Ui)
 	uiInitInfo.m_allocCallback = allocAligned;
 	uiInitInfo.m_allocCallbackUserData = nullptr;
 	uiInitInfo.m_grManager = gr;
-	uiInitInfo.m_input = in;
 	uiInitInfo.m_resourceFilesystem = fs;
 	uiInitInfo.m_resourceManager = resource;
 	uiInitInfo.m_rebarPool = stagingMem;
@@ -100,12 +98,12 @@ ANKI_TEST(Ui, Ui)
 		Bool done = false;
 		while(!done)
 		{
-			ANKI_TEST_EXPECT_NO_ERR(in->handleEvents());
+			ANKI_TEST_EXPECT_NO_ERR(Input::getSingleton().handleEvents());
 			HighRezTimer timer;
 			timer.start();
 
 			canvas->handleInput();
-			if(in->getKey(KeyCode::kEscape))
+			if(Input::getSingleton().getKey(KeyCode::kEscape))
 			{
 				done = true;
 			}
@@ -165,6 +163,6 @@ ANKI_TEST(Ui, Ui)
 	delete resource;
 	delete fs;
 	GrManager::deleteInstance(gr);
-	Input::deleteInstance(in);
-	NativeWindow::deleteInstance(win);
+	Input::freeSingleton();
+	NativeWindow::freeSingleton();
 }

+ 2 - 2
Tools/Image/ImageViewerMain.cpp

@@ -291,7 +291,7 @@ public:
 		StringRaii title(&pool);
 		title.sprintf("%s %u x %u Mips %u Format %s", argv[1], image->getWidth(), image->getHeight(),
 					  image->getTexture()->getMipmapCount(), getFormatInfo(image->getTexture()->getFormat()).m_name);
-		getWindow().setWindowTitle(title);
+		NativeWindow::getSingleton().setWindowTitle(title);
 
 		// Create the node
 		SceneGraph& scene = getSceneGraph();
@@ -304,7 +304,7 @@ public:
 
 	Error userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime) override
 	{
-		Input& input = getInput();
+		Input& input = Input::getSingleton();
 		if(input.getKey(KeyCode::kEscape))
 		{
 			quit = true;