Merge pull request #2179 from ey6es/master

Better frame rates on loading by reading cached data from disk in worker thread, render billboards if we haven't loaded the models yet, use voxel LOD parameter to control avatar LODs, too.
This commit is contained in:
Philip Rosedale 2014-03-03 17:21:46 -08:00
commit 7ce427b35c
9 changed files with 35 additions and 28 deletions

View file

@ -1612,6 +1612,13 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
return false; return false;
} }
void Application::updateLOD() {
// adjust it unless we were asked to disable this feature
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
}
void Application::updateMouseRay() { void Application::updateMouseRay() {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
@ -1852,6 +1859,8 @@ void Application::update(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()"); PerformanceWarning warn(showWarnings, "Application::update()");
updateLOD();
// check what's under the mouse and update the mouse voxel // check what's under the mouse and update the mouse voxel
updateMouseRay(); updateMouseRay();
@ -2325,14 +2334,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... voxels..."); "Application::displaySide() ... voxels...");
_voxels.render(); _voxels.render();
// double check that our LOD doesn't need to be auto-adjusted
// adjust it unless we were asked to disable this feature
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD)) {
Menu::getInstance()->autoAdjustLOD(_fps);
}
} }
// also, metavoxels // also, metavoxels

View file

@ -284,6 +284,7 @@ private:
void update(float deltaTime); void update(float deltaTime);
// Various helper functions called during update() // Various helper functions called during update()
void updateLOD();
void updateMouseRay(); void updateMouseRay();
void updateFaceshift(); void updateFaceshift();
void updateVisage(); void updateVisage();

View file

@ -84,6 +84,7 @@ public:
void autoAdjustLOD(float currentFPS); void autoAdjustLOD(float currentFPS);
void setVoxelSizeScale(float sizeScale); void setVoxelSizeScale(float sizeScale);
float getVoxelSizeScale() const { return _voxelSizeScale; } float getVoxelSizeScale() const { return _voxelSizeScale; }
float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; }
void setBoundaryLevelAdjust(int boundaryLevelAdjust); void setBoundaryLevelAdjust(int boundaryLevelAdjust);
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }

View file

@ -112,7 +112,8 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
} }
float Avatar::getLODDistance() const { float Avatar::getLODDistance() const {
return glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale; return Menu::getInstance()->getAvatarLODDistanceMultiplier() *
glm::distance(Application::getInstance()->getCamera()->getPosition(), _position) / _scale;
} }
void Avatar::simulate(float deltaTime) { void Avatar::simulate(float deltaTime) {
@ -305,13 +306,11 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
} }
void Avatar::renderBody() { void Avatar::renderBody() {
if (_shouldRenderBillboard) { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
// render the billboard until both models are loaded
renderBillboard(); renderBillboard();
return; return;
} }
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
return; // wait until both models are loaded
}
_skeletonModel.render(1.0f); _skeletonModel.render(1.0f);
getHead()->render(1.0f); getHead()->render(1.0f);
getHand()->render(false); getHand()->render(false);

View file

@ -450,7 +450,7 @@ class GeometryReader : public QRunnable {
public: public:
GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url, GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
const QByteArray& data, const QVariantHash& mapping); QNetworkReply* reply, const QVariantHash& mapping);
virtual void run(); virtual void run();
@ -458,40 +458,41 @@ private:
QWeakPointer<Resource> _geometry; QWeakPointer<Resource> _geometry;
QUrl _url; QUrl _url;
QByteArray _data; QNetworkReply* _reply;
QVariantHash _mapping; QVariantHash _mapping;
}; };
GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url, GeometryReader::GeometryReader(const QWeakPointer<Resource>& geometry, const QUrl& url,
const QByteArray& data, const QVariantHash& mapping) : QNetworkReply* reply, const QVariantHash& mapping) :
_geometry(geometry), _geometry(geometry),
_url(url), _url(url),
_data(data), _reply(reply),
_mapping(mapping) { _mapping(mapping) {
} }
void GeometryReader::run() { void GeometryReader::run() {
QSharedPointer<Resource> geometry = _geometry.toStrongRef(); QSharedPointer<Resource> geometry = _geometry.toStrongRef();
if (geometry.isNull()) { if (geometry.isNull()) {
_reply->deleteLater();
return; return;
} }
try { try {
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&,
_url.path().toLower().endsWith(".svo") ? readSVO(_data) : readFBX(_data, _mapping))); _url.path().toLower().endsWith(".svo") ? readSVO(_reply->readAll()) : readFBX(_reply->readAll(), _mapping)));
} catch (const QString& error) { } catch (const QString& error) {
qDebug() << "Error reading " << _url << ": " << error; qDebug() << "Error reading " << _url << ": " << error;
QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false)); QMetaObject::invokeMethod(geometry.data(), "finishedLoading", Q_ARG(bool, false));
} }
_reply->deleteLater();
} }
void NetworkGeometry::downloadFinished(QNetworkReply* reply) { void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
QUrl url = reply->url(); QUrl url = reply->url();
QByteArray data = reply->readAll();
if (url.path().toLower().endsWith(".fst")) { if (url.path().toLower().endsWith(".fst")) {
// it's a mapping file; parse it and get the mesh filename // it's a mapping file; parse it and get the mesh filename
_mapping = readMapping(data); _mapping = readMapping(reply->readAll());
reply->deleteLater();
QString filename = _mapping.value("filename").toString(); QString filename = _mapping.value("filename").toString();
if (filename.isNull()) { if (filename.isNull()) {
qDebug() << "Mapping file " << url << " has no filename."; qDebug() << "Mapping file " << url << " has no filename.";
@ -525,7 +526,7 @@ void NetworkGeometry::downloadFinished(QNetworkReply* reply) {
} }
// send the reader off to the thread pool // send the reader off to the thread pool
QThreadPool::globalInstance()->start(new GeometryReader(_self, url, data, _mapping)); QThreadPool::globalInstance()->start(new GeometryReader(_self, url, reply, _mapping));
} }
void NetworkGeometry::setGeometry(const FBXGeometry& geometry) { void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {

View file

@ -273,27 +273,28 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
class ImageReader : public QRunnable { class ImageReader : public QRunnable {
public: public:
ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data); ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply);
virtual void run(); virtual void run();
private: private:
QWeakPointer<Resource> _texture; QWeakPointer<Resource> _texture;
QByteArray _data; QNetworkReply* _reply;
}; };
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data) : ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply) :
_texture(texture), _texture(texture),
_data(data) { _reply(reply) {
} }
void ImageReader::run() { void ImageReader::run() {
QSharedPointer<Resource> texture = _texture.toStrongRef(); QSharedPointer<Resource> texture = _texture.toStrongRef();
if (texture.isNull()) { if (texture.isNull()) {
_reply->deleteLater();
return; return;
} }
QImage image = QImage::fromData(_data); QImage image = QImage::fromData(_reply->readAll());
if (image.format() != QImage::Format_ARGB32) { if (image.format() != QImage::Format_ARGB32) {
image = image.convertToFormat(QImage::Format_ARGB32); image = image.convertToFormat(QImage::Format_ARGB32);
} }
@ -320,11 +321,12 @@ void ImageReader::run() {
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)), Q_ARG(const glm::vec4&, accumulated / (imageArea * EIGHT_BIT_MAXIMUM)),
Q_ARG(bool, translucentPixels >= imageArea / 2)); Q_ARG(bool, translucentPixels >= imageArea / 2));
_reply->deleteLater();
} }
void NetworkTexture::downloadFinished(QNetworkReply* reply) { void NetworkTexture::downloadFinished(QNetworkReply* reply) {
// send the reader off to the thread pool // send the reader off to the thread pool
QThreadPool::globalInstance()->start(new ImageReader(_self, reply->readAll())); QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
} }
void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) { void NetworkTexture::setImage(const QImage& image, const glm::vec4& averageColor, bool translucent) {

View file

@ -61,6 +61,7 @@ NetworkProgram::NetworkProgram(ScriptCache* cache, const QUrl& url) :
void NetworkProgram::downloadFinished(QNetworkReply* reply) { void NetworkProgram::downloadFinished(QNetworkReply* reply) {
_program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString()); _program = QScriptProgram(QTextStream(reply).readAll(), reply->url().toString());
reply->deleteLater();
finishedLoading(true); finishedLoading(true);
emit loaded(); emit loaded();
} }

View file

@ -161,7 +161,6 @@ void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
return; return;
} }
_reply->disconnect(this); _reply->disconnect(this);
_reply->deleteLater();
QNetworkReply* reply = _reply; QNetworkReply* reply = _reply;
_reply = NULL; _reply = NULL;
ResourceCache::requestCompleted(); ResourceCache::requestCompleted();

View file

@ -99,6 +99,7 @@ protected slots:
protected: protected:
/// Called when the download has finished. The recipient should delete the reply when done with it.
virtual void downloadFinished(QNetworkReply* reply) = 0; virtual void downloadFinished(QNetworkReply* reply) = 0;
/// Should be called by subclasses when all the loading that will be done has been done. /// Should be called by subclasses when all the loading that will be done has been done.