diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 3b4300b6fd..8fe618b70d 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -175,9 +175,6 @@ AssignmentClient::~AssignmentClient() { void AssignmentClient::aboutToQuit() { stopAssignmentClient(); - - // clear the log handler so that Qt doesn't call the destructor on LogHandler - qInstallMessageHandler(0); } void AssignmentClient::setUpStatusToMonitor() { diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index c425a239dd..68e7b9b997 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -45,9 +45,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : setApplicationName("assignment-client"); setApplicationVersion(BuildInfo::VERSION); - // use the verbose message handler in Logging - qInstallMessageHandler(LogHandler::verboseMessageHandler); - // parse command-line QCommandLineParser parser; parser.setApplicationDescription("High Fidelity Assignment Client"); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 8ba253d549..1ee876ceea 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -126,9 +126,6 @@ void AssignmentClientMonitor::stopChildProcesses() { void AssignmentClientMonitor::aboutToQuit() { stopChildProcesses(); - - // clear the log handler so that Qt doesn't call the destructor on LogHandler - qInstallMessageHandler(0); } void AssignmentClientMonitor::spawnChildClient() { diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 052c4755f8..cf8d9ebe31 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -9,8 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - +#include #include #include "AssignmentClientApp.h" @@ -18,10 +17,14 @@ int main(int argc, char* argv[]) { disableQtBearerPoll(); // Fixes wifi ping spikes + qInstallMessageHandler(LogHandler::verboseMessageHandler); + qInfo() << "Starting."; + AssignmentClientApp app(argc, argv); int acReturn = app.exec(); qDebug() << "assignment-client process" << app.applicationPid() << "exiting with status code" << acReturn; - + + qInfo() << "Quitting."; return acReturn; } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 8b73b851b2..d13f9b883f 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -72,13 +72,10 @@ DomainServer::DomainServer(int argc, char* argv[]) : _iceServerPort(ICE_SERVER_DEFAULT_PORT) { parseCommandLine(); - qInstallMessageHandler(LogHandler::verboseMessageHandler); LogUtils::init(); Setting::init(); - connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit); - setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION); setOrganizationDomain("highfidelity.io"); setApplicationName("domain-server"); @@ -211,6 +208,7 @@ void DomainServer::parseCommandLine() { } DomainServer::~DomainServer() { + qInfo() << "Domain Server is shutting down."; // destroy the LimitedNodeList before the DomainServer QCoreApplication is down DependencyManager::destroy(); } @@ -223,12 +221,6 @@ void DomainServer::queuedQuit(QString quitMessage, int exitCode) { QCoreApplication::exit(exitCode); } -void DomainServer::aboutToQuit() { - - // clear the log handler so that Qt doesn't call the destructor on LogHandler - qInstallMessageHandler(0); -} - void DomainServer::restart() { qDebug() << "domain-server is restarting."; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 6330cf51a5..c14ec5eee0 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -72,8 +72,6 @@ public slots: void processICEServerHeartbeatACK(QSharedPointer message); private slots: - void aboutToQuit(); - void setupPendingAssignmentCredits(); void sendPendingTransactionsToServer(); @@ -150,13 +148,9 @@ private: bool isAuthenticatedRequest(HTTPConnection* connection, const QUrl& url); - void handleTokenRequestFinished(); QNetworkReply* profileRequestGivenTokenReply(QNetworkReply* tokenReply); - void handleProfileRequestFinished(); Headers setupCookieHeadersFromProfileReply(QNetworkReply* profileReply); - void loadExistingSessionsFromSettings(); - QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index b3b5c8b9be..fdf7a598aa 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -15,8 +15,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include #include @@ -29,6 +27,9 @@ int main(int argc, char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); #endif + qInstallMessageHandler(LogHandler::verboseMessageHandler); + qInfo() << "Starting."; + int currentExitCode = 0; // use a do-while to handle domain-server restart @@ -37,7 +38,7 @@ int main(int argc, char* argv[]) { currentExitCode = domainServer.exec(); } while (currentExitCode == DomainServer::EXIT_CODE_REBOOT); - + qInfo() << "Quitting."; return currentExitCode; } diff --git a/ice-server/src/main.cpp b/ice-server/src/main.cpp index 2326984668..ec8b9957cf 100644 --- a/ice-server/src/main.cpp +++ b/ice-server/src/main.cpp @@ -19,8 +19,9 @@ int main(int argc, char* argv[]) { #ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); #endif - + qInstallMessageHandler(LogHandler::verboseMessageHandler); + qInfo() << "Starting."; IceServer iceServer(argc, argv); return iceServer.exec(); 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 0a5e5e1789..b17697c021 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -601,7 +601,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; @@ -1121,9 +1122,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(); @@ -1240,7 +1244,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(); @@ -1656,7 +1663,8 @@ Application::~Application() { _window->deleteLater(); - qInstallMessageHandler(nullptr); // NOTE: Do this as late as possible so we continue to get our log messages + // Can't log to file passed this point, FileLogger about to be deleted + qInstallMessageHandler(LogHandler::verboseMessageHandler); } void Application::initializeGL() { @@ -3380,13 +3388,31 @@ void Application::loadSettings() { // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. auto pluginManager = PluginManager::getInstance(); auto plugins = pluginManager->getPreferredDisplayPlugins(); - for (auto plugin : plugins) { - auto menu = Menu::getInstance(); - if (auto action = menu->getActionForOption(plugin->getName())) { - action->setChecked(true); - action->trigger(); - // Find and activated highest priority plugin, bail for the rest - break; + auto menu = Menu::getInstance(); + if (plugins.size() > 0) { + for (auto plugin : plugins) { + if (auto action = menu->getActionForOption(plugin->getName())) { + action->setChecked(true); + action->trigger(); + // Find and activated highest priority plugin, bail for the rest + break; + } + } + } else { + // If this is our first run, and no preferred devices were set, default to + // an HMD device if available. + Setting::Handle firstRun { Settings::firstRun, true }; + if (firstRun.get()) { + auto displayPlugins = pluginManager->getDisplayPlugins(); + for (auto& plugin : displayPlugins) { + if (plugin->isHmd()) { + if (auto action = menu->getActionForOption(plugin->getName())) { + action->setChecked(true); + action->trigger(); + break; + } + } + } } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d357713bff..6207ecdb3c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -387,21 +387,9 @@ Menu::Menu() { }); #ifdef Q_OS_WIN - #define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5 - bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); - bool recommendedSparseTextures = recommendedIncrementalTransfers; - - qDebug() << "[TEXTURE TRANSFER SUPPORT]" - << "\n\tidealThreadCount:" << QThread::idealThreadCount() - << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures - << "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers; - - gpu::Texture::setEnableIncrementalTextureTransfers(recommendedIncrementalTransfers); - gpu::Texture::setEnableSparseTextures(recommendedSparseTextures); - - // Developer > Render > Enable Dynamic Texture Management + // Developer > Render > Enable Sparse Textures { - auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableDynamicTextureManagement, 0, recommendedSparseTextures); + auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::SparseTextureManagement, 0, gpu::Texture::getEnableSparseTextures()); connect(action, &QAction::triggered, [&](bool checked) { qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Dynamic Texture Management menu option:" << checked; gpu::Texture::setEnableSparseTextures(checked); @@ -410,7 +398,7 @@ Menu::Menu() { // Developer > Render > Enable Incremental Texture Transfer { - auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableIncrementalTextureTransfer, 0, recommendedIncrementalTransfers); + auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::IncrementalTextureTransfer, 0, gpu::Texture::getEnableIncrementalTextureTransfers()); connect(action, &QAction::triggered, [&](bool checked) { qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Incremental Texture Transfer menu option:" << checked; gpu::Texture::setEnableIncrementalTextureTransfers(checked); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 640a3e05d2..87e0e678f1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -97,8 +97,6 @@ namespace MenuOption { const QString EchoLocalAudio = "Echo Local Audio"; const QString EchoServerAudio = "Echo Server Audio"; const QString EnableCharacterController = "Enable avatar collisions"; - const QString EnableIncrementalTextureTransfer = "Enable Incremental Texture Transfer"; - const QString EnableDynamicTextureManagement = "Enable Dynamic Texture Management"; const QString EnableInverseKinematics = "Enable Inverse Kinematics"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; @@ -114,6 +112,7 @@ namespace MenuOption { const QString FrameTimer = "Show Timer"; const QString FullscreenMirror = "Mirror"; const QString Help = "Help..."; + const QString IncrementalTextureTransfer = "Enable Incremental Texture Transfer"; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IndependentMode = "Independent Mode"; const QString ActionMotorControl = "Enable Default Motor Control"; @@ -180,6 +179,7 @@ namespace MenuOption { const QString StandingHMDSensorMode = "Standing HMD Sensor Mode"; const QString SimulateEyeTracking = "Simulate"; const QString SMIEyeTracking = "SMI Eye Tracking"; + const QString SparseTextureManagement = "Enable Sparse Texture Management"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 0366d566d2..872d2af04e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -235,6 +235,14 @@ void Avatar::updateAvatarEntities() { properties.setParentID(getID()); } + // NOTE: if this avatar entity is not attached to us, strip its entity script completely... + auto attachedScript = properties.getScript(); + if (!isMyAvatar() && !attachedScript.isEmpty()) { + qCDebug(interfaceapp) << "removing entity script from avatar attached entity:" << entityID << "old script:" << attachedScript; + QString noScript; + properties.setScript(noScript); + } + EntityItemPointer entity = entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { 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-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 1be279b375..417b090d31 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -177,7 +177,6 @@ public: virtual void queueLambda(const std::function lambda) const; bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); } - bool isTextureManagementIncrementalTransferEnabled() const override { return (_textureManagement._incrementalTransferCapable && Texture::getEnableIncrementalTextureTransfers()); } protected: @@ -369,7 +368,6 @@ protected: struct TextureManagementStageState { bool _sparseCapable { false }; - bool _incrementalTransferCapable { false }; } _textureManagement; virtual void initTextureManagementStage() {} diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 3ce1c8e5c4..1e0dd08ae1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -116,7 +116,7 @@ float GLTexture::getMemoryPressure() { } // Return the consumed texture memory divided by the available texture memory. - auto consumedGpuMemory = Context::getTextureGPUSparseMemoryUsage(); + auto consumedGpuMemory = Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage(); float memoryPressure = (float)consumedGpuMemory / (float)availableTextureMemory; static Context::Size lastConsumedGpuMemory = 0; if (memoryPressure > 1.0f && lastConsumedGpuMemory != consumedGpuMemory) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 643d54af6a..438b1e9454 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -94,6 +94,7 @@ public: TransferState _transferState; uint32_t _allocatedPages { 0 }; uint32_t _lastMipAllocatedPages { 0 }; + uint16_t _mipOffset { 0 }; friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index ac9a84513e..f97364f5c5 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -148,13 +148,9 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { return pageCounts.x * pageCounts.y * pageCounts.z; } - - void GL45Backend::initTextureManagementStage() { - // enable the Sparse Texture on gl45 _textureManagement._sparseCapable = true; - _textureManagement._incrementalTransferCapable = true; // But now let s refine the behavior based on vendor std::string vendor { (const char*)glGetString(GL_VENDOR) }; @@ -282,20 +278,22 @@ GL45Texture::~GL45Texture() { if (!_gpuObject.getUsage().isExternal()) { qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str(); } - if (_sparseInfo.sparse) { - Backend::decrementTextureGPUSparseCount(); - // Remove this texture from the candidate list of derezzable textures - { - auto mipLevels = usedMipLevels(); - Lock lock(texturesByMipCountsMutex); - if (texturesByMipCounts.count(mipLevels)) { - auto& textures = texturesByMipCounts[mipLevels]; - textures.erase(this); - if (textures.empty()) { - texturesByMipCounts.erase(mipLevels); - } + + // Remove this texture from the candidate list of derezzable textures + if (_transferrable) { + auto mipLevels = usedMipLevels(); + Lock lock(texturesByMipCountsMutex); + if (texturesByMipCounts.count(mipLevels)) { + auto& textures = texturesByMipCounts[mipLevels]; + textures.erase(this); + if (textures.empty()) { + texturesByMipCounts.erase(mipLevels); } } + } + + if (_sparseInfo.sparse) { + Backend::decrementTextureGPUSparseCount(); // Experimenation suggests that allocating sparse textures on one context/thread and deallocating // them on another is buggy. So for sparse textures we need to queue a lambda with the deallocation @@ -355,7 +353,7 @@ void GL45Texture::allocateStorage() const { glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); // Get the dimensions, accounting for the downgrade level - Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); + Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip + _mipOffset); glTextureStorage2D(_id, usedMipLevels(), _internalFormat, dimensions.x, dimensions.y); (void)CHECK_GL_ERROR(); } @@ -370,7 +368,7 @@ void GL45Texture::updateSize() const { Backend::updateTextureGPUSparseMemoryUsage(_size, size); setSize(_allocatedPages * _sparseInfo.pageBytes); } else { - setSize(_virtualSize); + setSize(_gpuObject.evalTotalSize(_mipOffset)); } } @@ -381,15 +379,18 @@ void GL45Texture::startTransfer() { } bool GL45Texture::continueTransfer() { - auto backend = _backend.lock(); - if (!backend || !backend->isTextureManagementIncrementalTransferEnabled()) { + if (!Texture::getEnableIncrementalTextureTransfers()) { size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; for (uint8_t face = 0; face < maxFace; ++face) { for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { + auto size = _gpuObject.evalMipDimensions(mipLevel); + if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { + glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); + _allocatedPages += _sparseInfo.getPageCount(size); + } if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); - auto size = _gpuObject.evalMipDimensions(mipLevel); if (GL_TEXTURE_2D == _target) { glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); } else if (GL_TEXTURE_CUBE_MAP == _target) { @@ -481,35 +482,30 @@ void GL45Texture::syncSampler() const { glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + // FIXME account for mip offsets here auto baseMip = std::max(sampler.getMipOffset(), _minMip); glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip); glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip() - _mipOffset)); glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); } void GL45Texture::postTransfer() { Parent::postTransfer(); - if (_sparseInfo.sparse) { - auto mipLevels = usedMipLevels(); - if (mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { - Lock lock(texturesByMipCountsMutex); - texturesByMipCounts[mipLevels].insert(this); - } + auto mipLevels = usedMipLevels(); + if (_transferrable && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { + Lock lock(texturesByMipCountsMutex); + texturesByMipCounts[mipLevels].insert(this); } } void GL45Texture::stripToMip(uint16_t newMinMip) { - if (!_sparseInfo.sparse) { - return; - } - if (newMinMip < _minMip) { qCWarning(gpugl45logging) << "Cannot decrease the min mip"; return; } - if (newMinMip > _sparseInfo.maxSparseLevel) { + if (_sparseInfo.sparse && newMinMip > _sparseInfo.maxSparseLevel) { qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail"; return; } @@ -533,19 +529,53 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { - auto id = _id; - auto mipDimensions = _gpuObject.evalMipDimensions(mip); - _textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] { - glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); - }); + if (_sparseInfo.sparse) { + for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { + auto id = _id; + auto mipDimensions = _gpuObject.evalMipDimensions(mip); + _textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] { + glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); + }); - auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages < _allocatedPages); - _allocatedPages -= deallocatedPages; + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; + assert(deallocatedPages < _allocatedPages); + _allocatedPages -= deallocatedPages; + } + _minMip = newMinMip; + } else { + GLuint oldId = _id; + // Find the distance between the old min mip and the new one + uint16 mipDelta = newMinMip - _minMip; + _mipOffset += mipDelta; + const_cast(_maxMip) -= mipDelta; + auto newLevels = usedMipLevels(); + + // Create and setup the new texture (allocate) + glCreateTextures(_target, 1, &const_cast(_id)); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + Vec3u newDimensions = _gpuObject.evalMipDimensions(_mipOffset); + glTextureStorage2D(_id, newLevels, _internalFormat, newDimensions.x, newDimensions.y); + + // Copy the contents of the old texture to the new + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + for (uint16 targetMip = _minMip; targetMip <= _maxMip; ++targetMip) { + uint16 sourceMip = targetMip + mipDelta; + Vec3u mipDimensions = _gpuObject.evalMipDimensions(targetMip + _mipOffset); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, oldId, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, mipDimensions.x, mipDimensions.y); + (void)CHECK_GL_ERROR(); + } + } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &oldId); } - _minMip = newMinMip; // Re-sync the sampler to force access to the new mip level syncSampler(); updateSize(); @@ -553,7 +583,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); - if (_sparseInfo.sparse && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { + if (mipLevels > 1 && (!_sparseInfo.sparse || _minMip < _sparseInfo.maxSparseLevel)) { Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } @@ -570,8 +600,9 @@ void GL45Texture::updateMips() { } void GL45Texture::derez() { - assert(_sparseInfo.sparse); - assert(_minMip < _sparseInfo.maxSparseLevel); + if (_sparseInfo.sparse) { + assert(_minMip < _sparseInfo.maxSparseLevel); + } assert(_minMip < _maxMip); assert(_transferrable); stripToMip(_minMip + 1); @@ -595,7 +626,7 @@ void GL45Backend::derezTextures() const { } qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); - qCDebug(gpugl45logging) << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); GL45Texture* targetTexture = nullptr; { @@ -605,5 +636,5 @@ void GL45Backend::derezTextures() const { } lock.unlock(); targetTexture->derez(); - qCDebug(gpugl45logging) << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "New Used texture memory " << (Context::getTextureGPUMemoryUsage() - Context::getTextureGPUFramebufferMemoryUsage()); } 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..19d2ae767f 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -86,7 +86,6 @@ public: void getStats(ContextStats& stats) const { stats = _stats; } virtual bool isTextureManagementSparseEnabled() const = 0; - virtual bool isTextureManagementIncrementalTransferEnabled() const = 0; // These should only be accessed by Backend implementation to repport the buffer and texture allocations, // they are NOT public calls @@ -205,12 +204,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 +226,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/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 3283f5a4d9..33786155db 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -10,11 +10,13 @@ // -#include - #include "Texture.h" #include +#include + +#include +#include #include @@ -31,16 +33,27 @@ std::atomic Texture::_textureCPUCount{ 0 }; std::atomic Texture::_textureCPUMemoryUsage{ 0 }; std::atomic Texture::_allowedCPUMemoryUsage { 0 }; -std::atomic Texture::_enableSparseTextures { false }; -std::atomic Texture::_enableIncrementalTextureTransfers { false }; + +#define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5 +bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); +bool recommendedSparseTextures = recommendedIncrementalTransfers; + +std::atomic Texture::_enableSparseTextures { recommendedIncrementalTransfers }; +std::atomic Texture::_enableIncrementalTextureTransfers { recommendedSparseTextures }; + +struct ReportTextureState { + ReportTextureState() { + qDebug() << "[TEXTURE TRANSFER SUPPORT]" + << "\n\tidealThreadCount:" << QThread::idealThreadCount() + << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures + << "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers; + } +} report; void Texture::setEnableSparseTextures(bool enabled) { #ifdef Q_OS_WIN qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Sparse Textures and Dynamic Texture Management:" << enabled; _enableSparseTextures = enabled; - if (!_enableIncrementalTextureTransfers && _enableSparseTextures) { - qDebug() << "[TEXTURE TRANSFER SUPPORT] WARNING - Sparse texture management requires incremental texture transfer enabled."; - } #else qDebug() << "[TEXTURE TRANSFER SUPPORT] Sparse Textures and Dynamic Texture Management not supported on this platform."; #endif @@ -50,9 +63,6 @@ void Texture::setEnableIncrementalTextureTransfers(bool enabled) { #ifdef Q_OS_WIN qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Incremental Texture Transfer:" << enabled; _enableIncrementalTextureTransfers = enabled; - if (!_enableIncrementalTextureTransfers && _enableSparseTextures) { - qDebug() << "[TEXTURE TRANSFER SUPPORT] WARNING - Sparse texture management requires incremental texture transfer enabled."; - } #else qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer not supported on this platform."; #endif @@ -418,12 +428,18 @@ uint16 Texture::evalDimNumMips(uint16 size) { return 1 + (uint16) val; } +static const double LOG_2 = log(2.0); + +uint16 Texture::evalNumMips(const Vec3u& dimensions) { + double largerDim = glm::compMax(dimensions); + double val = log(largerDim) / LOG_2; + return 1 + (uint16)val; +} + // The number mips that the texture could have if all existed // = log2(max(width, height, depth)) uint16 Texture::evalNumMips() const { - double largerDim = std::max(std::max(_width, _height), _depth); - double val = log(largerDim)/log(2.0); - return 1 + (uint16) val; + return evalNumMips({ _width, _height, _depth }); } bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 1eacb46d77..2a93ec3066 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -369,9 +369,12 @@ public: // = 1 + log2(max(width, height, depth)) uint16 evalNumMips() const; + static uint16 evalNumMips(const Vec3u& dimensions); + // Eval the size that the mips level SHOULD have // not the one stored in the Texture static const uint MIN_DIMENSION = 1; + Vec3u evalMipDimensions(uint16 level) const; uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); } uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); } @@ -388,9 +391,9 @@ public: uint32 evalStoredMipFaceSize(uint16 level, const Element& format) const { return evalMipFaceNumTexels(level) * format.getSize(); } uint32 evalStoredMipSize(uint16 level, const Element& format) const { return evalMipNumTexels(level) * format.getSize(); } - uint32 evalTotalSize() const { + uint32 evalTotalSize(uint16 startingMip = 0) const { uint32 size = 0; - uint16 minMipLevel = minMip(); + uint16 minMipLevel = std::max(minMip(), startingMip); uint16 maxMipLevel = maxMip(); for (uint16 l = minMipLevel; l <= maxMipLevel; l++) { size += evalMipSize(l); 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/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index d142e3f839..35a3361c38 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -10,17 +10,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - -#include -#include -#include -#include -#include -#include - #include "LogHandler.h" +#include + +#include +#include +#include +#include +#include +#include +#include + QMutex LogHandler::_mutex; LogHandler& LogHandler::getInstance() { @@ -28,16 +29,15 @@ LogHandler& LogHandler::getInstance() { return staticInstance; } -LogHandler::LogHandler() -{ - // setup our timer to flush the verbose logs every 5 seconds - QTimer* logFlushTimer = new QTimer(this); - connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); - logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); - +LogHandler::LogHandler() { // when the log handler is first setup we should print our timezone QString timezoneString = "Time zone: " + QDateTime::currentDateTime().toString("t"); - printf("%s\n", qPrintable(timezoneString)); + printMessage(LogMsgType::LogInfo, QMessageLogContext(), timezoneString); +} + +LogHandler::~LogHandler() { + flushRepeatedMessages(); + printMessage(LogMsgType::LogDebug, QMessageLogContext(), "LogHandler shutdown."); } const char* stringForLogType(LogMsgType msgType) { @@ -165,7 +165,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont stringForLogType(type), context.category); if (_shouldOutputProcessID) { - prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid())); + prefixString.append(QString(" [%1]").arg(QCoreApplication::applicationPid())); } if (_shouldOutputThreadID) { @@ -187,6 +187,14 @@ void LogHandler::verboseMessageHandler(QtMsgType type, const QMessageLogContext& } const QString& LogHandler::addRepeatedMessageRegex(const QString& regexString) { + static std::once_flag once; + std::call_once(once, [&] { + // setup our timer to flush the verbose logs every 5 seconds + QTimer* logFlushTimer = new QTimer(this); + connect(logFlushTimer, &QTimer::timeout, this, &LogHandler::flushRepeatedMessages); + logFlushTimer->start(VERBOSE_LOG_INTERVAL_SECONDS * 1000); + }); + QMutexLocker lock(&_mutex); return *_repeatedMessageRegexes.insert(regexString); } diff --git a/libraries/shared/src/LogHandler.h b/libraries/shared/src/LogHandler.h index 890497b891..f80fad4c6a 100644 --- a/libraries/shared/src/LogHandler.h +++ b/libraries/shared/src/LogHandler.h @@ -52,8 +52,10 @@ public: const QString& addRepeatedMessageRegex(const QString& regexString); const QString& addOnlyOnceMessageRegex(const QString& regexString); + private: LogHandler(); + ~LogHandler(); void flushRepeatedMessages(); diff --git a/libraries/shared/src/ShutdownEventListener.cpp b/libraries/shared/src/ShutdownEventListener.cpp index e640126b7b..6f043cd43e 100644 --- a/libraries/shared/src/ShutdownEventListener.cpp +++ b/libraries/shared/src/ShutdownEventListener.cpp @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "ShutdownEventListener.h" #ifdef Q_OS_WIN @@ -19,6 +17,9 @@ #include #endif +#include +#include + ShutdownEventListener& ShutdownEventListener::getInstance() { static ShutdownEventListener staticInstance; return staticInstance; @@ -29,9 +30,7 @@ void signalHandler(int param) { QMetaObject::invokeMethod(qApp, "quit"); } -ShutdownEventListener::ShutdownEventListener(QObject* parent) : - QObject(parent) -{ +ShutdownEventListener::ShutdownEventListener(QObject* parent) : QObject(parent) { #ifndef Q_OS_WIN // be a signal handler for SIGTERM so we can stop our children when we get it signal(SIGTERM, signalHandler); diff --git a/libraries/shared/src/shared/FileLogger.cpp b/libraries/shared/src/shared/FileLogger.cpp index ef3436a8d7..143438ba68 100644 --- a/libraries/shared/src/shared/FileLogger.cpp +++ b/libraries/shared/src/shared/FileLogger.cpp @@ -109,7 +109,8 @@ bool FilePersistThread::processQueueItems(const Queue& messages) { } FileLogger::FileLogger(QObject* parent) : - AbstractLoggerInterface(parent), _fileName(getLogFilename()) + AbstractLoggerInterface(parent), + _fileName(getLogFilename()) { _persistThreadInstance = new FilePersistThread(*this); _persistThreadInstance->initialize(true, QThread::LowestPriority); diff --git a/libraries/shared/src/shared/FileLogger.h b/libraries/shared/src/shared/FileLogger.h index 697b96c6d8..f0f6dd5c09 100644 --- a/libraries/shared/src/shared/FileLogger.h +++ b/libraries/shared/src/shared/FileLogger.h @@ -24,7 +24,7 @@ public: FileLogger(QObject* parent = NULL); virtual ~FileLogger(); - QString getFilename() { return _fileName; } + QString getFilename() const { return _fileName; } virtual void addMessage(const QString&) override; virtual QString getLogData() override; virtual void locateLog() override; diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index f4b365265d..552d082aaa 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "OffscreenUi.h" @@ -58,6 +59,18 @@ public: _qml->setProperty("visible", _action->isVisible()); } + void clear() { + _qml->setProperty("checkable", 0); + _qml->setProperty("enabled", 0); + _qml->setProperty("text", 0); + _qml->setProperty("shortcut", 0); + _qml->setProperty("checked", 0); + _qml->setProperty("visible", 0); + + _action->setUserData(USER_DATA_ID, nullptr); + _qml->setUserData(USER_DATA_ID, nullptr); + } + const QUuid uuid{ QUuid::createUuid() }; @@ -217,6 +230,7 @@ void VrMenu::insertAction(QAction* before, QAction* action) { } class QQuickMenuBase; +class QQuickMenu1; void VrMenu::removeAction(QAction* action) { if (!action) { @@ -228,10 +242,7 @@ void VrMenu::removeAction(QAction* action) { qWarning("Attempted to remove menu action with no found QML object"); return; } - - QObject* item = findMenuObject(userData->uuid.toString()); - QObject* menu = item->parent(); - // Proxy QuickItem requests through the QML layer - QQuickMenuBase* qmlItem = reinterpret_cast(item); - QMetaObject::invokeMethod(menu, "removeItem", Qt::DirectConnection, Q_ARG(QQuickMenuBase*, qmlItem)); + + userData->clear(); + delete userData; } diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index fcce999839..aee8b40832 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -84,7 +84,7 @@ void Menu::scanMenu(QMenu& menu, settingsAction modifySetting, Settings& setting groups.pop_back(); } -void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, +void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, int menuItemLocation, const QString& grouping) { QAction* actionBefore = NULL; QAction* separator; @@ -123,7 +123,7 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QObject* receiver, const char* member, QAction::MenuRole role, - int menuItemLocation, + int menuItemLocation, const QString& grouping) { QAction* action = NULL; QAction* actionBefore = NULL; @@ -165,7 +165,7 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QString& actionName, const QKeySequence& shortcut, QAction::MenuRole role, - int menuItemLocation, + int menuItemLocation, const QString& grouping) { QAction* actionBefore = NULL; @@ -207,7 +207,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMe const bool checked, const QObject* receiver, const char* member, - int menuItemLocation, + int menuItemLocation, const QString& grouping) { QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, @@ -408,6 +408,10 @@ void Menu::removeMenu(const QString& menuName) { parent->removeAction(action); } else { QMenuBar::removeAction(action); + auto offscreenUi = DependencyManager::get(); + offscreenUi->addMenuInitializer([=](VrMenu* vrMenu) { + vrMenu->removeAction(action); + }); } QMenuBar::repaint(); @@ -496,15 +500,15 @@ void Menu::setGroupingIsVisible(const QString& grouping, bool isVisible) { void Menu::addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected, QObject* receiver, const char* slot) { auto menu = addMenu(groupName); - + QActionGroup* actionGroup = new QActionGroup(menu); actionGroup->setExclusive(true); - + for (auto action : actionList) { auto item = addCheckableActionToQMenuAndActionHash(menu, action, 0, action == selected, receiver, slot); actionGroup->addAction(item); } - + QMenuBar::repaint(); } @@ -582,4 +586,3 @@ void MenuWrapper::insertAction(QAction* before, QAction* action) { vrMenu->insertAction(before, action); }); } - diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index d6d9098e21..4fe13196f3 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -445,13 +445,11 @@ function hideUserDataTextArea() { }; function showStaticUserData() { - $('#static-userdata').show(); - $('#static-userdata').css('height', $('#userdata-editor').height()) if (editor !== null) { + $('#static-userdata').show(); + $('#static-userdata').css('height', $('#userdata-editor').height()) $('#static-userdata').text(editor.getText()); } - - }; function removeStaticUserData() { diff --git a/server-console/src/main.js b/server-console/src/main.js index 6c82230601..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 @@ -623,6 +627,7 @@ function checkNewContent() { } else { // They don't want to update, mark content set as current userConfig.set('homeContentLastModified', new Date()); + userConfig.save(configPath); } }); } @@ -676,6 +681,7 @@ function maybeInstallDefaultContentSet(onComplete) { } log.debug('Copied home content over to: ' + getRootHifiDataDirectory()); userConfig.set('homeContentLastModified', new Date()); + userConfig.save(configPath); onComplete(); }); return; @@ -756,6 +762,7 @@ function maybeInstallDefaultContentSet(onComplete) { // response and decompression complete, return log.debug("Finished unarchiving home content set"); userConfig.set('homeContentLastModified', new Date()); + userConfig.save(configPath); sendStateUpdate('complete'); }); @@ -766,6 +773,7 @@ function maybeInstallDefaultContentSet(onComplete) { }); userConfig.set('hasRun', true); + userConfig.save(configPath); }); } @@ -817,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/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index d4a8322f8a..b152c4b4bf 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -599,7 +599,7 @@ protected: return; case Qt::Key_End: - gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(256)); + gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(64)); return; 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(); +} diff --git a/tutorial/tutorial.js b/tutorial/tutorial.js index 3d2b4ce36b..957316734a 100644 --- a/tutorial/tutorial.js +++ b/tutorial/tutorial.js @@ -233,7 +233,7 @@ function playSuccessSound() { function playFirecrackerSound(position) { Audio.playSound(firecrackerSound, { position: position, - volume: 0.7, + volume: 0.5, loop: false }); }