diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 1c5df5c71d..9c55b1ce2d 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -189,6 +189,15 @@ Item { Column { id: octreeCol spacing: 4; x: 4; y: 4; + StatText { + text: " Frame timing:" + } + StatText { + text: " Batch: " + root.batchFrameTime.toFixed(1) + " ms" + } + StatText { + text: " GPU: " + root.gpuFrameTime.toFixed(1) + " ms" + } StatText { text: "Triangles: " + root.triangles + " / Material Switches: " + root.materialSwitches diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index a922e6efc7..9a38c3f0d6 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -118,6 +118,9 @@ ModalWindow { } } + property alias keyboardOverride: root.keyboardOverride + property alias keyboardRaised: root.keyboardRaised + property alias punctuationMode: root.punctuationMode Keyboard { id: keyboard raised: keyboardEnabled && keyboardRaised diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 16e6461631..cc81396d84 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -599,7 +599,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo qCDebug(interfaceapp) << "Home sandbox does not appear to be running...."; if (wantsSandboxRunning) { QString contentPath = getRunServerPath(); - SandboxUtils::runLocalSandbox(contentPath, true, RUNNING_MARKER_FILENAME); + bool noUpdater = SteamClient::isRunning(); + SandboxUtils::runLocalSandbox(contentPath, true, RUNNING_MARKER_FILENAME, noUpdater); sandboxIsRunning = true; } determinedSandboxState = true; @@ -1119,9 +1120,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setActiveEyeTracker(); #endif - auto applicationUpdater = DependencyManager::get(); - connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); - applicationUpdater->checkForUpdate(); + // If launched from Steam, let it handle updates + if (!SteamClient::isRunning()) { + auto applicationUpdater = DependencyManager::get(); + connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); + applicationUpdater->checkForUpdate(); + } // Now that menu is initialized we can sync myAvatar with it's state. myAvatar->updateMotionBehaviorFromMenu(); @@ -1238,7 +1242,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto glInfo = getGLContextData(); properties["gl_info"] = glInfo; + properties["gpu_used_memory"] = (int)BYTES_TO_MB(gpu::Context::getUsedGPUMemory()); properties["gpu_free_memory"] = (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()); + properties["gpu_frame_time"] = (float)(qApp->getGPUContext()->getFrameTimerGPUAverage()); + properties["batch_frame_time"] = (float)(qApp->getGPUContext()->getFrameTimerBatchAverage()); properties["ideal_thread_count"] = QThread::idealThreadCount(); auto hmdHeadPose = getHMDSensorPose(); diff --git a/interface/src/ui/SnapshotUploader.cpp b/interface/src/ui/SnapshotUploader.cpp index c36efddc14..5826c8bd38 100644 --- a/interface/src/ui/SnapshotUploader.cpp +++ b/interface/src/ui/SnapshotUploader.cpp @@ -64,7 +64,12 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) { } void SnapshotUploader::uploadFailure(QNetworkReply& reply) { - emit DependencyManager::get()->snapshotShared(reply.readAll()); // maybe someday include _inWorldLocation, _filename? + QString replyString = reply.readAll(); + qDebug() << "Error " << reply.errorString() << " uploading snapshot " << _pathname << " from " << _inWorldLocation; + if (replyString.size() == 0) { + replyString = reply.errorString(); + } + emit DependencyManager::get()->snapshotShared(replyString); // maybe someday include _inWorldLocation, _filename? delete this; } @@ -74,6 +79,12 @@ void SnapshotUploader::createStorySuccess(QNetworkReply& reply) { } void SnapshotUploader::createStoryFailure(QNetworkReply& reply) { - emit DependencyManager::get()->snapshotShared(reply.readAll()); - delete this; -} \ No newline at end of file + QString replyString = reply.readAll(); + qDebug() << "Error " << reply.errorString() << " uploading snapshot " << _pathname << " from " << _inWorldLocation; + if (replyString.size() == 0) { + replyString = reply.errorString(); + } + emit DependencyManager::get()->snapshotShared(replyString); + delete this; +} + diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 05632cb1e6..edf72d9758 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -290,6 +290,12 @@ void Stats::updateStats(bool force) { STAT_UPDATE(sendingMode, sendingModeResult); } + auto gpuContext = qApp->getGPUContext(); + + // Update Frame timing (in ms) + STAT_UPDATE(gpuFrameTime, (float)gpuContext->getFrameTimerGPUAverage()); + STAT_UPDATE(batchFrameTime, (float)gpuContext->getFrameTimerBatchAverage()); + STAT_UPDATE(gpuBuffers, (int)gpu::Context::getBufferGPUCount()); STAT_UPDATE(gpuBufferMemory, (int)BYTES_TO_MB(gpu::Context::getBufferGPUMemoryUsage())); STAT_UPDATE(gpuTextures, (int)gpu::Context::getTextureGPUCount()); @@ -302,7 +308,7 @@ void Stats::updateStats(bool force) { STAT_UPDATE(gpuTextureVirtualMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUVirtualMemoryUsage())); STAT_UPDATE(gpuTextureFramebufferMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUFramebufferMemoryUsage())); STAT_UPDATE(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage())); - STAT_UPDATE(gpuSparseTextureEnabled, qApp->getGPUContext()->getBackend()->isTextureManagementSparseEnabled() ? 1 : 0); + STAT_UPDATE(gpuSparseTextureEnabled, gpuContext->getBackend()->isTextureManagementSparseEnabled() ? 1 : 0); STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory())); STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load()); STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 76c6effed7..ffa5c08bc6 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -101,6 +101,8 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, gpuTextureSparseMemory, 0) STATS_PROPERTY(int, gpuSparseTextureEnabled, 0) STATS_PROPERTY(int, gpuFreeMemory, 0) + STATS_PROPERTY(float, gpuFrameTime, 0) + STATS_PROPERTY(float, batchFrameTime, 0) public: static Stats* getInstance(); @@ -198,6 +200,8 @@ signals: void gpuTextureSparseMemoryChanged(); void gpuSparseTextureEnabledChanged(); void gpuFreeMemoryChanged(); + void gpuFrameTimeChanged(); + void batchFrameTimeChanged(); void rectifiedTextureCountChanged(); void decimatedTextureCountChanged(); diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index a379ebd80a..0fd8ff595f 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -228,9 +228,7 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints) } } -#ifndef NDEBUG -#define DUMP_FBX_JOINTS -void AnimSkeleton::dump() const { +void AnimSkeleton::dump(bool verbose) const { qCDebug(animation) << "["; for (int i = 0; i < getNumJoints(); i++) { qCDebug(animation) << " {"; @@ -240,24 +238,24 @@ void AnimSkeleton::dump() const { qCDebug(animation) << " relBindPose =" << getRelativeBindPose(i); qCDebug(animation) << " absDefaultPose =" << getAbsoluteDefaultPose(i); qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i); -#ifdef DUMP_FBX_JOINTS - qCDebug(animation) << " fbxJoint ="; - qCDebug(animation) << " isFree =" << _joints[i].isFree; - qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage; - qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex; - qCDebug(animation) << " translation =" << _joints[i].translation; - qCDebug(animation) << " preTransform =" << _joints[i].preTransform; - qCDebug(animation) << " preRotation =" << _joints[i].preRotation; - qCDebug(animation) << " rotation =" << _joints[i].rotation; - qCDebug(animation) << " postRotation =" << _joints[i].postRotation; - qCDebug(animation) << " postTransform =" << _joints[i].postTransform; - qCDebug(animation) << " transform =" << _joints[i].transform; - qCDebug(animation) << " rotationMin =" << _joints[i].rotationMin << ", rotationMax =" << _joints[i].rotationMax; - qCDebug(animation) << " inverseDefaultRotation" << _joints[i].inverseDefaultRotation; - qCDebug(animation) << " inverseBindRotation" << _joints[i].inverseBindRotation; - qCDebug(animation) << " bindTransform" << _joints[i].bindTransform; - qCDebug(animation) << " isSkeletonJoint" << _joints[i].isSkeletonJoint; -#endif + if (verbose) { + qCDebug(animation) << " fbxJoint ="; + qCDebug(animation) << " isFree =" << _joints[i].isFree; + qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage; + qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex; + qCDebug(animation) << " translation =" << _joints[i].translation; + qCDebug(animation) << " preTransform =" << _joints[i].preTransform; + qCDebug(animation) << " preRotation =" << _joints[i].preRotation; + qCDebug(animation) << " rotation =" << _joints[i].rotation; + qCDebug(animation) << " postRotation =" << _joints[i].postRotation; + qCDebug(animation) << " postTransform =" << _joints[i].postTransform; + qCDebug(animation) << " transform =" << _joints[i].transform; + qCDebug(animation) << " rotationMin =" << _joints[i].rotationMin << ", rotationMax =" << _joints[i].rotationMax; + qCDebug(animation) << " inverseDefaultRotation" << _joints[i].inverseDefaultRotation; + qCDebug(animation) << " inverseBindRotation" << _joints[i].inverseBindRotation; + qCDebug(animation) << " bindTransform" << _joints[i].bindTransform; + qCDebug(animation) << " isSkeletonJoint" << _joints[i].isSkeletonJoint; + } if (getParentIndex(i) >= 0) { qCDebug(animation) << " parent =" << getJointName(getParentIndex(i)); } @@ -284,4 +282,4 @@ void AnimSkeleton::dump(const AnimPoseVec& poses) const { } qCDebug(animation) << "]"; } -#endif + diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index e1c6ae95c8..f588c14f90 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -63,10 +63,8 @@ public: void mirrorRelativePoses(AnimPoseVec& poses) const; void mirrorAbsolutePoses(AnimPoseVec& poses) const; -#ifndef NDEBUG - void dump() const; + void dump(bool verbose) const; void dump(const AnimPoseVec& poses) const; -#endif protected: void buildSkeletonFromJoints(const std::vector& joints); diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index ab6bba178a..4344cd4d2c 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -34,6 +34,10 @@ void Context::beginFrame(const glm::mat4& renderPose) { _frameActive = true; _currentFrame = std::make_shared(); _currentFrame->pose = renderPose; + + if (!_frameRangeTimer) { + _frameRangeTimer = std::make_shared(); + } } void Context::appendFrameBatch(Batch& batch) { @@ -73,10 +77,18 @@ void Context::executeFrame(const FramePointer& frame) const { consumeFrameUpdates(frame); _backend->setStereoState(frame->stereoState); { + Batch beginBatch; + _frameRangeTimer->begin(beginBatch); + _backend->render(beginBatch); + // Execute the frame rendering commands for (auto& batch : frame->batches) { _backend->render(batch); } + + Batch endBatch; + _frameRangeTimer->end(endBatch); + _backend->render(endBatch); } } @@ -127,6 +139,20 @@ void Context::getStats(ContextStats& stats) const { _backend->getStats(stats); } +double Context::getFrameTimerGPUAverage() const { + if (_frameRangeTimer) { + return _frameRangeTimer->getGPUAverage(); + } + return 0.0; +} + +double Context::getFrameTimerBatchAverage() const { + if (_frameRangeTimer) { + return _frameRangeTimer->getBatchAverage(); + } + return 0.0; +} + const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); @@ -183,6 +209,10 @@ Size Context::getFreeGPUMemory() { return _freeGPUMemory.load(); } +Size Context::getUsedGPUMemory() { + return getTextureGPUMemoryUsage() + getBufferGPUMemoryUsage(); +}; + void Context::incrementBufferGPUCount() { static std::atomic max { 0 }; auto total = ++_bufferGPUCount; @@ -349,3 +379,5 @@ void Backend::updateTextureGPUFramebufferMemoryUsage(Resource::Size prevObjectSi void Backend::updateTextureGPUSparseMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUSparseMemoryUsage(prevObjectSize, newObjectSize); } void Backend::incrementTextureGPUTransferCount() { Context::incrementTextureGPUTransferCount(); } void Backend::decrementTextureGPUTransferCount() { Context::decrementTextureGPUTransferCount(); } + + diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index e174e9d728..3564655a3d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -205,12 +205,16 @@ public: void getStats(ContextStats& stats) const; + double getFrameTimerGPUAverage() const; + double getFrameTimerBatchAverage() const; + static uint32_t getBufferGPUCount(); static Size getBufferGPUMemoryUsage(); static uint32_t getTextureGPUCount(); static uint32_t getTextureGPUSparseCount(); static Size getFreeGPUMemory(); + static Size getUsedGPUMemory(); static Size getTextureGPUMemoryUsage(); static Size getTextureGPUVirtualMemoryUsage(); static Size getTextureGPUFramebufferMemoryUsage(); @@ -223,8 +227,12 @@ protected: std::shared_ptr _backend; bool _frameActive { false }; FramePointer _currentFrame; + RangeTimerPointer _frameRangeTimer; StereoState _stereo; + double getGPUAverage() const; + double getBatchAverage() const; + // This function can only be called by "static Shader::makeProgram()" // makeProgramShader(...) make a program shader ready to be used in a Batch. // It compiles the sub shaders, link them and defines the Slots and their bindings. diff --git a/libraries/networking/src/SandboxUtils.cpp b/libraries/networking/src/SandboxUtils.cpp index 98c963b793..b16c169baa 100644 --- a/libraries/networking/src/SandboxUtils.cpp +++ b/libraries/networking/src/SandboxUtils.cpp @@ -61,15 +61,16 @@ void SandboxUtils::ifLocalSandboxRunningElse(std::function localSandboxR } -void SandboxUtils::runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName) { +void SandboxUtils::runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName, bool noUpdater) { QString applicationDirPath = QFileInfo(QCoreApplication::applicationFilePath()).path(); QString serverPath = applicationDirPath + "/server-console/server-console.exe"; qDebug() << "Application dir path is: " << applicationDirPath; qDebug() << "Server path is: " << serverPath; qDebug() << "autoShutdown: " << autoShutdown; + qDebug() << "noUpdater: " << noUpdater; bool hasContentPath = !contentPath.isEmpty(); - bool passArgs = autoShutdown || hasContentPath; + bool passArgs = autoShutdown || hasContentPath || noUpdater; QStringList args; @@ -87,6 +88,10 @@ void SandboxUtils::runLocalSandbox(QString contentPath, bool autoShutdown, QStri args << "--shutdownWatcher" << interfaceRunningStateFile; } + if (noUpdater) { + args << "--noUpdater"; + } + qDebug() << applicationDirPath; qDebug() << "Launching sandbox with:" << args; qDebug() << QProcess::startDetached(serverPath, args); diff --git a/libraries/networking/src/SandboxUtils.h b/libraries/networking/src/SandboxUtils.h index e40ff71a56..aaceafb9ef 100644 --- a/libraries/networking/src/SandboxUtils.h +++ b/libraries/networking/src/SandboxUtils.h @@ -26,7 +26,7 @@ public: void ifLocalSandboxRunningElse(std::function localSandboxRunningDoThis, std::function localSandboxNotRunningDoThat); - static void runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName); + static void runLocalSandbox(QString contentPath, bool autoShutdown, QString runningMarkerName, bool noUpdater); }; #endif // hifi_SandboxUtils_h diff --git a/server-console/src/main.js b/server-console/src/main.js index a7855ab063..be5a5cc107 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -579,6 +579,10 @@ function backupResourceDirectoriesAndRestart() { } function checkNewContent() { + if (argv.noUpdater) { + return; + } + // Start downloading content set var req = request.head({ url: HOME_CONTENT_URL @@ -821,7 +825,7 @@ function onContentLoaded() { // Disable splash window for now. // maybeShowSplash(); - if (buildInfo.releaseType == 'PRODUCTION') { + if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { var currentVersion = null; try { currentVersion = parseInt(buildInfo.buildIdentifier); diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index cf0e25a757..a85a112bf5 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -13,3 +13,7 @@ set_target_properties(ice-client PROPERTIES FOLDER "Tools") add_subdirectory(ac-client) set_target_properties(ac-client PROPERTIES FOLDER "Tools") + +add_subdirectory(skeleton-dump) +set_target_properties(skeleton-dump PROPERTIES FOLDER "Tools") + diff --git a/tools/skeleton-dump/CMakeLists.txt b/tools/skeleton-dump/CMakeLists.txt new file mode 100644 index 0000000000..04d450d9c2 --- /dev/null +++ b/tools/skeleton-dump/CMakeLists.txt @@ -0,0 +1,4 @@ +set(TARGET_NAME skeleton-dump) +setup_hifi_project(Core Widgets) +link_hifi_libraries(shared fbx model gpu gl animation) + diff --git a/tools/skeleton-dump/src/SkeletonDumpApp.cpp b/tools/skeleton-dump/src/SkeletonDumpApp.cpp new file mode 100644 index 0000000000..e9d8243e38 --- /dev/null +++ b/tools/skeleton-dump/src/SkeletonDumpApp.cpp @@ -0,0 +1,63 @@ +// +// SkeletonDumpApp.cpp +// tools/skeleton-dump/src +// +// Created by Anthony Thibault on 11/4/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SkeletonDumpApp.h" +#include +#include +#include +#include + +SkeletonDumpApp::SkeletonDumpApp(int argc, char* argv[]) : QCoreApplication(argc, argv) { + + // parse command-line + QCommandLineParser parser; + parser.setApplicationDescription("High Fidelity FBX Skeleton Analyzer"); + const QCommandLineOption helpOption = parser.addHelpOption(); + + const QCommandLineOption verboseOutput("v", "verbose output"); + parser.addOption(verboseOutput); + + const QCommandLineOption inputFilenameOption("i", "input file", "filename.fbx"); + parser.addOption(inputFilenameOption); + + if (!parser.parse(QCoreApplication::arguments())) { + qCritical() << parser.errorText() << endl; + parser.showHelp(); + _returnCode = 1; + return; + } + + if (parser.isSet(helpOption)) { + parser.showHelp(); + return; + } + + bool verbose = parser.isSet(verboseOutput); + + QString inputFilename; + if (parser.isSet(inputFilenameOption)) { + inputFilename = parser.value(inputFilenameOption); + } + + QFile file(inputFilename); + if (!file.open(QIODevice::ReadOnly)) { + qCritical() << "Failed to open file " << inputFilename; + _returnCode = 2; + return; + } + QByteArray blob = file.readAll(); + std::unique_ptr fbxGeometry(readFBX(blob, QVariantHash())); + std::unique_ptr skeleton(new AnimSkeleton(*fbxGeometry)); + skeleton->dump(verbose); +} + +SkeletonDumpApp::~SkeletonDumpApp() { +} diff --git a/tools/skeleton-dump/src/SkeletonDumpApp.h b/tools/skeleton-dump/src/SkeletonDumpApp.h new file mode 100644 index 0000000000..40df98eb65 --- /dev/null +++ b/tools/skeleton-dump/src/SkeletonDumpApp.h @@ -0,0 +1,29 @@ +// +// SkeletonDumpApp.h +// tools/skeleton-dump/src +// +// Created by Anthony Thibault on 11/4/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SkeletonDumpApp_h +#define hifi_SkeletonDumpApp_h + +#include + +class SkeletonDumpApp : public QCoreApplication { + Q_OBJECT +public: + SkeletonDumpApp(int argc, char* argv[]); + ~SkeletonDumpApp(); + + int getReturnCode() const { return _returnCode; } + +private: + int _returnCode { 0 }; +}; + +#endif //hifi_SkeletonDumpApp_h diff --git a/tools/skeleton-dump/src/main.cpp b/tools/skeleton-dump/src/main.cpp new file mode 100644 index 0000000000..6cf4d41f31 --- /dev/null +++ b/tools/skeleton-dump/src/main.cpp @@ -0,0 +1,22 @@ +// +// main.cpp +// tools/skeleton-dump/src +// +// Created by Anthony Thibault on 11/4/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +#include +#include +#include +#include +#include + +#include "SkeletonDumpApp.h" + +int main(int argc, char * argv[]) { + SkeletonDumpApp app(argc, argv); + return app.getReturnCode(); +}