diff --git a/ext/ghoul b/ext/ghoul index aa350fd8d3..9353bc4eba 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit aa350fd8d357984ca59c7aa2df8e08f904f31615 +Subproject commit 9353bc4eba6f455af9502fc180963722ae2e8f57 diff --git a/include/openspace/engine/gui.h b/include/openspace/engine/gui.h index 1df5293589..32f35a7aea 100644 --- a/include/openspace/engine/gui.h +++ b/include/openspace/engine/gui.h @@ -34,6 +34,10 @@ #include #include +namespace ghoul { + class SharedMemory; +} + namespace openspace { namespace properties { @@ -67,10 +71,20 @@ public: static scripting::ScriptEngine::LuaLibrary luaLibrary(); private: + void renderMainWindow(); + void renderPropertyWindow(); + void renderPerformanceWindow(); bool _isEnabled; + bool _showPropertyWindow; + bool _showPerformanceWindow; + bool _showHelp; + + ghoul::SharedMemory* _performanceMemory; + float _minMaxValues[2]; + std::set _boolProperties; std::set _intProperties; std::set _floatProperties; diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index b8144b8aae..e56f8745dc 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -56,6 +56,7 @@ public: virtual bool deinitialize() = 0; virtual bool isReady() const = 0; + bool isEnabled() const; void setBoundingSphere(const PowerScaledScalar& boundingSphere); const PowerScaledScalar& getBoundingSphere(); diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index af3b67d751..10cce4f07a 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -43,6 +43,8 @@ class ScreenLog; class RenderEngine { public: + static const std::string PerformanceMeasurementSharedData; + RenderEngine(); ~RenderEngine(); @@ -64,6 +66,7 @@ public: void toggleVisualizeABuffer(bool b); void setPerformanceMeasurements(bool performanceMeasurements); + bool doesPerformanceMeasurements() const; void serialize(SyncBuffer* syncBuffer); void deserialize(SyncBuffer* syncBuffer); diff --git a/scripts/bind_keys.lua b/scripts/bind_keys.lua index b082e5ed3d..2d90bb73ed 100644 --- a/scripts/bind_keys.lua +++ b/scripts/bind_keys.lua @@ -9,8 +9,8 @@ interaction_speed = 2.75 -- Key Bindings openspace.bindKey("f1", "openspace.gui.toggle()") -openspace.bindKey("f3", "openspace.setPropertyValue('Earth.renderable.enabled', true)") -openspace.bindKey("f4", "openspace.setPropertyValue('Earth.renderable.enabled', false)") +openspace.bindKey("f2", "openspace.setPerformanceMeasurement(true)") +openspace.bindKey("f3", "openspace.setPerformanceMeasurement(false)") openspace.bindKey("f5", "loadKeyBindings()") diff --git a/src/engine/gui.cpp b/src/engine/gui.cpp index 60d47ec66a..873e2b9faa 100644 --- a/src/engine/gui.cpp +++ b/src/engine/gui.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,8 @@ static void ImImpl_RenderDrawLists(ImDrawList** const commandLists, int nCommand for (int n = 0; n < nCommandLists; n++) total_vtx_count += commandLists[n]->vtx_buffer.size(); glBindBuffer(GL_ARRAY_BUFFER, vbo); - size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert); + // @BUGFIX @HACK The imgui crashes on complex scenes without the * 2 ---abock + size_t neededBufferSize = total_vtx_count * sizeof(ImDrawVert) * 2; if (neededBufferSize > vboMaxSize) { vboMaxSize = neededBufferSize + 5000; // Grow buffer glBufferData(GL_ARRAY_BUFFER, neededBufferSize, NULL, GL_STREAM_DRAW); @@ -105,8 +107,10 @@ static void ImImpl_RenderDrawLists(ImDrawList** const commandLists, int nCommand unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); if (!buffer_data) return; + int totalSize = 0; for (int n = 0; n < nCommandLists; ++n) { const ImDrawList* cmd_list = commandLists[n]; + totalSize += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert); memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)); buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert); } @@ -132,13 +136,83 @@ static void ImImpl_RenderDrawLists(ImDrawList** const commandLists, int nCommand glDisable(GL_SCISSOR_TEST); glBindTexture(GL_TEXTURE_2D, 0); } + +using namespace openspace::properties; + +void renderBoolProperty(Property* prop, const std::string& ownerName) { + BoolProperty* p = static_cast(prop); + std::string name = p->guiName(); + + BoolProperty::ValueType value = *p; + ImGui::Checkbox((ownerName + "." + name).c_str(), &value); + p->set(value); +} + +void renderOptionProperty(Property* prop, const std::string& ownerName) { + OptionProperty* p = static_cast(prop); + std::string name = p->guiName(); + + int value = *p; + std::vector options = p->options(); + for (auto o : options) { + ImGui::RadioButton((ownerName + "." + name).c_str(), &value, o.value); + ImGui::SameLine(); + ImGui::Text(o.description.c_str()); + } + p->set(value); +} + +void renderIntProperty(Property* prop, const std::string& ownerName) { + IntProperty* p = static_cast(prop); + std::string name = p->guiName(); + + IntProperty::ValueType value = *p; + ImGui::SliderInt((ownerName + "." + name).c_str(), &value, p->minValue(), p->maxValue()); + p->set(value); +} + +void renderFloatProperty(Property* prop, const std::string& ownerName) { + FloatProperty* p = static_cast(prop); + std::string name = p->guiName(); + + FloatProperty::ValueType value = *p; + ImGui::SliderFloat((ownerName + "." + name).c_str(), &value, p->minValue(), p->maxValue()); + p->set(value); +} + +void renderVec2Property(Property* prop, const std::string& ownerName) { + Vec2Property* p = static_cast(prop); + std::string name = p->guiName(); + + Vec2Property::ValueType value = *p; + + ImGui::SliderFloat2((ownerName + "." + name).c_str(), &value.x, p->minValue().x, p->maxValue().x); + p->set(value); +} + + +void renderVec3Property(Property* prop, const std::string& ownerName) { + Vec3Property* p = static_cast(prop); + std::string name = p->guiName(); + + Vec3Property::ValueType value = *p; + + ImGui::SliderFloat3((ownerName + "." + name).c_str(), &value.x, p->minValue().x, p->maxValue().x); + p->set(value); +} + } namespace openspace { GUI::GUI() : _isEnabled(false) + , _showPropertyWindow(false) + , _showHelp(false) + , _performanceMemory(nullptr) { + _minMaxValues[0] = 100.f; + _minMaxValues[1] = 1000.f; } GUI::~GUI() { @@ -257,8 +331,11 @@ void GUI::startFrame(float deltaTime, void GUI::endFrame() { static bool show = true; //ImGui::ShowTestWindow(&show); - - renderPropertyWindow(); + renderMainWindow(); + if (_showPropertyWindow) + renderPropertyWindow(); + if (_showPerformanceWindow) + renderPerformanceWindow(); ImGui::Render(); } @@ -336,73 +413,26 @@ void GUI::registerProperty(properties::Property* prop) { } -void renderBoolProperty(properties::Property* prop, const std::string& ownerName) { - properties::BoolProperty* p = static_cast(prop); - std::string name = p->guiName(); +void GUI::renderMainWindow() { + ImGui::Begin("OpenSpace GUI", nullptr); - properties::BoolProperty::ValueType value = *p; - ImGui::Checkbox((ownerName + "." + name).c_str(), &value); - p->set(value); -} + ImGui::Checkbox("Properties", &_showPropertyWindow); + ImGui::Checkbox("Performance", &_showPerformanceWindow); + ImGui::Checkbox("Help", &_showHelp); -void renderOptionProperty(properties::Property* prop, const std::string& ownerName) { - properties::OptionProperty* p = static_cast(prop); - std::string name = p->guiName(); - - int value = *p; - std::vector options = p->options(); - for (auto o : options) { - ImGui::RadioButton((ownerName + "." + name).c_str(), &value, o.value); - ImGui::SameLine(); - ImGui::Text(o.description.c_str()); + if (_showHelp) { + ImGui::Separator(); + ImGui::ShowUserGuide(); + ImGui::ShowTestWindow(); } - p->set(value); + + ImGui::End(); } -void renderIntProperty(properties::Property* prop, const std::string& ownerName) { - properties::IntProperty* p = static_cast(prop); - std::string name = p->guiName(); - - properties::IntProperty::ValueType value = *p; - ImGui::SliderInt((ownerName + "." + name).c_str(), &value, p->minValue(), p->maxValue()); - p->set(value); -} - -void renderFloatProperty(properties::Property* prop, const std::string& ownerName) { - properties::FloatProperty* p = static_cast(prop); - std::string name = p->guiName(); - - properties::FloatProperty::ValueType value = *p; - ImGui::SliderFloat((ownerName + "." + name).c_str(), &value, p->minValue(), p->maxValue()); - p->set(value); -} - -void renderVec2Property(properties::Property* prop, const std::string& ownerName) { - properties::Vec2Property* p = static_cast(prop); - std::string name = p->guiName(); - - properties::Vec2Property::ValueType value = *p; - - ImGui::SliderFloat2((ownerName + "." + name).c_str(), &value.x, p->minValue().x, p->maxValue().x); - p->set(value); -} - - -void renderVec3Property(properties::Property* prop, const std::string& ownerName) { - properties::Vec3Property* p = static_cast(prop); - std::string name = p->guiName(); - - properties::Vec3Property::ValueType value = *p; - - ImGui::SliderFloat3((ownerName + "." + name).c_str(), &value.x, p->minValue().x, p->maxValue().x); - p->set(value); -} - - void GUI::renderPropertyWindow() { using namespace properties; - ImGui::Begin("Properties", nullptr, size, 0.5f); + ImGui::Begin("Properties", &_showPropertyWindow, size, 0.5f); //ImGui::ShowUserGuide(); ImGui::Spacing(); @@ -444,46 +474,71 @@ void GUI::renderPropertyWindow() { } } + ImGui::End(); +} - //for (auto pair : _propertiesByOwner) { - // auto p = _propertiesByOwner.equal_range(pair); +void GUI::renderPerformanceWindow() { + // Copy and paste from renderengine.cpp::storePerformanceMeasurements method + const int8_t Version = 0; + const int nValues = 1000; + const int lengthName = 256; + const int maxValues = 50; - // if (ImGui::CollapsingHeader(pair->first.c_str())) { - // for () - // if (_boolProperties.find(p->second) != _boolProperties.end()) { + struct PerformanceLayout { + int8_t version; + int32_t nValuesPerEntry; + int32_t nEntries; + int32_t maxNameLength; + int32_t maxEntries; - // } - // } - //} + struct PerformanceLayoutEntry { + char name[lengthName]; + float renderTime[nValues]; + float updateRenderable[nValues]; + float updateEphemeris[nValues]; - //for (auto prop : _boolProperties) { - // BoolProperty* p = static_cast(prop); - // std::string name = p->fullyQualifiedIdentifier(); + int32_t currentRenderTime; + int32_t currentUpdateRenderable; + int32_t currentUpdateEphemeris; + }; - // BoolProperty::ValueType value = *p; - // ImGui::Checkbox(name.c_str(), &value); - // p->set(value); + PerformanceLayoutEntry entries[maxValues]; + }; - //} + ImGui::Begin("Performance", &_showPerformanceWindow); + if (OsEng.renderEngine().doesPerformanceMeasurements() && + ghoul::SharedMemory::exists(RenderEngine::PerformanceMeasurementSharedData)) + { + ImGui::SliderFloat2("Min values, max Value", _minMaxValues, 0.f, 10000.f); + _minMaxValues[1] = std::max(_minMaxValues[0], _minMaxValues[1]); - //for (auto prop : _intProperties) { - // IntProperty* p = static_cast(prop); - // std::string name = p->fullyQualifiedIdentifier(); + if (!_performanceMemory) { + _performanceMemory = new ghoul::SharedMemory(RenderEngine::PerformanceMeasurementSharedData); + } - // IntProperty::ValueType value = *p; - // ImGui::SliderInt(name.c_str(), &value, p->minValue(), p->maxValue()); - // p->set(value); - //} + PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); - //for (auto prop : _StringProperties) { - // StringProperty* p = static_cast(prop); - // std::string name = p->fullyQualifiedIdentifier(); + for (int i = 0; i < layout->nEntries; ++i) { + const PerformanceLayout::PerformanceLayoutEntry& entry = layout->entries[i]; - // //ImGui::TextUnformatted() - //} + if (ImGui::CollapsingHeader(entry.name)) { + std::string updateEphemerisTime = std::to_string(entry.updateEphemeris[entry.currentUpdateEphemeris - 1]) + "us"; + ImGui::PlotLines("UpdateEphemeris", &entry.updateEphemeris[0], layout->nValuesPerEntry, 0, updateEphemerisTime.c_str(), _minMaxValues[0], _minMaxValues[1], ImVec2(0, 40)); + + std::string updateRenderableTime = std::to_string(entry.updateRenderable[entry.currentUpdateRenderable - 1]) + "us"; + ImGui::PlotLines("UpdateRender", &entry.updateRenderable[0], layout->nValuesPerEntry, 0, updateRenderableTime.c_str(), _minMaxValues[0], _minMaxValues[1], ImVec2(0, 40)); + + std::string renderTime = std::to_string(entry.renderTime[entry.currentRenderTime - 1]) + "us"; + ImGui::PlotLines("RenderTime", &entry.renderTime[0], layout->nValuesPerEntry, 0, renderTime.c_str(), _minMaxValues[0], _minMaxValues[1], ImVec2(0, 40)); + } + } + } + else { + ImGui::TextWrapped("Performance monitoring is disabled. Enable with " + "'openspace.setPerformanceMeasurement(true)'"); + } ImGui::End(); - } namespace { diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index fac2359542..9260a617a8 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -122,4 +122,8 @@ bool Renderable::isReady() const { return true; } +bool Renderable::isEnabled() const { + return _enabled; +} + } // namespace openspace diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index c2453e6f9b..71f008bfcb 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -69,13 +69,13 @@ namespace { const std::string _loggerCat = "RenderEngine"; - - const std::string PerformanceMeasurementSharedData = - "OpenSpacePerformanceMeasurementSharedData"; } namespace openspace { +const std::string RenderEngine::PerformanceMeasurementSharedData = + "OpenSpacePerformanceMeasurementSharedData"; + namespace luascriptfunctions { /** @@ -595,12 +595,18 @@ void RenderEngine::setPerformanceMeasurements(bool performanceMeasurements) { _doPerformanceMeasurements = performanceMeasurements; } +bool RenderEngine::doesPerformanceMeasurements() const { + return _doPerformanceMeasurements; +} + void RenderEngine::storePerformanceMeasurements() { + const int8_t Version = 0; const int nValues = 1000; const int lengthName = 256; const int maxValues = 50; struct PerformanceLayout { + int8_t version; int32_t nValuesPerEntry; int32_t nEntries; int32_t maxNameLength; @@ -608,9 +614,9 @@ void RenderEngine::storePerformanceMeasurements() { struct PerformanceLayoutEntry { char name[lengthName]; - int64_t renderTime[nValues]; - int64_t updateRenderable[nValues]; - int64_t updateEphemeris[nValues]; + float renderTime[nValues]; + float updateRenderable[nValues]; + float updateEphemeris[nValues]; int32_t currentRenderTime; int32_t currentUpdateRenderable; @@ -624,14 +630,15 @@ void RenderEngine::storePerformanceMeasurements() { if (!_performanceMemory) { // Compute the total size - const int totalSize = 4 * sizeof(int32_t) + + const int totalSize = sizeof(int8_t) + 4 * sizeof(int32_t) + maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry); - LINFO("Create shared memory of size '" << totalSize << "' bytes"); + LINFO("Create shared memory of " << totalSize << " bytes"); ghoul::SharedMemory::create(PerformanceMeasurementSharedData, totalSize); _performanceMemory = new ghoul::SharedMemory(PerformanceMeasurementSharedData); PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); + layout->version = Version; layout->nValuesPerEntry = nValues; layout->nEntries = nNodes; layout->maxNameLength = lengthName; @@ -658,9 +665,9 @@ void RenderEngine::storePerformanceMeasurements() { 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.renderTime[entry.currentRenderTime] = r.renderTime / 1000.f; + entry.updateEphemeris[entry.currentUpdateEphemeris] = r.updateTimeEphemeris / 1000.f; + entry.updateRenderable[entry.currentUpdateRenderable] = r.updateTimeRenderable / 1000.f; entry.currentRenderTime = (entry.currentRenderTime + 1) % nValues; entry.currentUpdateEphemeris = (entry.currentUpdateEphemeris + 1) % nValues; diff --git a/src/scenegraph/scenegraphnode.cpp b/src/scenegraph/scenegraphnode.cpp index 4c968236a7..31b0033cd2 100644 --- a/src/scenegraph/scenegraphnode.cpp +++ b/src/scenegraph/scenegraphnode.cpp @@ -250,7 +250,8 @@ void SceneGraphNode::render(const RenderData& data) { RenderData newData = {data.camera, thisPosition, data.doPerformanceMeasurement}; - if (_renderableVisible && _renderable->isVisible() && _renderable->isReady()) { + _performanceRecord.renderTime = 0.f; + if (_renderableVisible && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled()) { if (data.doPerformanceMeasurement) { glFinish(); ghoul::HighResClock::time_point start = ghoul::HighResClock::now();