|
|
@@ -1,368 +1,366 @@
|
|
|
-#include "BsCoreApplication.h"
|
|
|
-
|
|
|
-#include "BsRenderAPI.h"
|
|
|
-#include "BsRenderAPIManager.h"
|
|
|
-
|
|
|
-#include "BsPlatform.h"
|
|
|
-#include "BsHardwareBufferManager.h"
|
|
|
-#include "BsRenderWindow.h"
|
|
|
-#include "BsViewport.h"
|
|
|
-#include "BsVector2.h"
|
|
|
-#include "BsGpuProgram.h"
|
|
|
-#include "BsCoreObjectManager.h"
|
|
|
-#include "BsGameObjectManager.h"
|
|
|
-#include "BsDynLib.h"
|
|
|
-#include "BsDynLibManager.h"
|
|
|
-#include "BsCoreSceneManager.h"
|
|
|
-#include "BsImporter.h"
|
|
|
-#include "BsResources.h"
|
|
|
-#include "BsMesh.h"
|
|
|
-#include "BsSceneObject.h"
|
|
|
-#include "BsTime.h"
|
|
|
-#include "BsInput.h"
|
|
|
-#include "BsRendererManager.h"
|
|
|
-#include "BsGpuProgramManager.h"
|
|
|
-#include "BsMeshManager.h"
|
|
|
-#include "BsMaterialManager.h"
|
|
|
-#include "BsFontManager.h"
|
|
|
-#include "BsRenderWindowManager.h"
|
|
|
-#include "BsCoreRenderer.h"
|
|
|
-#include "BsDeferredCallManager.h"
|
|
|
-#include "BsCoreThread.h"
|
|
|
-#include "BsStringTableManager.h"
|
|
|
-#include "BsProfilingManager.h"
|
|
|
-#include "BsProfilerCPU.h"
|
|
|
-#include "BsProfilerGPU.h"
|
|
|
-#include "BsQueryManager.h"
|
|
|
-#include "BsThreadPool.h"
|
|
|
-#include "BsTaskScheduler.h"
|
|
|
-#include "BsRenderStats.h"
|
|
|
-#include "BsMessageHandler.h"
|
|
|
-#include "BsResourceListenerManager.h"
|
|
|
-#include "BsRenderStateManager.h"
|
|
|
-#include "BsShaderManager.h"
|
|
|
-
|
|
|
-#include "BsMaterial.h"
|
|
|
-#include "BsShader.h"
|
|
|
-#include "BsTechnique.h"
|
|
|
-#include "BsPass.h"
|
|
|
-#include "BsRendererManager.h"
|
|
|
-
|
|
|
-namespace BansheeEngine
|
|
|
-{
|
|
|
- CoreApplication::CoreApplication(START_UP_DESC desc)
|
|
|
- :mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false),
|
|
|
- mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
|
|
|
- { }
|
|
|
-
|
|
|
- CoreApplication::~CoreApplication()
|
|
|
- {
|
|
|
- mPrimaryWindow->destroy();
|
|
|
- mPrimaryWindow = nullptr;
|
|
|
-
|
|
|
- Importer::shutDown();
|
|
|
- FontManager::shutDown();
|
|
|
- MaterialManager::shutDown();
|
|
|
- MeshManager::shutDown();
|
|
|
- ProfilerGPU::shutDown();
|
|
|
-
|
|
|
- CoreSceneManager::shutDown();
|
|
|
-
|
|
|
- Input::shutDown();
|
|
|
-
|
|
|
- StringTableManager::shutDown();
|
|
|
- Resources::shutDown();
|
|
|
- ResourceListenerManager::shutDown();
|
|
|
- GameObjectManager::shutDown();
|
|
|
- RenderStateManager::shutDown();
|
|
|
-
|
|
|
- RendererManager::shutDown();
|
|
|
-
|
|
|
- // All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
|
|
|
- // we need to wait for those objects to get destroyed before continuing.
|
|
|
- CoreObjectManager::instance().clearDirty();
|
|
|
- gCoreThread().update();
|
|
|
- gCoreThread().submitAccessors(true);
|
|
|
-
|
|
|
- unloadPlugin(mRendererPlugin);
|
|
|
-
|
|
|
- RenderAPIManager::shutDown();
|
|
|
- GpuProgramCoreManager::shutDown();
|
|
|
- GpuProgramManager::shutDown();
|
|
|
-
|
|
|
- CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
|
|
|
- DynLibManager::shutDown();
|
|
|
- Time::shutDown();
|
|
|
- DeferredCallManager::shutDown();
|
|
|
-
|
|
|
- CoreThread::shutDown();
|
|
|
- RenderStats::shutDown();
|
|
|
- TaskScheduler::shutDown();
|
|
|
- ThreadPool::shutDown();
|
|
|
- ProfilingManager::shutDown();
|
|
|
- ProfilerCPU::shutDown();
|
|
|
- MessageHandler::shutDown();
|
|
|
- ShaderManager::shutDown();
|
|
|
-
|
|
|
- MemStack::endThread();
|
|
|
- Platform::_shutDown();
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::onStartUp()
|
|
|
- {
|
|
|
- UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
|
|
|
-
|
|
|
- Platform::_startUp();
|
|
|
- MemStack::beginThread();
|
|
|
-
|
|
|
- ShaderManager::startUp(getShaderIncludeHandler());
|
|
|
- MessageHandler::startUp();
|
|
|
- ProfilerCPU::startUp();
|
|
|
- ProfilingManager::startUp();
|
|
|
- ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
|
|
|
- TaskScheduler::startUp();
|
|
|
- TaskScheduler::instance().removeWorker();
|
|
|
- RenderStats::startUp();
|
|
|
- CoreThread::startUp();
|
|
|
- StringTableManager::startUp();
|
|
|
- DeferredCallManager::startUp();
|
|
|
- Time::startUp();
|
|
|
- DynLibManager::startUp();
|
|
|
- CoreObjectManager::startUp();
|
|
|
- GameObjectManager::startUp();
|
|
|
- Resources::startUp();
|
|
|
- ResourceListenerManager::startUp();
|
|
|
- GpuProgramManager::startUp();
|
|
|
- RenderStateManager::startUp();
|
|
|
- GpuProgramCoreManager::startUp();
|
|
|
- RenderAPIManager::startUp();
|
|
|
-
|
|
|
- mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
|
|
|
-
|
|
|
- Input::startUp();
|
|
|
- RendererManager::startUp();
|
|
|
-
|
|
|
- loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
|
|
|
-
|
|
|
- SceneManagerFactory::create();
|
|
|
- RendererManager::instance().setActive(mStartUpDesc.renderer);
|
|
|
- startUpRenderer();
|
|
|
-
|
|
|
- ProfilerGPU::startUp();
|
|
|
- MeshManager::startUp();
|
|
|
- MaterialManager::startUp();
|
|
|
- FontManager::startUp();
|
|
|
-
|
|
|
- Importer::startUp();
|
|
|
-
|
|
|
- for (auto& importerName : mStartUpDesc.importers)
|
|
|
- loadPlugin(importerName);
|
|
|
-
|
|
|
- loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::runMainLoop()
|
|
|
- {
|
|
|
- mRunMainLoop = true;
|
|
|
-
|
|
|
- while(mRunMainLoop)
|
|
|
- {
|
|
|
- gProfilerCPU().beginThread("Sim");
|
|
|
-
|
|
|
- Platform::_update();
|
|
|
- DeferredCallManager::instance()._update();
|
|
|
- gTime().update();
|
|
|
- gInput()._update();
|
|
|
- // RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
|
|
|
- // so that all input is properly captured in case there is a focus change, and so that
|
|
|
- // focus change is registered before input events are sent out (mouse press can result in code
|
|
|
- // checking if a window is in focus, so it has to be up to date)
|
|
|
- RenderWindowManager::instance()._update();
|
|
|
- gInput()._triggerCallbacks();
|
|
|
- gDebug()._triggerCallbacks();
|
|
|
-
|
|
|
- preUpdate();
|
|
|
-
|
|
|
- PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
|
|
|
-
|
|
|
- gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
|
|
|
- gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
|
|
|
- gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
|
|
|
-
|
|
|
- // Update plugins
|
|
|
- for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
|
|
|
- pluginUpdateFunc.second();
|
|
|
-
|
|
|
- postUpdate();
|
|
|
-
|
|
|
- // Send out resource events in case any were loaded/destroyed/modified
|
|
|
- ResourceListenerManager::instance().update();
|
|
|
-
|
|
|
- gCoreSceneManager()._updateCoreObjectTransforms();
|
|
|
- PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
|
|
|
-
|
|
|
- // Core and sim thread run in lockstep. This will result in a larger input latency than if I was
|
|
|
- // running just a single thread. Latency becomes worse if the core thread takes longer than sim
|
|
|
- // thread, in which case sim thread needs to wait. Optimal solution would be to get an average
|
|
|
- // difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
|
|
|
- {
|
|
|
- BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
|
|
|
-
|
|
|
- while(!mIsFrameRenderingFinished)
|
|
|
- {
|
|
|
- TaskScheduler::instance().addWorker();
|
|
|
- BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
|
|
|
- TaskScheduler::instance().removeWorker();
|
|
|
- }
|
|
|
-
|
|
|
- mIsFrameRenderingFinished = false;
|
|
|
- }
|
|
|
-
|
|
|
- gCoreThread().queueCommand(&Platform::_coreUpdate);
|
|
|
-
|
|
|
- gCoreThread().update();
|
|
|
- gCoreThread().submitAccessors();
|
|
|
-
|
|
|
- gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
|
|
|
- gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
|
|
|
-
|
|
|
- gProfilerCPU().endThread();
|
|
|
- gProfiler()._update();
|
|
|
- }
|
|
|
-
|
|
|
- // Wait until last core frame is finished before exiting
|
|
|
- {
|
|
|
- BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
|
|
|
-
|
|
|
- while (!mIsFrameRenderingFinished)
|
|
|
- {
|
|
|
- TaskScheduler::instance().addWorker();
|
|
|
- BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
|
|
|
- TaskScheduler::instance().removeWorker();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::preUpdate()
|
|
|
- {
|
|
|
- // Do nothing
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::postUpdate()
|
|
|
- {
|
|
|
- // Do nothing
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::stopMainLoop()
|
|
|
- {
|
|
|
- mRunMainLoop = false; // No sync primitives needed, in that rare case of
|
|
|
- // a race condition we might run the loop one extra iteration which is acceptable
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::quitRequested()
|
|
|
- {
|
|
|
- stopMainLoop();
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::frameRenderingFinishedCallback()
|
|
|
- {
|
|
|
- BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
|
|
|
-
|
|
|
- mIsFrameRenderingFinished = true;
|
|
|
- BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::startUpRenderer()
|
|
|
- {
|
|
|
- RendererManager::instance().initialize();
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::beginCoreProfiling()
|
|
|
- {
|
|
|
- gProfilerCPU().beginThread("Core");
|
|
|
- ProfilerGPU::instance().beginFrame();
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::endCoreProfiling()
|
|
|
- {
|
|
|
- ProfilerGPU::instance().endFrame();
|
|
|
- ProfilerGPU::instance()._update();
|
|
|
-
|
|
|
- gProfilerCPU().endThread();
|
|
|
- gProfiler()._updateCore();
|
|
|
- }
|
|
|
-
|
|
|
- void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
|
|
|
- {
|
|
|
- String name = pluginName;
|
|
|
-#if BS_PLATFORM == BS_PLATFORM_LINUX
|
|
|
- if (name.substr(name.length() - 3, 3) != ".so")
|
|
|
- name += ".so";
|
|
|
-#elif BS_PLATFORM == BS_PLATFORM_APPLE
|
|
|
- if (name.substr(name.length() - 6, 6) != ".dylib")
|
|
|
- name += ".dylib";
|
|
|
-#elif BS_PLATFORM == BS_PLATFORM_WIN32
|
|
|
- // Although LoadLibraryEx will add .dll itself when you only specify the library name,
|
|
|
- // if you include a relative path then it does not. So, add it to be sure.
|
|
|
- if (name.substr(name.length() - 4, 4) != ".dll")
|
|
|
- name += ".dll";
|
|
|
-#endif
|
|
|
-
|
|
|
- DynLib* loadedLibrary = gDynLibManager().load(name);
|
|
|
- if(library != nullptr)
|
|
|
- *library = loadedLibrary;
|
|
|
-
|
|
|
- void* retVal = nullptr;
|
|
|
- if(loadedLibrary != nullptr)
|
|
|
- {
|
|
|
- if (passThrough == nullptr)
|
|
|
- {
|
|
|
- typedef void* (*LoadPluginFunc)();
|
|
|
-
|
|
|
- LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
|
|
|
-
|
|
|
- if (loadPluginFunc != nullptr)
|
|
|
- retVal = loadPluginFunc();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- typedef void* (*LoadPluginFunc)(void*);
|
|
|
-
|
|
|
- LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
|
|
|
-
|
|
|
- if (loadPluginFunc != nullptr)
|
|
|
- retVal = loadPluginFunc(passThrough);
|
|
|
- }
|
|
|
-
|
|
|
- UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
|
|
|
-
|
|
|
- if (loadPluginFunc != nullptr)
|
|
|
- mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
|
|
|
- }
|
|
|
-
|
|
|
- return retVal;
|
|
|
- }
|
|
|
-
|
|
|
- void CoreApplication::unloadPlugin(DynLib* library)
|
|
|
- {
|
|
|
- typedef void (*UnloadPluginFunc)();
|
|
|
-
|
|
|
- UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
|
|
|
-
|
|
|
- if(unloadPluginFunc != nullptr)
|
|
|
- unloadPluginFunc();
|
|
|
-
|
|
|
- mPluginUpdateFunctions.erase(library);
|
|
|
- gDynLibManager().unload(library);
|
|
|
- }
|
|
|
-
|
|
|
- ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
|
|
|
- {
|
|
|
- return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
|
|
|
- }
|
|
|
-
|
|
|
- CoreApplication& gCoreApplication()
|
|
|
- {
|
|
|
- return CoreApplication::instance();
|
|
|
- }
|
|
|
+#include "BsCoreApplication.h"
|
|
|
+
|
|
|
+#include "BsRenderAPI.h"
|
|
|
+#include "BsRenderAPIManager.h"
|
|
|
+
|
|
|
+#include "BsPlatform.h"
|
|
|
+#include "BsHardwareBufferManager.h"
|
|
|
+#include "BsRenderWindow.h"
|
|
|
+#include "BsViewport.h"
|
|
|
+#include "BsVector2.h"
|
|
|
+#include "BsGpuProgram.h"
|
|
|
+#include "BsCoreObjectManager.h"
|
|
|
+#include "BsGameObjectManager.h"
|
|
|
+#include "BsDynLib.h"
|
|
|
+#include "BsDynLibManager.h"
|
|
|
+#include "BsCoreSceneManager.h"
|
|
|
+#include "BsImporter.h"
|
|
|
+#include "BsResources.h"
|
|
|
+#include "BsMesh.h"
|
|
|
+#include "BsSceneObject.h"
|
|
|
+#include "BsTime.h"
|
|
|
+#include "BsInput.h"
|
|
|
+#include "BsRendererManager.h"
|
|
|
+#include "BsGpuProgramManager.h"
|
|
|
+#include "BsMeshManager.h"
|
|
|
+#include "BsMaterialManager.h"
|
|
|
+#include "BsFontManager.h"
|
|
|
+#include "BsRenderWindowManager.h"
|
|
|
+#include "BsCoreRenderer.h"
|
|
|
+#include "BsDeferredCallManager.h"
|
|
|
+#include "BsCoreThread.h"
|
|
|
+#include "BsStringTableManager.h"
|
|
|
+#include "BsProfilingManager.h"
|
|
|
+#include "BsProfilerCPU.h"
|
|
|
+#include "BsProfilerGPU.h"
|
|
|
+#include "BsQueryManager.h"
|
|
|
+#include "BsThreadPool.h"
|
|
|
+#include "BsTaskScheduler.h"
|
|
|
+#include "BsRenderStats.h"
|
|
|
+#include "BsMessageHandler.h"
|
|
|
+#include "BsResourceListenerManager.h"
|
|
|
+#include "BsRenderStateManager.h"
|
|
|
+#include "BsShaderManager.h"
|
|
|
+
|
|
|
+namespace BansheeEngine
|
|
|
+{
|
|
|
+ CoreApplication::CoreApplication(START_UP_DESC desc)
|
|
|
+ :mPrimaryWindow(nullptr), mIsFrameRenderingFinished(true), mRunMainLoop(false),
|
|
|
+ mRendererPlugin(nullptr), mSimThreadId(BS_THREAD_CURRENT_ID), mStartUpDesc(desc)
|
|
|
+ {
|
|
|
+#if BS_DEBUG_MODE
|
|
|
+ IReflectable::_checkForCircularReferences();
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ CoreApplication::~CoreApplication()
|
|
|
+ {
|
|
|
+ mPrimaryWindow->destroy();
|
|
|
+ mPrimaryWindow = nullptr;
|
|
|
+
|
|
|
+ Importer::shutDown();
|
|
|
+ FontManager::shutDown();
|
|
|
+ MaterialManager::shutDown();
|
|
|
+ MeshManager::shutDown();
|
|
|
+ ProfilerGPU::shutDown();
|
|
|
+
|
|
|
+ CoreSceneManager::shutDown();
|
|
|
+
|
|
|
+ Input::shutDown();
|
|
|
+
|
|
|
+ StringTableManager::shutDown();
|
|
|
+ Resources::shutDown();
|
|
|
+ ResourceListenerManager::shutDown();
|
|
|
+ GameObjectManager::shutDown();
|
|
|
+ RenderStateManager::shutDown();
|
|
|
+
|
|
|
+ RendererManager::shutDown();
|
|
|
+
|
|
|
+ // All CoreObject related modules should be shut down now. They have likely queued CoreObjects for destruction, so
|
|
|
+ // we need to wait for those objects to get destroyed before continuing.
|
|
|
+ CoreObjectManager::instance().clearDirty();
|
|
|
+ gCoreThread().update();
|
|
|
+ gCoreThread().submitAccessors(true);
|
|
|
+
|
|
|
+ unloadPlugin(mRendererPlugin);
|
|
|
+
|
|
|
+ RenderAPIManager::shutDown();
|
|
|
+ GpuProgramCoreManager::shutDown();
|
|
|
+ GpuProgramManager::shutDown();
|
|
|
+
|
|
|
+ CoreObjectManager::shutDown(); // Must shut down before DynLibManager to ensure all objects are destroyed before unloading their libraries
|
|
|
+ DynLibManager::shutDown();
|
|
|
+ Time::shutDown();
|
|
|
+ DeferredCallManager::shutDown();
|
|
|
+
|
|
|
+ CoreThread::shutDown();
|
|
|
+ RenderStats::shutDown();
|
|
|
+ TaskScheduler::shutDown();
|
|
|
+ ThreadPool::shutDown();
|
|
|
+ ProfilingManager::shutDown();
|
|
|
+ ProfilerCPU::shutDown();
|
|
|
+ MessageHandler::shutDown();
|
|
|
+ ShaderManager::shutDown();
|
|
|
+
|
|
|
+ MemStack::endThread();
|
|
|
+ Platform::_shutDown();
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::onStartUp()
|
|
|
+ {
|
|
|
+ UINT32 numWorkerThreads = BS_THREAD_HARDWARE_CONCURRENCY - 1; // Number of cores while excluding current thread.
|
|
|
+
|
|
|
+ Platform::_startUp();
|
|
|
+ MemStack::beginThread();
|
|
|
+
|
|
|
+ ShaderManager::startUp(getShaderIncludeHandler());
|
|
|
+ MessageHandler::startUp();
|
|
|
+ ProfilerCPU::startUp();
|
|
|
+ ProfilingManager::startUp();
|
|
|
+ ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
|
|
|
+ TaskScheduler::startUp();
|
|
|
+ TaskScheduler::instance().removeWorker();
|
|
|
+ RenderStats::startUp();
|
|
|
+ CoreThread::startUp();
|
|
|
+ StringTableManager::startUp();
|
|
|
+ DeferredCallManager::startUp();
|
|
|
+ Time::startUp();
|
|
|
+ DynLibManager::startUp();
|
|
|
+ CoreObjectManager::startUp();
|
|
|
+ GameObjectManager::startUp();
|
|
|
+ Resources::startUp();
|
|
|
+ ResourceListenerManager::startUp();
|
|
|
+ GpuProgramManager::startUp();
|
|
|
+ RenderStateManager::startUp();
|
|
|
+ GpuProgramCoreManager::startUp();
|
|
|
+ RenderAPIManager::startUp();
|
|
|
+
|
|
|
+ mPrimaryWindow = RenderAPIManager::instance().initialize(mStartUpDesc.renderAPI, mStartUpDesc.primaryWindowDesc);
|
|
|
+
|
|
|
+ Input::startUp();
|
|
|
+ RendererManager::startUp();
|
|
|
+
|
|
|
+ loadPlugin(mStartUpDesc.renderer, &mRendererPlugin);
|
|
|
+
|
|
|
+ SceneManagerFactory::create();
|
|
|
+ RendererManager::instance().setActive(mStartUpDesc.renderer);
|
|
|
+ startUpRenderer();
|
|
|
+
|
|
|
+ ProfilerGPU::startUp();
|
|
|
+ MeshManager::startUp();
|
|
|
+ MaterialManager::startUp();
|
|
|
+ FontManager::startUp();
|
|
|
+
|
|
|
+ Importer::startUp();
|
|
|
+
|
|
|
+ for (auto& importerName : mStartUpDesc.importers)
|
|
|
+ loadPlugin(importerName);
|
|
|
+
|
|
|
+ loadPlugin(mStartUpDesc.input, nullptr, mPrimaryWindow.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::runMainLoop()
|
|
|
+ {
|
|
|
+ mRunMainLoop = true;
|
|
|
+
|
|
|
+ while(mRunMainLoop)
|
|
|
+ {
|
|
|
+ gProfilerCPU().beginThread("Sim");
|
|
|
+
|
|
|
+ Platform::_update();
|
|
|
+ DeferredCallManager::instance()._update();
|
|
|
+ gTime().update();
|
|
|
+ gInput()._update();
|
|
|
+ // RenderWindowManager::update needs to happen after Input::update and before Input::_triggerCallbacks,
|
|
|
+ // so that all input is properly captured in case there is a focus change, and so that
|
|
|
+ // focus change is registered before input events are sent out (mouse press can result in code
|
|
|
+ // checking if a window is in focus, so it has to be up to date)
|
|
|
+ RenderWindowManager::instance()._update();
|
|
|
+ gInput()._triggerCallbacks();
|
|
|
+ gDebug()._triggerCallbacks();
|
|
|
+
|
|
|
+ preUpdate();
|
|
|
+
|
|
|
+ PROFILE_CALL(gCoreSceneManager()._update(), "SceneManager");
|
|
|
+
|
|
|
+ gCoreThread().queueCommand(std::bind(&CoreApplication::beginCoreProfiling, this));
|
|
|
+ gCoreThread().queueCommand(std::bind(&RenderWindowCoreManager::_update, RenderWindowCoreManager::instancePtr()));
|
|
|
+ gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
|
|
|
+
|
|
|
+ // Update plugins
|
|
|
+ for (auto& pluginUpdateFunc : mPluginUpdateFunctions)
|
|
|
+ pluginUpdateFunc.second();
|
|
|
+
|
|
|
+ postUpdate();
|
|
|
+
|
|
|
+ // Send out resource events in case any were loaded/destroyed/modified
|
|
|
+ ResourceListenerManager::instance().update();
|
|
|
+
|
|
|
+ gCoreSceneManager()._updateCoreObjectTransforms();
|
|
|
+ PROFILE_CALL(RendererManager::instance().getActive()->renderAll(), "Render");
|
|
|
+
|
|
|
+ // Core and sim thread run in lockstep. This will result in a larger input latency than if I was
|
|
|
+ // running just a single thread. Latency becomes worse if the core thread takes longer than sim
|
|
|
+ // thread, in which case sim thread needs to wait. Optimal solution would be to get an average
|
|
|
+ // difference between sim/core thread and start the sim thread a bit later so they finish at nearly the same time.
|
|
|
+ {
|
|
|
+ BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
|
|
|
+
|
|
|
+ while(!mIsFrameRenderingFinished)
|
|
|
+ {
|
|
|
+ TaskScheduler::instance().addWorker();
|
|
|
+ BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
|
|
|
+ TaskScheduler::instance().removeWorker();
|
|
|
+ }
|
|
|
+
|
|
|
+ mIsFrameRenderingFinished = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ gCoreThread().queueCommand(&Platform::_coreUpdate);
|
|
|
+
|
|
|
+ gCoreThread().update();
|
|
|
+ gCoreThread().submitAccessors();
|
|
|
+
|
|
|
+ gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
|
|
|
+ gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
|
|
|
+
|
|
|
+ gProfilerCPU().endThread();
|
|
|
+ gProfiler()._update();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wait until last core frame is finished before exiting
|
|
|
+ {
|
|
|
+ BS_LOCK_MUTEX_NAMED(mFrameRenderingFinishedMutex, lock);
|
|
|
+
|
|
|
+ while (!mIsFrameRenderingFinished)
|
|
|
+ {
|
|
|
+ TaskScheduler::instance().addWorker();
|
|
|
+ BS_THREAD_WAIT(mFrameRenderingFinishedCondition, mFrameRenderingFinishedMutex, lock);
|
|
|
+ TaskScheduler::instance().removeWorker();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::preUpdate()
|
|
|
+ {
|
|
|
+ // Do nothing
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::postUpdate()
|
|
|
+ {
|
|
|
+ // Do nothing
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::stopMainLoop()
|
|
|
+ {
|
|
|
+ mRunMainLoop = false; // No sync primitives needed, in that rare case of
|
|
|
+ // a race condition we might run the loop one extra iteration which is acceptable
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::quitRequested()
|
|
|
+ {
|
|
|
+ stopMainLoop();
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::frameRenderingFinishedCallback()
|
|
|
+ {
|
|
|
+ BS_LOCK_MUTEX(mFrameRenderingFinishedMutex);
|
|
|
+
|
|
|
+ mIsFrameRenderingFinished = true;
|
|
|
+ BS_THREAD_NOTIFY_ONE(mFrameRenderingFinishedCondition);
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::startUpRenderer()
|
|
|
+ {
|
|
|
+ RendererManager::instance().initialize();
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::beginCoreProfiling()
|
|
|
+ {
|
|
|
+ gProfilerCPU().beginThread("Core");
|
|
|
+ ProfilerGPU::instance().beginFrame();
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::endCoreProfiling()
|
|
|
+ {
|
|
|
+ ProfilerGPU::instance().endFrame();
|
|
|
+ ProfilerGPU::instance()._update();
|
|
|
+
|
|
|
+ gProfilerCPU().endThread();
|
|
|
+ gProfiler()._updateCore();
|
|
|
+ }
|
|
|
+
|
|
|
+ void* CoreApplication::loadPlugin(const String& pluginName, DynLib** library, void* passThrough)
|
|
|
+ {
|
|
|
+ String name = pluginName;
|
|
|
+#if BS_PLATFORM == BS_PLATFORM_LINUX
|
|
|
+ if (name.substr(name.length() - 3, 3) != ".so")
|
|
|
+ name += ".so";
|
|
|
+#elif BS_PLATFORM == BS_PLATFORM_APPLE
|
|
|
+ if (name.substr(name.length() - 6, 6) != ".dylib")
|
|
|
+ name += ".dylib";
|
|
|
+#elif BS_PLATFORM == BS_PLATFORM_WIN32
|
|
|
+ // Although LoadLibraryEx will add .dll itself when you only specify the library name,
|
|
|
+ // if you include a relative path then it does not. So, add it to be sure.
|
|
|
+ if (name.substr(name.length() - 4, 4) != ".dll")
|
|
|
+ name += ".dll";
|
|
|
+#endif
|
|
|
+
|
|
|
+ DynLib* loadedLibrary = gDynLibManager().load(name);
|
|
|
+ if(library != nullptr)
|
|
|
+ *library = loadedLibrary;
|
|
|
+
|
|
|
+ void* retVal = nullptr;
|
|
|
+ if(loadedLibrary != nullptr)
|
|
|
+ {
|
|
|
+ if (passThrough == nullptr)
|
|
|
+ {
|
|
|
+ typedef void* (*LoadPluginFunc)();
|
|
|
+
|
|
|
+ LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
|
|
|
+
|
|
|
+ if (loadPluginFunc != nullptr)
|
|
|
+ retVal = loadPluginFunc();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ typedef void* (*LoadPluginFunc)(void*);
|
|
|
+
|
|
|
+ LoadPluginFunc loadPluginFunc = (LoadPluginFunc)loadedLibrary->getSymbol("loadPlugin");
|
|
|
+
|
|
|
+ if (loadPluginFunc != nullptr)
|
|
|
+ retVal = loadPluginFunc(passThrough);
|
|
|
+ }
|
|
|
+
|
|
|
+ UpdatePluginFunc loadPluginFunc = (UpdatePluginFunc)loadedLibrary->getSymbol("updatePlugin");
|
|
|
+
|
|
|
+ if (loadPluginFunc != nullptr)
|
|
|
+ mPluginUpdateFunctions[loadedLibrary] = loadPluginFunc;
|
|
|
+ }
|
|
|
+
|
|
|
+ return retVal;
|
|
|
+ }
|
|
|
+
|
|
|
+ void CoreApplication::unloadPlugin(DynLib* library)
|
|
|
+ {
|
|
|
+ typedef void (*UnloadPluginFunc)();
|
|
|
+
|
|
|
+ UnloadPluginFunc unloadPluginFunc = (UnloadPluginFunc)library->getSymbol("unloadPlugin");
|
|
|
+
|
|
|
+ if(unloadPluginFunc != nullptr)
|
|
|
+ unloadPluginFunc();
|
|
|
+
|
|
|
+ mPluginUpdateFunctions.erase(library);
|
|
|
+ gDynLibManager().unload(library);
|
|
|
+ }
|
|
|
+
|
|
|
+ ShaderIncludeHandlerPtr CoreApplication::getShaderIncludeHandler() const
|
|
|
+ {
|
|
|
+ return bs_shared_ptr_new<DefaultShaderIncludeHandler>();
|
|
|
+ }
|
|
|
+
|
|
|
+ CoreApplication& gCoreApplication()
|
|
|
+ {
|
|
|
+ return CoreApplication::instance();
|
|
|
+ }
|
|
|
}
|