mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-03 17:30:04 -05:00
Making the documentation generation a bit more performant
Outsource the file writing to a second thread to start the rendering earlier
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include <openspace/util/touch.h>
|
||||
#include <openspace/util/versionchecker.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -127,6 +128,8 @@ private:
|
||||
//grabs json from each module to pass to the documentation engine.
|
||||
std::string _documentationJson;
|
||||
|
||||
std::future<void> _writeDocumentationTask;
|
||||
|
||||
ShutdownInformation _shutdown;
|
||||
|
||||
// The first frame might take some more time in the update loop, so we need to know to
|
||||
|
||||
@@ -291,7 +291,7 @@ public:
|
||||
*/
|
||||
void removeTag(const std::string& tag);
|
||||
|
||||
//Generate JSON for documentation
|
||||
// Generate JSON for documentation
|
||||
std::string generateJson() const override;
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@@ -194,6 +195,8 @@ std::vector<Documentation> DocumentationEngine::documentations() const {
|
||||
void DocumentationEngine::writeDocumentationHtml(const std::string& path,
|
||||
std::string data)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
std::ifstream handlebarsInput;
|
||||
handlebarsInput.exceptions(~std::ofstream::goodbit);
|
||||
handlebarsInput.open(absPath(HandlebarsFilename));
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
|
||||
#include <glbinding/glbinding.h>
|
||||
#include <glbinding-aux/types_to_string.h>
|
||||
#include <future>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
|
||||
@@ -852,7 +853,7 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
|
||||
|
||||
runGlobalCustomizationScripts();
|
||||
|
||||
writeSceneDocumentation();
|
||||
_writeDocumentationTask = std::async(&OpenSpaceEngine::writeSceneDocumentation, this);
|
||||
|
||||
LTRACE("OpenSpaceEngine::loadSingleAsset(end)");
|
||||
}
|
||||
@@ -1013,6 +1014,18 @@ void OpenSpaceEngine::writeSceneDocumentation() {
|
||||
|
||||
std::string path = global::configuration.documentation.path;
|
||||
if (!path.empty()) {
|
||||
std::future<std::string> root = std::async(
|
||||
&properties::PropertyOwner::generateJson,
|
||||
&global::rootPropertyOwner
|
||||
);
|
||||
|
||||
std::future<std::string> scene = std::async(
|
||||
&properties::PropertyOwner::generateJson,
|
||||
_scene.get()
|
||||
);
|
||||
|
||||
|
||||
|
||||
path = absPath(path) + "/";
|
||||
_documentationJson += "{\"name\":\"Keybindings\",\"identifier\":\"";
|
||||
_documentationJson += global::keybindingManager.jsonName() + "\",";
|
||||
@@ -1026,11 +1039,11 @@ void OpenSpaceEngine::writeSceneDocumentation() {
|
||||
_documentationJson += "},";
|
||||
_documentationJson += "{\"name\":\"Scene Properties\",";
|
||||
_documentationJson += "\"identifier\":\"propertylist";// + _scene->jsonName();
|
||||
_documentationJson += "\",\"data\":" + global::rootPropertyOwner.generateJson();
|
||||
_documentationJson += "\",\"data\":" + root.get();
|
||||
_documentationJson += "},";
|
||||
_documentationJson += "{\"name\":\"Scene Graph Information\",";
|
||||
_documentationJson += "\"identifier\":\"propertylist";
|
||||
_documentationJson += "\",\"data\":" + _scene->generateJson();
|
||||
_documentationJson += "\",\"data\":" + scene.get();
|
||||
_documentationJson += "}";
|
||||
|
||||
//add templates for the jsons we just registered
|
||||
@@ -1149,7 +1162,14 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
|
||||
|
||||
const bool updated = _assetManager->update();
|
||||
if (updated) {
|
||||
writeSceneDocumentation();
|
||||
if (_writeDocumentationTask.valid()) {
|
||||
// If there still is a documentation creation task the previous frame, we need
|
||||
// to wait for it to finish first, or else we might write to the same file
|
||||
_writeDocumentationTask.wait();
|
||||
}
|
||||
_writeDocumentationTask = std::async(
|
||||
&OpenSpaceEngine::writeSceneDocumentation, this
|
||||
);
|
||||
}
|
||||
|
||||
if (!global::windowDelegate.isMaster()) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <sstream>
|
||||
|
||||
@@ -170,6 +171,8 @@ KeybindingManager::keyBindings() const
|
||||
}
|
||||
|
||||
std::string KeybindingManager::generateJson() const {
|
||||
ZoneScoped
|
||||
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
bool first = true;
|
||||
|
||||
@@ -35,6 +35,111 @@
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "PropertyOwner";
|
||||
|
||||
std::string escapedJson(const std::string& text) {
|
||||
std::string jsonString;
|
||||
for (const char& c : text) {
|
||||
switch (c) {
|
||||
case '\t':
|
||||
jsonString += "\\t"; // Replace tab with \t.
|
||||
break;
|
||||
case '"':
|
||||
jsonString += "\\\""; // Replace " with \".
|
||||
break;
|
||||
case '\\':
|
||||
jsonString += "\\\\"; // Replace \ with \\.
|
||||
break;
|
||||
case '\n':
|
||||
jsonString += "\\\\n"; // Replace newline with \n.
|
||||
break;
|
||||
case '\r':
|
||||
jsonString += "\\r"; // Replace carriage return with \r.
|
||||
break;
|
||||
default:
|
||||
jsonString += c;
|
||||
}
|
||||
}
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
void createJson(openspace::properties::PropertyOwner* owner, std::vector<char>& buf) {
|
||||
ZoneScoped
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
constexpr const char* replStr = R"("{}": "{}")";
|
||||
|
||||
//std::stringstream json;
|
||||
//json << "{";
|
||||
buf.push_back('{');
|
||||
//json << fmt::format(replStr, "name", owner->identifier()) << ",";
|
||||
fmt::format_to(std::back_inserter(buf), replStr, "name", owner->identifier());
|
||||
buf.push_back(',');
|
||||
|
||||
constexpr const char propertiesText[] = "\"properties\": [";
|
||||
//constexpr const std::array<char, 16> propertiesText = { "\"properties\": [" };
|
||||
buf.insert(buf.end(), std::begin(propertiesText), std::end(propertiesText) - 1);
|
||||
//json << "\"properties\": [";
|
||||
const std::vector<properties::Property*>& properties = owner->properties();
|
||||
for (properties::Property* p : properties) {
|
||||
//json << "{";
|
||||
buf.push_back('{');
|
||||
//json << fmt::format(replStr, "id", p->identifier()) << ",";
|
||||
fmt::format_to(std::back_inserter(buf), replStr, "id", p->identifier());
|
||||
buf.push_back(',');
|
||||
//json << fmt::format(replStr, "type", p->className()) << ",";
|
||||
fmt::format_to(std::back_inserter(buf), replStr, "type", p->className());
|
||||
buf.push_back(',');
|
||||
|
||||
//json << fmt::format(
|
||||
// replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
|
||||
//) << ",";
|
||||
fmt::format_to(
|
||||
std::back_inserter(buf),
|
||||
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
|
||||
);
|
||||
buf.push_back(',');
|
||||
|
||||
//json << fmt::format(replStr, "guiName", p->guiName()) << ",";
|
||||
fmt::format_to(std::back_inserter(buf), replStr, "guiName", p->guiName());
|
||||
buf.push_back(',');
|
||||
|
||||
//json << fmt::format(replStr, "description", escapedJson(p->description()));
|
||||
fmt::format_to(
|
||||
std::back_inserter(buf),
|
||||
replStr, "description", escapedJson(p->description())
|
||||
);
|
||||
//json << "}";
|
||||
buf.push_back('}');
|
||||
if (p != properties.back()) {
|
||||
//json << ",";
|
||||
buf.push_back(',');
|
||||
}
|
||||
}
|
||||
//json << "],";
|
||||
buf.push_back(']');
|
||||
buf.push_back(',');
|
||||
|
||||
constexpr const char propertyOwnersText[] = "\"propertyOwners\": [";
|
||||
//constexpr const std::array<char, 20> propertyOwnersText = { "\"propertyOwners\": [" };
|
||||
//json << "\"propertyOwners\": [";
|
||||
buf.insert(buf.end(), std::begin(propertyOwnersText), std::end(propertyOwnersText) - 1);
|
||||
auto propertyOwners = owner->propertySubOwners();
|
||||
for (properties::PropertyOwner* o : propertyOwners) {
|
||||
createJson(o, buf);
|
||||
//json << createJson(o);
|
||||
if (o != propertyOwners.back()) {
|
||||
//json << ",";
|
||||
buf.push_back(',');
|
||||
}
|
||||
}
|
||||
//json << "]";
|
||||
buf.push_back(']');
|
||||
//json << "}";
|
||||
buf.push_back('}');
|
||||
|
||||
//return json.str();
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace::properties {
|
||||
@@ -356,67 +461,19 @@ void PropertyOwner::removeTag(const std::string& tag) {
|
||||
}
|
||||
|
||||
std::string PropertyOwner::generateJson() const {
|
||||
std::function<std::string(properties::PropertyOwner*)> createJson =
|
||||
[&createJson](properties::PropertyOwner* owner) -> std::string
|
||||
{
|
||||
constexpr const char* replStr = R"("{}": "{}")";
|
||||
ZoneScoped
|
||||
|
||||
std::stringstream json;
|
||||
json << "{";
|
||||
json << fmt::format(replStr, "name", owner->identifier()) << ",";
|
||||
|
||||
json << "\"properties\": [";
|
||||
const std::vector<properties::Property*>& properties = owner->properties();
|
||||
for (properties::Property* p : properties) {
|
||||
json << "{";
|
||||
json << fmt::format(replStr, "id", p->identifier()) << ",";
|
||||
json << fmt::format(replStr, "type", p->className()) << ",";
|
||||
json << fmt::format(
|
||||
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
|
||||
) << ",";
|
||||
json << fmt::format(replStr, "guiName", p->guiName()) << ",";
|
||||
json << fmt::format(replStr, "description", escapedJson(p->description()));
|
||||
json << "}";
|
||||
if (p != properties.back()) {
|
||||
json << ",";
|
||||
}
|
||||
}
|
||||
json << "],";
|
||||
|
||||
json << "\"propertyOwners\": [";
|
||||
auto propertyOwners = owner->propertySubOwners();
|
||||
for (properties::PropertyOwner* o : propertyOwners) {
|
||||
json << createJson(o);
|
||||
if (o != propertyOwners.back()) {
|
||||
json << ",";
|
||||
}
|
||||
}
|
||||
json << "]";
|
||||
json << "}";
|
||||
|
||||
return json.str();
|
||||
};
|
||||
|
||||
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
std::vector<char> res;
|
||||
res.reserve(5 * 51024 * 1024); // 5 MB
|
||||
res.push_back('[');
|
||||
std::vector<PropertyOwner*> subOwners = propertySubOwners();
|
||||
if (!subOwners.empty()) {
|
||||
json << std::accumulate(
|
||||
std::next(subOwners.begin()),
|
||||
subOwners.end(),
|
||||
createJson(*subOwners.begin()),
|
||||
[createJson](std::string a, PropertyOwner* n) {
|
||||
//TODO figure out how to ignore scene when its not the root
|
||||
//right now will be done on client side
|
||||
return a + "," + createJson(n);
|
||||
}
|
||||
);
|
||||
for (PropertyOwner* owner : subOwners) {
|
||||
createJson(owner, res);
|
||||
res.push_back(',');
|
||||
}
|
||||
res.back() = ']';
|
||||
|
||||
json << "]";
|
||||
|
||||
return json.str();
|
||||
return std::string(res.begin(), res.end());
|
||||
}
|
||||
|
||||
} // namespace openspace::properties
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/scene/asset.h>
|
||||
#include <openspace/scene/assetmanager.h>
|
||||
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace openspace {
|
||||
@@ -45,6 +45,8 @@ SceneLicenseWriter::SceneLicenseWriter()
|
||||
{}
|
||||
|
||||
std::string SceneLicenseWriter::generateJson() const {
|
||||
ZoneScoped
|
||||
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user