mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-30 07:49:31 -05:00
Merge branch 'master' into feature/multitouch
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -62,8 +62,11 @@ const string ConfigurationManager::KeyConfigScene = "Scene";
|
||||
const string ConfigurationManager::KeyConfigTask = "Task";
|
||||
|
||||
const string ConfigurationManager::KeyLogging = "Logging";
|
||||
const string ConfigurationManager::PartLogDir = "LogDir";
|
||||
const string ConfigurationManager::PartLogLevel = "LogLevel";
|
||||
const string ConfigurationManager::PartImmediateFlush = "ImmediateFlush";
|
||||
const string ConfigurationManager::PartLogPerformancePrefix = "PerformancePrefix";
|
||||
|
||||
const string ConfigurationManager::PartLogs = "Logs";
|
||||
const string ConfigurationManager::PartAppend = "Append";
|
||||
const string ConfigurationManager::PartCapabilitiesVerbosity = "CapabilitiesVerbosity";
|
||||
@@ -97,6 +100,8 @@ const string ConfigurationManager::PartFilterIdentifierSource = "Source";
|
||||
const string ConfigurationManager::PartFilterIdentifierType = "Type";
|
||||
const string ConfigurationManager::PartFilterIdentifierIdentifier = "Identifier";
|
||||
const string ConfigurationManager::PartFilterSeverity = "PartFilterSeverity";
|
||||
const string ConfigurationManager::KeyCheckOpenGLState = "CheckOpenGLState";
|
||||
const string ConfigurationManager::KeyLogEachOpenGLCall = "LogEachOpenGLCall";
|
||||
|
||||
string ConfigurationManager::findConfiguration(const string& filename) {
|
||||
using ghoul::filesystem::Directory;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -86,6 +86,20 @@ documentation::Documentation ConfigurationManager::Documentation() {
|
||||
{
|
||||
ConfigurationManager::KeyLogging,
|
||||
new TableVerifier({
|
||||
{
|
||||
ConfigurationManager::PartLogDir,
|
||||
new StringVerifier,
|
||||
"The directory for logs."
|
||||
"Default value is \"${BASE_PATH}\"",
|
||||
Optional::Yes
|
||||
},
|
||||
{
|
||||
ConfigurationManager::PartLogPerformancePrefix,
|
||||
new StringVerifier,
|
||||
"A string to prefix PerformanceMeasurement logfiles."
|
||||
"Default value is \"PM-\"",
|
||||
Optional::Yes
|
||||
},
|
||||
{
|
||||
ConfigurationManager::PartLogLevel,
|
||||
new StringInListVerifier(
|
||||
@@ -383,6 +397,23 @@ documentation::Documentation ConfigurationManager::Documentation() {
|
||||
}),
|
||||
"Determines the settings for the creation of an OpenGL debug context.",
|
||||
Optional::Yes
|
||||
},
|
||||
{
|
||||
ConfigurationManager::KeyCheckOpenGLState,
|
||||
new BoolVerifier,
|
||||
"Determines whether the OpenGL state is checked after each OpenGL function "
|
||||
"call. This will dramatically slow down the rendering, but will make finding "
|
||||
"OpenGL errors easier. This defaults to 'false'.",
|
||||
Optional::Yes
|
||||
},
|
||||
{
|
||||
ConfigurationManager::KeyLogEachOpenGLCall,
|
||||
new BoolVerifier,
|
||||
"Determines whether each OpenGL call that happens should be logged using the "
|
||||
"'TRACE' loglevel. This will bring the rendering to a crawl but provides "
|
||||
"useful debugging features for the order in which OpenGL calls occur. This "
|
||||
"defaults to 'false'.",
|
||||
Optional::Yes
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*****************************************************************************************
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <openspace/util/transformationmanager.h>
|
||||
|
||||
#include <ghoul/ghoul.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/misc/onscopeexit.h>
|
||||
#include <ghoul/cmdparser/commandlineparser.h>
|
||||
#include <ghoul/cmdparser/singlecommand.h>
|
||||
@@ -70,6 +71,7 @@
|
||||
#include <ghoul/opengl/debugcontext.h>
|
||||
#include <ghoul/systemcapabilities/systemcapabilities>
|
||||
|
||||
#include <glbinding/callbacks.h>
|
||||
|
||||
#if defined(_MSC_VER) && defined(OPENSPACE_ENABLE_VLD)
|
||||
#include <vld.h>
|
||||
@@ -79,6 +81,8 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include "openspaceengine_lua.inl"
|
||||
|
||||
using namespace openspace::scripting;
|
||||
@@ -978,6 +982,90 @@ void OpenSpaceEngine::initializeGL() {
|
||||
LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)");
|
||||
}
|
||||
|
||||
// The ordering of the KeyCheckOpenGLState and KeyLogEachOpenGLCall are important as
|
||||
// the callback mask in glbinding is stateful for each context, and since
|
||||
// KeyLogEachOpenGLCall is more specific, we want it to be able to overwrite the
|
||||
// state from KeyCheckOpenGLState
|
||||
if (_configurationManager->hasKey(ConfigurationManager::KeyCheckOpenGLState)) {
|
||||
const bool val = _configurationManager->value<bool>(
|
||||
ConfigurationManager::KeyCheckOpenGLState
|
||||
);
|
||||
|
||||
if (val) {
|
||||
using namespace glbinding;
|
||||
setCallbackMaskExcept(CallbackMask::After, { "glGetError" });
|
||||
setAfterCallback([](const FunctionCall& f) {
|
||||
const GLenum error = glGetError();
|
||||
switch (error) {
|
||||
case GL_NO_ERROR:
|
||||
break;
|
||||
case GL_INVALID_ENUM:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Function " << f.toString() << ": GL_INVALID_ENUM"
|
||||
);
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Function " << f.toString() << ": GL_INVALID_VALUE"
|
||||
);
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Function " << f.toString() << ": GL_INVALID_OPERATION"
|
||||
);
|
||||
break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Function " << f.toString() <<
|
||||
": GL_INVALID_FRAMEBUFFER_OPERATION"
|
||||
);
|
||||
break;
|
||||
case GL_OUT_OF_MEMORY:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Function " << f.toString() << ": GL_OUT_OF_MEMORY"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
LERRORC(
|
||||
"OpenGL Invalid State",
|
||||
"Unknown error code: " << std::hex << error
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (_configurationManager->hasKey(ConfigurationManager::KeyLogEachOpenGLCall)) {
|
||||
const bool val = _configurationManager->value<bool>(
|
||||
ConfigurationManager::KeyLogEachOpenGLCall
|
||||
);
|
||||
|
||||
if (val) {
|
||||
using namespace glbinding;
|
||||
setCallbackMask(CallbackMask::After | CallbackMask::ParametersAndReturnValue);
|
||||
glbinding::setAfterCallback([](const glbinding::FunctionCall& call) {
|
||||
std::string arguments = std::accumulate(
|
||||
call.parameters.begin(),
|
||||
call.parameters.end(),
|
||||
std::string("("),
|
||||
[](std::string a, AbstractValue* v) {
|
||||
return a + ", " + v->asString();
|
||||
}
|
||||
);
|
||||
|
||||
std::string returnValue = call.returnValue ?
|
||||
" -> " + call.returnValue->asString() :
|
||||
"";
|
||||
|
||||
LTRACEC("OpenGL", call.function->name() << arguments << returnValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
LINFO("Initializing Rendering Engine");
|
||||
_renderEngine->initializeGL();
|
||||
|
||||
@@ -30,9 +30,12 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/sharedmemory.h>
|
||||
#include <ghoul/misc/onscopeexit.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "PerformanceManager";
|
||||
@@ -130,12 +133,16 @@ void PerformanceManager::destroyGlobalSharedMemory() {
|
||||
|
||||
PerformanceManager::PerformanceManager()
|
||||
: _performanceMemory(nullptr)
|
||||
, _tick(0)
|
||||
, _loggingEnabled(false)
|
||||
, _logDir(absPath("${BASE_PATH}"))
|
||||
, _prefix("PM-")
|
||||
, _ext("log")
|
||||
{
|
||||
using ghoul::SharedMemory;
|
||||
PerformanceManager::createGlobalSharedMemory();
|
||||
|
||||
|
||||
SharedMemory sharedMemory(GlobalSharedMemoryName);
|
||||
ghoul::SharedMemory sharedMemory(GlobalSharedMemoryName);
|
||||
sharedMemory.acquireLock();
|
||||
OnExit([&](){sharedMemory.releaseLock();});
|
||||
|
||||
@@ -151,7 +158,7 @@ PerformanceManager::PerformanceManager()
|
||||
const int totalSize = sizeof(PerformanceLayout);
|
||||
LINFO("Create shared memory '" + localName + "' of " << totalSize << " bytes");
|
||||
|
||||
if (SharedMemory::exists(localName)) {
|
||||
if (ghoul::SharedMemory::exists(localName)) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Shared Memory '" + localName + "' block already existed"
|
||||
);
|
||||
@@ -196,11 +203,131 @@ bool PerformanceManager::isMeasuringPerformance() const {
|
||||
return _doPerformanceMeasurements;
|
||||
}
|
||||
|
||||
void PerformanceManager::outputLogs() {
|
||||
|
||||
// Log Layout values
|
||||
PerformanceLayout* layout = performanceData();
|
||||
|
||||
// Log function performance
|
||||
for (size_t n = 0; n < layout->nFunctionEntries; n++) {
|
||||
const auto function = layout->functionEntries[n];
|
||||
const std::string filename = formatLogName(function.name);
|
||||
std::ofstream out = std::ofstream(absPath(filename), std::ofstream::out | std::ofstream::app);
|
||||
|
||||
// Comma separate data
|
||||
for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) {
|
||||
const std::vector<float> data = { function.time[i] };
|
||||
writeData(out, data);
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
// Log scene object performance
|
||||
for (size_t n = 0; n < layout->nScaleGraphEntries; n++) {
|
||||
const auto node = layout->sceneGraphEntries[n];
|
||||
|
||||
// Open file
|
||||
const std::string filename = formatLogName(node.name);
|
||||
std::ofstream out = std::ofstream(absPath(filename), std::ofstream::out | std::ofstream::app);
|
||||
|
||||
// Comma separate data
|
||||
for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) {
|
||||
const std::vector<float> data = {
|
||||
node.renderTime[i],
|
||||
node.updateRenderable[i],
|
||||
node.updateRotation[i],
|
||||
node.updateScaling[i],
|
||||
node.updateTranslation[i]
|
||||
};
|
||||
writeData(out, data);
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceManager::writeData(std::ofstream& out, const std::vector<float>& data) {
|
||||
for (size_t i = 0; i < data.size() - 1; i++) {
|
||||
out << data[i] << ",";
|
||||
}
|
||||
out << data[data.size() - 1] << "\n";
|
||||
}
|
||||
|
||||
std::string PerformanceManager::formatLogName(std::string nodeName) {
|
||||
// Replace any colons with dashes
|
||||
std::replace(nodeName.begin(), nodeName.end(), ':', '-');
|
||||
return _logDir + "/" + _prefix + nodeName + _suffix + "." + _ext;
|
||||
}
|
||||
|
||||
void PerformanceManager::logDir(std::string dir) {
|
||||
_logDir = absPath(dir);
|
||||
}
|
||||
|
||||
std::string PerformanceManager::logDir() const {
|
||||
return _logDir;
|
||||
}
|
||||
|
||||
void PerformanceManager::prefix(std::string prefix) {
|
||||
_prefix = prefix;
|
||||
}
|
||||
|
||||
std::string PerformanceManager::prefix() const {
|
||||
return _prefix;
|
||||
}
|
||||
|
||||
void PerformanceManager::enableLogging() {
|
||||
setLogging(true);
|
||||
}
|
||||
|
||||
void PerformanceManager::disableLogging() {
|
||||
setLogging(false);
|
||||
}
|
||||
|
||||
void PerformanceManager::toggleLogging() {
|
||||
setLogging(!_loggingEnabled);
|
||||
}
|
||||
|
||||
void PerformanceManager::setLogging(bool enabled) {
|
||||
// Create the log directory if it doesn't exist. Do it here, so that it
|
||||
// only tests once each time output is enabled
|
||||
if (enabled) {
|
||||
// If it can't create the directory, it's not logging so set false
|
||||
enabled = createLogDir();
|
||||
}
|
||||
|
||||
_loggingEnabled = enabled;
|
||||
}
|
||||
|
||||
bool PerformanceManager::createLogDir() {
|
||||
// Done if it exists
|
||||
ghoul::filesystem::Directory dir(_logDir);
|
||||
if (FileSys.directoryExists(dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Error and set false if can't create
|
||||
try {
|
||||
FileSys.createDirectory(dir, ghoul::filesystem::FileSystem::Recursive::Yes);
|
||||
}
|
||||
catch (const ghoul::filesystem::FileSystem::FileSystemException& e) {
|
||||
LERROR("Could not create log directory: " << e.message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PerformanceManager::loggingEnabled() const {
|
||||
return _loggingEnabled;
|
||||
}
|
||||
|
||||
PerformanceLayout* PerformanceManager::performanceData() {
|
||||
void* ptr = _performanceMemory->memory();
|
||||
return reinterpret_cast<PerformanceLayout*>(ptr);
|
||||
}
|
||||
|
||||
void PerformanceManager::tick() {
|
||||
_tick = (_tick + 1) % PerformanceLayout::NumberValues;
|
||||
}
|
||||
|
||||
void PerformanceManager::storeIndividualPerformanceMeasurement
|
||||
(std::string identifier, long long microseconds)
|
||||
{
|
||||
@@ -261,42 +388,51 @@ void PerformanceManager::storeScenePerformanceMeasurements(
|
||||
SceneGraphNode::PerformanceRecord r = node->performanceRecord();
|
||||
PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i];
|
||||
|
||||
// Covert nano to microseconds
|
||||
const float micro = 1000.f;
|
||||
|
||||
std::rotate(
|
||||
std::begin(entry.renderTime),
|
||||
std::next(std::begin(entry.renderTime)),
|
||||
std::end(entry.renderTime)
|
||||
);
|
||||
entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / 1000.f;
|
||||
entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / micro;
|
||||
|
||||
std::rotate(
|
||||
std::begin(entry.updateTranslation),
|
||||
std::next(std::begin(entry.updateTranslation)),
|
||||
std::end(entry.updateTranslation)
|
||||
);
|
||||
entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / 1000.f;
|
||||
entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / micro;
|
||||
|
||||
std::rotate(
|
||||
std::begin(entry.updateRotation),
|
||||
std::next(std::begin(entry.updateRotation)),
|
||||
std::end(entry.updateRotation)
|
||||
);
|
||||
entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / 1000.f;
|
||||
entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / micro;
|
||||
|
||||
std::rotate(
|
||||
std::begin(entry.updateScaling),
|
||||
std::next(std::begin(entry.updateScaling)),
|
||||
std::end(entry.updateScaling)
|
||||
);
|
||||
entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / 1000.f;
|
||||
entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / micro;
|
||||
|
||||
std::rotate(
|
||||
std::begin(entry.updateRenderable),
|
||||
std::next(std::begin(entry.updateRenderable)),
|
||||
std::end(entry.updateRenderable)
|
||||
);
|
||||
entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / 1000.f;
|
||||
entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / micro;
|
||||
}
|
||||
_performanceMemory->releaseLock();
|
||||
|
||||
if (_loggingEnabled && _tick == PerformanceLayout::NumberValues - 1) {
|
||||
outputLogs();
|
||||
}
|
||||
|
||||
tick();
|
||||
}
|
||||
|
||||
} // namespace performance
|
||||
|
||||
@@ -134,6 +134,14 @@ RenderEngine::RenderEngine()
|
||||
if (_performanceMeasurements) {
|
||||
if (!_performanceManager) {
|
||||
_performanceManager = std::make_unique<performance::PerformanceManager>();
|
||||
const std::string KeyLogDir = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogDir;
|
||||
const std::string KeyPrefix = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogPerformancePrefix;
|
||||
if (OsEng.configurationManager().hasKeyAndValue<std::string>(KeyLogDir)) {
|
||||
_performanceManager->logDir(OsEng.configurationManager().value<std::string>(KeyLogDir));
|
||||
}
|
||||
if (OsEng.configurationManager().hasKeyAndValue<std::string>(KeyPrefix)) {
|
||||
_performanceManager->prefix(OsEng.configurationManager().value<std::string>(KeyPrefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user