diff --git a/ext/ghoul b/ext/ghoul index 8418f394f4..aa350fd8d3 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 8418f394f472457db9ca7684d27e910063cfd898 +Subproject commit aa350fd8d357984ca59c7aa2df8e08f904f31615 diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index c3d8c9ee35..af3b67d751 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -27,6 +27,10 @@ #include +namespace ghoul { + class SharedMemory; +} + namespace openspace { // Forward declare to minimize dependencies @@ -59,6 +63,8 @@ public: void takeScreenshot(); void toggleVisualizeABuffer(bool b); + void setPerformanceMeasurements(bool performanceMeasurements); + void serialize(SyncBuffer* syncBuffer); void deserialize(SyncBuffer* syncBuffer); @@ -72,8 +78,9 @@ public: */ static scripting::ScriptEngine::LuaLibrary luaLibrary(); - private: + void storePerformanceMeasurements(); + Camera* _mainCamera; SceneGraph* _sceneGraph; ABuffer* _abuffer; @@ -83,6 +90,9 @@ private: bool _showScreenLog; bool _takeScreenshot; + bool _doPerformanceMeasurements; + ghoul::SharedMemory* _performanceMemory; + void generateGlslConfig(); bool _visualizeABuffer; diff --git a/include/openspace/scenegraph/scenegraph.h b/include/openspace/scenegraph/scenegraph.h index b6fa08546e..1a75ed6970 100644 --- a/include/openspace/scenegraph/scenegraph.h +++ b/include/openspace/scenegraph/scenegraph.h @@ -35,7 +35,6 @@ #include #include -// ghoul includes #include #include @@ -44,6 +43,8 @@ namespace openspace { class SceneGraphNode; +// Notifications: +// SceneGraphFinishedLoading class SceneGraph { public: // constructors & destructor @@ -99,6 +100,8 @@ public: */ SceneGraphNode* sceneGraphNode(const std::string& name) const; + std::vector allSceneGraphNodes() const; + /** * Returns the Lua library that contains all Lua functions available to change the * scene graph. The functions contained are diff --git a/include/openspace/scenegraph/scenegraphnode.h b/include/openspace/scenegraph/scenegraphnode.h index 2dade38bb6..c25b2a3ef2 100644 --- a/include/openspace/scenegraph/scenegraphnode.h +++ b/include/openspace/scenegraph/scenegraphnode.h @@ -44,9 +44,14 @@ namespace openspace { class SceneGraphNode : public properties::PropertyOwner { public: + struct PerformanceRecord { + long long renderTime; // time in ns + long long updateTimeRenderable; // time in ns + long long updateTimeEphemeris; // time in ns + }; + static std::string RootNodeName; - // constructors & destructor SceneGraphNode(); ~SceneGraphNode(); @@ -55,12 +60,10 @@ public: bool initialize(); bool deinitialize(); - // essential void update(const UpdateData& data); void evaluate(const Camera* camera, const psc& parentPosition = psc()); void render(const RenderData& data); - // set & get void addNode(SceneGraphNode* child); void setParent(SceneGraphNode* parent); @@ -70,7 +73,6 @@ public: SceneGraphNode* parent() const; const std::vector& children() const; - // bounding sphere PowerScaledScalar calculateBoundingSphere(); PowerScaledScalar boundingSphere() const; @@ -78,27 +80,26 @@ public: void print() const; - // renderable + const PerformanceRecord& performanceRecord() const { return _performanceRecord; } + void setRenderable(Renderable* renderable); const Renderable* renderable() const; Renderable* renderable(); private: - // essential - std::vector _children; + bool sphereInsideFrustum(const psc s_pos, const PowerScaledScalar& s_rad, const Camera* camera); + + std::vector _children; SceneGraphNode* _parent; Ephemeris* _ephemeris; - // renderable + PerformanceRecord _performanceRecord; + Renderable* _renderable; bool _renderableVisible; - // bounding sphere bool _boundingSphereVisible; PowerScaledScalar _boundingSphere; - - // private helper methods - bool sphereInsideFrustum(const psc s_pos, const PowerScaledScalar& s_rad, const Camera* camera); }; } // namespace openspace diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index ac5d31740a..bbc66e82ef 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -33,12 +33,13 @@ namespace openspace { struct UpdateData { double time; double delta; + bool doPerformanceMeasurement; }; struct RenderData { const Camera& camera; psc position; - + bool doPerformanceMeasurement; }; } diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 189dd3bc42..c2453e6f9b 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #ifdef GHOUL_USE_DEVIL @@ -68,6 +69,9 @@ namespace { const std::string _loggerCat = "RenderEngine"; + + const std::string PerformanceMeasurementSharedData = + "OpenSpacePerformanceMeasurementSharedData"; } namespace openspace { @@ -103,6 +107,21 @@ int visualizeABuffer(lua_State* L) { return 0; } +/** +* \ingroup LuaScripts +* visualizeABuffer(bool): +* Toggle the visualization of the ABuffer +*/ +int setPerformanceMeasurement(lua_State* L) { + int nArguments = lua_gettop(L); + if (nArguments != 1) + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + + bool b = lua_toboolean(L, -1) != 0; + OsEng.renderEngine().setPerformanceMeasurements(b); + return 0; +} + } // namespace luascriptfunctions @@ -114,6 +133,8 @@ RenderEngine::RenderEngine() , _showInfo(true) , _showScreenLog(true) , _takeScreenshot(false) + , _doPerformanceMeasurements(false) + , _performanceMemory(nullptr) , _visualizeABuffer(false) , _visualizer(nullptr) { @@ -124,6 +145,10 @@ RenderEngine::~RenderEngine() delete _mainCamera; if (_visualizer) delete _visualizer; + + delete _performanceMemory; + if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) + ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); } bool RenderEngine::initialize() @@ -266,7 +291,11 @@ void RenderEngine::postSynchronizationPreDraw() UpdateData a = { Time::ref().currentTime(), Time::ref().deltaTime() }; // update and evaluate the scene starting from the root node - _sceneGraph->update(a); + _sceneGraph->update({ + Time::ref().currentTime(), + Time::ref().deltaTime(), + _doPerformanceMeasurements + }); _sceneGraph->evaluate(_mainCamera); // clear the abuffer before rendering the scene @@ -320,7 +349,11 @@ void RenderEngine::render() // render the scene starting from the root node if (!_visualizeABuffer) { _abuffer->preRender(); - _sceneGraph->render({ *_mainCamera, psc() }); + _sceneGraph->render({ + *_mainCamera, + psc(), + _doPerformanceMeasurements + }); _abuffer->postRender(); glEnable(GL_BLEND); @@ -442,6 +475,9 @@ void RenderEngine::postDraw() { sgct::Engine::instance()->takeScreenshot(); _takeScreenshot = false; } + + if (_doPerformanceMeasurements) + storePerformanceMeasurements(); } void RenderEngine::takeScreenshot() { @@ -544,9 +580,93 @@ scripting::ScriptEngine::LuaLibrary RenderEngine::luaLibrary() { &luascriptfunctions::visualizeABuffer, "bool", "Toggles the visualization of the ABuffer" + }, + { + "setPerformanceMeasurement", + &luascriptfunctions::setPerformanceMeasurement, + "bool", + "Sets the performance measurements" } }, }; } +void RenderEngine::setPerformanceMeasurements(bool performanceMeasurements) { + _doPerformanceMeasurements = performanceMeasurements; +} + +void RenderEngine::storePerformanceMeasurements() { + const int nValues = 1000; + const int lengthName = 256; + const int maxValues = 50; + + struct PerformanceLayout { + int32_t nValuesPerEntry; + int32_t nEntries; + int32_t maxNameLength; + int32_t maxEntries; + + struct PerformanceLayoutEntry { + char name[lengthName]; + int64_t renderTime[nValues]; + int64_t updateRenderable[nValues]; + int64_t updateEphemeris[nValues]; + + int32_t currentRenderTime; + int32_t currentUpdateRenderable; + int32_t currentUpdateEphemeris; + }; + + PerformanceLayoutEntry entries[maxValues]; + }; + + const int nNodes = sceneGraph()->allSceneGraphNodes().size(); + if (!_performanceMemory) { + + // Compute the total size + const int totalSize = 4 * sizeof(int32_t) + + maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry); + LINFO("Create shared memory of size '" << totalSize << "' bytes"); + + ghoul::SharedMemory::create(PerformanceMeasurementSharedData, totalSize); + _performanceMemory = new ghoul::SharedMemory(PerformanceMeasurementSharedData); + + PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); + layout->nValuesPerEntry = nValues; + layout->nEntries = nNodes; + layout->maxNameLength = lengthName; + layout->maxEntries = maxValues; + + memset(layout->entries, 0, maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry)); + + for (int i = 0; i < nNodes; ++i) { + SceneGraphNode* node = sceneGraph()->allSceneGraphNodes()[i]; + + memset(layout->entries[i].name, 0, lengthName); + strcpy(layout->entries[i].name, node->name().c_str()); + + layout->entries[i].currentRenderTime = 0; + layout->entries[i].currentUpdateRenderable = 0; + layout->entries[i].currentUpdateEphemeris = 0; + } + } + + PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); + _performanceMemory->acquireLock(); + for (int i = 0; i < nNodes; ++i) { + SceneGraphNode* node = sceneGraph()->allSceneGraphNodes()[i]; + SceneGraphNode::PerformanceRecord r = node->performanceRecord(); + PerformanceLayout::PerformanceLayoutEntry& entry = layout->entries[i]; + + entry.renderTime[entry.currentRenderTime] = r.renderTime; + entry.updateEphemeris[entry.currentUpdateEphemeris] = r.updateTimeEphemeris; + entry.updateRenderable[entry.currentUpdateRenderable] = r.updateTimeRenderable; + + entry.currentRenderTime = (entry.currentRenderTime + 1) % nValues; + entry.currentUpdateEphemeris = (entry.currentUpdateEphemeris + 1) % nValues; + entry.currentUpdateRenderable = (entry.currentUpdateRenderable + 1) % nValues; + } + _performanceMemory->releaseLock(); +} + } // namespace openspace diff --git a/src/scenegraph/scenegraph.cpp b/src/scenegraph/scenegraph.cpp index 97cca49847..ac09a2d80e 100644 --- a/src/scenegraph/scenegraph.cpp +++ b/src/scenegraph/scenegraph.cpp @@ -22,7 +22,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -// open space includes #include #include #include @@ -34,7 +33,6 @@ #include #include -// ghoul includes #include "ghoul/logging/logmanager.h" #include "ghoul/opengl/programobject.h" #include "ghoul/io/texture/texturereader.h" @@ -526,6 +524,10 @@ SceneGraphNode* SceneGraph::sceneGraphNode(const std::string& name) const { return it->second; } +std::vector SceneGraph::allSceneGraphNodes() const { + return _nodes; +} + scripting::ScriptEngine::LuaLibrary SceneGraph::luaLibrary() { return { "", diff --git a/src/scenegraph/scenegraphnode.cpp b/src/scenegraph/scenegraphnode.cpp index 0f902cf724..4c968236a7 100644 --- a/src/scenegraph/scenegraphnode.cpp +++ b/src/scenegraph/scenegraphnode.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,7 @@ SceneGraphNode::SceneGraphNode() , _renderable(nullptr) , _renderableVisible(false) , _boundingSphereVisible(false) + , _performanceRecord({0, 0, 0}) { } @@ -170,17 +172,39 @@ bool SceneGraphNode::deinitialize() return true; } -// essential -void SceneGraphNode::update(const UpdateData& data) -{ - if (_ephemeris) - _ephemeris->update(data); - if (_renderable && _renderable->isReady()) - _renderable->update(data); +void SceneGraphNode::update(const UpdateData& data) { + if (_ephemeris) { + if (data.doPerformanceMeasurement) { + glFinish(); + ghoul::HighResClock::time_point start = ghoul::HighResClock::now(); + + _ephemeris->update(data); + + glFinish(); + ghoul::HighResClock::time_point end = ghoul::HighResClock::now(); + _performanceRecord.updateTimeEphemeris = (end - start).count(); + } + else + _ephemeris->update(data); + } + + if (_renderable && _renderable->isReady()) { + if (data.doPerformanceMeasurement) { + glFinish(); + ghoul::HighResClock::time_point start = ghoul::HighResClock::now(); + + _renderable->update(data); + + glFinish(); + ghoul::HighResClock::time_point end = ghoul::HighResClock::now(); + _performanceRecord.updateTimeRenderable = (end - start).count(); + } + else + _renderable->update(data); + } } -void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) -{ +void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) { //const psc thisPosition = parentPosition + _ephemeris->position(); //const psc camPos = camera->position(); //const psc toCamera = thisPosition - camPos; @@ -221,20 +245,24 @@ void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) } } -void SceneGraphNode::render(const RenderData& data) -{ +void SceneGraphNode::render(const RenderData& data) { const psc thisPosition = data.position + _ephemeris->position(); - RenderData newData = {data.camera, thisPosition}; - - // check if camera is outside the node boundingsphere - /*if (!_boundingSphereVisible) { - return; - }*/ + RenderData newData = {data.camera, thisPosition, data.doPerformanceMeasurement}; if (_renderableVisible && _renderable->isVisible() && _renderable->isReady()) { - // LDEBUG("Render"); - _renderable->render(newData); + if (data.doPerformanceMeasurement) { + glFinish(); + ghoul::HighResClock::time_point start = ghoul::HighResClock::now(); + + _renderable->render(newData); + + glFinish(); + ghoul::HighResClock::time_point end = ghoul::HighResClock::now(); + _performanceRecord.renderTime = (end - start).count(); + } + else + _renderable->render(newData); } // evaluate all the children, tail-recursive function(?)