mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 09:08:37 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
7d99183474
21 changed files with 230 additions and 98 deletions
|
@ -8,14 +8,14 @@ like to get paid for your work, make sure you report the bug via a job on
|
||||||
[Worklist.net](https://worklist.net).
|
[Worklist.net](https://worklist.net).
|
||||||
|
|
||||||
We're hiring! We're looking for skilled developers;
|
We're hiring! We're looking for skilled developers;
|
||||||
send your resume to hiring@highfidelity.io
|
send your resume to hiring@highfidelity.com
|
||||||
|
|
||||||
##### Chat with us
|
##### Chat with us
|
||||||
Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi!
|
Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi!
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
=========
|
=========
|
||||||
Documentation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project).
|
Documentation is available at [docs.highfidelity.com](http://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project).
|
||||||
|
|
||||||
Build Instructions
|
Build Instructions
|
||||||
=========
|
=========
|
||||||
|
|
|
@ -77,6 +77,18 @@ void AssetServer::completeSetup() {
|
||||||
|
|
||||||
auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY].toObject();
|
auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY].toObject();
|
||||||
|
|
||||||
|
static const QString MAX_BANDWIDTH_OPTION = "max_bandwidth";
|
||||||
|
auto maxBandwidthValue = assetServerObject[MAX_BANDWIDTH_OPTION];
|
||||||
|
auto maxBandwidthFloat = maxBandwidthValue.toDouble(-1);
|
||||||
|
|
||||||
|
if (maxBandwidthFloat > 0.0) {
|
||||||
|
const int BYTES_PER_MEGABITS = (1024 * 1024) / 8;
|
||||||
|
int maxBandwidth = maxBandwidthFloat * BYTES_PER_MEGABITS;
|
||||||
|
nodeList->setConnectionMaxBandwidth(maxBandwidth);
|
||||||
|
qInfo() << "Set maximum bandwith per connection to" << maxBandwidthFloat << "Mb/s."
|
||||||
|
" (" << maxBandwidth << "bytes/sec)";
|
||||||
|
}
|
||||||
|
|
||||||
// get the path to the asset folder from the domain server settings
|
// get the path to the asset folder from the domain server settings
|
||||||
static const QString ASSETS_PATH_OPTION = "assets_path";
|
static const QString ASSETS_PATH_OPTION = "assets_path";
|
||||||
auto assetsJSONValue = assetServerObject[ASSETS_PATH_OPTION];
|
auto assetsJSONValue = assetServerObject[ASSETS_PATH_OPTION];
|
||||||
|
|
2
cmake/externals/oglplus/CMakeLists.txt
vendored
2
cmake/externals/oglplus/CMakeLists.txt
vendored
|
@ -4,7 +4,7 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
${EXTERNAL_NAME}
|
${EXTERNAL_NAME}
|
||||||
URL http://iweb.dl.sourceforge.net/project/oglplus/oglplus-0.63.x/oglplus-0.63.0.zip
|
URL http://hifi-public.s3.amazonaws.com/dependencies/oglplus-0.63.0.zip
|
||||||
URL_MD5 de984ab245b185b45c87415c0e052135
|
URL_MD5 de984ab245b185b45c87415c0e052135
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
BUILD_COMMAND ""
|
BUILD_COMMAND ""
|
||||||
|
|
|
@ -186,6 +186,15 @@
|
||||||
"help": "The path to the directory assets are stored in.<br/>If this path is relative, it will be relative to the application data directory.<br/>If you change this path you will need to manually copy any existing assets from the previous directory.",
|
"help": "The path to the directory assets are stored in.<br/>If this path is relative, it will be relative to the application data directory.<br/>If you change this path you will need to manually copy any existing assets from the previous directory.",
|
||||||
"default": "",
|
"default": "",
|
||||||
"advanced": true
|
"advanced": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_bandwidth",
|
||||||
|
"type": "double",
|
||||||
|
"label": "Max Bandwidth Per User",
|
||||||
|
"help": "The maximum upstream bandwidth each user can use (in Mb/s).",
|
||||||
|
"placeholder": "10.0",
|
||||||
|
"default": "",
|
||||||
|
"advanced": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -239,11 +239,7 @@ class DeadlockWatchdogThread : public QThread {
|
||||||
public:
|
public:
|
||||||
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
||||||
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
||||||
#ifdef DEBUG
|
|
||||||
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 600 * USECS_PER_SECOND;
|
|
||||||
#else
|
|
||||||
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
|
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the heartbeat on launch
|
// Set the heartbeat on launch
|
||||||
DeadlockWatchdogThread() {
|
DeadlockWatchdogThread() {
|
||||||
|
@ -511,8 +507,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
// Set up a watchdog thread to intentionally crash the application on deadlocks
|
// Set up a watchdog thread to intentionally crash the application on deadlocks
|
||||||
auto deadlockWatchdog = new DeadlockWatchdogThread();
|
_deadlockWatchdogThread = new DeadlockWatchdogThread();
|
||||||
deadlockWatchdog->start();
|
_deadlockWatchdogThread->start();
|
||||||
|
|
||||||
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||||
|
|
||||||
|
@ -586,7 +582,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
ResourceManager::init();
|
ResourceManager::init();
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
// Setup MessagesClient
|
// Setup MessagesClient
|
||||||
auto messagesClient = DependencyManager::get<MessagesClient>();
|
auto messagesClient = DependencyManager::get<MessagesClient>();
|
||||||
|
@ -734,7 +730,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
initializeGL();
|
initializeGL();
|
||||||
_offscreenContext->makeCurrent();
|
_offscreenContext->makeCurrent();
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
// Tell our entity edit sender about our known jurisdictions
|
// Tell our entity edit sender about our known jurisdictions
|
||||||
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
||||||
|
@ -746,7 +742,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
_overlays.init(); // do this before scripts load
|
_overlays.init(); // do this before scripts load
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
|
||||||
|
|
||||||
|
@ -900,11 +896,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
// do this as late as possible so that all required subsystems are initialized
|
// do this as late as possible so that all required subsystems are initialized
|
||||||
scriptEngines->loadScripts();
|
scriptEngines->loadScripts();
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
|
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
|
||||||
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
|
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
|
||||||
|
@ -1019,7 +1015,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
deadlockWatchdog->updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
||||||
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
|
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
|
||||||
|
@ -1060,6 +1056,10 @@ void Application::showCursor(const QCursor& cursor) {
|
||||||
_cursorNeedsChanging = true;
|
_cursorNeedsChanging = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::updateHeartbeat() {
|
||||||
|
static_cast<DeadlockWatchdogThread*>(_deadlockWatchdogThread)->updateHeartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
emit beforeAboutToQuit();
|
emit beforeAboutToQuit();
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,8 @@ public slots:
|
||||||
|
|
||||||
void reloadResourceCaches();
|
void reloadResourceCaches();
|
||||||
|
|
||||||
|
void updateHeartbeat();
|
||||||
|
|
||||||
void crashApplication();
|
void crashApplication();
|
||||||
void deadlockApplication();
|
void deadlockApplication();
|
||||||
|
|
||||||
|
@ -505,6 +507,8 @@ private:
|
||||||
mutable QMutex _changeCursorLock { QMutex::Recursive };
|
mutable QMutex _changeCursorLock { QMutex::Recursive };
|
||||||
QCursor _desiredCursor{ Qt::BlankCursor };
|
QCursor _desiredCursor{ Qt::BlankCursor };
|
||||||
bool _cursorNeedsChanging { false };
|
bool _cursorNeedsChanging { false };
|
||||||
|
|
||||||
|
QThread* _deadlockWatchdogThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
#include <Finally.h>
|
||||||
|
|
||||||
#include "OffscreenGLCanvas.h"
|
#include "OffscreenGLCanvas.h"
|
||||||
#include "GLEscrow.h"
|
#include "GLEscrow.h"
|
||||||
|
@ -84,6 +85,7 @@ protected:
|
||||||
Queue _queue;
|
Queue _queue;
|
||||||
QMutex _mutex;
|
QMutex _mutex;
|
||||||
QWaitCondition _waitCondition;
|
QWaitCondition _waitCondition;
|
||||||
|
std::atomic<bool> _rendering { false };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Event-driven methods
|
// Event-driven methods
|
||||||
|
@ -214,22 +216,19 @@ void OffscreenQmlRenderThread::init() {
|
||||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, _surface, &OffscreenQmlSurface::requestUpdate);
|
connect(_renderControl, &QQuickRenderControl::sceneChanged, _surface, &OffscreenQmlSurface::requestUpdate);
|
||||||
|
|
||||||
if (!_canvas.makeCurrent()) {
|
if (!_canvas.makeCurrent()) {
|
||||||
qWarning("Failed to make context current on render thread");
|
// Failed to make GL context current, this OffscreenQmlSurface is basically dead
|
||||||
|
qWarning("Failed to make context current on QML Renderer Thread");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderControl->initialize(_canvas.getContext());
|
_renderControl->initialize(_canvas.getContext());
|
||||||
setupFbo();
|
setupFbo();
|
||||||
_escrow.setRecycler([this](GLuint texture){
|
_escrow.setRecycler([this](GLuint texture){
|
||||||
_textures.recycleTexture(texture);
|
_textures.recycleTexture(texture);
|
||||||
});
|
});
|
||||||
_canvas.doneCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlRenderThread::cleanup() {
|
void OffscreenQmlRenderThread::cleanup() {
|
||||||
if (!_canvas.makeCurrent()) {
|
|
||||||
qFatal("Failed to make context current on render thread");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_renderControl->invalidate();
|
_renderControl->invalidate();
|
||||||
|
|
||||||
_fbo.reset();
|
_fbo.reset();
|
||||||
|
@ -237,7 +236,6 @@ void OffscreenQmlRenderThread::cleanup() {
|
||||||
_textures.clear();
|
_textures.clear();
|
||||||
|
|
||||||
_canvas.doneCurrent();
|
_canvas.doneCurrent();
|
||||||
|
|
||||||
_canvas.getContextObject()->moveToThread(QCoreApplication::instance()->thread());
|
_canvas.getContextObject()->moveToThread(QCoreApplication::instance()->thread());
|
||||||
|
|
||||||
_quit = true;
|
_quit = true;
|
||||||
|
@ -245,57 +243,55 @@ void OffscreenQmlRenderThread::cleanup() {
|
||||||
|
|
||||||
void OffscreenQmlRenderThread::resize() {
|
void OffscreenQmlRenderThread::resize() {
|
||||||
// Lock _newSize changes
|
// Lock _newSize changes
|
||||||
QMutexLocker locker(&_mutex);
|
{
|
||||||
|
QMutexLocker locker(&_mutex);
|
||||||
|
|
||||||
// Update our members
|
// Update our members
|
||||||
if (_quickWindow) {
|
if (_quickWindow) {
|
||||||
_quickWindow->setGeometry(QRect(QPoint(), _newSize));
|
_quickWindow->setGeometry(QRect(QPoint(), _newSize));
|
||||||
_quickWindow->contentItem()->setSize(_newSize);
|
_quickWindow->contentItem()->setSize(_newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt bug in 5.4 forces this check of pixel ratio,
|
||||||
|
// even though we're rendering offscreen.
|
||||||
|
qreal pixelRatio = 1.0;
|
||||||
|
if (_renderControl && _renderControl->_renderWindow) {
|
||||||
|
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec2 newOffscreenSize = toGlm(_newSize * pixelRatio);
|
||||||
|
if (newOffscreenSize == _size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio;
|
||||||
|
_size = newOffscreenSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Qt bug in 5.4 forces this check of pixel ratio,
|
_textures.setSize(_size);
|
||||||
// even though we're rendering offscreen.
|
|
||||||
qreal pixelRatio = 1.0;
|
|
||||||
if (_renderControl && _renderControl->_renderWindow) {
|
|
||||||
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
uvec2 newOffscreenSize = toGlm(_newSize * pixelRatio);
|
|
||||||
_textures.setSize(newOffscreenSize);
|
|
||||||
if (newOffscreenSize == _size) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_size = newOffscreenSize;
|
|
||||||
|
|
||||||
// Clear out any fbos with the old size
|
|
||||||
if (!_canvas.makeCurrent()) {
|
|
||||||
qWarning("Failed to make context current on render thread");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio;
|
|
||||||
|
|
||||||
locker.unlock();
|
|
||||||
|
|
||||||
setupFbo();
|
setupFbo();
|
||||||
_canvas.doneCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlRenderThread::render() {
|
void OffscreenQmlRenderThread::render() {
|
||||||
if (_surface->_paused) {
|
// Ensure we always release the main thread
|
||||||
|
Finally releaseMainThread([this] {
|
||||||
_waitCondition.wakeOne();
|
_waitCondition.wakeOne();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_surface->_paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_canvas.makeCurrent()) {
|
_rendering = true;
|
||||||
qWarning("Failed to make context current on render thread");
|
Finally unmarkRenderingFlag([this] {
|
||||||
return;
|
_rendering = false;
|
||||||
}
|
});
|
||||||
|
|
||||||
QMutexLocker locker(&_mutex);
|
{
|
||||||
_renderControl->sync();
|
QMutexLocker locker(&_mutex);
|
||||||
_waitCondition.wakeOne();
|
_renderControl->sync();
|
||||||
locker.unlock();
|
releaseMainThread.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
using namespace oglplus;
|
using namespace oglplus;
|
||||||
|
|
||||||
|
@ -308,6 +304,7 @@ void OffscreenQmlRenderThread::render() {
|
||||||
_fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0);
|
_fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0);
|
||||||
_fbo->Complete(Framebuffer::Target::Draw);
|
_fbo->Complete(Framebuffer::Target::Draw);
|
||||||
{
|
{
|
||||||
|
PROFILE_RANGE("qml_render->rendercontrol")
|
||||||
_renderControl->render();
|
_renderControl->render();
|
||||||
// FIXME The web browsers seem to be leaving GL in an error state.
|
// FIXME The web browsers seem to be leaving GL in an error state.
|
||||||
// Need a debug context with sync logging to figure out why.
|
// Need a debug context with sync logging to figure out why.
|
||||||
|
@ -338,10 +335,10 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||||
QObject::disconnect(&_updateTimer);
|
QObject::disconnect(&_updateTimer);
|
||||||
QObject::disconnect(qApp);
|
QObject::disconnect(qApp);
|
||||||
|
|
||||||
qDebug() << "Stopping QML render thread " << _renderer->currentThreadId();
|
qDebug() << "Stopping QML Renderer Thread " << _renderer->currentThreadId();
|
||||||
_renderer->_queue.add(STOP);
|
_renderer->_queue.add(STOP);
|
||||||
if (!_renderer->wait(MAX_SHUTDOWN_WAIT_SECS * USECS_PER_SECOND)) {
|
if (!_renderer->wait(MAX_SHUTDOWN_WAIT_SECS * USECS_PER_SECOND)) {
|
||||||
qWarning() << "Failed to shut down the QML render thread";
|
qWarning() << "Failed to shut down the QML Renderer Thread";
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _rootItem;
|
delete _rootItem;
|
||||||
|
@ -396,8 +393,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize_) {
|
||||||
std::max(static_cast<int>(scale * newSize.height()), 10));
|
std::max(static_cast<int>(scale * newSize.height()), 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QSize currentSize = _renderer->_quickWindow->geometry().size();
|
QSize currentSize = _renderer->_quickWindow->geometry().size();
|
||||||
if (newSize == currentSize) {
|
if (newSize == currentSize) {
|
||||||
return;
|
return;
|
||||||
|
@ -426,7 +421,11 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
_qmlComponent->loadUrl(qmlSource);
|
// Synchronous loading may take a while; restart the deadlock timer
|
||||||
|
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
||||||
|
|
||||||
|
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
|
||||||
|
|
||||||
if (_qmlComponent->isLoading()) {
|
if (_qmlComponent->isLoading()) {
|
||||||
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
|
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
|
||||||
[this, f](QQmlComponent::Status){
|
[this, f](QQmlComponent::Status){
|
||||||
|
@ -504,7 +503,12 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QOb
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::updateQuick() {
|
void OffscreenQmlSurface::updateQuick() {
|
||||||
if (!_renderer || !_renderer->allowNewFrame(_maxFps)) {
|
// If we're
|
||||||
|
// a) not set up
|
||||||
|
// b) already rendering a frame
|
||||||
|
// c) rendering too fast
|
||||||
|
// then skip this
|
||||||
|
if (!_renderer || _renderer->_rendering || !_renderer->allowNewFrame(_maxFps)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,11 +518,11 @@ void OffscreenQmlSurface::updateQuick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_render) {
|
if (_render) {
|
||||||
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
// Lock the GUI size while syncing
|
// Lock the GUI size while syncing
|
||||||
QMutexLocker locker(&(_renderer->_mutex));
|
QMutexLocker locker(&(_renderer->_mutex));
|
||||||
_renderer->_queue.add(RENDER);
|
_renderer->_queue.add(RENDER);
|
||||||
_renderer->_waitCondition.wait(&(_renderer->_mutex));
|
_renderer->_waitCondition.wait(&(_renderer->_mutex));
|
||||||
|
|
||||||
_render = false;
|
_render = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,74 @@
|
||||||
//
|
//
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
|
||||||
|
class AllocationDebugger {
|
||||||
|
public:
|
||||||
|
void operator+=(size_t size) {
|
||||||
|
_allocatedMemory += size;
|
||||||
|
maybeReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator-=(size_t size) {
|
||||||
|
_allocatedMemory -= size;
|
||||||
|
maybeReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString formatSize(size_t size) {
|
||||||
|
float num = size;
|
||||||
|
QStringList list;
|
||||||
|
list << "KB" << "MB" << "GB" << "TB";
|
||||||
|
|
||||||
|
QStringListIterator i(list);
|
||||||
|
QString unit("bytes");
|
||||||
|
|
||||||
|
while (num >= K && i.hasNext()) {
|
||||||
|
unit = i.next();
|
||||||
|
num /= K;
|
||||||
|
}
|
||||||
|
return QString().setNum(num, 'f', 2) + " " + unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybeReport() {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
if (now - _lastReportTime < MAX_REPORT_FREQUENCY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t current = _allocatedMemory;
|
||||||
|
size_t last = _lastReportedMemory;
|
||||||
|
size_t delta = (current > last) ? (current - last) : (last - current);
|
||||||
|
if (delta > MIN_REPORT_DELTA) {
|
||||||
|
_lastReportTime = now;
|
||||||
|
_lastReportedMemory = current;
|
||||||
|
qDebug() << "Total allocation " << formatSize(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<size_t> _allocatedMemory;
|
||||||
|
std::atomic<size_t> _lastReportedMemory;
|
||||||
|
std::atomic<uint64_t> _lastReportTime;
|
||||||
|
|
||||||
|
static const float K;
|
||||||
|
// Report changes of 5 megabytes
|
||||||
|
static const size_t MIN_REPORT_DELTA = 1024 * 1024 * 5;
|
||||||
|
// Report changes no more frequently than every 15 seconds
|
||||||
|
static const uint64_t MAX_REPORT_FREQUENCY = USECS_PER_SECOND * 15;
|
||||||
|
};
|
||||||
|
|
||||||
|
const float AllocationDebugger::K = 1024.0f;
|
||||||
|
|
||||||
|
static AllocationDebugger allocationDebugger;
|
||||||
|
|
||||||
Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) {
|
Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size) {
|
||||||
|
allocationDebugger += size;
|
||||||
if ( !dataAllocated ) {
|
if ( !dataAllocated ) {
|
||||||
qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer.";
|
qWarning() << "Buffer::Sysmem::allocateMemory() : Must have a valid dataAllocated pointer.";
|
||||||
return NOT_ALLOCATED;
|
return NOT_ALLOCATED;
|
||||||
|
@ -38,6 +101,7 @@ Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size)
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resource::Sysmem::deallocateMemory(Byte* dataAllocated, Size size) {
|
void Resource::Sysmem::deallocateMemory(Byte* dataAllocated, Size size) {
|
||||||
|
allocationDebugger -= size;
|
||||||
if (dataAllocated) {
|
if (dataAllocated) {
|
||||||
delete[] dataAllocated;
|
delete[] dataAllocated;
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,6 +219,8 @@ public:
|
||||||
|
|
||||||
udt::Socket::StatsVector sampleStatsForAllConnections() { return _nodeSocket.sampleStatsForAllConnections(); }
|
udt::Socket::StatsVector sampleStatsForAllConnections() { return _nodeSocket.sampleStatsForAllConnections(); }
|
||||||
|
|
||||||
|
void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
void eraseAllNodes();
|
void eraseAllNodes();
|
||||||
|
|
|
@ -20,13 +20,19 @@ using namespace std::chrono;
|
||||||
|
|
||||||
static const double USECS_PER_SECOND = 1000000.0;
|
static const double USECS_PER_SECOND = 1000000.0;
|
||||||
|
|
||||||
|
void CongestionControl::setMaxBandwidth(int maxBandwidth) {
|
||||||
|
_maxBandwidth = maxBandwidth;
|
||||||
|
setPacketSendPeriod(_packetSendPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
void CongestionControl::setPacketSendPeriod(double newSendPeriod) {
|
void CongestionControl::setPacketSendPeriod(double newSendPeriod) {
|
||||||
Q_ASSERT_X(newSendPeriod >= 0, "CongestionControl::setPacketPeriod", "Can not set a negative packet send period");
|
Q_ASSERT_X(newSendPeriod >= 0, "CongestionControl::setPacketPeriod", "Can not set a negative packet send period");
|
||||||
|
|
||||||
if (_maxBandwidth > 0) {
|
auto maxBandwidth = _maxBandwidth.load();
|
||||||
|
if (maxBandwidth > 0) {
|
||||||
// anytime the packet send period is about to be increased, make sure it stays below the minimum period,
|
// anytime the packet send period is about to be increased, make sure it stays below the minimum period,
|
||||||
// calculated based on the maximum desired bandwidth
|
// calculated based on the maximum desired bandwidth
|
||||||
double minPacketSendPeriod = USECS_PER_SECOND / (((double) _maxBandwidth) / _mss);
|
double minPacketSendPeriod = USECS_PER_SECOND / (((double) maxBandwidth) / _mss);
|
||||||
_packetSendPeriod = std::max(newSendPeriod, minPacketSendPeriod);
|
_packetSendPeriod = std::max(newSendPeriod, minPacketSendPeriod);
|
||||||
} else {
|
} else {
|
||||||
_packetSendPeriod = newSendPeriod;
|
_packetSendPeriod = newSendPeriod;
|
||||||
|
@ -39,7 +45,7 @@ DefaultCC::DefaultCC() :
|
||||||
_mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER;
|
_mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER;
|
||||||
|
|
||||||
_congestionWindowSize = 16.0;
|
_congestionWindowSize = 16.0;
|
||||||
_packetSendPeriod = 1.0;
|
setPacketSendPeriod(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultCC::onACK(SequenceNumber ackNum) {
|
void DefaultCC::onACK(SequenceNumber ackNum) {
|
||||||
|
@ -73,10 +79,10 @@ void DefaultCC::onACK(SequenceNumber ackNum) {
|
||||||
|
|
||||||
if (_receiveRate > 0) {
|
if (_receiveRate > 0) {
|
||||||
// if we have a valid receive rate we set the send period to whatever the receive rate dictates
|
// if we have a valid receive rate we set the send period to whatever the receive rate dictates
|
||||||
_packetSendPeriod = USECS_PER_SECOND / _receiveRate;
|
setPacketSendPeriod(USECS_PER_SECOND / _receiveRate);
|
||||||
} else {
|
} else {
|
||||||
// no valid receive rate, packet send period is dictated by estimated RTT and current congestion window size
|
// no valid receive rate, packet send period is dictated by estimated RTT and current congestion window size
|
||||||
_packetSendPeriod = (_rtt + synInterval()) / _congestionWindowSize;
|
setPacketSendPeriod((_rtt + synInterval()) / _congestionWindowSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,8 +154,8 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {
|
||||||
if (rangeStart > _lastDecreaseMaxSeq) {
|
if (rangeStart > _lastDecreaseMaxSeq) {
|
||||||
|
|
||||||
_lastDecreasePeriod = _packetSendPeriod;
|
_lastDecreasePeriod = _packetSendPeriod;
|
||||||
|
|
||||||
_packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE);
|
setPacketSendPeriod(ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE));
|
||||||
|
|
||||||
// use EWMA to update the average number of NAKs per congestion
|
// use EWMA to update the average number of NAKs per congestion
|
||||||
static const double NAK_EWMA_ALPHA = 0.125;
|
static const double NAK_EWMA_ALPHA = 0.125;
|
||||||
|
@ -175,7 +181,7 @@ void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {
|
||||||
// there have been fewer than MAX_DECREASES_PER_CONGESTION_EPOCH AND this NAK matches the random count at which we
|
// there have been fewer than MAX_DECREASES_PER_CONGESTION_EPOCH AND this NAK matches the random count at which we
|
||||||
// decided we would decrease the packet send period
|
// decided we would decrease the packet send period
|
||||||
|
|
||||||
_packetSendPeriod = ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE);
|
setPacketSendPeriod(ceil(_packetSendPeriod * INTER_PACKET_ARRIVAL_INCREASE));
|
||||||
_lastDecreaseMaxSeq = _sendCurrSeqNum;
|
_lastDecreaseMaxSeq = _sendCurrSeqNum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,12 +204,12 @@ void DefaultCC::stopSlowStart() {
|
||||||
|
|
||||||
if (_receiveRate > 0) {
|
if (_receiveRate > 0) {
|
||||||
// Set the sending rate to the receiving rate.
|
// Set the sending rate to the receiving rate.
|
||||||
_packetSendPeriod = USECS_PER_SECOND / _receiveRate;
|
setPacketSendPeriod(USECS_PER_SECOND / _receiveRate);
|
||||||
} else {
|
} else {
|
||||||
// If no receiving rate is observed, we have to compute the sending
|
// If no receiving rate is observed, we have to compute the sending
|
||||||
// rate according to the current window size, and decrease it
|
// rate according to the current window size, and decrease it
|
||||||
// using the method below.
|
// using the method below.
|
||||||
_packetSendPeriod = _congestionWindowSize / (_rtt + synInterval());
|
setPacketSendPeriod(_congestionWindowSize / (_rtt + synInterval()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_CongestionControl_h
|
#ifndef hifi_CongestionControl_h
|
||||||
#define hifi_CongestionControl_h
|
#define hifi_CongestionControl_h
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -37,6 +38,7 @@ public:
|
||||||
virtual ~CongestionControl() {}
|
virtual ~CongestionControl() {}
|
||||||
|
|
||||||
int synInterval() const { return _synInterval; }
|
int synInterval() const { return _synInterval; }
|
||||||
|
void setMaxBandwidth(int maxBandwidth);
|
||||||
|
|
||||||
virtual void init() {}
|
virtual void init() {}
|
||||||
virtual void onACK(SequenceNumber ackNum) {}
|
virtual void onACK(SequenceNumber ackNum) {}
|
||||||
|
@ -49,7 +51,6 @@ protected:
|
||||||
void setMSS(int mss) { _mss = mss; }
|
void setMSS(int mss) { _mss = mss; }
|
||||||
void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; }
|
void setMaxCongestionWindowSize(int window) { _maxCongestionWindowSize = window; }
|
||||||
void setBandwidth(int bandwidth) { _bandwidth = bandwidth; }
|
void setBandwidth(int bandwidth) { _bandwidth = bandwidth; }
|
||||||
void setMaxBandwidth(int maxBandwidth) { _maxBandwidth = maxBandwidth; }
|
|
||||||
virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0;
|
virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0;
|
||||||
void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; }
|
void setSendCurrentSequenceNumber(SequenceNumber seqNum) { _sendCurrSeqNum = seqNum; }
|
||||||
void setReceiveRate(int rate) { _receiveRate = rate; }
|
void setReceiveRate(int rate) { _receiveRate = rate; }
|
||||||
|
@ -60,7 +61,7 @@ protected:
|
||||||
double _congestionWindowSize { 16.0 }; // Congestion window size, in packets
|
double _congestionWindowSize { 16.0 }; // Congestion window size, in packets
|
||||||
|
|
||||||
int _bandwidth { 0 }; // estimated bandwidth, packets per second
|
int _bandwidth { 0 }; // estimated bandwidth, packets per second
|
||||||
int _maxBandwidth { -1 }; // Maximum desired bandwidth, packets per second
|
std::atomic<int> _maxBandwidth { -1 }; // Maximum desired bandwidth, bytes per second
|
||||||
double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets
|
double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets
|
||||||
|
|
||||||
int _mss { 0 }; // Maximum Packet Size, including all packet headers
|
int _mss { 0 }; // Maximum Packet Size, including all packet headers
|
||||||
|
|
|
@ -80,6 +80,10 @@ void Connection::resetRTT() {
|
||||||
_rttVariance = _rtt / 2;
|
_rttVariance = _rtt / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::setMaxBandwidth(int maxBandwidth) {
|
||||||
|
_congestionControl->setMaxBandwidth(maxBandwidth);
|
||||||
|
}
|
||||||
|
|
||||||
SendQueue& Connection::getSendQueue() {
|
SendQueue& Connection::getSendQueue() {
|
||||||
if (!_sendQueue) {
|
if (!_sendQueue) {
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,8 @@ public:
|
||||||
|
|
||||||
HifiSockAddr getDestination() const { return _destination; }
|
HifiSockAddr getDestination() const { return _destination; }
|
||||||
|
|
||||||
|
void setMaxBandwidth(int maxBandwidth);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void packetSent();
|
void packetSent();
|
||||||
void connectionInactive(const HifiSockAddr& sockAddr);
|
void connectionInactive(const HifiSockAddr& sockAddr);
|
||||||
|
|
|
@ -176,7 +176,9 @@ Connection& Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) {
|
||||||
auto it = _connectionsHash.find(sockAddr);
|
auto it = _connectionsHash.find(sockAddr);
|
||||||
|
|
||||||
if (it == _connectionsHash.end()) {
|
if (it == _connectionsHash.end()) {
|
||||||
auto connection = std::unique_ptr<Connection>(new Connection(this, sockAddr, _ccFactory->create()));
|
auto congestionControl = _ccFactory->create();
|
||||||
|
congestionControl->setMaxBandwidth(_maxBandwidth);
|
||||||
|
auto connection = std::unique_ptr<Connection>(new Connection(this, sockAddr, std::move(congestionControl)));
|
||||||
|
|
||||||
// we queue the connection to cleanup connection in case it asks for it during its own rate control sync
|
// we queue the connection to cleanup connection in case it asks for it during its own rate control sync
|
||||||
QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection);
|
QObject::connect(connection.get(), &Connection::connectionInactive, this, &Socket::cleanupConnection);
|
||||||
|
@ -350,6 +352,17 @@ void Socket::setCongestionControlFactory(std::unique_ptr<CongestionControlVirtua
|
||||||
_synInterval = _ccFactory->synInterval();
|
_synInterval = _ccFactory->synInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Socket::setConnectionMaxBandwidth(int maxBandwidth) {
|
||||||
|
qInfo() << "Setting socket's maximum bandwith to" << maxBandwidth << ". ("
|
||||||
|
<< _connectionsHash.size() << "live connections)";
|
||||||
|
_maxBandwidth = maxBandwidth;
|
||||||
|
for (auto& pair : _connectionsHash) {
|
||||||
|
auto& connection = pair.second;
|
||||||
|
connection->setMaxBandwidth(_maxBandwidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& destination) {
|
ConnectionStats::Stats Socket::sampleStatsForConnection(const HifiSockAddr& destination) {
|
||||||
auto it = _connectionsHash.find(destination);
|
auto it = _connectionsHash.find(destination);
|
||||||
if (it != _connectionsHash.end()) {
|
if (it != _connectionsHash.end()) {
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
{ _unfilteredHandlers[senderSockAddr] = handler; }
|
{ _unfilteredHandlers[senderSockAddr] = handler; }
|
||||||
|
|
||||||
void setCongestionControlFactory(std::unique_ptr<CongestionControlVirtualFactory> ccFactory);
|
void setCongestionControlFactory(std::unique_ptr<CongestionControlVirtualFactory> ccFactory);
|
||||||
|
void setConnectionMaxBandwidth(int maxBandwidth);
|
||||||
|
|
||||||
void messageReceived(std::unique_ptr<Packet> packet);
|
void messageReceived(std::unique_ptr<Packet> packet);
|
||||||
void messageFailed(Connection* connection, Packet::MessageNumber messageNumber);
|
void messageFailed(Connection* connection, Packet::MessageNumber messageNumber);
|
||||||
|
@ -109,8 +110,10 @@ private:
|
||||||
std::unordered_map<HifiSockAddr, SequenceNumber> _unreliableSequenceNumbers;
|
std::unordered_map<HifiSockAddr, SequenceNumber> _unreliableSequenceNumbers;
|
||||||
std::unordered_map<HifiSockAddr, std::unique_ptr<Connection>> _connectionsHash;
|
std::unordered_map<HifiSockAddr, std::unique_ptr<Connection>> _connectionsHash;
|
||||||
|
|
||||||
int _synInterval = 10; // 10ms
|
int _synInterval { 10 }; // 10ms
|
||||||
QTimer* _synTimer;
|
QTimer* _synTimer { nullptr };
|
||||||
|
|
||||||
|
int _maxBandwidth { -1 };
|
||||||
|
|
||||||
std::unique_ptr<CongestionControlVirtualFactory> _ccFactory { new CongestionControlFactory<DefaultCC>() };
|
std::unique_ptr<CongestionControlVirtualFactory> _ccFactory { new CongestionControlFactory<DefaultCC>() };
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();
|
static int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
|
||||||
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();
|
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();
|
||||||
static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
||||||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||||
|
@ -821,21 +821,21 @@ QStringList Model::getJointNames() const {
|
||||||
class Blender : public QRunnable {
|
class Blender : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Blender(Model* model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
Blender(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QPointer<Model> _model;
|
ModelPointer _model;
|
||||||
int _blendNumber;
|
int _blendNumber;
|
||||||
QWeakPointer<NetworkGeometry> _geometry;
|
QWeakPointer<NetworkGeometry> _geometry;
|
||||||
QVector<FBXMesh> _meshes;
|
QVector<FBXMesh> _meshes;
|
||||||
QVector<float> _blendshapeCoefficients;
|
QVector<float> _blendshapeCoefficients;
|
||||||
};
|
};
|
||||||
|
|
||||||
Blender::Blender(Model* model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
Blender::Blender(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
||||||
_model(model),
|
_model(model),
|
||||||
_blendNumber(blendNumber),
|
_blendNumber(blendNumber),
|
||||||
|
@ -847,7 +847,7 @@ Blender::Blender(Model* model, int blendNumber, const QWeakPointer<NetworkGeomet
|
||||||
void Blender::run() {
|
void Blender::run() {
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
QVector<glm::vec3> vertices, normals;
|
QVector<glm::vec3> vertices, normals;
|
||||||
if (!_model.isNull()) {
|
if (_model) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
foreach (const FBXMesh& mesh, _meshes) {
|
foreach (const FBXMesh& mesh, _meshes) {
|
||||||
if (mesh.blendshapes.isEmpty()) {
|
if (mesh.blendshapes.isEmpty()) {
|
||||||
|
@ -877,7 +877,7 @@ void Blender::run() {
|
||||||
}
|
}
|
||||||
// post the result to the geometry cache, which will dispatch to the model if still alive
|
// post the result to the geometry cache, which will dispatch to the model if still alive
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
|
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
|
||||||
Q_ARG(const QPointer<Model>&, _model), Q_ARG(int, _blendNumber),
|
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
|
||||||
Q_ARG(const QWeakPointer<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
Q_ARG(const QWeakPointer<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
||||||
Q_ARG(const QVector<glm::vec3>&, normals));
|
Q_ARG(const QVector<glm::vec3>&, normals));
|
||||||
}
|
}
|
||||||
|
@ -1088,7 +1088,7 @@ float Model::getLimbLength(int jointIndex) const {
|
||||||
bool Model::maybeStartBlender() {
|
bool Model::maybeStartBlender() {
|
||||||
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry();
|
||||||
if (fbxGeometry.hasBlendedMeshes()) {
|
if (fbxGeometry.hasBlendedMeshes()) {
|
||||||
QThreadPool::globalInstance()->start(new Blender(this, ++_blendNumber, _geometry,
|
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry,
|
||||||
fbxGeometry.meshes, _blendshapeCoefficients));
|
fbxGeometry.meshes, _blendshapeCoefficients));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1284,10 +1284,9 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelBlender::setBlendedVertices(const QPointer<Model>& model, int blendNumber,
|
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber,
|
||||||
const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
const QWeakPointer<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||||
|
if (model) {
|
||||||
if (!model.isNull()) {
|
|
||||||
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
||||||
}
|
}
|
||||||
_pendingBlenders--;
|
_pendingBlenders--;
|
||||||
|
|
|
@ -384,7 +384,7 @@ protected:
|
||||||
RigPointer _rig;
|
RigPointer _rig;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QPointer<Model>)
|
Q_DECLARE_METATYPE(ModelPointer)
|
||||||
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
||||||
|
|
||||||
/// Handle management of pending models that need blending
|
/// Handle management of pending models that need blending
|
||||||
|
@ -398,7 +398,7 @@ public:
|
||||||
void noteRequiresBlend(ModelPointer model);
|
void noteRequiresBlend(ModelPointer model);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setBlendedVertices(const QPointer<Model>& model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
void setBlendedVertices(ModelPointer model, int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
|
||||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -158,6 +158,13 @@ void ScriptEngine::disconnectNonEssentialSignals() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::runInThread() {
|
void ScriptEngine::runInThread() {
|
||||||
|
Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once");
|
||||||
|
|
||||||
|
if (_isThreaded) {
|
||||||
|
qCWarning(scriptengine) << "ScriptEngine already running in thread: " << getFilename();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_isThreaded = true;
|
_isThreaded = true;
|
||||||
QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
|
QThread* workerThread = new QThread(); // thread is not owned, so we need to manage the delete
|
||||||
QString scriptEngineName = QString("Script Thread:") + getFilename();
|
QString scriptEngineName = QString("Script Thread:") + getFilename();
|
||||||
|
|
|
@ -20,6 +20,10 @@ public:
|
||||||
template <typename F>
|
template <typename F>
|
||||||
Finally(F f) : _f(f) {}
|
Finally(F f) : _f(f) {}
|
||||||
~Finally() { _f(); }
|
~Finally() { _f(); }
|
||||||
|
void trigger() {
|
||||||
|
_f();
|
||||||
|
_f = [] {};
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::function<void()> _f;
|
std::function<void()> _f;
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,7 +82,6 @@ void LogHandler::flushRepeatedMessages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
|
QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||||
|
|
||||||
if (message.isEmpty()) {
|
if (message.isEmpty()) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,6 @@ QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto argumentObject = context->argument(0);
|
auto argumentObject = context->argument(0);
|
||||||
qDebug() << argumentObject.toString();
|
|
||||||
if (!argumentObject.property(TITLE_PROPERTY).isUndefined()) {
|
if (!argumentObject.property(TITLE_PROPERTY).isUndefined()) {
|
||||||
title = argumentObject.property(TITLE_PROPERTY).toString();
|
title = argumentObject.property(TITLE_PROPERTY).toString();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue