From c71abf207b94711dc2bcad0dc7bac3f35950b12e Mon Sep 17 00:00:00 2001 From: floralrainfall Date: Thu, 20 Jul 2023 03:49:39 -0400 Subject: [PATCH] multithreaded physics --- Projects/Client/Common/Source/OgreWidget.cpp | 2 + Projects/Client/Studio/Source/main.cpp | 2 - Projects/Engine/CMakeLists.txt | 1 + .../Engine/Header/App/V8/Tree/Instance.hpp | 3 ++ Projects/Engine/Header/App/V8/World/World.hpp | 14 ++++++ Projects/Engine/Header/Helpers/Lock.hpp | 12 +++++ Projects/Engine/Source/App/GUI/TopMenuBar.cpp | 3 +- Projects/Engine/Source/App/V8/World/World.cpp | 48 +++++++++++++++++-- 8 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 Projects/Engine/Header/Helpers/Lock.hpp diff --git a/Projects/Client/Common/Source/OgreWidget.cpp b/Projects/Client/Common/Source/OgreWidget.cpp index 8e4dbf2..9b47d7e 100644 --- a/Projects/Client/Common/Source/OgreWidget.cpp +++ b/Projects/Client/Common/Source/OgreWidget.cpp @@ -127,6 +127,8 @@ namespace RNR this->render_time += ogreRoot->getTimer()->getMilliseconds() / 1000.0; ogreRoot->getTimer()->reset(); + world->preRender(this->delta); + if(world->getWorkspace()->getCurrentCamera()) { Camera* cam = world->getWorkspace()->getCurrentCamera(); diff --git a/Projects/Client/Studio/Source/main.cpp b/Projects/Client/Studio/Source/main.cpp index 8c4d815..35d0b41 100644 --- a/Projects/Client/Studio/Source/main.cpp +++ b/Projects/Client/Studio/Source/main.cpp @@ -35,8 +35,6 @@ int main(int argc, char** argv) window.statusBar()->showMessage(QString::asprintf("Dt=%f, Rt=%f, FPS=%f", window.ogreWidget->delta, window.ogreWidget->render_time, 1 / window.ogreWidget->delta)); app.processEvents(); window.ogreWidget->render(); - world->preStep(); - world->step(window.ogreWidget->delta); world->update(); } } \ No newline at end of file diff --git a/Projects/Engine/CMakeLists.txt b/Projects/Engine/CMakeLists.txt index 7eb355a..dddd4cd 100644 --- a/Projects/Engine/CMakeLists.txt +++ b/Projects/Engine/CMakeLists.txt @@ -4,6 +4,7 @@ add_library(Engine STATIC Header/Helpers/XML.hpp Header/Helpers/NormalId.hpp Header/Helpers/Bullet.hpp + Header/Helpers/Lock.hpp Header/App/Script/ReflectionProperty.hpp Header/App/Script/Script.hpp Header/App/Script/ScriptContext.hpp diff --git a/Projects/Engine/Header/App/V8/Tree/Instance.hpp b/Projects/Engine/Header/App/V8/Tree/Instance.hpp index f261e40..07f2bec 100644 --- a/Projects/Engine/Header/App/V8/Tree/Instance.hpp +++ b/Projects/Engine/Header/App/V8/Tree/Instance.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -78,5 +79,7 @@ namespace RNR virtual void onChildRemoved(RNR::Instance* childRemoved); virtual void onDescendantRemoved(RNR::Instance* descendantRemoved); // make sure this is called in any derived versions of this virtual void onSetParent(RNR::Instance* newParent); + + Lock instanceLock; }; } \ No newline at end of file diff --git a/Projects/Engine/Header/App/V8/World/World.hpp b/Projects/Engine/Header/App/V8/World/World.hpp index d0617a6..3ab28f7 100644 --- a/Projects/Engine/Header/App/V8/World/World.hpp +++ b/Projects/Engine/Header/App/V8/World/World.hpp @@ -30,6 +30,10 @@ namespace RNR class World { private: + std::thread m_physicsThread; + Ogre::Timer* m_physicsTimer; + + bool m_runPhysics; std::map m_refs; std::stack m_undeserialized; btDiscreteDynamicsWorld* m_dynamicsWorld; @@ -43,6 +47,8 @@ namespace RNR InstanceFactory* m_instanceFactory; IInputManager* m_inputManager; float m_lastDelta; + float m_lastPhysicsDelta; + float m_physicsTime; void xmlAddItem(pugi::xml_node node, Instance* parent); public: @@ -53,12 +59,14 @@ namespace RNR void load(char* path); + void preRender(float timestep); void preStep(); double step(float timestep); void update(); btDiscreteDynamicsWorld* getDynamicsWorld() { return m_dynamicsWorld; } float getLastDelta() { return m_lastDelta; } + float getLastPhysicsDelta() { return m_lastPhysicsDelta; } DataModel* getDatamodel() { return m_datamodel; } void setInputManager(IInputManager* inputManager) { m_inputManager = inputManager; } IInputManager* getInputManager() { return m_inputManager; } @@ -69,8 +77,14 @@ namespace RNR void setRunService(RunService* runService) { m_runService = runService; } Ogre::Root* getOgreRoot() { return m_ogreRoot; } Ogre::SceneManager* getOgreSceneManager() { return m_ogreSceneManager; } + Ogre::Timer* getPhysicsTimer() { return m_physicsTimer; } + float getPhysicsTime() { return m_physicsTime; } + void setPhysicsTime(float newTime) { m_physicsTime = newTime; } // should only be used by physicsThread + bool getPhysicsShouldBeRunningPleaseStopIfItIsStillRunning() { return m_runPhysics; } void registerPhysicsPart(PartInstance* partRegistered); void deletePhysicsPart(PartInstance* partDelete); + + Lock physicsIterateLock; }; } \ No newline at end of file diff --git a/Projects/Engine/Header/Helpers/Lock.hpp b/Projects/Engine/Header/Helpers/Lock.hpp new file mode 100644 index 0000000..ebd9cf8 --- /dev/null +++ b/Projects/Engine/Header/Helpers/Lock.hpp @@ -0,0 +1,12 @@ +#include + +namespace RNR +{ + struct Lock { + std::atomic lock_ = {false}; + + void lock() { while(lock_.exchange(true, std::memory_order_acquire)); } + + void unlock() { lock_.store(false, std::memory_order_release); } + }; +} \ No newline at end of file diff --git a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp index 6760da6..f52ef2d 100644 --- a/Projects/Engine/Source/App/GUI/TopMenuBar.cpp +++ b/Projects/Engine/Source/App/GUI/TopMenuBar.cpp @@ -128,9 +128,10 @@ namespace RNR snprintf(render_debugtext, 255, "using BATCH_STATIC_GEOMETRY\nGeom Regions: %i", workspace->m_geom->getRegions().size()); break; } - snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n\nPhysics\n%i objects, %i constraints\nRunService: running = %s, paused = %s", + snprintf(debugtext, 512, "Render\nLast DT = %f\n%s\n\nPhysics\nDT = %f\n%i objects, %i constraints\nRunService: running = %s, paused = %s", m_world->getLastDelta(), render_debugtext, + m_world->getLastPhysicsDelta(), dynamicsWorld->getNumCollisionObjects(), dynamicsWorld->getNumConstraints(), m_world->getRunService()->getRunning() ? "true" : "false", m_world->getRunService()->getPaused() ? "true" : "false"); diff --git a/Projects/Engine/Source/App/V8/World/World.cpp b/Projects/Engine/Source/App/V8/World/World.cpp index fb3492e..17f95d5 100644 --- a/Projects/Engine/Source/App/V8/World/World.cpp +++ b/Projects/Engine/Source/App/V8/World/World.cpp @@ -12,6 +12,21 @@ namespace RNR { + void physicsThread(World* world) + { + float delta; + float time; + while(world->getPhysicsShouldBeRunningPleaseStopIfItIsStillRunning()) + { + delta = world->getPhysicsTimer()->getMicroseconds() / 1000000.0; + time += world->getPhysicsTimer()->getMilliseconds() / 1000.0; + world->setPhysicsTime(time); + world->getPhysicsTimer()->reset(); + world->preStep(); + world->step(delta); + } + } + World::World(Ogre::Root* ogre, Ogre::SceneManager* ogreSceneManager) { Instance::setWorld(this); @@ -46,6 +61,10 @@ namespace RNR m_runService = (RunService*)m_datamodel->getService("RunService"); m_players = (Players*)m_datamodel->getService("Players"); + m_runPhysics = true; + m_physicsTimer = new Ogre::Timer(); + m_physicsThread = std::thread(physicsThread, this); + m_tmb = new TopMenuBar(this); Camera* start_cam = new Camera(); @@ -55,7 +74,8 @@ namespace RNR World::~World() { - // + m_runPhysics = false; + m_physicsThread.join(); } void World::xmlAddItem(pugi::xml_node node, Instance* parent) @@ -142,11 +162,27 @@ namespace RNR m_workspace->build(); } - void World::preStep() + void World::preRender(float timestep) { if(m_inputManager) m_inputManager->frame(); m_tmb->frame(); + m_lastDelta = timestep; + physicsIterateLock.lock(); + for(int j = m_dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[j]; + if(!obj->isActive()) + continue; + PartInstance* part = (PartInstance*)obj->getUserPointer(); + part->updateMatrix(); + } + physicsIterateLock.unlock(); + } + + void World::preStep() + { + } double World::step(float timestep) @@ -154,8 +190,9 @@ namespace RNR if(m_runService && m_runService->getRunning() && !m_runService->getPaused()) { m_runService->step(timestep); - m_dynamicsWorld->stepSimulation(timestep, 4, 1.0/60.0); + m_dynamicsWorld->stepSimulation(timestep, 2); + physicsIterateLock.lock(); for(int j = m_dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--) { btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[j]; @@ -177,10 +214,10 @@ namespace RNR Ogre::Quaternion transOgre = Bullet::qtToOgre(trans.getRotation()); transOgre.ToRotationMatrix(partRot); part->getCFrame().setRotation(partRot); - part->updateMatrix(); } + physicsIterateLock.unlock(); } - m_lastDelta = timestep; + m_lastPhysicsDelta = timestep; return 0.0; } @@ -206,6 +243,7 @@ namespace RNR btVector3 localInertia = btVector3(0,0,0); if(mass) partShape->calculateLocalInertia(mass, localInertia); + btDefaultMotionState* partMotionState = new btDefaultMotionState(partTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, partMotionState, partShape, localInertia); btRigidBody* body = new btRigidBody(rbInfo);