From 24b26e3097fc781efd72f3a1507dba25aa9aa025 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Mar 2016 19:18:46 -0700 Subject: [PATCH 01/61] first few elements --- libraries/gpu/src/gpu/Texture.cpp | 36 +++++++++++++++++++++++++++++-- libraries/gpu/src/gpu/Texture.h | 20 ++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 3f2415d240..8b219a55de 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -17,6 +17,30 @@ using namespace gpu; +std::atomic Texture::_textureSystemMemoryUsage; +std::atomic Texture::_textureVideoMemoryUsage; + +uint32_t Texture::getCurrentSystemMemoryUsage() { + return _textureSystemMemoryUsage.load(); +} +uint32_t Texture::getCurrentVideoMemoryUsage() { + return _textureVideoMemoryUsage.load(); +} + +void Texture::addSystemMemoryUsage(uint32_t memorySize) { + _textureSystemMemoryUsage.fetch_add(memorySize); +} +void Texture::subSystemMemoryUsage(uint32_t memorySize) { + _textureSystemMemoryUsage.fetch_sub(memorySize); +} + +void Texture::addVideoMemoryUsage(uint32_t memorySize) { + _textureVideoMemoryUsage.fetch_add(memorySize); +} +void Texture::subVideoMemoryUsage(uint32_t memorySize) { + _textureVideoMemoryUsage.fetch_sub(memorySize); +} + uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : @@ -28,6 +52,15 @@ Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : Texture::Pixels::~Pixels() { } +Texture::Size Texture::Pixels::resize(Size pSize) { + return _sysmem.resize(pSize); +} + +void Texture::Pixels::notifyGPULoaded() { + _isGPULoaded = true; + _sysmem.resize(0); +} + void Texture::Storage::assignTexture(Texture* texture) { _texture = texture; if (_texture) { @@ -60,8 +93,7 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); if (mipFace && (_type != TEX_CUBE)) { - mipFace->_isGPULoaded = true; - mipFace->_sysmem.resize(0); + mipFace->notifyGPULoaded(); } } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index e05dc84c25..106b179f69 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -15,6 +15,7 @@ #include //min max and more #include +#include #include @@ -138,8 +139,20 @@ protected: }; class Texture : public Resource { + static std::atomic _textureSystemMemoryUsage; + static std::atomic _textureVideoMemoryUsage; + + void addSystemMemoryUsage(uint32_t memorySize); + void subSystemMemoryUsage(uint32_t memorySize); + + void addVideoMemoryUsage(uint32_t memorySize); + void subVideoMemoryUsage(uint32_t memorySize); + public: + uint32_t getCurrentSystemMemoryUsage(); + uint32_t getCurrentVideoMemoryUsage(); + class Usage { public: enum FlagBit { @@ -194,8 +207,13 @@ public: Pixels(const Element& format, Size size, const Byte* bytes); ~Pixels(); - Sysmem _sysmem; + Size getSize() const { return _sysmem.getSize(); } + Size resize(Size pSize); + void notifyGPULoaded(); + + protected: Element _format; + Sysmem _sysmem; bool _isGPULoaded; }; typedef std::shared_ptr< Pixels > PixelsPointer; From b29ef7b037dcb04110f1fec77469d2af0ffaee3d Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 09:45:38 -0700 Subject: [PATCH 02/61] IMplementing a memory counter --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 16 ++-- libraries/gpu/src/gpu/Texture.cpp | 84 +++++++++++++------- libraries/gpu/src/gpu/Texture.h | 26 +++--- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index a70904a4bf..fe3c6cd6d1 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -427,8 +427,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (needUpdate) { if (texture.isStoredMipFaceAvailable(0)) { Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - const GLvoid* bytes = mip->_sysmem.read(); - Element srcFormat = mip->_format; + const GLvoid* bytes = mip->readData(); + Element srcFormat = mip->getFormat(); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); @@ -458,8 +458,8 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { if (texture.isStoredMipFaceAvailable(0)) { Texture::PixelsPointer mip = texture.accessStoredMipFace(0); - bytes = mip->_sysmem.read(); - srcFormat = mip->_format; + bytes = mip->readData(); + srcFormat = mip->getFormat(); object->_contentStamp = texture.getDataStamp(); } @@ -507,11 +507,11 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { for (int f = 0; f < NUM_FACES; f++) { if (texture.isStoredMipFaceAvailable(0, f)) { Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->_format; + Element srcFormat = mipFace->getFormat(); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); glTexSubImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read())); + texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); // At this point the mip pixels have been loaded, we can notify texture.notifyMipFaceGPULoaded(0, f); @@ -536,11 +536,11 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { for (int f = 0; f < NUM_FACES; f++) { if (texture.isStoredMipFaceAvailable(0, f)) { Texture::PixelsPointer mipFace = texture.accessStoredMipFace(0, f); - Element srcFormat = mipFace->_format; + Element srcFormat = mipFace->getFormat(); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); glTexImage2D(FACE_LAYOUT[f], 0, texelFormat.internalFormat, texture.getWidth(), texture.getWidth(), 0, - texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->_sysmem.read())); + texelFormat.format, texelFormat.type, (GLvoid*) (mipFace->readData())); // At this point the mip pixels have been loaded, we can notify texture.notifyMipFaceGPULoaded(0, f); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 8b219a55de..7f697c223d 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -12,53 +12,82 @@ #include "Texture.h" #include - -#include +#include "GPULogging.h" +//#include using namespace gpu; -std::atomic Texture::_textureSystemMemoryUsage; -std::atomic Texture::_textureVideoMemoryUsage; +std::atomic Texture::_textureSystemMemoryUsage{ 0 }; +std::atomic Texture::_textureVideoMemoryUsage{ 0 }; -uint32_t Texture::getCurrentSystemMemoryUsage() { +Texture::Size Texture::getCurrentSystemMemoryUsage() { return _textureSystemMemoryUsage.load(); } -uint32_t Texture::getCurrentVideoMemoryUsage() { +Texture::Size Texture::getCurrentVideoMemoryUsage() { return _textureVideoMemoryUsage.load(); } -void Texture::addSystemMemoryUsage(uint32_t memorySize) { +void Texture::addSystemMemoryUsage(Size memorySize) { _textureSystemMemoryUsage.fetch_add(memorySize); } -void Texture::subSystemMemoryUsage(uint32_t memorySize) { +void Texture::subSystemMemoryUsage(Size memorySize) { _textureSystemMemoryUsage.fetch_sub(memorySize); } -void Texture::addVideoMemoryUsage(uint32_t memorySize) { +void Texture::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (prevObjectSize > newObjectSize) { + subSystemMemoryUsage(prevObjectSize - newObjectSize); + } else { + addSystemMemoryUsage(newObjectSize - prevObjectSize); + } + + qCDebug(gpulogging) << "Texture::SysMem = " << getCurrentSystemMemoryUsage(); +} + +void Texture::addVideoMemoryUsage(Size memorySize) { _textureVideoMemoryUsage.fetch_add(memorySize); } -void Texture::subVideoMemoryUsage(uint32_t memorySize) { +void Texture::subVideoMemoryUsage(Size memorySize) { _textureVideoMemoryUsage.fetch_sub(memorySize); } uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : - _sysmem(size, bytes), _format(format), + _sysmem(size, bytes), _isGPULoaded(false) { + Texture::updateSystemMemoryUsage(0, _sysmem.getSize()); } Texture::Pixels::~Pixels() { + Texture::updateSystemMemoryUsage(_sysmem.getSize(), 0); } Texture::Size Texture::Pixels::resize(Size pSize) { - return _sysmem.resize(pSize); + auto prevSize = _sysmem.getSize(); + auto newSize = _sysmem.resize(pSize); + Texture::updateSystemMemoryUsage(prevSize, newSize); + return newSize; +} + +Texture::Size Texture::Pixels::setData(const Element& format, Size size, const Byte* bytes ) { + _format = format; + auto prevSize = _sysmem.getSize(); + auto newSize = _sysmem.setData(size, bytes); + Texture::updateSystemMemoryUsage(prevSize, newSize); + _isGPULoaded = false; + return newSize; } void Texture::Pixels::notifyGPULoaded() { _isGPULoaded = true; - _sysmem.resize(0); + auto prevSize = _sysmem.getSize(); + auto newSize = _sysmem.resize(0); + Texture::updateSystemMemoryUsage(prevSize, newSize); } void Texture::Storage::assignTexture(Texture* texture) { @@ -92,14 +121,15 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); - if (mipFace && (_type != TEX_CUBE)) { - mipFace->notifyGPULoaded(); + // if (mipFace && (_type != TEX_CUBE)) { + if (mipFaced) { + mipFace->notifyGPULoaded(); } } bool Texture::Storage::isMipAvailable(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); - return (mipFace && mipFace->_sysmem.getSize()); + return (mipFace && mipFace->getSize()); } bool Texture::Storage::allocateMip(uint16 level) { @@ -135,9 +165,7 @@ bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size s auto faceBytes = bytes; Size allocated = 0; for (auto& face : mip) { - face->_format = format; - allocated += face->_sysmem.setData(sizePerFace, faceBytes); - face->_isGPULoaded = false; + allocated += face->setData(format, sizePerFace, faceBytes); faceBytes += sizePerFace; } @@ -154,9 +182,7 @@ bool Texture::Storage::assignMipFaceData(uint16 level, const Element& format, Si Size allocated = 0; if (face < mip.size()) { auto mipFace = mip[face]; - mipFace->_format = format; - allocated += mipFace->_sysmem.setData(size, bytes); - mipFace->_isGPULoaded = false; + allocated += mipFace->setData(format, size, bytes); bumpStamp(); } @@ -396,7 +422,7 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) { uint16 Texture::getStoredMipWidth(uint16 level) const { PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->_sysmem.getSize()) { + if (mipFace && mipFace->getSize()) { return evalMipWidth(level); } return 0; @@ -404,7 +430,7 @@ uint16 Texture::getStoredMipWidth(uint16 level) const { uint16 Texture::getStoredMipHeight(uint16 level) const { PixelsPointer mip = accessStoredMipFace(level); - if (mip && mip->_sysmem.getSize()) { + if (mip && mip->getSize()) { return evalMipHeight(level); } return 0; @@ -412,7 +438,7 @@ uint16 Texture::getStoredMipHeight(uint16 level) const { uint16 Texture::getStoredMipDepth(uint16 level) const { PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->_sysmem.getSize()) { + if (mipFace && mipFace->getSize()) { return evalMipDepth(level); } return 0; @@ -420,7 +446,7 @@ uint16 Texture::getStoredMipDepth(uint16 level) const { uint32 Texture::getStoredMipNumTexels(uint16 level) const { PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->_sysmem.getSize()) { + if (mipFace && mipFace->getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } return 0; @@ -428,7 +454,7 @@ uint32 Texture::getStoredMipNumTexels(uint16 level) const { uint32 Texture::getStoredMipSize(uint16 level) const { PixelsPointer mipFace = accessStoredMipFace(level); - if (mipFace && mipFace->_sysmem.getSize()) { + if (mipFace && mipFace->getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); } return 0; @@ -674,8 +700,8 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector< // for each face of cube texture for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) { - auto numComponents = cubeTexture.accessStoredMipFace(0,face)->_format.getScalarCount(); - auto data = cubeTexture.accessStoredMipFace(0,face)->_sysmem.readData(); + auto numComponents = cubeTexture.accessStoredMipFace(0,face)->getFormat().getScalarCount(); + auto data = cubeTexture.accessStoredMipFace(0,face)->readData(); if (data == nullptr) { continue; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 106b179f69..b5a6f5ed7c 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -139,19 +139,20 @@ protected: }; class Texture : public Resource { - static std::atomic _textureSystemMemoryUsage; - static std::atomic _textureVideoMemoryUsage; + static std::atomic _textureSystemMemoryUsage; + static std::atomic _textureVideoMemoryUsage; - void addSystemMemoryUsage(uint32_t memorySize); - void subSystemMemoryUsage(uint32_t memorySize); + static void addSystemMemoryUsage(Size memorySize); + static void subSystemMemoryUsage(Size memorySize); + static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); - void addVideoMemoryUsage(uint32_t memorySize); - void subVideoMemoryUsage(uint32_t memorySize); + static void addVideoMemoryUsage(Size memorySize); + static void subVideoMemoryUsage(Size memorySize); public: - uint32_t getCurrentSystemMemoryUsage(); - uint32_t getCurrentVideoMemoryUsage(); + static Size getCurrentSystemMemoryUsage(); + static Size getCurrentVideoMemoryUsage(); class Usage { public: @@ -207,14 +208,21 @@ public: Pixels(const Element& format, Size size, const Byte* bytes); ~Pixels(); + const Byte* readData() const { return _sysmem.readData(); } Size getSize() const { return _sysmem.getSize(); } Size resize(Size pSize); + Size setData(const Element& format, Size size, const Byte* bytes ); + + const Element& getFormat() const { return _format; } + void notifyGPULoaded(); - + protected: Element _format; Sysmem _sysmem; bool _isGPULoaded; + + friend class Texture; }; typedef std::shared_ptr< Pixels > PixelsPointer; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 61ebfe4515..e17332a20f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1,4 +1,4 @@ -// +d// // ScriptEngine.cpp // libraries/script-engine/src // From 138a9960137d2f4343a872e9735eb4762df1e52c Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 15:46:17 -0700 Subject: [PATCH 03/61] First draft of monitoring the memeory consumption --- .../utilities/tools/render/renderStats.js | 20 +++++ examples/utilities/tools/render/stats.qml | 40 +++++++++ interface/src/Application.cpp | 2 +- libraries/gpu/src/gpu/GLBackend.h | 6 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 23 +++++- libraries/gpu/src/gpu/Texture.cpp | 22 +++-- libraries/gpu/src/gpu/Texture.h | 7 +- libraries/render/src/render/Engine.cpp | 16 ++++ libraries/render/src/render/Engine.h | 81 +++++++++++++------ libraries/script-engine/src/ScriptEngine.cpp | 2 +- 10 files changed, 184 insertions(+), 35 deletions(-) create mode 100644 examples/utilities/tools/render/renderStats.js create mode 100644 examples/utilities/tools/render/stats.qml diff --git a/examples/utilities/tools/render/renderStats.js b/examples/utilities/tools/render/renderStats.js new file mode 100644 index 0000000000..da12ad1b31 --- /dev/null +++ b/examples/utilities/tools/render/renderStats.js @@ -0,0 +1,20 @@ +// +// renderStats.js +// examples/utilities/tools/render +// +// Sam Gateau, created on 3/22/2016. +// 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 +// + +// Set up the qml ui +var qml = Script.resolvePath('stats.qml'); +var window = new OverlayWindow({ + title: 'Render Stats', + source: qml, + width: 300 +}); +window.setPosition(500, 50); +window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml new file mode 100644 index 0000000000..eb7bb44a73 --- /dev/null +++ b/examples/utilities/tools/render/stats.qml @@ -0,0 +1,40 @@ +// +// stats.qml +// examples/utilities/tools/render +// +// Created by Zach Pomerantz on 2/8/2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Column { + spacing: 8 + Column { + id: stats + property var config: Render.getConfig("Stats") + + Repeater { + model: [ + "num Textures:numTextures", + "Sysmem Usage:textureSysmemUsage", + "num GPU Textures:numGPUTextures", + "Vidmem Usage:textureVidmemUsage" + ] + Row { + Label { + text: qsTr(modelData.split(":")[0]) + } + property var value: stats.config[modelData.split(":")[1]] + Label { + text: value + horizontalAlignment: AlignRight + } + + } + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 65a8f83871..61d92cebe7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -268,7 +268,7 @@ public: void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); -#ifdef NDEBUG +#ifdef ____NDEBUG auto now = usecTimestampNow(); auto lastHeartbeatAge = now - _heartbeat; if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 39b54c109b..d93962f5a1 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -72,12 +72,16 @@ public: static GLuint getBufferID(const Buffer& buffer); class GLTexture : public GPUObject { + GLuint _size; public: Stamp _storageStamp; Stamp _contentStamp; GLuint _texture; GLenum _target; - GLuint _size; + + + void setSize(GLuint size); + GLuint size() const { return _size; } GLTexture(); ~GLTexture(); diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index fe3c6cd6d1..6a96c5a651 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -19,12 +19,29 @@ GLBackend::GLTexture::GLTexture() : _texture(0), _target(GL_TEXTURE_2D), _size(0) -{} +{ + Texture::_numGPUTextures++; +} GLBackend::GLTexture::~GLTexture() { if (_texture != 0) { glDeleteTextures(1, &_texture); } + Texture::_textureVideoMemoryUsage.fetch_sub(_size); + Texture::_numGPUTextures--; +} + +void GLBackend::GLTexture::setSize(GLuint size) { + if (_size == size) { + return; + } + if (size > _size) { + Texture::_textureVideoMemoryUsage.fetch_add(size - _size); + } else { + Texture::_textureVideoMemoryUsage.fetch_sub(_size - size); + } + + _size = size; } class GLTexelFormat { @@ -483,7 +500,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { object->_storageStamp = texture.getStamp(); object->_contentStamp = texture.getDataStamp(); - object->_size = (GLuint)texture.getSize(); + object->setSize((GLuint)texture.getSize()); } glBindTexture(GL_TEXTURE_2D, boundTex); @@ -561,7 +578,7 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) { object->_storageStamp = texture.getStamp(); object->_contentStamp = texture.getDataStamp(); - object->_size = (GLuint)texture.getSize(); + object->setSize((GLuint)texture.getSize()); } glBindTexture(GL_TEXTURE_CUBE_MAP, boundTex); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 7f697c223d..7a0e198ec9 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -17,12 +17,24 @@ using namespace gpu; -std::atomic Texture::_textureSystemMemoryUsage{ 0 }; -std::atomic Texture::_textureVideoMemoryUsage{ 0 }; +std::atomic Texture::_numTextures{ 0 }; +std::atomic Texture::_numGPUTextures{ 0 }; +std::atomic Texture::_textureSystemMemoryUsage{ 0 }; +std::atomic Texture::_textureVideoMemoryUsage{ 0 }; + + +int Texture::getCurrentNumTextures() { + return _numTextures.load(); +} Texture::Size Texture::getCurrentSystemMemoryUsage() { return _textureSystemMemoryUsage.load(); } + +int Texture::getCurrentNumGPUTextures() { + return _numGPUTextures.load(); +} + Texture::Size Texture::getCurrentVideoMemoryUsage() { return _textureVideoMemoryUsage.load(); } @@ -43,8 +55,6 @@ void Texture::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { } else { addSystemMemoryUsage(newObjectSize - prevObjectSize); } - - qCDebug(gpulogging) << "Texture::SysMem = " << getCurrentSystemMemoryUsage(); } void Texture::addVideoMemoryUsage(Size memorySize) { @@ -122,7 +132,7 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); // if (mipFace && (_type != TEX_CUBE)) { - if (mipFaced) { + if (mipFace) { mipFace->notifyGPULoaded(); } } @@ -229,10 +239,12 @@ Texture* Texture::createFromStorage(Storage* storage) { Texture::Texture(): Resource() { + _numTextures++; } Texture::~Texture() { + _numTextures--; } Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index b5a6f5ed7c..06b0077458 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -139,9 +139,12 @@ protected: }; class Texture : public Resource { + static std::atomic _numTextures; static std::atomic _textureSystemMemoryUsage; +public: + static std::atomic _numGPUTextures; static std::atomic _textureVideoMemoryUsage; - +private: static void addSystemMemoryUsage(Size memorySize); static void subSystemMemoryUsage(Size memorySize); static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); @@ -151,7 +154,9 @@ class Texture : public Resource { public: + static int getCurrentNumTextures(); static Size getCurrentSystemMemoryUsage(); + static int getCurrentNumGPUTextures(); static Size getCurrentVideoMemoryUsage(); class Usage { diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 806c964ec0..2118c3c734 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -23,6 +23,7 @@ using namespace render; Engine::Engine() : _sceneContext(std::make_shared()), _renderContext(std::make_shared()) { + addJob("Stats"); } void Engine::load() { @@ -57,4 +58,19 @@ void Engine::run() { for (auto job : _jobs) { job.run(_sceneContext, _renderContext); } + +} + +#include +void EngineStats::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + const size_t KILO_BYTES = 1024; + // Update the stats + auto config = std::static_pointer_cast(renderContext->jobConfig); + + config->numTextures = gpu::Texture::getCurrentNumTextures(); + config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); + config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); + config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); + + config->emitDirty(); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 1af0e6d76f..71c52c5910 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -19,34 +19,69 @@ namespace render { -// The render engine holds all render tasks, and is itself a render task. -// State flows through tasks to jobs via the render and scene contexts - -// the engine should not be known from its jobs. -class Engine : public Task { -public: - Engine(); - ~Engine() = default; + // The render engine holds all render tasks, and is itself a render task. + // State flows through tasks to jobs via the render and scene contexts - + // the engine should not be known from its jobs. + class Engine : public Task { + public: - // Load any persisted settings, and set up the presets - // This should be run after adding all jobs, and before building ui - void load(); + Engine(); + ~Engine() = default; - // Register the scene - void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; } + // Load any persisted settings, and set up the presets + // This should be run after adding all jobs, and before building ui + void load(); - // Push a RenderContext - void setRenderContext(const RenderContext& renderContext) { (*_renderContext) = renderContext; } - RenderContextPointer getRenderContext() const { return _renderContext; } + // Register the scene + void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; } - // Render a frame - // A frame must have a scene registered and a context set to render - void run(); + // Push a RenderContext + void setRenderContext(const RenderContext& renderContext) { (*_renderContext) = renderContext; } + RenderContextPointer getRenderContext() const { return _renderContext; } + + // Render a frame + // A frame must have a scene registered and a context set to render + void run(); + + protected: + SceneContextPointer _sceneContext; + RenderContextPointer _renderContext; + }; + using EnginePointer = std::shared_ptr; + + + // A simple job collecting global stats on the Engine / Scene / GPU + class EngineStatsConfig : public Job::Config{ + Q_OBJECT + Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) + Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) + Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) + Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) + public: + EngineStatsConfig() : Job::Config(true) {} + + int numTextures{ 0 }; + int numGPUTextures{ 0 }; + qint64 textureSysmemUsage{ 0 }; + qint64 textureVidmemUsage{ 0 }; + + void emitDirty() { emit dirty(); } + + signals: + void dirty(); + }; + + class EngineStats { + public: + using Config = EngineStatsConfig; + using JobModel = Job::Model; + + EngineStats() {} + + void configure(const Config& configuration) {} + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + }; -protected: - SceneContextPointer _sceneContext; - RenderContextPointer _renderContext; -}; -using EnginePointer = std::shared_ptr; } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e17332a20f..61ebfe4515 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1,4 +1,4 @@ -d// +// // ScriptEngine.cpp // libraries/script-engine/src // From 851cbb1c4611334e68c5f861db56f51f16b7d149 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 16:07:41 -0700 Subject: [PATCH 04/61] change --- examples/utilities/tools/render/stats.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index eb7bb44a73..bc70358c54 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -19,7 +19,7 @@ Column { Repeater { model: [ - "num Textures:numTextures", + "num Textures:numTextures:1", "Sysmem Usage:textureSysmemUsage", "num GPU Textures:numGPUTextures", "Vidmem Usage:textureVidmemUsage" From 6d6f0398f53fb442ced4a97f67b8544354889877 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 17:52:06 -0700 Subject: [PATCH 05/61] TRying to create a graph :) --- examples/utilities/tools/render/stats.qml | 37 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index bc70358c54..7140f81270 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -11,6 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 + Column { spacing: 8 Column { @@ -28,12 +29,44 @@ Column { Label { text: qsTr(modelData.split(":")[0]) } - property var value: stats.config[modelData.split(":")[1]] + property var value: stats.config[modelData.split(":")[1]] + property var valueHistory : new Array() + property var valueMax : 1000 + property var tick : 0 Label { text: value horizontalAlignment: AlignRight } - + Canvas { + id: mycanvas + width: 100 + height: 200 + onPaint: { + tick++; + valueHistory.push(value) + if (valueHistory.length > 100) { + valueHistory.shift(); + } + var ctx = getContext("2d"); + if (tick % 2) { + ctx.fillStyle = Qt.rgba(0, 1, 0, 0.5); + } else { + ctx.fillStyle = Qt.rgba(0, 0, 0, 0.5); + } + ctx.fillRect(0, 0, width, height); + var widthStep= width / valueHistory.length; + ctx.lineWidth="5"; + ctx.beginPath(); + ctx.strokeStyle="green"; // Green path + ctx.moveTo(0,height); + + for (var i = 0; i < valueHistory.length; i++) { + ctx.lineTo(i * widthStep, height * (1 - valueHistory[i] / valueMax) ); + } + ctx.lineTo(width, height); + ctx.stroke(); // Draw it + } + } } } } From fc8b34f8c79d0940df835d6f9d49f02c515f12be Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 23 Mar 2016 14:01:11 -0700 Subject: [PATCH 06/61] Move tex alpha detection to cv method --- libraries/model/src/model/Material.cpp | 61 ++++++++++++++------------ libraries/model/src/model/Material.h | 12 ++--- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 0a6a4bb695..5260143a7f 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -83,41 +83,48 @@ void Material::setMetallic(float metallic) { void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { _key.setMapChannel(channel, (true)); - - if (channel == MaterialKey::ALBEDO_MAP) { - // clear the previous flags whatever they were: - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(false); - - if (textureMap->useAlphaChannel() && textureMap->isDefined() && textureMap->getTextureView().isValid()) { - auto usage = textureMap->getTextureView()._texture->getUsage(); - if (usage.isAlpha()) { - // Texture has alpha, is not just a mask or a true transparent channel - if (usage.isAlphaMask()) { - _key.setOpacityMaskMap(true); - _key.setTranslucentMap(false); - } else { - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(true); - } - } - } - } - _textureMaps[channel] = textureMap; } else { _key.setMapChannel(channel, (false)); - - if (channel == MaterialKey::ALBEDO_MAP) { - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(false); - } - _textureMaps.erase(channel); } _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); + if (channel == MaterialKey::ALBEDO_MAP) { + resetOpacityMap(); + } + + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); + +} + +void Material::resetOpacityMap() const { + // Clear the previous flags + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(false); + + const auto& textureMap = getTextureMap(MaterialKey::ALBEDO_MAP); + if (textureMap && + textureMap->useAlphaChannel() && + textureMap->isDefined() && + textureMap->getTextureView().isValid()) { + + auto usage = textureMap->getTextureView()._texture->getUsage(); + if (usage.isAlpha()) { + if (usage.isAlphaMask()) { + // Texture has alpha, but it is just a mask + _key.setOpacityMaskMap(true); + _key.setTranslucentMap(false); + } else { + // Texture has alpha, it is a true translucency channel + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(true); + } + } + } + + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 5a7b919994..c500e9ec10 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -291,15 +291,17 @@ public: const TextureMaps& getTextureMaps() const { return _textureMaps; } const TextureMapPointer getTextureMap(MapChannel channel) const; + // Albedo maps cannot have opacity detected until they are loaded + // This method allows const changing of the key/schemaBuffer without touching the map + void resetOpacityMap() const; + // conversion from legacy material properties to PBR equivalent static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; } -protected: - - MaterialKey _key; - UniformBufferView _schemaBuffer; +private: + mutable MaterialKey _key; + mutable UniformBufferView _schemaBuffer; TextureMaps _textureMaps; - }; typedef std::shared_ptr< Material > MaterialPointer; From 7f05e4453b6821bf6526255691522c83d431d1a2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 23 Mar 2016 14:01:22 -0700 Subject: [PATCH 07/61] Fetch model geometries through cache --- .../src/model-networking/ModelCache.cpp | 821 ++++++++---------- .../src/model-networking/ModelCache.h | 266 +++--- 2 files changed, 493 insertions(+), 594 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index b0b769d5e9..bb7efb8f75 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -1,53 +1,101 @@ // // ModelCache.cpp -// interface/src/renderer +// libraries/model-networking // -// Created by Andrzej Kapolka on 6/21/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Zach Pomerantz on 3/15/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 "ModelCache.h" +#include +#include "FBXReader.h" +#include "OBJReader.h" -#include +#include +#include -#include #include -#include -#include - -#include "TextureCache.h" #include "ModelNetworkingLogging.h" -#include "model/TextureMap.h" +class GeometryReader; -//#define WANT_DEBUG +class GeometryExtra { +public: + const QVariantHash& mapping; + const QUrl& textureBaseUrl; +}; -ModelCache::ModelCache() -{ - const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; - setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE); +class GeometryMappingResource : public GeometryResource { + Q_OBJECT +public: + GeometryMappingResource(const QUrl& url) : GeometryResource(url) {}; + + virtual void downloadFinished(const QByteArray& data) override; + +private slots: + void onGeometryMappingLoaded(bool success); + +private: + GeometryResource::Pointer _geometryResource; +}; + +void GeometryMappingResource::downloadFinished(const QByteArray& data) { + auto mapping = FSTReader::readMapping(data); + + QString filename = mapping.value("filename").toString(); + if (filename.isNull()) { + qCDebug(modelnetworking) << "Mapping file" << _url << "has no \"filename\" field"; + finishedLoading(false); + } else { + QUrl url = _url.resolved(filename); + QUrl textureBaseUrl; + + QString texdir = mapping.value("texdir").toString(); + if (!texdir.isNull()) { + if (!texdir.endsWith('/')) { + texdir += '/'; + } + textureBaseUrl = _url.resolved(texdir); + } + + auto modelCache = DependencyManager::get(); + GeometryExtra extra{ mapping, textureBaseUrl }; + + // Get the raw GeometryResource, not the wrapped NetworkGeometry + _geometryResource = modelCache->getResource(url, QUrl(), true, &extra).staticCast(); + connect(_geometryResource.data(), &Resource::finished, this, &GeometryMappingResource::onGeometryMappingLoaded); + } } -ModelCache::~ModelCache() { +void GeometryMappingResource::onGeometryMappingLoaded(bool success) { + if (success) { + _geometry = _geometryResource->_geometry; + _shapes = _geometryResource->_shapes; + _meshes = _geometryResource->_meshes; + _materials = _geometryResource->_materials; + } + finishedLoading(success); } -QSharedPointer ModelCache::createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra) { - // NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual. - assert(false); - return QSharedPointer(); -} +class GeometryReader : public QRunnable { +public: + GeometryReader(QWeakPointer& resource, const QUrl& url, const QVariantHash& mapping, + const QByteArray& data) : + _resource(resource), _url(url), _mapping(mapping), _data(data) {} + virtual ~GeometryReader() = default; + virtual void run() override; -GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) : - _url(url), - _data(data), - _mapping(mapping) { -} +private: + QWeakPointer _resource; + QUrl _url; + QVariantHash _mapping; + QByteArray _data; +}; void GeometryReader::run() { auto originalPriority = QThread::currentThread()->priority(); @@ -55,458 +103,353 @@ void GeometryReader::run() { originalPriority = QThread::NormalPriority; } QThread::currentThread()->setPriority(QThread::LowPriority); + + // Ensure the resource is still being requested + auto resource = _resource.toStrongRef(); + if (!resource) { + qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref"; + return; + } + try { if (_data.isEmpty()) { - throw QString("Reply is NULL ?!"); + throw QString("reply is NULL"); } - QString urlname = _url.path().toLower(); - bool urlValid = true; - urlValid &= !urlname.isEmpty(); - urlValid &= !_url.path().isEmpty(); - urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"); - if (urlValid) { - // Let's read the binaries from the network - FBXGeometry* fbxgeo = nullptr; + QString urlname = _url.path().toLower(); + if (!urlname.isEmpty() && !_url.path().isEmpty() && + (_url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"))) { + FBXGeometry* fbxGeometry = nullptr; + if (_url.path().toLower().endsWith(".fbx")) { - const bool grabLightmaps = true; - const float lightmapLevel = 1.0f; - fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel); - if (fbxgeo->meshes.size() == 0 && fbxgeo->joints.size() == 0) { - // empty fbx geometry, indicates error + fbxGeometry = readFBX(_data, _mapping, _url.path()); + if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) { throw QString("empty geometry, possibly due to an unsupported FBX version"); } } else if (_url.path().toLower().endsWith(".obj")) { - fbxgeo = OBJReader().readOBJ(_data, _mapping, _url); + fbxGeometry = OBJReader().readOBJ(_data, _mapping, _url); } else { - QString errorStr("unsupported format"); - throw errorStr; + throw QString("unsupported format"); } - emit onSuccess(fbxgeo); + + QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition", + Q_ARG(void*, fbxGeometry)); } else { throw QString("url is invalid"); } - } catch (const QString& error) { qCDebug(modelnetworking) << "Error reading " << _url << ": " << error; - emit onError(NetworkGeometry::ModelParseError, error); + QMetaObject::invokeMethod(resource.data(), "finishedLoading", Q_ARG(bool, false)); } QThread::currentThread()->setPriority(originalPriority); } -NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) : - _url(url), - _mapping(mapping), - _textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) { +class GeometryDefinitionResource : public GeometryResource { + Q_OBJECT +public: + GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) : + GeometryResource(url), _mapping(mapping), _textureBaseUrl(textureBaseUrl) {} - if (delayLoad) { - _state = DelayState; - } else { - attemptRequestInternal(); - } + virtual void downloadFinished(const QByteArray& data) override; + +protected: + Q_INVOKABLE void setGeometryDefinition(void* fbxGeometry); + +private: + QVariantHash _mapping; + QUrl _textureBaseUrl; +}; + +void GeometryDefinitionResource::downloadFinished(const QByteArray& data) { + QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data)); } -NetworkGeometry::~NetworkGeometry() { - if (_resource) { - _resource->deleteLater(); - } -} +void GeometryDefinitionResource::setGeometryDefinition(void* fbxGeometry) { + // Assume ownership of the geometry pointer + _geometry.reset(static_cast(fbxGeometry)); -void NetworkGeometry::attemptRequest() { - if (_state == DelayState) { - attemptRequestInternal(); - } -} - -void NetworkGeometry::attemptRequestInternal() { - if (_url.path().toLower().endsWith(".fst")) { - _mappingUrl = _url; - requestMapping(_url); - } else { - _modelUrl = _url; - requestModel(_url); - } -} - -bool NetworkGeometry::isLoaded() const { - return _state == SuccessState; -} - -bool NetworkGeometry::isLoadedWithTextures() const { - if (!isLoaded()) { - return false; + // Copy materials + QHash materialIDAtlas; + for (const FBXMaterial& material : _geometry->materials) { + materialIDAtlas[material.materialID] = _materials.size(); + _materials.push_back(std::make_shared(material, _textureBaseUrl)); } - if (!_isLoadedWithTextures) { - _hasTransparentTextures = false; - - for (auto&& material : _materials) { - if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || - (material->normalTexture && !material->normalTexture->isLoaded()) || - (material->roughnessTexture && !material->roughnessTexture->isLoaded()) || - (material->metallicTexture && !material->metallicTexture->isLoaded()) || - (material->occlusionTexture && !material->occlusionTexture->isLoaded()) || - (material->emissiveTexture && !material->emissiveTexture->isLoaded()) || - (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { - return false; - } - if (material->albedoTexture && material->albedoTexture->getGPUTexture()) { - // Reassign the texture to make sure that itsalbedo alpha channel material key is detected correctly - material->_material->setTextureMap(model::MaterialKey::ALBEDO_MAP, material->_material->getTextureMap(model::MaterialKey::ALBEDO_MAP)); - const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); - bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); - _hasTransparentTextures |= isTransparentTexture; - } - } - - _isLoadedWithTextures = true; - } - return true; -} - -void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) { - if (_meshes.size() > 0) { - auto textureCache = DependencyManager::get(); - for (auto&& material : _materials) { - auto networkMaterial = material->_material; - auto oldTextureMaps = networkMaterial->getTextureMaps(); - if (material->albedoTextureName == name) { - material->albedoTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); - - auto albedoMap = model::TextureMapPointer(new model::TextureMap()); - albedoMap->setTextureSource(material->albedoTexture->_textureSource); - albedoMap->setTextureTransform(oldTextureMaps[model::MaterialKey::ALBEDO_MAP]->getTextureTransform()); - // when reassigning the albedo texture we also check for the alpha channel used as opacity - albedoMap->setUseAlphaChannel(true); - networkMaterial->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); - } else if (material->normalTextureName == name) { - material->normalTexture = textureCache->getTexture(url); - - auto normalMap = model::TextureMapPointer(new model::TextureMap()); - normalMap->setTextureSource(material->normalTexture->_textureSource); - - networkMaterial->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); - } else if (material->roughnessTextureName == name) { - // FIXME: If passing a gloss map instead of a roughmap how to say that ? looking for gloss in the name ? - material->roughnessTexture = textureCache->getTexture(url, ROUGHNESS_TEXTURE); - - auto roughnessMap = model::TextureMapPointer(new model::TextureMap()); - roughnessMap->setTextureSource(material->roughnessTexture->_textureSource); - - networkMaterial->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); - } else if (material->metallicTextureName == name) { - // FIXME: If passing a specular map instead of a metallic how to say that ? looking for wtf in the name ? - material->metallicTexture = textureCache->getTexture(url, METALLIC_TEXTURE); - - auto glossMap = model::TextureMapPointer(new model::TextureMap()); - glossMap->setTextureSource(material->metallicTexture->_textureSource); - - networkMaterial->setTextureMap(model::MaterialKey::METALLIC_MAP, glossMap); - } else if (material->emissiveTextureName == name) { - material->emissiveTexture = textureCache->getTexture(url, EMISSIVE_TEXTURE); - - auto emissiveMap = model::TextureMapPointer(new model::TextureMap()); - emissiveMap->setTextureSource(material->emissiveTexture->_textureSource); - - networkMaterial->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); - } else if (material->lightmapTextureName == name) { - material->lightmapTexture = textureCache->getTexture(url, LIGHTMAP_TEXTURE); - - auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); - lightmapMap->setTextureSource(material->lightmapTexture->_textureSource); - lightmapMap->setTextureTransform( - oldTextureMaps[model::MaterialKey::LIGHTMAP_MAP]->getTextureTransform()); - glm::vec2 oldOffsetScale = - oldTextureMaps[model::MaterialKey::LIGHTMAP_MAP]->getLightmapOffsetScale(); - lightmapMap->setLightmapOffsetScale(oldOffsetScale.x, oldOffsetScale.y); - - networkMaterial->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); - } - } - } else { - qCWarning(modelnetworking) << "Ignoring setTextureWithNameToURL() geometry not ready." << name << url; - } - _isLoadedWithTextures = false; -} - -QStringList NetworkGeometry::getTextureNames() const { - QStringList result; - for (auto&& material : _materials) { - if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) { - QString textureURL = material->emissiveTexture->getURL().toString(); - result << material->emissiveTextureName + ":\"" + textureURL + "\""; - } - - if (!material->albedoTextureName.isEmpty() && material->albedoTexture) { - QString textureURL = material->albedoTexture->getURL().toString(); - result << material->albedoTextureName + ":\"" + textureURL + "\""; - } - - if (!material->normalTextureName.isEmpty() && material->normalTexture) { - QString textureURL = material->normalTexture->getURL().toString(); - result << material->normalTextureName + ":\"" + textureURL + "\""; - } - - if (!material->roughnessTextureName.isEmpty() && material->roughnessTexture) { - QString textureURL = material->roughnessTexture->getURL().toString(); - result << material->roughnessTextureName + ":\"" + textureURL + "\""; - } - - if (!material->metallicTextureName.isEmpty() && material->metallicTexture) { - QString textureURL = material->metallicTexture->getURL().toString(); - result << material->metallicTextureName + ":\"" + textureURL + "\""; - } - - if (!material->occlusionTextureName.isEmpty() && material->occlusionTexture) { - QString textureURL = material->occlusionTexture->getURL().toString(); - result << material->occlusionTextureName + ":\"" + textureURL + "\""; - } - - if (!material->lightmapTextureName.isEmpty() && material->lightmapTexture) { - QString textureURL = material->lightmapTexture->getURL().toString(); - result << material->lightmapTextureName + ":\"" + textureURL + "\""; - } - } - - return result; -} - -void NetworkGeometry::requestMapping(const QUrl& url) { - _state = RequestMappingState; - if (_resource) { - _resource->deleteLater(); - } - _resource = new Resource(url, false); - connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone); - connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError); -} - -void NetworkGeometry::requestModel(const QUrl& url) { - _state = RequestModelState; - if (_resource) { - _resource->deleteLater(); - } - _modelUrl = url; - _resource = new Resource(url, false); - connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone); - connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError); -} - -void NetworkGeometry::mappingRequestDone(const QByteArray& data) { - assert(_state == RequestMappingState); - - // parse the mapping file - _mapping = FSTReader::readMapping(data); - - QUrl replyUrl = _mappingUrl; - QString modelUrlStr = _mapping.value("filename").toString(); - if (modelUrlStr.isNull()) { - qCDebug(modelnetworking) << "Mapping file " << _url << "has no \"filename\" entry"; - emit onFailure(*this, MissingFilenameInMapping); - } else { - // read _textureBase from mapping file, if present - QString texdir = _mapping.value("texdir").toString(); - if (!texdir.isNull()) { - if (!texdir.endsWith('/')) { - texdir += '/'; - } - _textureBaseUrl = replyUrl.resolved(texdir); - } - - _modelUrl = replyUrl.resolved(modelUrlStr); - requestModel(_modelUrl); - } -} - -void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) { - assert(_state == RequestMappingState); - _state = ErrorState; - emit onFailure(*this, MappingRequestError); -} - -void NetworkGeometry::modelRequestDone(const QByteArray& data) { - assert(_state == RequestModelState); - - _state = ParsingModelState; - - // asynchronously parse the model file. - GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping); - connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*))); - connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString))); - - QThreadPool::globalInstance()->start(geometryReader); -} - -void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) { - assert(_state == RequestModelState); - _state = ErrorState; - emit onFailure(*this, ModelRequestError); -} - -static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) { - NetworkMesh* networkMesh = new NetworkMesh(); - - networkMesh->_mesh = mesh._mesh; - - return networkMesh; -} - - -static model::TextureMapPointer setupNetworkTextureMap(NetworkGeometry* geometry, const QUrl& textureBaseUrl, - const FBXTexture& texture, TextureType type, - NetworkTexturePointer& networkTexture, QString& networkTextureName) { - auto textureCache = DependencyManager::get(); - - // If content is inline, cache it under the fbx file, not its base url - const auto baseUrl = texture.content.isEmpty() ? textureBaseUrl : QUrl(textureBaseUrl.url() + "/"); - const auto filename = baseUrl.resolved(QUrl(texture.filename)); - - networkTexture = textureCache->getTexture(filename, type, texture.content); - QObject::connect(networkTexture.data(), &NetworkTexture::networkTextureCreated, geometry, &NetworkGeometry::textureLoaded); - networkTextureName = texture.name; - - auto map = std::make_shared(); - map->setTextureSource(networkTexture->_textureSource); - return map; -} - -static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FBXMaterial& material, const QUrl& textureBaseUrl) { - NetworkMaterial* networkMaterial = new NetworkMaterial(); - networkMaterial->_material = material._material; - - if (!material.albedoTexture.filename.isEmpty()) { - auto albedoMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, - networkMaterial->albedoTexture, networkMaterial->albedoTextureName); - albedoMap->setTextureTransform(material.albedoTexture.transform); - - if (!material.opacityTexture.filename.isEmpty()) { - if (material.albedoTexture.filename == material.opacityTexture.filename) { - // Best case scenario, just indicating that the albedo map contains transparency - albedoMap->setUseAlphaChannel(true); - } else { - // Opacity Map is different from the Abledo map, not supported - } - } - - material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); - } - - - if (!material.normalTexture.filename.isEmpty()) { - auto normalMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.normalTexture, - (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), - networkMaterial->normalTexture, networkMaterial->normalTextureName); - networkMaterial->_material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); - } - - // Roughness first or gloss maybe - if (!material.roughnessTexture.filename.isEmpty()) { - auto roughnessMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.roughnessTexture, ROUGHNESS_TEXTURE, - networkMaterial->roughnessTexture, networkMaterial->roughnessTextureName); - material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); - } else if (!material.glossTexture.filename.isEmpty()) { - auto roughnessMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.glossTexture, GLOSS_TEXTURE, - networkMaterial->roughnessTexture, networkMaterial->roughnessTextureName); - material._material->setTextureMap(model::MaterialKey::ROUGHNESS_MAP, roughnessMap); - } - - // Metallic first or specular maybe - - if (!material.metallicTexture.filename.isEmpty()) { - auto metallicMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.metallicTexture, METALLIC_TEXTURE, - networkMaterial->metallicTexture, networkMaterial->metallicTextureName); - material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); - } else if (!material.specularTexture.filename.isEmpty()) { - - auto metallicMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.specularTexture, SPECULAR_TEXTURE, - networkMaterial->metallicTexture, networkMaterial->metallicTextureName); - material._material->setTextureMap(model::MaterialKey::METALLIC_MAP, metallicMap); - } - - if (!material.occlusionTexture.filename.isEmpty()) { - auto occlusionMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.occlusionTexture, OCCLUSION_TEXTURE, - networkMaterial->occlusionTexture, networkMaterial->occlusionTextureName); - material._material->setTextureMap(model::MaterialKey::OCCLUSION_MAP, occlusionMap); - } - - if (!material.emissiveTexture.filename.isEmpty()) { - auto emissiveMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.emissiveTexture, EMISSIVE_TEXTURE, - networkMaterial->emissiveTexture, networkMaterial->emissiveTextureName); - material._material->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); - } - - if (!material.lightmapTexture.filename.isEmpty()) { - auto lightmapMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.lightmapTexture, LIGHTMAP_TEXTURE, - networkMaterial->lightmapTexture, networkMaterial->lightmapTextureName); - lightmapMap->setTextureTransform(material.lightmapTexture.transform); - lightmapMap->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y); - material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); - } - - return networkMaterial; -} - - -void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) { - // assume owner ship of geometry pointer - _geometry.reset(geometry); - - - - foreach(const FBXMesh& mesh, _geometry->meshes) { - _meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl)); - } - - QHash fbxMatIDToMatID; - foreach(const FBXMaterial& material, _geometry->materials) { - fbxMatIDToMatID[material.materialID] = _materials.size(); - _materials.emplace_back(buildNetworkMaterial(this, material, _textureBaseUrl)); - } - - + std::shared_ptr meshes = std::make_shared(); + std::shared_ptr shapes = std::make_shared(); int meshID = 0; - foreach(const FBXMesh& mesh, _geometry->meshes) { + for (const FBXMesh& mesh : _geometry->meshes) { + // Copy mesh pointers + meshes->emplace_back(mesh._mesh); int partID = 0; - foreach (const FBXMeshPart& part, mesh.parts) { - NetworkShape* networkShape = new NetworkShape(); - networkShape->_meshID = meshID; - networkShape->_partID = partID; - networkShape->_materialID = (int)fbxMatIDToMatID[part.materialID]; - _shapes.emplace_back(networkShape); + for (const FBXMeshPart& part : mesh.parts) { + // Construct local shapes + shapes->emplace_back(meshID, partID, (int)materialIDAtlas[part.materialID]); partID++; } meshID++; } + _meshes = meshes; + _shapes = shapes; - _state = SuccessState; - emit onSuccess(*this, *_geometry.get()); - - delete _resource; - _resource = nullptr; + finishedLoading(true); } -void NetworkGeometry::modelParseError(int error, QString str) { - _state = ErrorState; - emit onFailure(*this, (NetworkGeometry::Error)error); - - delete _resource; - _resource = nullptr; +ModelCache::ModelCache() { + const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; + setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE); } -const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) { - if ((shapeID >= 0) && (shapeID < (int)_shapes.size())) { - int materialID = _shapes[shapeID]->_materialID; - if ((materialID >= 0) && ((unsigned int)materialID < _materials.size())) { - return _materials[materialID].get(); - } else { - return 0; +QSharedPointer ModelCache::createResource(const QUrl& url, const QSharedPointer& fallback, + bool delayLoad, const void* extra) { + const GeometryExtra* geometryExtra = static_cast(extra); + + Resource* resource = nullptr; + if (url.path().toLower().endsWith(".fst")) { + resource = new GeometryMappingResource(url); + } else { + resource = new GeometryDefinitionResource(url, geometryExtra->mapping, geometryExtra->textureBaseUrl); + } + + return QSharedPointer(resource, &Resource::allReferencesCleared); +} + +std::shared_ptr ModelCache::getGeometry(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) { + GeometryExtra geometryExtra = { mapping, textureBaseUrl }; + GeometryResource::Pointer resource = getResource(url, QUrl(), true, &geometryExtra).staticCast(); + return std::make_shared(resource); +} + +const QVariantMap Geometry::getTextures() const { + QVariantMap textures; + for (const auto& material : _materials) { + for (const auto& texture : material->_textures) { + if (texture.texture) { + textures[texture.name] = texture.texture->getURL(); + } + } + } + + return textures; +} + +void Geometry::setTextures(const QVariantMap& textureMap) { + if (_meshes->size() > 0) { + for (auto& material : _materials) { + // Check if any material textures actually changed + if (std::any_of(material->_textures.cbegin(), material->_textures.cend(), + [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.texture && textureMap.contains(it.name); })) { + + material = std::make_shared(*material, textureMap); + _areTexturesLoaded = false; + } } } else { - return 0; + qCWarning(modelnetworking) << "Ignoring setTextures(); geometry not ready"; } } -void NetworkGeometry::textureLoaded(const QWeakPointer& networkTexture) { - numTextureLoaded++; +bool Geometry::areTexturesLoaded() const { + if (!_areTexturesLoaded) { + _hasTransparentTextures = false; + + for (auto& material : _materials) { + // Check if material textures are loaded + if (std::any_of(material->_textures.cbegin(), material->_textures.cend(), + [](const NetworkMaterial::Textures::value_type& it) { return it.texture && !it.texture->isLoaded(); })) { + + return false; + } + + // If material textures are loaded, check the material translucency + const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP]; + if (albedoTexture.texture && albedoTexture.texture->getGPUTexture()) { + material->resetOpacityMap(); + + _hasTransparentTextures |= material->getKey().isTranslucent(); + } + } + + _areTexturesLoaded = true; + } + return true; } + +const std::shared_ptr Geometry::getShapeMaterial(int shapeID) const { + if ((shapeID >= 0) && (shapeID < (int)_shapes->size())) { + int materialID = _shapes->at(shapeID).materialID; + if ((materialID >= 0) && (materialID < (int)_materials.size())) { + return _materials[materialID]; + } + } + return nullptr; +} + +NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometry) : _resource(networkGeometry) { + connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished); + connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed); + if (_resource->isLoaded()) { + resourceFinished(); + } +} + +void NetworkGeometry::resourceFinished() { + _instance = std::make_shared(*_resource); +} + +void NetworkGeometry::resourceRefreshed() { + _instance.reset(); +} + +const QString NetworkMaterial::NO_TEXTURE = QString(); + +const QString& NetworkMaterial::getTextureName(MapChannel channel) { + if (_textures[channel].texture) { + return _textures[channel].name; + } + return NO_TEXTURE; +} + +QUrl NetworkMaterial::getTextureUrl(const QUrl& url, const FBXTexture& texture) { + // If content is inline, cache it under the fbx file, not its url + const auto baseUrl = texture.content.isEmpty() ? url: QUrl(url.url() + "/"); + return baseUrl.resolved(QUrl(texture.filename)); +} + +model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, + TextureType type, MapChannel channel) { + const auto url = getTextureUrl(baseUrl, fbxTexture); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content); + _textures[channel] = Texture { fbxTexture.name, texture }; + + auto map = std::make_shared(); + map->setTextureSource(texture->_textureSource); + return map; +} + +model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, TextureType type, MapChannel channel) { + const auto texture = DependencyManager::get()->getTexture(url, type); + _textures[channel].texture = texture; + + auto map = std::make_shared(); + map->setTextureSource(texture->_textureSource); + return map; +} + +NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { + _textures = Textures(MapChannel::NUM_MAP_CHANNELS); + if (!material.albedoTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); + map->setTextureTransform(material.albedoTexture.transform); + + if (!material.opacityTexture.filename.isEmpty()) { + if (material.albedoTexture.filename == material.opacityTexture.filename) { + // Best case scenario, just indicating that the albedo map contains transparency + // TODO: Different albedo/opacity maps are not currently supported + map->setUseAlphaChannel(true); + } + } + + setTextureMap(MapChannel::ALBEDO_MAP, map); + } + + + if (!material.normalTexture.filename.isEmpty()) { + auto type = (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE); + auto map = fetchTextureMap(textureBaseUrl, material.normalTexture, type, MapChannel::NORMAL_MAP); + setTextureMap(MapChannel::NORMAL_MAP, map); + } + + if (!material.roughnessTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.roughnessTexture, ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } else if (!material.glossTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.glossTexture, GLOSS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } + + if (!material.metallicTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.metallicTexture, METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } else if (!material.specularTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.specularTexture, SPECULAR_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } + + if (!material.occlusionTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.occlusionTexture, OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + setTextureMap(MapChannel::OCCLUSION_MAP, map); + } + + if (!material.emissiveTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.emissiveTexture, EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } + + if (!material.lightmapTexture.filename.isEmpty()) { + auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + map->setTextureTransform(material.lightmapTexture.transform); + map->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y); + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } +} + +NetworkMaterial::NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap) : NetworkMaterial(material) { + _textures = material._textures; + + const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); + const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); + const auto& roughnessName = getTextureName(MapChannel::ROUGHNESS_MAP); + const auto& metallicName = getTextureName(MapChannel::METALLIC_MAP); + const auto& occlusionName = getTextureName(MapChannel::OCCLUSION_MAP); + const auto& emissiveName = getTextureName(MapChannel::EMISSIVE_MAP); + const auto& lightmapName = getTextureName(MapChannel::LIGHTMAP_MAP); + + if (!albedoName.isEmpty() && textureMap.contains(albedoName)) { + auto map = fetchTextureMap(textureMap[albedoName].toUrl(), DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); + map->setTextureTransform(getTextureMap(MapChannel::ALBEDO_MAP)->getTextureTransform()); + // when reassigning the albedo texture we also check for the alpha channel used as opacity + map->setUseAlphaChannel(true); + setTextureMap(MapChannel::ALBEDO_MAP, map); + } + + if (!normalName.isEmpty() && textureMap.contains(normalName)) { + auto map = fetchTextureMap(textureMap[normalName].toUrl(), DEFAULT_TEXTURE, MapChannel::NORMAL_MAP); + setTextureMap(MapChannel::NORMAL_MAP, map); + } + + if (!roughnessName.isEmpty() && textureMap.contains(roughnessName)) { + // FIXME: If passing a gloss map instead of a roughmap how do we know? + auto map = fetchTextureMap(textureMap[roughnessName].toUrl(), ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + setTextureMap(MapChannel::ROUGHNESS_MAP, map); + } + + if (!metallicName.isEmpty() && textureMap.contains(metallicName)) { + // FIXME: If passing a specular map instead of a metallic how do we know? + auto map = fetchTextureMap(textureMap[metallicName].toUrl(), METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + setTextureMap(MapChannel::METALLIC_MAP, map); + } + + if (!occlusionName.isEmpty() && textureMap.contains(occlusionName)) { + auto map = fetchTextureMap(textureMap[occlusionName].toUrl(), OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + setTextureMap(MapChannel::OCCLUSION_MAP, map); + } + + if (!emissiveName.isEmpty() && textureMap.contains(emissiveName)) { + auto map = fetchTextureMap(textureMap[emissiveName].toUrl(), EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + setTextureMap(MapChannel::EMISSIVE_MAP, map); + } + + if (!lightmapName.isEmpty() && textureMap.contains(lightmapName)) { + auto map = fetchTextureMap(textureMap[lightmapName].toUrl(), LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + auto oldMap = getTextureMap(MapChannel::LIGHTMAP_MAP); + map->setTextureTransform(oldMap->getTextureTransform()); + glm::vec2 offsetScale = oldMap->getLightmapOffsetScale(); + map->setLightmapOffsetScale(offsetScale.x, offsetScale.y); + setTextureMap(MapChannel::LIGHTMAP_MAP, map); + } +} + +#include "ModelCache.moc" + diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 1c76a0b878..a2fcc9d741 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -1,9 +1,9 @@ // // ModelCache.h -// libraries/model-networking/src/model-networking +// libraries/model-networking // -// Created by Sam Gateau on 9/21/15. -// Copyright 2013 High Fidelity, Inc. +// Created by Zach Pomerantz on 3/15/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 @@ -12,200 +12,156 @@ #ifndef hifi_ModelCache_h #define hifi_ModelCache_h -#include -#include - #include #include -#include "FBXReader.h" -#include "OBJReader.h" - -#include -#include - - #include #include -class NetworkGeometry; -class NetworkMesh; +#include "FBXReader.h" +#include "TextureCache.h" + +// Alias instead of derive to avoid copying +using NetworkMesh = model::Mesh; + class NetworkTexture; class NetworkMaterial; class NetworkShape; +class NetworkGeometry; -/// Stores cached geometry. +class GeometryMappingResource; + +/// Stores cached model geometries. class ModelCache : public ResourceCache, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra); + /// Loads a model geometry from the specified URL. + std::shared_ptr getGeometry(const QUrl& url, + const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl()); - /// Loads geometry from the specified URL. - /// \param fallback a fallback URL to load if the desired one is unavailable - /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested - QSharedPointer getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); +protected: + friend class GeometryMappingResource; + + virtual QSharedPointer createResource(const QUrl& url, + const QSharedPointer& fallback, bool delayLoad, const void* extra); private: ModelCache(); - virtual ~ModelCache(); + virtual ~ModelCache() = default; +}; - QHash > _networkGeometry; +class Geometry { +public: + using Pointer = std::shared_ptr; + + // Immutable over lifetime + using NetworkMeshes = std::vector>; + using NetworkShapes = std::vector; + + // Mutable, but must retain structure of vector + using NetworkMaterials = std::vector>; + + const FBXGeometry& getGeometry() const { return *_geometry; } + const NetworkMeshes& getMeshes() const { return *_meshes; } + const std::shared_ptr getShapeMaterial(int shapeID) const; + + const QVariantMap getTextures() const; + void setTextures(const QVariantMap& textureMap); + + virtual bool areTexturesLoaded() const; + // Returns true if any albedo texture has a non-masking alpha channel. + // This can only be known after areTexturesLoaded(). + bool hasTransparentTextures() const { return _hasTransparentTextures; } + +protected: + friend class GeometryMappingResource; + + // Shared across all geometries, constant throughout lifetime + std::shared_ptr _geometry; + std::shared_ptr _meshes; + std::shared_ptr _shapes; + + // Copied to each geometry, mutable throughout lifetime via setTextures + NetworkMaterials _materials; + +private: + mutable bool _areTexturesLoaded { false }; + mutable bool _hasTransparentTextures { false }; +}; + +/// A geometry loaded from the network. +class GeometryResource : public Resource, public Geometry { +public: + using Pointer = QSharedPointer; + + GeometryResource(const QUrl& url) : Resource(url) {} + + virtual bool areTexturesLoaded() const { return isLoaded() && Geometry::areTexturesLoaded(); } + +protected: + virtual bool isCacheable() const override { return _loaded; } }; class NetworkGeometry : public QObject { Q_OBJECT - public: - // mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file. - // if delayLoad is true, the url will not be immediately downloaded. - // use the attemptRequest method to initiate the download. - NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl()); - ~NetworkGeometry(); + using Pointer = std::shared_ptr; - const QUrl& getURL() const { return _url; } + NetworkGeometry() = delete; + NetworkGeometry(const GeometryResource::Pointer& networkGeometry); - void attemptRequest(); + const QUrl& getURL() { return _resource->getURL(); } - // true when the geometry is loaded (but maybe not it's associated textures) - bool isLoaded() const; + /// Returns the geometry, if it is loaded (must be checked!) + const Geometry::Pointer& getGeometry() { return _instance; } - // true when the requested geometry and its textures are loaded. - bool isLoadedWithTextures() const; +private slots: + void resourceFinished(); + void resourceRefreshed(); - // true if the albedo texture has a non-masking alpha channel. - // This can only be known after isLoadedWithTextures(). - bool hasTransparentTextures() const { return _hasTransparentTextures; } +private: + GeometryResource::Pointer _resource; + Geometry::Pointer _instance { nullptr }; +}; - // WARNING: only valid when isLoaded returns true. - const FBXGeometry& getFBXGeometry() const { return *_geometry; } - const std::vector>& getMeshes() const { return _meshes; } - // const model::AssetPointer getAsset() const { return _asset; } - - // model::MeshPointer getShapeMesh(int shapeID); - // int getShapePart(int shapeID); - - // This would be the final verison - // model::MaterialPointer getShapeMaterial(int shapeID); - const NetworkMaterial* getShapeMaterial(int shapeID); - - - void setTextureWithNameToURL(const QString& name, const QUrl& url); - QStringList getTextureNames() const; - - enum Error { - MissingFilenameInMapping = 0, - MappingRequestError, - ModelRequestError, - ModelParseError - }; - -signals: - // Fired when everything has downloaded and parsed successfully. - void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry); - - // Fired when something went wrong. - void onFailure(NetworkGeometry& networkGeometry, Error error); - -public slots: - void textureLoaded(const QWeakPointer& networkTexture); - -protected slots: - void mappingRequestDone(const QByteArray& data); - void mappingRequestError(QNetworkReply::NetworkError error); - - void modelRequestDone(const QByteArray& data); - void modelRequestError(QNetworkReply::NetworkError error); - - void modelParseSuccess(FBXGeometry* geometry); - void modelParseError(int error, QString str); +class NetworkMaterial : public model::Material { +public: + using MapChannel = model::Material::MapChannel; + NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); + NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap); protected: - void attemptRequestInternal(); - void requestMapping(const QUrl& url); - void requestModel(const QUrl& url); + friend class Geometry; - enum State { DelayState, - RequestMappingState, - RequestModelState, - ParsingModelState, - SuccessState, - ErrorState }; - State _state; + class Texture { + public: + QString name; + QSharedPointer texture; + }; + using Textures = std::vector; - QUrl _url; - QUrl _mappingUrl; - QUrl _modelUrl; - QVariantHash _mapping; - QUrl _textureBaseUrl; - int numTextureLoaded = 0; + Textures _textures; - Resource* _resource = nullptr; - std::unique_ptr _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer - std::vector> _meshes; - std::vector> _materials; - std::vector> _shapes; + static const QString NO_TEXTURE; + const QString& getTextureName(MapChannel channel); - - // The model asset created from this NetworkGeometry - // model::AssetPointer _asset; - - // cache for isLoadedWithTextures() - mutable bool _isLoadedWithTextures = false; - mutable bool _hasTransparentTextures = false; -}; - -/// Reads geometry in a worker thread. -class GeometryReader : public QObject, public QRunnable { - Q_OBJECT -public: - GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping); - virtual void run(); -signals: - void onSuccess(FBXGeometry* geometry); - void onError(int error, QString str); private: - QUrl _url; - QByteArray _data; - QVariantHash _mapping; + // Helpers for the ctors + QUrl getTextureUrl(const QUrl& baseUrl, const FBXTexture& fbxTexture); + model::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, + TextureType type, MapChannel channel); + model::TextureMapPointer fetchTextureMap(const QUrl& url, TextureType type, MapChannel channel); }; - class NetworkShape { public: - int _meshID{ -1 }; - int _partID{ -1 }; - int _materialID{ -1 }; + NetworkShape(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {} + int meshID { -1 }; + int partID { -1 }; + int materialID { -1 }; }; -class NetworkMaterial { -public: - - model::MaterialPointer _material; - QString emissiveTextureName; - QSharedPointer emissiveTexture; - QString albedoTextureName; - QSharedPointer albedoTexture; - QString normalTextureName; - QSharedPointer normalTexture; - QString roughnessTextureName; - QSharedPointer roughnessTexture; - QString metallicTextureName; - QSharedPointer metallicTexture; - QString occlusionTextureName; - QSharedPointer occlusionTexture; - QString lightmapTextureName; - QSharedPointer lightmapTexture; -}; - - -/// The state associated with a single mesh. -class NetworkMesh { -public: - model::MeshPointer _mesh; -}; - -#endif // hifi_GeometryCache_h +#endif // hifi_ModelCache_h From 3e9e083df56146ed29d12e7f3c15b42e166b412a Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 23 Mar 2016 19:21:38 -0700 Subject: [PATCH 08/61] Update users of NetworkGeometry --- interface/src/avatar/Avatar.cpp | 12 +- interface/src/avatar/MyAvatar.cpp | 4 +- interface/src/avatar/SkeletonModel.cpp | 26 ++-- interface/src/avatar/SkeletonModel.h | 4 +- interface/src/avatar/SoftAttachmentModel.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 11 +- .../src/RenderableModelEntityItem.cpp | 76 +++------- .../src/RenderableModelEntityItem.h | 5 +- .../entities/src/EntityItemProperties.cpp | 4 +- libraries/entities/src/EntityItemProperties.h | 6 +- .../render-utils/src/MeshPartPayload.cpp | 23 +-- libraries/render-utils/src/MeshPartPayload.h | 8 +- libraries/render-utils/src/Model.cpp | 131 ++++++++---------- libraries/render-utils/src/Model.h | 50 +++---- 14 files changed, 158 insertions(+), 204 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7b63b7fc5a..778f5af4c8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -466,8 +466,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { * (1.0f - ((float)(now - getHead()->getLookingAtMeStarted())) / (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND)); if (alpha > 0.0f) { - QSharedPointer geometry = _skeletonModel->getGeometry(); - if (geometry && geometry->isLoaded()) { + if (_skeletonModel->isLoaded()) { + const auto& geometry = _skeletonModel->getFBXGeometry(); const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye const float RADIUS_INCREMENT = 0.005f; batch.setModelTransform(Transform()); @@ -475,7 +475,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { glm::vec3 position = getHead()->getLeftEyePosition(); Transform transform; transform.setTranslation(position); - float eyeDiameter = geometry->getFBXGeometry().leftEyeSize; + float eyeDiameter = geometry.leftEyeSize; if (eyeDiameter == 0.0f) { eyeDiameter = DEFAULT_EYE_DIAMETER; } @@ -486,7 +486,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { position = getHead()->getRightEyePosition(); transform.setTranslation(position); - eyeDiameter = geometry->getFBXGeometry().rightEyeSize; + eyeDiameter = geometry.rightEyeSize; if (eyeDiameter == 0.0f) { eyeDiameter = DEFAULT_EYE_DIAMETER; } @@ -815,7 +815,7 @@ int Avatar::getJointIndex(const QString& name) const { Q_RETURN_ARG(int, result), Q_ARG(const QString&, name)); return result; } - return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointIndex(name) : -1; + return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointIndex(name) : -1; } QStringList Avatar::getJointNames() const { @@ -825,7 +825,7 @@ QStringList Avatar::getJointNames() const { Q_RETURN_ARG(QStringList, result)); return result; } - return _skeletonModel->isActive() ? _skeletonModel->getGeometry()->getFBXGeometry().getJointNames() : QStringList(); + return _skeletonModel->isActive() ? _skeletonModel->getFBXGeometry().getJointNames() : QStringList(); } glm::vec3 Avatar::getJointPosition(int index) const { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8f11c635e9..c69a6a9ebd 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1270,8 +1270,8 @@ void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene void MyAvatar::initHeadBones() { int neckJointIndex = -1; - if (_skeletonModel->getGeometry()) { - neckJointIndex = _skeletonModel->getGeometry()->getFBXGeometry().neckJointIndex; + if (_skeletonModel->isLoaded()) { + neckJointIndex = _skeletonModel->getFBXGeometry().neckJointIndex; } if (neckJointIndex == -1) { return; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8bb097d97e..7019944f3b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -39,12 +39,12 @@ SkeletonModel::~SkeletonModel() { } void SkeletonModel::initJointStates() { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->initJointStates(geometry, modelOffset); // Determine the default eye position for avatar scale = 1.0 - int headJointIndex = _geometry->getFBXGeometry().headJointIndex; + int headJointIndex = geometry.headJointIndex; if (0 > headJointIndex || headJointIndex >= _rig->getJointStateCount()) { qCWarning(interfaceapp) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig->getJointStateCount(); } @@ -52,7 +52,7 @@ void SkeletonModel::initJointStates() { getEyeModelPositions(leftEyePosition, rightEyePosition); glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f; - int rootJointIndex = _geometry->getFBXGeometry().rootJointIndex; + int rootJointIndex = geometry.rootJointIndex; glm::vec3 rootModelPosition; getJointPosition(rootJointIndex, rootModelPosition); @@ -87,10 +87,12 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle // Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { + const FBXGeometry& geometry = getFBXGeometry(); + Head* head = _owningAvatar->getHead(); + if (_owningAvatar->isMyAvatar()) { MyAvatar* myAvatar = static_cast(_owningAvatar); - const FBXGeometry& geometry = _geometry->getFBXGeometry(); Rig::HeadParameters headParams; headParams.enableLean = qApp->isHMDMode(); @@ -183,7 +185,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { // Thus this should really only be ... else if (_owningAvatar->getHead()->isLookingAtMe()) {... // However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now. // We will revisit that as priorities allow, and particularly after the new rig/animation/joints. - const FBXGeometry& geometry = _geometry->getFBXGeometry(); // If the head is not positioned, updateEyeJoints won't get the math right glm::quat headOrientation; @@ -329,22 +330,23 @@ float SkeletonModel::getRightArmLength() const { } bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { - return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().headJointIndex, headPosition); + return isActive() && getJointPositionInWorldFrame(getFBXGeometry().headJointIndex, headPosition); } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); + return isActive() && getJointPositionInWorldFrame(getFBXGeometry().neckJointIndex, neckPosition); } bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const { - return isActive() && getJointPosition(_geometry->getFBXGeometry().neckJointIndex, neckPosition); + return isActive() && getJointPosition(getFBXGeometry().neckJointIndex, neckPosition); } bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); + if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) { return true; @@ -386,11 +388,11 @@ float VERY_BIG_MASS = 1.0e6f; // virtual void SkeletonModel::computeBoundingShape() { - if (_geometry == NULL || _rig->jointStatesEmpty()) { + if (!isLoaded() || _rig->jointStatesEmpty()) { return; } - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) { // rootJointIndex == -1 if the avatar model has no skeleton return; @@ -429,7 +431,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale } bool SkeletonModel::hasSkeleton() { - return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false; + return isActive() ? getFBXGeometry().rootJointIndex != -1 : false; } void SkeletonModel::onInvalidate() { diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 26b2e9c666..8e61e6f3ca 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -38,10 +38,10 @@ public: void updateAttitude(); /// Returns the index of the left hand joint, or -1 if not found. - int getLeftHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().leftHandJointIndex : -1; } + int getLeftHandJointIndex() const { return isActive() ? getFBXGeometry().leftHandJointIndex : -1; } /// Returns the index of the right hand joint, or -1 if not found. - int getRightHandJointIndex() const { return isActive() ? _geometry->getFBXGeometry().rightHandJointIndex : -1; } + int getRightHandJointIndex() const { return isActive() ? getFBXGeometry().rightHandJointIndex : -1; } bool getLeftGrabPosition(glm::vec3& position) const; bool getRightGrabPosition(glm::vec3& position) const; diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp index 8f0404e36c..b90fd9470c 100644 --- a/interface/src/avatar/SoftAttachmentModel.cpp +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -43,7 +43,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu } _needsUpdateClusterMatrices = false; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); glm::mat4 modelToWorld = glm::mat4_cast(modelOrientation); for (int i = 0; i < _meshStates.size(); i++) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 22695663e3..07d19dbd92 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -421,8 +421,8 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en std::dynamic_pointer_cast(entityItem); assert(modelEntityItem); // we need this!!! ModelPointer model = modelEntityItem->getModel(this); - if (model) { - result = &model->getGeometry()->getFBXGeometry(); + if (model && model->isLoaded()) { + result = &model->getFBXGeometry(); } } return result; @@ -446,11 +446,8 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP std::dynamic_pointer_cast(entityItem); if (modelEntityItem->hasCompoundShapeURL()) { ModelPointer model = modelEntityItem->getModel(this); - if (model) { - const QSharedPointer collisionNetworkGeometry = model->getCollisionGeometry(); - if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) { - result = &collisionNetworkGeometry->getFBXGeometry(); - } + if (model && model->isCollisionLoaded()) { + result = &model->getCollisionFBXGeometry(); } } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ff4ed28150..d6fbdd5229 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -110,14 +110,16 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c QVariantMap RenderableModelEntityItem::parseTexturesToMap(QString textures) { // If textures are unset, revert to original textures if (textures == "") { - return _originalTexturesMap; + return _originalTextures; } + // TODO: Remove this line and enforce passing a texturemap as stringified JSON QString jsonTextures = "{\"" + textures.replace(":\"", "\":\"").replace(",\n", ",\"") + "}"; QJsonParseError error; QJsonDocument texturesAsJson = QJsonDocument::fromJson(jsonTextures.toUtf8(), &error); if (error.error != QJsonParseError::NoError) { qCWarning(entitiesrenderer) << "Could not evaluate textures property value:" << _textures; + return _originalTextures; } QJsonObject texturesAsJsonObject = texturesAsJson.object(); return texturesAsJsonObject.toVariantMap(); @@ -131,44 +133,23 @@ void RenderableModelEntityItem::remapTextures() { if (!_model->isLoaded()) { return; // nothing to do if the model has not yet loaded } - + + auto& geometry = _model->getGeometry()->getGeometry(); + if (!_originalTexturesRead) { - const QSharedPointer& networkGeometry = _model->getGeometry(); - if (networkGeometry) { - _originalTextures = networkGeometry->getTextureNames(); - _originalTexturesMap = parseTexturesToMap(_originalTextures.join(",\n")); - _originalTexturesRead = true; - } - } - - if (_currentTextures == _textures) { - return; // nothing to do if our recently mapped textures match our desired textures - } - - // since we're changing here, we need to run through our current texture map - // and any textures in the recently mapped texture, that is not in our desired - // textures, we need to "unset" - QVariantMap currentTextureMap = parseTexturesToMap(_currentTextures); - QVariantMap textureMap = parseTexturesToMap(_textures); + _originalTextures = geometry->getTextures(); + _originalTexturesRead = true; - foreach(const QString& key, currentTextureMap.keys()) { - // if the desired texture map (what we're setting the textures to) doesn't - // contain this texture, then remove it by setting the URL to null - if (!textureMap.contains(key)) { - QUrl noURL; - qCDebug(entitiesrenderer) << "Removing texture named" << key << "by replacing it with no URL"; - _model->setTextureWithNameToURL(key, noURL); - } + // Default to _originalTextures to avoid remapping immediately and lagging on load + _currentTextures = _originalTextures; } - // here's where we remap any textures if needed... - foreach(const QString& key, textureMap.keys()) { - QUrl newTextureURL = textureMap[key].toUrl(); - qCDebug(entitiesrenderer) << "Updating texture named" << key << "to texture at URL" << newTextureURL; - _model->setTextureWithNameToURL(key, newTextureURL); + auto textures = parseTexturesToMap(_textures); + + if (textures != _currentTextures) { + geometry->setTextures(textures); + _currentTextures = textures; } - - _currentTextures = _textures; } // TODO: we need a solution for changes to the postion/rotation/etc of a model... @@ -519,8 +500,7 @@ bool RenderableModelEntityItem::needsToCallUpdate() const { void RenderableModelEntityItem::update(const quint64& now) { if (!_dimensionsInitialized && _model && _model->isActive()) { - const QSharedPointer renderNetworkGeometry = _model->getGeometry(); - if (renderNetworkGeometry && renderNetworkGeometry->isLoaded()) { + if (_model->isLoaded()) { EntityItemProperties properties; auto extents = _model->getMeshExtents(); properties.setDimensions(extents.maximum - extents.minimum); @@ -586,13 +566,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return false; } - const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); - const QSharedPointer renderNetworkGeometry = _model->getGeometry(); - - if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) && - (renderNetworkGeometry && renderNetworkGeometry->isLoaded())) { + if (_model->isLoaded() && _model->isCollisionLoaded()) { // we have both URLs AND both geometries AND they are both fully loaded. - if (_needsInitialSimulation) { // the _model's offset will be wrong until _needsInitialSimulation is false PerformanceTimer perfTimer("_model->simulate"); @@ -617,15 +592,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { adjustShapeInfoByRegistration(info); } else { updateModelBounds(); - const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); // should never fall in here when collision model not fully loaded - // hence we assert collisionNetworkGeometry is not NULL - assert(collisionNetworkGeometry); - - const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); - const QSharedPointer renderNetworkGeometry = _model->getGeometry(); - const FBXGeometry& renderGeometry = renderNetworkGeometry->getFBXGeometry(); + // hence we assert that all geometries exist and are loaded + assert(_model->isLoaded() && _model->isCollisionLoaded()); + const FBXGeometry& renderGeometry = _model->getFBXGeometry(); + const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); _points.clear(); unsigned int i = 0; @@ -727,10 +699,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { - if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) { - const QSharedPointer collisionNetworkGeometry = _model->getCollisionGeometry(); - const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry(); - return collisionGeometry.convexHullContains(worldToEntity(point)); + if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) { + return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point)); } return false; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 069b7385b5..03aa9124d5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -85,9 +85,8 @@ private: bool _needsInitialSimulation = true; bool _needsModelReload = true; EntityTreeRenderer* _myRenderer = nullptr; - QString _currentTextures; - QStringList _originalTextures; - QVariantMap _originalTexturesMap; + QVariantMap _currentTextures; + QVariantMap _originalTextures; bool _originalTexturesRead = false; QVector> _points; bool _dimensionsInitialized = true; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 550ec205c0..32aac1efe5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -529,9 +529,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable } - QString textureNamesList = _textureNames.join(",\n"); + QString textureNamesStr = QJsonDocument::fromVariant(_textureNames).toJson(); if (!skipDefaults) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesStr); // gettable, but not settable } COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c732d01fa5..2cf31e5632 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -245,8 +245,8 @@ public: const glm::vec3& getNaturalPosition() const { return _naturalPosition; } void calculateNaturalPosition(const glm::vec3& min, const glm::vec3& max); - const QStringList& getTextureNames() const { return _textureNames; } - void setTextureNames(const QStringList& value) { _textureNames = value; } + const QVariantMap& getTextureNames() const { return _textureNames; } + void setTextureNames(const QVariantMap& value) { _textureNames = value; } QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); } @@ -297,7 +297,7 @@ private: // NOTE: The following are pseudo client only properties. They are only used in clients which can access // properties of model geometry. But these properties are not serialized like other properties. QVector _sittingPoints; - QStringList _textureNames; + QVariantMap _textureNames; glm::vec3 _naturalDimensions; glm::vec3 _naturalPosition; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 363def05a1..854630abf0 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -45,14 +45,14 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr } } -MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { +MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { updateMeshPart(mesh, partIndex); updateMaterial(material); updateTransform(transform, offsetTransform); } -void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) { +void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { _drawMesh = drawMesh; if (_drawMesh) { auto vertexFormat = _drawMesh->getVertexFormat(); @@ -320,7 +320,9 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par _model(model), _meshIndex(_meshIndex), _shapeID(shapeIndex) { - auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh; + + assert(_model && _model->isLoaded()); + auto& modelMesh = _model->getGeometry()->getGeometry()->getMeshes().at(_meshIndex); updateMeshPart(modelMesh, partIndex); updateTransform(transform, offsetTransform); @@ -328,20 +330,22 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par } void ModelMeshPartPayload::initCache() { + assert(_model->isLoaded()); + if (_drawMesh) { auto vertexFormat = _drawMesh->getVertexFormat(); _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); _isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX); - - const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); + const FBXGeometry& geometry = _model->getFBXGeometry(); const FBXMesh& mesh = geometry.meshes.at(_meshIndex); + _isBlendShaped = !mesh.blendshapes.isEmpty(); } - auto networkMaterial = _model->_geometry->getShapeMaterial(_shapeID); + auto networkMaterial = _model->getGeometry()->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { - _drawMaterial = networkMaterial->_material; + _drawMaterial = networkMaterial; }; } @@ -380,8 +384,9 @@ Item::Bound ModelMeshPartPayload::getBound() const { } ShapeKey ModelMeshPartPayload::getShapeKey() const { - const FBXGeometry& geometry = _model->_geometry->getFBXGeometry(); - const std::vector>& networkMeshes = _model->_geometry->getMeshes(); + assert(_model->isLoaded()); + const FBXGeometry& geometry = _model->getFBXGeometry(); + const auto& networkMeshes = _model->getGeometry()->getGeometry()->getMeshes(); // guard against partially loaded meshes if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index feccf7ee64..9f73a46a93 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -24,12 +24,12 @@ class Model; class MeshPartPayload { public: MeshPartPayload() {} - MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform); + MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex); + virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); virtual void notifyLocationChanged() {} virtual void updateTransform(const Transform& transform, const Transform& offsetTransform); @@ -49,11 +49,11 @@ public: virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool canCauterize = true) const; // Payload resource cached values - model::MeshPointer _drawMesh; + std::shared_ptr _drawMesh; int _partIndex = 0; model::Mesh::Part _drawPart; - model::MaterialPointer _drawMaterial; + std::shared_ptr _drawMaterial; model::Box _localBound; Transform _drawTransform; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0a483914df..09cf433d47 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -30,7 +30,7 @@ using namespace std; static int nakedModelPointerTypeId = qRegisterMetaType(); -static int weakNetworkGeometryPointerTypeId = qRegisterMetaType >(); +static int weakNetworkGeometryPointerTypeId = qRegisterMetaType >(); static int vec3VectorTypeId = qRegisterMetaType >(); float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; #define HTTP_INVALID_COM "http://invalid.com" @@ -74,12 +74,12 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; -bool Model::needsFixupInScene() { +bool Model::needsFixupInScene() const { if (readyToAddToScene()) { // Once textures are loaded, fixup if they are now transparent - if (!_needsReload && _needsUpdateTransparentTextures && _geometry->isLoadedWithTextures()) { + if (_needsUpdateTransparentTextures && _geometry->getGeometry()->areTexturesLoaded()) { _needsUpdateTransparentTextures = false; - if (_hasTransparentTextures != _geometry->hasTransparentTextures()) { + if (_hasTransparentTextures != _geometry->getGeometry()->hasTransparentTextures()) { return true; } } @@ -150,19 +150,18 @@ void Model::enqueueLocationChange() { } void Model::initJointTransforms() { - if (!_geometry || !_geometry->isLoaded()) { - return; + if (isLoaded()) { + glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); + _rig->setModelOffset(modelOffset); } - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); - _rig->setModelOffset(modelOffset); } void Model::init() { } void Model::reset() { - if (_geometry && _geometry->isLoaded()) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + if (isLoaded()) { + const FBXGeometry& geometry = getFBXGeometry(); _rig->reset(geometry); } } @@ -171,17 +170,16 @@ bool Model::updateGeometry() { PROFILE_RANGE(__FUNCTION__); bool needFullUpdate = false; - if (!_geometry || !_geometry->isLoaded()) { - // geometry is not ready + if (!isLoaded()) { return false; } _needsReload = false; - if (_rig->jointStatesEmpty() && _geometry->getFBXGeometry().joints.size() > 0) { + if (_rig->jointStatesEmpty() && getFBXGeometry().joints.size() > 0) { initJointStates(); - const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& fbxGeometry = getFBXGeometry(); foreach (const FBXMesh& mesh, fbxGeometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); @@ -205,7 +203,7 @@ bool Model::updateGeometry() { // virtual void Model::initJointStates() { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->initJointStates(geometry, modelOffset); @@ -248,7 +246,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g glm::vec3 subMeshSurfaceNormal; int subMeshIndex = 0; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); // If we hit the models box, then consider the submeshes... _mutex.lock(); @@ -367,7 +365,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); _calculatedMeshTriangles.clear(); @@ -478,7 +476,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { void Model::renderSetup(RenderArgs* args) { // set up dilated textures on first render after load/simulate - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); if (_dilatedTextures.isEmpty()) { foreach (const FBXMesh& mesh, geometry.meshes) { QVector > dilated; @@ -627,7 +625,7 @@ Extents Model::getBindExtents() const { if (!isActive()) { return Extents(); } - const Extents& bindExtents = _geometry->getFBXGeometry().bindExtents; + const Extents& bindExtents = getFBXGeometry().bindExtents; Extents scaledExtents = { bindExtents.minimum * _scale, bindExtents.maximum * _scale }; return scaledExtents; } @@ -636,12 +634,12 @@ Extents Model::getMeshExtents() const { if (!isActive()) { return Extents(); } - const Extents& extents = _geometry->getFBXGeometry().meshExtents; + const Extents& extents = getFBXGeometry().meshExtents; // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which // is captured in the offset matrix - glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); - glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); + glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); + glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); Extents scaledExtents = { minimum * _scale, maximum * _scale }; return scaledExtents; } @@ -651,12 +649,12 @@ Extents Model::getUnscaledMeshExtents() const { return Extents(); } - const Extents& extents = _geometry->getFBXGeometry().meshExtents; + const Extents& extents = getFBXGeometry().meshExtents; // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which // is captured in the offset matrix - glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); - glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); + glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); + glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); Extents scaledExtents = { minimum, maximum }; return scaledExtents; @@ -665,8 +663,8 @@ Extents Model::getUnscaledMeshExtents() const { Extents Model::calculateScaledOffsetExtents(const Extents& extents, glm::vec3 modelPosition, glm::quat modelOrientation) const { // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix - glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); - glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); + glm::vec3 minimum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); + glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), ((maximum + _offset) * _scale) }; @@ -686,7 +684,7 @@ AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPositio glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix - glm::vec3 offsetPoint = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(point, 1.0f)); + glm::vec3 offsetPoint = glm::vec3(getFBXGeometry().offset * glm::vec4(point, 1.0f)); glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale); glm::vec3 rotatedPoint = _rotation * scaledPoint; glm::vec3 translatedPoint = rotatedPoint + _translation; @@ -714,11 +712,11 @@ void Model::setJointTranslation(int index, bool valid, const glm::vec3& translat } int Model::getParentJointIndex(int jointIndex) const { - return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).parentIndex : -1; + return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).parentIndex : -1; } int Model::getLastFreeJointIndex(int jointIndex) const { - return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1; + return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1; } void Model::setURL(const QUrl& url) { @@ -743,29 +741,16 @@ void Model::setURL(const QUrl& url) { invalidCalculatedMeshBoxes(); deleteGeometry(); - _geometry.reset(new NetworkGeometry(url, false, QVariantHash())); + _geometry = DependencyManager::get()->getGeometry(url); onInvalidate(); } -const QSharedPointer Model::getCollisionGeometry(bool delayLoad) -{ - if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) { - _collisionGeometry.reset(new NetworkGeometry(_collisionUrl, delayLoad, QVariantHash())); - } - - if (_collisionGeometry && _collisionGeometry->isLoaded()) { - return _collisionGeometry; - } - - return QSharedPointer(); -} - void Model::setCollisionModelURL(const QUrl& url) { if (_collisionUrl == url) { return; } _collisionUrl = url; - _collisionGeometry.reset(new NetworkGeometry(url, false, QVariantHash())); + _collisionGeometry = DependencyManager::get()->getGeometry(url); } bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { @@ -815,13 +800,13 @@ QStringList Model::getJointNames() const { Q_RETURN_ARG(QStringList, result)); return result; } - return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList(); + return isActive() ? getFBXGeometry().getJointNames() : QStringList(); } class Blender : public QRunnable { public: - Blender(ModelPointer model, int blendNumber, const QWeakPointer& geometry, + Blender(ModelPointer model, int blendNumber, const std::weak_ptr& geometry, const QVector& meshes, const QVector& blendshapeCoefficients); virtual void run(); @@ -830,12 +815,12 @@ private: ModelPointer _model; int _blendNumber; - QWeakPointer _geometry; + std::weak_ptr _geometry; QVector _meshes; QVector _blendshapeCoefficients; }; -Blender::Blender(ModelPointer model, int blendNumber, const QWeakPointer& geometry, +Blender::Blender(ModelPointer model, int blendNumber, const std::weak_ptr& geometry, const QVector& meshes, const QVector& blendshapeCoefficients) : _model(model), _blendNumber(blendNumber), @@ -878,7 +863,7 @@ void Blender::run() { // post the result to the geometry cache, which will dispatch to the model if still alive QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices", Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), - Q_ARG(const QWeakPointer&, _geometry), Q_ARG(const QVector&, vertices), + Q_ARG(const std::weak_ptr&, _geometry), Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); } @@ -1010,7 +995,7 @@ void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrient return; } _needsUpdateClusterMatrices = false; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); glm::mat4 zeroScale(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), @@ -1067,26 +1052,26 @@ void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrient } void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(endIndex).freeLineage; glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); _rig->inverseKinematics(endIndex, targetPosition, targetRotation, priority, freeLineage, parentTransform); } bool Model::restoreJointPosition(int jointIndex, float fraction, float priority) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return _rig->restoreJointPosition(jointIndex, fraction, priority, freeLineage); } float Model::getLimbLength(int jointIndex) const { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXGeometry& geometry = getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; return _rig->getLimbLength(jointIndex, freeLineage, _scale, geometry.joints); } bool Model::maybeStartBlender() { - const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& fbxGeometry = getFBXGeometry(); if (fbxGeometry.hasBlendedMeshes()) { QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry, fbxGeometry.meshes, _blendshapeCoefficients)); @@ -1095,13 +1080,13 @@ bool Model::maybeStartBlender() { return false; } -void Model::setBlendedVertices(int blendNumber, const QWeakPointer& geometry, +void Model::setBlendedVertices(int blendNumber, const std::weak_ptr& geometry, const QVector& vertices, const QVector& normals) { - if (_geometry != geometry || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { + if (_geometry != geometry.lock() || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { return; } _appliedBlendNumber = blendNumber; - const FBXGeometry& fbxGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& fbxGeometry = getFBXGeometry(); int index = 0; for (int i = 0; i < fbxGeometry.meshes.size(); i++) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); @@ -1118,13 +1103,6 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointer& newGeometry) { - if (_geometry == newGeometry) { - return; - } - _geometry = newGeometry; -} - void Model::deleteGeometry() { _blendedVertexBuffers.clear(); _meshStates.clear(); @@ -1134,7 +1112,7 @@ void Model::deleteGeometry() { AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation) const { - if (!_geometry || !_geometry->isLoaded()) { + if (!isLoaded()) { return AABox(); } @@ -1143,10 +1121,10 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition bool isSkinned = state.clusterMatrices.size() > 1; if (isSkinned) { // if we're skinned return the entire mesh extents because we can't know for sure our clusters don't move us - return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents, modelPosition, modelOrientation); + return calculateScaledOffsetAABox(getFBXGeometry().meshExtents, modelPosition, modelOrientation); } } - if (_geometry->getFBXGeometry().meshes.size() > meshIndex) { + if (getFBXGeometry().meshes.size() > meshIndex) { // FIX ME! - This is currently a hack because for some mesh parts our efforts to calculate the bounding // box of the mesh part fails. It seems to create boxes that are not consistent with where the @@ -1160,27 +1138,28 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition // return _calculatedMeshBoxes[meshIndex]; // // If we not skinned use the bounds of the subMesh for all it's parts - const FBXMesh& mesh = _geometry->getFBXGeometry().meshes.at(meshIndex); + const FBXMesh& mesh = getFBXGeometry().meshes.at(meshIndex); return calculateScaledOffsetExtents(mesh.meshExtents, modelPosition, modelOrientation); } return AABox(); } void Model::segregateMeshGroups() { - QSharedPointer networkGeometry; + NetworkGeometry::Pointer networkGeometry; bool showingCollisionHull = false; if (_showCollisionHull && _collisionGeometry) { - if (_collisionGeometry->isLoaded()) { + if (isCollisionLoaded()) { networkGeometry = _collisionGeometry; showingCollisionHull = true; } else { return; } } else { + assert(isLoaded()); networkGeometry = _geometry; } - const FBXGeometry& geometry = networkGeometry->getFBXGeometry(); - const std::vector>& networkMeshes = networkGeometry->getMeshes(); + const FBXGeometry& geometry = networkGeometry->getGeometry()->getGeometry(); + const auto& networkMeshes = networkGeometry->getGeometry()->getMeshes(); // all of our mesh vectors must match in size auto geoMeshesSize = geometry.meshes.size(); @@ -1208,7 +1187,7 @@ void Model::segregateMeshGroups() { int shapeID = 0; for (int i = 0; i < (int)networkMeshes.size(); i++) { const FBXMesh& mesh = geometry.meshes.at(i); - const NetworkMesh& networkMesh = *(networkMeshes.at(i).get()); + const auto& networkMesh = networkMeshes.at(i); // Create the render payloads int totalParts = mesh.parts.size(); @@ -1220,7 +1199,7 @@ void Model::segregateMeshGroups() { _collisionHullMaterial->setMetallic(0.02f); _collisionHullMaterial->setRoughness(0.5f); } - _renderItemsSet << std::make_shared(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset); + _renderItemsSet << std::make_shared(networkMesh, partIndex, _collisionHullMaterial, transform, offset); } else { _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); } @@ -1285,7 +1264,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { } void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, - const QWeakPointer& geometry, const QVector& vertices, const QVector& normals) { + const std::weak_ptr& geometry, const QVector& vertices, const QVector& normals) { if (model) { model->setBlendedVertices(blendNumber, geometry, vertices, normals); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4e51dc4f33..632e8089a8 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -78,9 +78,9 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool needsFixupInScene(); - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { - return !_needsReload && isRenderable() && isActive() && isLoaded(); + bool needsFixupInScene() const; + bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { + return !_needsReload && isRenderable() && isActive(); } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, @@ -92,7 +92,7 @@ public: bool showCollisionHull = false); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void renderSetup(RenderArgs* args); - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); } + bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && getGeometry()->getGeometry()->getMeshes().empty()); } bool isVisible() const { return _isVisible; } @@ -102,11 +102,11 @@ public: bool maybeStartBlender(); /// Sets blended vertices computed in a separate thread. - void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, + void setBlendedVertices(int blendNumber, const std::weak_ptr& geometry, const QVector& vertices, const QVector& normals); - bool isLoaded() const { return _geometry && _geometry->isLoaded(); } - bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); } + bool isLoaded() const { return _geometry && _geometry->getGeometry(); } + bool isCollisionLoaded() const { return _collisionGeometry && _collisionGeometry->getGeometry(); } void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } @@ -123,12 +123,22 @@ public: virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation); /// Returns a reference to the shared geometry. - const QSharedPointer& getGeometry() const { return _geometry; } + const NetworkGeometry::Pointer& getGeometry() const { return _geometry; } + /// Returns a reference to the shared collision geometry. + const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; } - bool isActive() const { return _geometry && _geometry->isLoaded(); } + /// Provided as a convenience, will crash if !isLoaded() + // And so that getGeometry() isn't chained everywhere + const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); } + /// Provided as a convenience, will crash if !isCollisionLoaded() + const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return getCollisionGeometry()->getGeometry()->getGeometry(); } - Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) - { _geometry->setTextureWithNameToURL(name, url); } + // Set the model to use for collisions + Q_INVOKABLE void setCollisionModelURL(const QUrl& url); + const QUrl& getCollisionURL() const { return _collisionUrl; } + + + bool isActive() const { return isLoaded(); } bool convexHullContains(glm::vec3 point); @@ -143,13 +153,6 @@ public: BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo, bool pickAgainstTriangles = false); - // Set the model to use for collisions - Q_INVOKABLE void setCollisionModelURL(const QUrl& url); - const QUrl& getCollisionURL() const { return _collisionUrl; } - - /// Returns a reference to the shared collision geometry. - const QSharedPointer getCollisionGeometry(bool delayLoad = false); - void setOffset(const glm::vec3& offset); const glm::vec3& getOffset() const { return _offset; } @@ -257,8 +260,7 @@ protected: /// \return true if joint exists bool getJointPosition(int jointIndex, glm::vec3& position) const; - QSharedPointer _geometry; - void setGeometry(const QSharedPointer& newGeometry); + NetworkGeometry::Pointer _geometry; glm::vec3 _translation; glm::quat _rotation; @@ -325,7 +327,7 @@ protected: void deleteGeometry(); void initJointTransforms(); - QSharedPointer _collisionGeometry; + NetworkGeometry::Pointer _collisionGeometry; float _pupilDilation; QVector _blendshapeCoefficients; @@ -376,7 +378,7 @@ protected: bool _readyWhenAdded { false }; bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; - bool _needsUpdateTransparentTextures { true }; + mutable bool _needsUpdateTransparentTextures { true }; bool _hasTransparentTextures { false }; bool _showCollisionHull { false }; @@ -385,7 +387,7 @@ protected: }; Q_DECLARE_METATYPE(ModelPointer) -Q_DECLARE_METATYPE(QWeakPointer) +Q_DECLARE_METATYPE(std::weak_ptr) /// Handle management of pending models that need blending class ModelBlender : public QObject, public Dependency { @@ -398,7 +400,7 @@ public: void noteRequiresBlend(ModelPointer model); public slots: - void setBlendedVertices(ModelPointer model, int blendNumber, const QWeakPointer& geometry, + void setBlendedVertices(ModelPointer model, int blendNumber, const std::weak_ptr& geometry, const QVector& vertices, const QVector& normals); private: From 4d47126ae4a993e9b420f988feef5a3fdf7f2eba Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Mar 2016 12:17:55 -0700 Subject: [PATCH 09/61] Don't mark failed models loaded, emit failure --- .../model-networking/src/model-networking/ModelCache.cpp | 9 ++++++--- .../model-networking/src/model-networking/ModelCache.h | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index bb7efb8f75..ce255f0b4e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -290,12 +290,15 @@ NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometr connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished); connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed); if (_resource->isLoaded()) { - resourceFinished(); + resourceFinished(true); } } -void NetworkGeometry::resourceFinished() { - _instance = std::make_shared(*_resource); +void NetworkGeometry::resourceFinished(bool success) { + if (success) { + _instance = std::make_shared(*_resource); + } + emit finished(success); } void NetworkGeometry::resourceRefreshed() { diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index a2fcc9d741..7da3e2894f 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -117,8 +117,12 @@ public: /// Returns the geometry, if it is loaded (must be checked!) const Geometry::Pointer& getGeometry() { return _instance; } +signals: + /// Emitted when the NetworkGeometry loads (or fails to) + void finished(bool success); + private slots: - void resourceFinished(); + void resourceFinished(bool success); void resourceRefreshed(); private: From aa038bac58a282619dceb35e1bbac5dfb86ecb99 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Mar 2016 14:26:03 -0700 Subject: [PATCH 10/61] Don't cache nested geometries --- .../src/model-networking/ModelCache.cpp | 12 ++++++++++-- .../src/model-networking/ModelCache.h | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index ce255f0b4e..dfb3cf60c1 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -67,7 +67,15 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) { // Get the raw GeometryResource, not the wrapped NetworkGeometry _geometryResource = modelCache->getResource(url, QUrl(), true, &extra).staticCast(); - connect(_geometryResource.data(), &Resource::finished, this, &GeometryMappingResource::onGeometryMappingLoaded); + + if (_geometryResource->isLoaded()) { + onGeometryMappingLoaded(!_geometryResource->getURL().isEmpty()); + } else { + connect(_geometryResource.data(), &Resource::finished, this, &GeometryMappingResource::onGeometryMappingLoaded); + } + + // Avoid caching nested resources - their references will be held by the parent + _geometryResource->_isCacheable = false; } } @@ -290,7 +298,7 @@ NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometr connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished); connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed); if (_resource->isLoaded()) { - resourceFinished(true); + resourceFinished(!_resource->getURL().isEmpty()); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 7da3e2894f..5f860e8990 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -101,7 +101,11 @@ public: virtual bool areTexturesLoaded() const { return isLoaded() && Geometry::areTexturesLoaded(); } protected: - virtual bool isCacheable() const override { return _loaded; } + friend class GeometryMappingResource; + + virtual bool isCacheable() const override { return _loaded && _isCacheable; } + + bool _isCacheable { true }; }; class NetworkGeometry : public QObject { From 0c8556528b495c8ac119a70a12acb9ee11c88604 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 24 Mar 2016 17:25:58 -0700 Subject: [PATCH 11/61] Polishing the PerfPlot qml to display usefull things --- examples/utilities/tools/render/PlotPerf.qml | 130 +++++++++++++++++++ examples/utilities/tools/render/stats.qml | 59 ++------- 2 files changed, 139 insertions(+), 50 deletions(-) create mode 100644 examples/utilities/tools/render/PlotPerf.qml diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml new file mode 100644 index 0000000000..dc5c16bf79 --- /dev/null +++ b/examples/utilities/tools/render/PlotPerf.qml @@ -0,0 +1,130 @@ +// +// PlotPerf.qml +// examples/utilities/tools/render +// +// Created by Sam Gateau on 3//2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Item { + id: root + width: 400 + height: 100 + property var config + property string parameters + + property var trigger: config["numTextures"] + + property var inputs: parameters.split(":") + property var valueScale: +inputs[0] + property var valueUnit: inputs[1] + property var valueNumDigits: inputs[2] + property var valueMax : 1 + + property var _values : new Array() + property var tick : 0 + + function createValues() { + if (inputs.length > 3) { + for (var i = 3; i < inputs.length; i++) { + var varProps = inputs[i].split("-") + _values.push( { + value: varProps[1], + valueMax: 1, + valueHistory: new Array(), + label: varProps[0], + color: varProps[2] + }) + } + } + print("in creator" + JSON.stringify(_values)); + + } + + Component.onCompleted: { + createValues(); + print(JSON.stringify(_values)); + + } + + function pullFreshValues() { + //print("pullFreshValues"); + var VALUE_HISTORY_SIZE = 100; + var UPDATE_CANVAS_RATE = 20; + tick++; + + valueMax = 0 + for (var i = 0; i < _values.length; i++) { + var currentVal = stats.config[_values[i].value]; + if (_values[i].valueMax < currentVal) { + _values[i].valueMax = currentVal; + } + _values[i].valueHistory.push(currentVal) + if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) { + var lostValue = _values[i].valueHistory.shift(); + if (lostValue >= _values[i].valueMax) { + _values[i].valueMax *= 0.99 + } + } + + if (valueMax < _values[i].valueMax) { + valueMax = _values[i].valueMax + } + } + + + if (tick % UPDATE_CANVAS_RATE == 0) { + mycanvas.requestPaint() + } + } + onTriggerChanged: pullFreshValues() + + Canvas { + id: mycanvas + width: 300 + height: 100 + onPaint: { + function displayValue(val) { + return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + root.valueUnit + } + + function pixelFromVal(val) { + return height * (1 - (0.9) * val / valueMax); + } + function plotValueHistory(ctx, valHistory, color) { + var widthStep= width / (valHistory.length - 1); + + ctx.beginPath(); + ctx.strokeStyle= color; // Green path + ctx.lineWidth="4"; + ctx.moveTo(0, pixelFromVal(valHistory[i])); + + for (var i = 1; i < valHistory.length; i++) { + ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i])); + } + + ctx.stroke(); + } + function plotValueLegend(ctx, val, num) { + var lineHeight = 12; + ctx.font="14px Verdana"; + ctx.fillStyle = val.color; + ctx.fillText(displayValue(val.valueHistory[val.valueHistory.length -1]), 0, height - num * lineHeight); + } + var ctx = getContext("2d"); + ctx.clearRect(0, 0, width, height); + ctx.fillStyle = Qt.rgba(0, 0, 0, 0.4); + ctx.fillRect(0, 0, width, height); + + for (var i = 0; i < _values.length; i++) { + plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) + plotValueLegend(ctx, _values[i], i) + } + } + } +} diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 7140f81270..6edd3b7ae0 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -15,59 +15,18 @@ import QtQuick.Controls 1.4 Column { spacing: 8 Column { + spacing: 4 + id: stats property var config: Render.getConfig("Stats") - Repeater { - model: [ - "num Textures:numTextures:1", - "Sysmem Usage:textureSysmemUsage", - "num GPU Textures:numGPUTextures", - "Vidmem Usage:textureVidmemUsage" - ] - Row { - Label { - text: qsTr(modelData.split(":")[0]) - } - property var value: stats.config[modelData.split(":")[1]] - property var valueHistory : new Array() - property var valueMax : 1000 - property var tick : 0 - Label { - text: value - horizontalAlignment: AlignRight - } - Canvas { - id: mycanvas - width: 100 - height: 200 - onPaint: { - tick++; - valueHistory.push(value) - if (valueHistory.length > 100) { - valueHistory.shift(); - } - var ctx = getContext("2d"); - if (tick % 2) { - ctx.fillStyle = Qt.rgba(0, 1, 0, 0.5); - } else { - ctx.fillStyle = Qt.rgba(0, 0, 0, 0.5); - } - ctx.fillRect(0, 0, width, height); - var widthStep= width / valueHistory.length; - ctx.lineWidth="5"; - ctx.beginPath(); - ctx.strokeStyle="green"; // Green path - ctx.moveTo(0,height); - - for (var i = 0; i < valueHistory.length; i++) { - ctx.lineTo(i * widthStep, height * (1 - valueHistory[i] / valueMax) ); - } - ctx.lineTo(width, height); - ctx.stroke(); // Draw it - } - } - } + PlotPerf { + config: stats.config + parameters: "1::0:num Textures-numTextures-blue:num GPU Textures-numGPUTextures-green" + } + PlotPerf { + config: stats.config + parameters: "1048576:Mb:1:Sysmem-textureSysmemUsage-blue:Vidmem-textureVidmemUsage-green" } } } From 3402635f995532f2ba424e3123cebbfad1dbf333 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Mar 2016 17:19:32 -0700 Subject: [PATCH 12/61] Lock geometry on blender --- libraries/render-utils/src/Model.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 09cf433d47..67d7d5df8f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1071,18 +1071,21 @@ float Model::getLimbLength(int jointIndex) const { } bool Model::maybeStartBlender() { - const FBXGeometry& fbxGeometry = getFBXGeometry(); - if (fbxGeometry.hasBlendedMeshes()) { - QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry, - fbxGeometry.meshes, _blendshapeCoefficients)); - return true; + if (isLoaded()) { + const FBXGeometry& fbxGeometry = getFBXGeometry(); + if (fbxGeometry.hasBlendedMeshes()) { + QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry, + fbxGeometry.meshes, _blendshapeCoefficients)); + return true; + } } return false; } void Model::setBlendedVertices(int blendNumber, const std::weak_ptr& geometry, const QVector& vertices, const QVector& normals) { - if (_geometry != geometry.lock() || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { + auto geometryRef = geometry.lock(); + if (!geometryRef || _geometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { return; } _appliedBlendNumber = blendNumber; From eeeb175bb8bba000e0084a8b66c11b1d14a05e99 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Mar 2016 17:55:03 -0700 Subject: [PATCH 13/61] Derive NetworkMaterial, avoid copying it --- .../src/model-networking/ModelCache.cpp | 26 ++++++++++++++----- .../src/model-networking/ModelCache.h | 10 +++++-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index dfb3cf60c1..586990db09 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -193,7 +193,7 @@ void GeometryDefinitionResource::setGeometryDefinition(void* fbxGeometry) { int partID = 0; for (const FBXMeshPart& part : mesh.parts) { // Construct local shapes - shapes->emplace_back(meshID, partID, (int)materialIDAtlas[part.materialID]); + shapes->push_back(std::make_shared(meshID, partID, (int)materialIDAtlas[part.materialID])); partID++; } meshID++; @@ -249,7 +249,13 @@ void Geometry::setTextures(const QVariantMap& textureMap) { if (std::any_of(material->_textures.cbegin(), material->_textures.cend(), [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.texture && textureMap.contains(it.name); })) { - material = std::make_shared(*material, textureMap); + if (material->isOriginal()) { + // On first mutation, copy the material to avoid altering the cache + material = std::make_shared(*material, textureMap); + } else { + // On later mutations, we can mutate in-place + material->setTextures(textureMap); + } _areTexturesLoaded = false; } } @@ -286,7 +292,7 @@ bool Geometry::areTexturesLoaded() const { const std::shared_ptr Geometry::getShapeMaterial(int shapeID) const { if ((shapeID >= 0) && (shapeID < (int)_shapes->size())) { - int materialID = _shapes->at(shapeID).materialID; + int materialID = _shapes->at(shapeID)->materialID; if ((materialID >= 0) && (materialID < (int)_materials.size())) { return _materials[materialID]; } @@ -348,7 +354,15 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, Textu return map; } -NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) { +NetworkMaterial::NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap) : + _textures(material._textures), _isOriginal(false) +{ + setTextures(textureMap); +} + +NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) : + model::Material(*material._material), _isOriginal(true) +{ _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); @@ -406,9 +420,7 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur } } -NetworkMaterial::NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap) : NetworkMaterial(material) { - _textures = material._textures; - +void NetworkMaterial::setTextures(const QVariantMap& textureMap) { const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); const auto& roughnessName = getTextureName(MapChannel::ROUGHNESS_MAP); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 5f860e8990..0832478648 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -58,10 +58,10 @@ public: // Immutable over lifetime using NetworkMeshes = std::vector>; - using NetworkShapes = std::vector; + using NetworkShapes = std::vector>; // Mutable, but must retain structure of vector - using NetworkMaterials = std::vector>; + using NetworkMaterials = std::vector>; const FBXGeometry& getGeometry() const { return *_geometry; } const NetworkMeshes& getMeshes() const { return *_meshes; } @@ -156,12 +156,18 @@ protected: static const QString NO_TEXTURE; const QString& getTextureName(MapChannel channel); + void setTextures(const QVariantMap& textureMap); + + const bool& isOriginal() const { return _isOriginal; } + private: // Helpers for the ctors QUrl getTextureUrl(const QUrl& baseUrl, const FBXTexture& fbxTexture); model::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel); model::TextureMapPointer fetchTextureMap(const QUrl& url, TextureType type, MapChannel channel); + + bool _isOriginal; }; class NetworkShape { From c625d36bd8ee2f37ae84c68729d0c75df157e54b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 24 Mar 2016 19:18:38 -0700 Subject: [PATCH 14/61] Persist material transform/params --- .../src/model-networking/ModelCache.cpp | 22 ++++++++++--------- .../src/model-networking/ModelCache.h | 4 ++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 586990db09..6c7c98047d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -355,8 +355,9 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, Textu } NetworkMaterial::NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap) : - _textures(material._textures), _isOriginal(false) + NetworkMaterial(material) { + _isOriginal = false; setTextures(textureMap); } @@ -366,7 +367,8 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); - map->setTextureTransform(material.albedoTexture.transform); + _albedoTransform = material.albedoTexture.transform; + map->setTextureTransform(_albedoTransform); if (!material.opacityTexture.filename.isEmpty()) { if (material.albedoTexture.filename == material.opacityTexture.filename) { @@ -414,8 +416,10 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur if (!material.lightmapTexture.filename.isEmpty()) { auto map = fetchTextureMap(textureBaseUrl, material.lightmapTexture, LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); - map->setTextureTransform(material.lightmapTexture.transform); - map->setLightmapOffsetScale(material.lightmapParams.x, material.lightmapParams.y); + _lightmapTransform = material.lightmapTexture.transform; + _lightmapParams = material.lightmapParams; + map->setTextureTransform(_lightmapTransform); + map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); setTextureMap(MapChannel::LIGHTMAP_MAP, map); } } @@ -431,9 +435,9 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!albedoName.isEmpty() && textureMap.contains(albedoName)) { auto map = fetchTextureMap(textureMap[albedoName].toUrl(), DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); - map->setTextureTransform(getTextureMap(MapChannel::ALBEDO_MAP)->getTextureTransform()); + map->setTextureTransform(_albedoTransform); // when reassigning the albedo texture we also check for the alpha channel used as opacity - map->setUseAlphaChannel(true); + map->setUseAlphaChannel(true); setTextureMap(MapChannel::ALBEDO_MAP, map); } @@ -466,10 +470,8 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { if (!lightmapName.isEmpty() && textureMap.contains(lightmapName)) { auto map = fetchTextureMap(textureMap[lightmapName].toUrl(), LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); - auto oldMap = getTextureMap(MapChannel::LIGHTMAP_MAP); - map->setTextureTransform(oldMap->getTextureTransform()); - glm::vec2 offsetScale = oldMap->getLightmapOffsetScale(); - map->setLightmapOffsetScale(offsetScale.x, offsetScale.y); + map->setTextureTransform(_lightmapTransform); + map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); setTextureMap(MapChannel::LIGHTMAP_MAP, map); } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 0832478648..01a5e2165e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -167,6 +167,10 @@ private: TextureType type, MapChannel channel); model::TextureMapPointer fetchTextureMap(const QUrl& url, TextureType type, MapChannel channel); + Transform _albedoTransform; + Transform _lightmapTransform; + vec2 _lightmapParams; + bool _isOriginal; }; From 9fb1a9a2a8347f69958e0c58ed81845745d33a84 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 25 Mar 2016 03:02:18 -0700 Subject: [PATCH 15/61] Merge and many more counters --- examples/utilities/tools/render/PlotPerf.qml | 47 ++++++++++---- .../utilities/tools/render/renderStats.js | 3 +- examples/utilities/tools/render/stats.qml | 27 ++++++-- libraries/gpu/src/gpu/Context.cpp | 5 ++ libraries/gpu/src/gpu/Context.h | 21 ++++++ libraries/gpu/src/gpu/GLBackend.h | 19 +----- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 21 +++++- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 3 + libraries/gpu/src/gpu/Resource.cpp | 65 ++++++++++++++++++- libraries/gpu/src/gpu/Resource.h | 15 +++++ libraries/gpu/src/gpu/Texture.cpp | 7 -- libraries/gpu/src/gpu/Texture.h | 4 -- libraries/render/src/render/Engine.cpp | 14 +++- libraries/render/src/render/Engine.h | 23 ++++++- 14 files changed, 219 insertions(+), 55 deletions(-) diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml index dc5c16bf79..00b7848936 100644 --- a/examples/utilities/tools/render/PlotPerf.qml +++ b/examples/utilities/tools/render/PlotPerf.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 Item { id: root - width: 400 height: 100 + property string title property var config property string parameters @@ -24,14 +24,15 @@ Item { property var valueScale: +inputs[0] property var valueUnit: inputs[1] property var valueNumDigits: inputs[2] + property var input_VALUE_OFFSET: 3 property var valueMax : 1 property var _values : new Array() property var tick : 0 function createValues() { - if (inputs.length > 3) { - for (var i = 3; i < inputs.length; i++) { + if (inputs.length > input_VALUE_OFFSET) { + for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { var varProps = inputs[i].split("-") _values.push( { value: varProps[1], @@ -83,25 +84,26 @@ Item { } } onTriggerChanged: pullFreshValues() - + Canvas { id: mycanvas - width: 300 - height: 100 + anchors.fill:parent onPaint: { + var lineHeight = 12; + function displayValue(val) { return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + root.valueUnit } function pixelFromVal(val) { - return height * (1 - (0.9) * val / valueMax); + return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax); } function plotValueHistory(ctx, valHistory, color) { var widthStep= width / (valHistory.length - 1); ctx.beginPath(); ctx.strokeStyle= color; // Green path - ctx.lineWidth="4"; + ctx.lineWidth="2"; ctx.moveTo(0, pixelFromVal(valHistory[i])); for (var i = 1; i < valHistory.length; i++) { @@ -110,21 +112,38 @@ Item { ctx.stroke(); } - function plotValueLegend(ctx, val, num) { - var lineHeight = 12; - ctx.font="14px Verdana"; - ctx.fillStyle = val.color; - ctx.fillText(displayValue(val.valueHistory[val.valueHistory.length -1]), 0, height - num * lineHeight); + function displayValueLegend(ctx, val, num) { + ctx.fillStyle = val.color; + var bestValue = val.valueHistory[val.valueHistory.length -1]; + ctx.textAlign = "right"; + ctx.fillText(displayValue(bestValue), width, height - num * lineHeight); + ctx.textAlign = "left"; + ctx.fillText(val.label, 0, height - num * lineHeight); } + + function displayTitle(ctx, text, maxVal) { + ctx.fillStyle = "grey"; + ctx.textAlign = "right"; + ctx.fillText(displayValue(maxVal), width, lineHeight); + + ctx.fillStyle = "white"; + ctx.textAlign = "left"; + ctx.fillText(text, 0, lineHeight); + } + var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); ctx.fillStyle = Qt.rgba(0, 0, 0, 0.4); ctx.fillRect(0, 0, width, height); + ctx.font="12px Verdana"; + for (var i = 0; i < _values.length; i++) { plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) - plotValueLegend(ctx, _values[i], i) + displayValueLegend(ctx, _values[i], i) } + + displayTitle(ctx, title, valueMax) } } } diff --git a/examples/utilities/tools/render/renderStats.js b/examples/utilities/tools/render/renderStats.js index da12ad1b31..2e8487ca34 100644 --- a/examples/utilities/tools/render/renderStats.js +++ b/examples/utilities/tools/render/renderStats.js @@ -14,7 +14,8 @@ var qml = Script.resolvePath('stats.qml'); var window = new OverlayWindow({ title: 'Render Stats', source: qml, - width: 300 + width: 300, + height: 200 }); window.setPosition(500, 50); window.closed.connect(function() { Script.stop(); }); \ No newline at end of file diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 6edd3b7ae0..47c0f98568 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -13,20 +13,39 @@ import QtQuick.Controls 1.4 Column { + id: statsUI + width: 300 spacing: 8 Column { - spacing: 4 + spacing: 8 - id: stats property var config: Render.getConfig("Stats") + id: stats PlotPerf { + title: "Num Buffers" + width:statsUI.width config: stats.config - parameters: "1::0:num Textures-numTextures-blue:num GPU Textures-numGPUTextures-green" + parameters: "1::0:CPU-numBuffers-#00B4EF:GPU-numGPUBuffers-#1AC567" } PlotPerf { + title: "Memory Usage" + width:statsUI.width config: stats.config - parameters: "1048576:Mb:1:Sysmem-textureSysmemUsage-blue:Vidmem-textureVidmemUsage-green" + parameters: "1048576:Mb:1:CPU-bufferSysmemUsage-#00B4EF:GPU-bufferVidmemUsage-#1AC567" + } + + PlotPerf { + title: "Num Textures" + width:statsUI.width + config: stats.config + parameters: "1::0:CPU-numTextures-#00B4EF:GPU-numGPUTextures-#1AC567:Frame-numFrameTextures-#E2334D" + } + PlotPerf { + title: "Memory Usage" + width:statsUI.width + config: stats.config + parameters: "1048576:Mb:1:CPU-textureSysmemUsage-#00B4EF:GPU-textureVidmemUsage-#1AC567" } } } diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index dd26ab2823..6148994a1b 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -74,6 +74,11 @@ void Context::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, cons _backend->downloadFramebuffer(srcFramebuffer, region, destImage); } + +void Context::getStats(ContextStats& stats) const { + _backend->getStats(stats); +} + const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const { _projectionInverse = glm::inverse(_projection); diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index d584f54acc..c4ad35020a 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -27,6 +27,21 @@ class QImage; namespace gpu { +struct ContextStats { +public: + int _ISNumFormatChanges = 0; + int _ISNumInputBufferChanges = 0; + int _ISNumIndexBufferChanges = 0; + + int _RSNumTextureBounded = 0; + + int _DSNumDrawcalls = 0; + int _DSNumTriangles = 0; + + ContextStats() {} + ContextStats(const ContextStats& stats) = default; +}; + struct StereoState { bool _enable{ false }; bool _skybox{ false }; @@ -100,9 +115,11 @@ public: return reinterpret_cast(object.gpuObject.getGPUObject()); } + void getStats(ContextStats& stats) const { stats = _stats; } protected: StereoState _stereo; + ContextStats _stats; }; class Context { @@ -125,6 +142,7 @@ public: ~Context(); void render(Batch& batch); + void enableStereo(bool enable = true); bool isStereo(); void setStereoProjections(const mat4 eyeProjections[2]); @@ -137,6 +155,9 @@ public: // It s here for convenience to easily capture a snapshot void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage); + // Repporting stats of the context + void getStats(ContextStats& stats) const; + protected: Context(const Context& context); diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index d93962f5a1..c8e3be81d1 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -67,6 +67,8 @@ public: GLBuffer(); ~GLBuffer(); + + void setSize(GLuint size); }; static GLBuffer* syncGPUObject(const Buffer& buffer); static GLuint getBufferID(const Buffer& buffer); @@ -234,26 +236,11 @@ public: void do_setStateBlend(State::BlendFunction blendFunction); void do_setStateColorWriteMask(uint32 mask); - - // Repporting stats of the context - class Stats { - public: - int _ISNumFormatChanges = 0; - int _ISNumInputBufferChanges = 0; - int _ISNumIndexBufferChanges = 0; - - Stats() {} - Stats(const Stats& stats) = default; - }; - - void getStats(Stats& stats) const { stats = _stats; } - + protected: void renderPassTransfer(Batch& batch); void renderPassDraw(Batch& batch); - Stats _stats; - // Draw Stage void do_draw(Batch& batch, size_t paramOffset); void do_drawIndexed(Batch& batch, size_t paramOffset); diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 49aeeca38e..56dd907b2e 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -16,12 +16,29 @@ GLBackend::GLBuffer::GLBuffer() : _stamp(0), _buffer(0), _size(0) -{} +{ + Buffer::_numGPUBuffers++; +} GLBackend::GLBuffer::~GLBuffer() { if (_buffer != 0) { glDeleteBuffers(1, &_buffer); } + Buffer::_bufferVideoMemoryUsage.fetch_sub(_size); + Buffer::_numGPUBuffers--; +} + +void GLBackend::GLBuffer::setSize(GLuint size) { + if (_size == size) { + return; + } + if (size > _size) { + Buffer::_bufferVideoMemoryUsage.fetch_add(size - _size); + } else { + Buffer::_bufferVideoMemoryUsage.fetch_sub(_size - size); + } + + _size = size; } GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { @@ -46,7 +63,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); object->_stamp = buffer.getSysmem().getStamp(); - object->_size = (GLuint)buffer.getSysmem().getSize(); + object->setSize((GLuint)buffer.getSysmem().getSize()); //} (void) CHECK_GL_ERROR(); diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 8c9647e0f2..046f1ff0e5 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -251,6 +251,9 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { return; } + // One more True texture bound + _stats._RSNumTextureBounded++; + // Always make sure the GLObject is in sync GLTexture* object = GLBackend::syncGPUObject(*resourceTexture); if (object) { diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index 197263f392..d0527d6d3a 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -232,19 +232,66 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) { return 0; } +std::atomic Buffer::_numBuffers{ 0 }; +std::atomic Buffer::_numGPUBuffers{ 0 }; +std::atomic Buffer::_bufferSystemMemoryUsage{ 0 }; +std::atomic Buffer::_bufferVideoMemoryUsage{ 0 }; + + +int Buffer::getCurrentNumBuffers() { + return _numBuffers.load(); +} + +Buffer::Size Buffer::getCurrentSystemMemoryUsage() { + return _bufferSystemMemoryUsage.load(); +} + +int Buffer::getCurrentNumGPUBuffers() { + return _numGPUBuffers.load(); +} + +Buffer::Size Buffer::getCurrentVideoMemoryUsage() { + return _bufferVideoMemoryUsage.load(); +} + +void Buffer::addSystemMemoryUsage(Size memorySize) { + _bufferSystemMemoryUsage.fetch_add(memorySize); +} +void Buffer::subSystemMemoryUsage(Size memorySize) { + _bufferSystemMemoryUsage.fetch_sub(memorySize); +} + +void Buffer::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (prevObjectSize > newObjectSize) { + subSystemMemoryUsage(prevObjectSize - newObjectSize); + } else { + addSystemMemoryUsage(newObjectSize - prevObjectSize); + } +} + + Buffer::Buffer() : Resource(), _sysmem(new Sysmem()) { + _numBuffers++; + } Buffer::Buffer(Size size, const Byte* bytes) : Resource(), _sysmem(new Sysmem(size, bytes)) { + _numBuffers++; + Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); } Buffer::Buffer(const Buffer& buf) : Resource(), _sysmem(new Sysmem(buf.getSysmem())) { + _numBuffers++; + Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); } Buffer& Buffer::operator=(const Buffer& buf) { @@ -253,18 +300,27 @@ Buffer& Buffer::operator=(const Buffer& buf) { } Buffer::~Buffer() { + _numBuffers--; + if (_sysmem) { + Buffer::updateSystemMemoryUsage(_sysmem->getSize(), 0); delete _sysmem; _sysmem = NULL; } } Buffer::Size Buffer::resize(Size size) { - return editSysmem().resize(size); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().resize(size); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } Buffer::Size Buffer::setData(Size size, const Byte* data) { - return editSysmem().setData(size, data); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().setData(size, data); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { @@ -272,6 +328,9 @@ Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { } Buffer::Size Buffer::append(Size size, const Byte* data) { - return editSysmem().append( size, data); + auto prevSize = editSysmem().getSize(); + auto newSize = editSysmem().append( size, data); + Buffer::updateSystemMemoryUsage(prevSize, newSize); + return newSize; } diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 3517b67203..d40e9131a1 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -16,6 +16,7 @@ #include "Format.h" #include +#include #include #ifdef _DEBUG @@ -109,7 +110,21 @@ protected: }; class Buffer : public Resource { + static std::atomic _numBuffers; + static std::atomic _bufferSystemMemoryUsage; public: + static std::atomic _numGPUBuffers; + static std::atomic _bufferVideoMemoryUsage; +private: + static void addSystemMemoryUsage(Size memorySize); + static void subSystemMemoryUsage(Size memorySize); + static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); + +public: + static int getCurrentNumBuffers(); + static Size getCurrentSystemMemoryUsage(); + static int getCurrentNumGPUBuffers(); + static Size getCurrentVideoMemoryUsage(); Buffer(); Buffer(Size size, const Byte* bytes); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 7a0e198ec9..cb0ef20c6c 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -57,13 +57,6 @@ void Texture::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { } } -void Texture::addVideoMemoryUsage(Size memorySize) { - _textureVideoMemoryUsage.fetch_add(memorySize); -} -void Texture::subVideoMemoryUsage(Size memorySize) { - _textureVideoMemoryUsage.fetch_sub(memorySize); -} - uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; Texture::Pixels::Pixels(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 06b0077458..087f305224 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -15,7 +15,6 @@ #include //min max and more #include -#include #include @@ -149,9 +148,6 @@ private: static void subSystemMemoryUsage(Size memorySize); static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); - static void addVideoMemoryUsage(Size memorySize); - static void subVideoMemoryUsage(Size memorySize); - public: static int getCurrentNumTextures(); diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 2118c3c734..b4ee713e74 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -67,10 +67,22 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte // Update the stats auto config = std::static_pointer_cast(renderContext->jobConfig); + config->numBuffers = gpu::Buffer::getCurrentNumBuffers(); + config->numGPUBuffers = gpu::Buffer::getCurrentNumGPUBuffers(); + config->bufferSysmemUsage = gpu::Buffer::getCurrentSystemMemoryUsage(); + config->bufferVidmemUsage = gpu::Buffer::getCurrentVideoMemoryUsage(); + config->numTextures = gpu::Texture::getCurrentNumTextures(); - config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); + config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); + gpu::ContextStats gpuStats(_gpuStats); + renderContext->args->_context->getStats(_gpuStats); + + config->numFrameTextures = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded; + + config->numFrameTriangles = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles; + config->emitDirty(); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 71c52c5910..4fd29b5d66 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -13,10 +13,10 @@ #define hifi_render_Engine_h #include +#include #include "Context.h" #include "Task.h" - namespace render { // The render engine holds all render tasks, and is itself a render task. @@ -53,18 +53,33 @@ namespace render { // A simple job collecting global stats on the Engine / Scene / GPU class EngineStatsConfig : public Job::Config{ Q_OBJECT - Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) - Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) + + Q_PROPERTY(int numBuffers MEMBER numBuffers NOTIFY dirty) + Q_PROPERTY(int numGPUBuffers MEMBER numGPUBuffers NOTIFY dirty) + Q_PROPERTY(qint64 bufferSysmemUsage MEMBER bufferSysmemUsage NOTIFY dirty) + Q_PROPERTY(qint64 bufferVidmemUsage MEMBER bufferVidmemUsage NOTIFY dirty) + + Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) + Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) + Q_PROPERTY(int numFrameTextures MEMBER numFrameTextures NOTIFY dirty) public: EngineStatsConfig() : Job::Config(true) {} + int numBuffers{ 0 }; + int numGPUBuffers{ 0 }; + qint64 bufferSysmemUsage{ 0 }; + qint64 bufferVidmemUsage{ 0 }; + int numTextures{ 0 }; int numGPUTextures{ 0 }; qint64 textureSysmemUsage{ 0 }; qint64 textureVidmemUsage{ 0 }; + int numFrameTriangles{ 0 }; + int numFrameTextures{ 0 }; + void emitDirty() { emit dirty(); } signals: @@ -78,6 +93,8 @@ namespace render { EngineStats() {} + gpu::ContextStats _gpuStats; + void configure(const Config& configuration) {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); }; From 864def31eabdfe1c6bebf71f64abd72b7065a892 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 10:56:20 -0700 Subject: [PATCH 16/61] Don't refresh NetworkGeometry with cache --- .../model-networking/src/model-networking/ModelCache.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 6c7c98047d..de4409a5a3 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -309,6 +309,10 @@ NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometr } void NetworkGeometry::resourceFinished(bool success) { + // FIXME: Model is not set up to handle a refresh + if (_instance) { + return; + } if (success) { _instance = std::make_shared(*_resource); } @@ -316,7 +320,8 @@ void NetworkGeometry::resourceFinished(bool success) { } void NetworkGeometry::resourceRefreshed() { - _instance.reset(); + // FIXME: Model is not set up to handle a refresh + // _instance.reset(); } const QString NetworkMaterial::NO_TEXTURE = QString(); From af55547766a2be8888344855087a919de43677a6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 11:46:24 -0700 Subject: [PATCH 17/61] Copy material schema buffers as new ref --- libraries/model/src/model/Material.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 5260143a7f..802650df93 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -18,26 +18,34 @@ using namespace gpu; Material::Material() : _key(0), _schemaBuffer(), - _textureMaps() { - - // only if created from nothing shall we create the Buffer to store the properties - Schema schema; - _schemaBuffer = gpu::BufferView(std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema)); + _textureMaps() +{ + // created from nothing: create the Buffer to store the properties + Schema schema; + _schemaBuffer = gpu::BufferView(std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema)); } Material::Material(const Material& material) : _key(material._key), - _schemaBuffer(material._schemaBuffer), - _textureMaps(material._textureMaps) { + _textureMaps(material._textureMaps) +{ + // copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer + Schema schema; + _schemaBuffer = gpu::BufferView(std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema)); + _schemaBuffer.edit() = material._schemaBuffer.get(); } Material& Material::operator= (const Material& material) { _key = (material._key); - _schemaBuffer = (material._schemaBuffer); _textureMaps = (material._textureMaps); + // copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer + Schema schema; + _schemaBuffer = gpu::BufferView(std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema)); + _schemaBuffer.edit() = material._schemaBuffer.get(); + return (*this); } From a262d9960cce3b02ce014197c257f5dded9e5504 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 11:47:33 -0700 Subject: [PATCH 18/61] Mind differently tex'ed instances --- .../src/model-networking/ModelCache.cpp | 20 +++++++------------ .../src/model-networking/ModelCache.h | 3 +-- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index de4409a5a3..7c692f1565 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -250,12 +250,11 @@ void Geometry::setTextures(const QVariantMap& textureMap) { [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.texture && textureMap.contains(it.name); })) { if (material->isOriginal()) { - // On first mutation, copy the material to avoid altering the cache - material = std::make_shared(*material, textureMap); - } else { - // On later mutations, we can mutate in-place - material->setTextures(textureMap); + // Copy the material to avoid mutating the cached version + material = std::make_shared(*material); } + + material->setTextures(textureMap); _areTexturesLoaded = false; } } @@ -359,15 +358,8 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, Textu return map; } -NetworkMaterial::NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap) : - NetworkMaterial(material) -{ - _isOriginal = false; - setTextures(textureMap); -} - NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) : - model::Material(*material._material), _isOriginal(true) + model::Material(*material._material) { _textures = Textures(MapChannel::NUM_MAP_CHANNELS); if (!material.albedoTexture.filename.isEmpty()) { @@ -430,6 +422,8 @@ NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textur } void NetworkMaterial::setTextures(const QVariantMap& textureMap) { + _isOriginal = false; + const auto& albedoName = getTextureName(MapChannel::ALBEDO_MAP); const auto& normalName = getTextureName(MapChannel::NORMAL_MAP); const auto& roughnessName = getTextureName(MapChannel::ROUGHNESS_MAP); diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 01a5e2165e..166ad128f2 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -139,7 +139,6 @@ public: using MapChannel = model::Material::MapChannel; NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl); - NetworkMaterial(const NetworkMaterial& material, const QVariantMap& textureMap); protected: friend class Geometry; @@ -171,7 +170,7 @@ private: Transform _lightmapTransform; vec2 _lightmapParams; - bool _isOriginal; + bool _isOriginal { true }; }; class NetworkShape { From 581bbea36ed3326d4d2ced740b49652908cba2df Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 11:57:02 -0700 Subject: [PATCH 19/61] Accomodate the caching Model --- .../src/model-networking/ModelCache.cpp | 22 +++++++++++++++---- .../src/model-networking/ModelCache.h | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 7c692f1565..d16fef040f 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -242,6 +242,18 @@ const QVariantMap Geometry::getTextures() const { return textures; } +// FIXME: The materials should only be copied when modified, but the Model currently caches the original +Geometry::Geometry(const Geometry& geometry) { + _geometry = geometry._geometry; + _meshes = geometry._meshes; + _shapes = geometry._shapes; + + _materials.reserve(geometry._materials.size()); + for (const auto& material : geometry._materials) { + _materials.push_back(std::make_shared(*material)); + } +} + void Geometry::setTextures(const QVariantMap& textureMap) { if (_meshes->size() > 0) { for (auto& material : _materials) { @@ -249,10 +261,12 @@ void Geometry::setTextures(const QVariantMap& textureMap) { if (std::any_of(material->_textures.cbegin(), material->_textures.cend(), [&textureMap](const NetworkMaterial::Textures::value_type& it) { return it.texture && textureMap.contains(it.name); })) { - if (material->isOriginal()) { - // Copy the material to avoid mutating the cached version - material = std::make_shared(*material); - } + // FIXME: The Model currently caches the materials (waste of space!) + // so they must be copied in the Geometry copy-ctor + // if (material->isOriginal()) { + // // Copy the material to avoid mutating the cached version + // material = std::make_shared(*material); + //} material->setTextures(textureMap); _areTexturesLoaded = false; diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 166ad128f2..dad7883a6a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -56,6 +56,9 @@ class Geometry { public: using Pointer = std::shared_ptr; + Geometry() = default; + Geometry(const Geometry& geometry); + // Immutable over lifetime using NetworkMeshes = std::vector>; using NetworkShapes = std::vector>; From d40e510752a426577e8df0a1a62d122868d52fcc Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 25 Mar 2016 12:59:28 -0700 Subject: [PATCH 20/61] no vrvj --- .../VR-VJ/VRVJSoundCartridgeEntityScript.js | 35 ----------- .../VR-VJ/VRVJVisualCartridgeEntityScript.js | 58 ------------------- examples/VR-VJ/cartridgesSpawner.js | 49 ---------------- 3 files changed, 142 deletions(-) delete mode 100644 examples/VR-VJ/VRVJSoundCartridgeEntityScript.js delete mode 100644 examples/VR-VJ/VRVJVisualCartridgeEntityScript.js delete mode 100644 examples/VR-VJ/cartridgesSpawner.js diff --git a/examples/VR-VJ/VRVJSoundCartridgeEntityScript.js b/examples/VR-VJ/VRVJSoundCartridgeEntityScript.js deleted file mode 100644 index c8e106c468..0000000000 --- a/examples/VR-VJ/VRVJSoundCartridgeEntityScript.js +++ /dev/null @@ -1,35 +0,0 @@ - -(function() { - var _this; - Script.include("../libraries/utils.js"); - VRVJSoundEntity = function() { - _this = this; - - }; - - VRVJSoundEntity.prototype = { - playSound: function() { - // _this.soundInjector = Audio.playSound(_this.clip, {position: _this.position, volume: 1.0}); - }, - - preload: function(entityID) { - _this.entityID = entityID; - _this.position = Entities.getEntityProperties(_this.entityID, "position").position; - _this.userData = getEntityUserData(_this.entityID); - _this.clip = SoundCache.getSound(_this.userData.soundURL); - - }, - - unload: function() { - if (_this.soundInjector) { - _this.soundInjector.stop(); - delete _this.soundInjector; - } - } - - - }; - - // entity scripts always need to return a newly constructed object of our type - return new VRVJSoundEntity(); -}); \ No newline at end of file diff --git a/examples/VR-VJ/VRVJVisualCartridgeEntityScript.js b/examples/VR-VJ/VRVJVisualCartridgeEntityScript.js deleted file mode 100644 index a37b830a58..0000000000 --- a/examples/VR-VJ/VRVJVisualCartridgeEntityScript.js +++ /dev/null @@ -1,58 +0,0 @@ -(function() { - var _this; - Script.include("../libraries/utils.js"); - var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; - var ZERO_VEC = {x: 0, y: 0, z: 0}; - VRVJVisualEntity = function() { - _this = this; - _this.SOUND_LOOP_NAME = "VRVJ-Sound-Cartridge"; - _this.SOUND_CARTRIDGE_SEARCH_RANGE = 0.1; - - }; - - VRVJVisualEntity.prototype = { - - releaseGrab: function() { - print("RELEASE GRAB") - // search for nearby sound loop entities and if found, add it as a parent - Script.setTimeout(function() { - _this.searchForNearbySoundLoops(); - }, 100); - }, - - searchForNearbySoundLoops: function() { - _this.position = Entities.getEntityProperties(_this.entityID, "position").position; - var entities = Entities.findEntities(_this.position, _this.SOUND_CARTRIDGE_SEARCH_RANGE); - for (var i = 0; i < entities.length; i++) { - var entity = entities[i]; - var props = Entities.getEntityProperties(entity, ["name", "color"]); - if (props.name.indexOf(_this.SOUND_LOOP_NAME) !== -1) { - // Need to set a timeout to wait for grab script to stop messing with entity - Entities.editEntity(_this.entityID, { - parentID: entity, - dynamic: false - }); - Script.setTimeout(function() { - Entities.editEntity(_this.entityID, {dynamic: true, velocity: ZERO_VEC, color: props.color}); - }, 100); - return; - } - - } - Entities.editEntity(_this.entityID, { - parentID: NULL_UUID, - color: _this.originalColor - }); - }, - - preload: function(entityID) { - print("YAAAA") - _this.entityID = entityID; - _this.originalColor = Entities.getEntityProperties(_this.entityID, "color").color; - - }, - }; - - // entity scripts always need to return a newly constructed object of our type - return new VRVJVisualEntity(); -}); \ No newline at end of file diff --git a/examples/VR-VJ/cartridgesSpawner.js b/examples/VR-VJ/cartridgesSpawner.js deleted file mode 100644 index 3ce8fd953a..0000000000 --- a/examples/VR-VJ/cartridgesSpawner.js +++ /dev/null @@ -1,49 +0,0 @@ - var orientation = MyAvatar.orientation; - orientation = Quat.safeEulerAngles(orientation); - orientation.x = 0; - orientation = Quat.fromVec3Degrees(orientation); - var center = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(2, Quat.getFront(orientation))); - - -Script.include("../libraries/utils.js"); - -var SOUND_SCRIPT_URL = Script.resolvePath("VRVJSoundCartridgeEntityScript.js"); -var SOUND_CARTRIDGE_NAME = "VRVJ-Sound-Cartridge"; -var soundEntity = Entities.addEntity({ - type: "Box", - name: SOUND_CARTRIDGE_NAME, - dimensions: {x: 0.1, y: 0.1, z: 0.1}, - color: {red: 200, green: 10, blue: 200}, - position: center, - damping: 1, - angularDamping: 1, - dynamic: true, - script: SOUND_SCRIPT_URL, - userData: JSON.stringify({ - soundURL: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/VRVJ/Synth-MarchToWar.wav", - }) -}); - -var VISUAL_SCRIPT_URL = Script.resolvePath("VRVJVisualCartridgeEntityScript.js?v1" + Math.random()); -var visualEntity = Entities.addEntity({ - type: "Sphere", - name: "VRVJ-Visual-Cartridge", - dimensions: {x: 0.1, y: 0.1, z: 0.1}, - damping: 1, - angularDamping: 1, - color: {red: 0, green: 200, blue: 10}, - dynamic: true, - position: Vec3.subtract(center, {x: 0, y: 0.2, z: 0}), - script: VISUAL_SCRIPT_URL -}); -Script.setTimeout(function() { - // Wait for sounds to load - Entities.callEntityMethod(soundEntity, "playSound"); -}, 1000) - -function cleanup() { - Entities.deleteEntity(soundEntity); - Entities.deleteEntity(visualEntity); -} - -Script.scriptEnding.connect(cleanup); \ No newline at end of file From fac54b6ee3900e5d7443b416be117123a752641e Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 13:00:18 -0700 Subject: [PATCH 21/61] Maintain parity with tex changes --- .../src/model-networking/ModelCache.cpp | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index d16fef040f..78ea7dd30e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -348,7 +348,7 @@ const QString& NetworkMaterial::getTextureName(MapChannel channel) { QUrl NetworkMaterial::getTextureUrl(const QUrl& url, const FBXTexture& texture) { // If content is inline, cache it under the fbx file, not its url - const auto baseUrl = texture.content.isEmpty() ? url: QUrl(url.url() + "/"); + const auto baseUrl = texture.content.isEmpty() ? url : QUrl(url.url() + "/"); return baseUrl.resolved(QUrl(texture.filename)); } @@ -446,43 +446,50 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { const auto& emissiveName = getTextureName(MapChannel::EMISSIVE_MAP); const auto& lightmapName = getTextureName(MapChannel::LIGHTMAP_MAP); - if (!albedoName.isEmpty() && textureMap.contains(albedoName)) { - auto map = fetchTextureMap(textureMap[albedoName].toUrl(), DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); + if (!albedoName.isEmpty()) { + auto url = textureMap.contains(albedoName) ? textureMap[albedoName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::ALBEDO_MAP); map->setTextureTransform(_albedoTransform); // when reassigning the albedo texture we also check for the alpha channel used as opacity map->setUseAlphaChannel(true); setTextureMap(MapChannel::ALBEDO_MAP, map); } - if (!normalName.isEmpty() && textureMap.contains(normalName)) { - auto map = fetchTextureMap(textureMap[normalName].toUrl(), DEFAULT_TEXTURE, MapChannel::NORMAL_MAP); + if (!normalName.isEmpty()) { + auto url = textureMap.contains(normalName) ? textureMap[normalName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, DEFAULT_TEXTURE, MapChannel::NORMAL_MAP); setTextureMap(MapChannel::NORMAL_MAP, map); } - if (!roughnessName.isEmpty() && textureMap.contains(roughnessName)) { + if (!roughnessName.isEmpty()) { + auto url = textureMap.contains(roughnessName) ? textureMap[roughnessName].toUrl() : QUrl(); // FIXME: If passing a gloss map instead of a roughmap how do we know? - auto map = fetchTextureMap(textureMap[roughnessName].toUrl(), ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); + auto map = fetchTextureMap(url, ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP); setTextureMap(MapChannel::ROUGHNESS_MAP, map); } - if (!metallicName.isEmpty() && textureMap.contains(metallicName)) { + if (!metallicName.isEmpty()) { + auto url = textureMap.contains(metallicName) ? textureMap[metallicName].toUrl() : QUrl(); // FIXME: If passing a specular map instead of a metallic how do we know? - auto map = fetchTextureMap(textureMap[metallicName].toUrl(), METALLIC_TEXTURE, MapChannel::METALLIC_MAP); + auto map = fetchTextureMap(url, METALLIC_TEXTURE, MapChannel::METALLIC_MAP); setTextureMap(MapChannel::METALLIC_MAP, map); } - if (!occlusionName.isEmpty() && textureMap.contains(occlusionName)) { - auto map = fetchTextureMap(textureMap[occlusionName].toUrl(), OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); + if (!occlusionName.isEmpty()) { + auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP); setTextureMap(MapChannel::OCCLUSION_MAP, map); } - if (!emissiveName.isEmpty() && textureMap.contains(emissiveName)) { - auto map = fetchTextureMap(textureMap[emissiveName].toUrl(), EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); + if (!emissiveName.isEmpty()) { + auto url = textureMap.contains(emissiveName) ? textureMap[emissiveName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP); setTextureMap(MapChannel::EMISSIVE_MAP, map); } - if (!lightmapName.isEmpty() && textureMap.contains(lightmapName)) { - auto map = fetchTextureMap(textureMap[lightmapName].toUrl(), LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); + if (!lightmapName.isEmpty()) { + auto url = textureMap.contains(lightmapName) ? textureMap[lightmapName].toUrl() : QUrl(); + auto map = fetchTextureMap(url, LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP); map->setTextureTransform(_lightmapTransform); map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y); setTextureMap(MapChannel::LIGHTMAP_MAP, map); From b90f2b2e0a9b895c6f6111e56df5f9a9fa69b2a0 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 25 Mar 2016 13:17:29 -0700 Subject: [PATCH 22/61] Use correct textureBaseUrl --- libraries/model-networking/src/model-networking/ModelCache.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 78ea7dd30e..2a6f33b964 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -157,7 +157,7 @@ class GeometryDefinitionResource : public GeometryResource { Q_OBJECT public: GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) : - GeometryResource(url), _mapping(mapping), _textureBaseUrl(textureBaseUrl) {} + GeometryResource(url), _mapping(mapping), _textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {} virtual void downloadFinished(const QByteArray& data) override; @@ -497,4 +497,3 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { } #include "ModelCache.moc" - From 9b58d50fd4ed96dc04f365baf2ea457e67e28ee1 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 25 Mar 2016 15:28:06 -0700 Subject: [PATCH 23/61] BUilding a more complete set of tools to monitor performances --- examples/utilities/tools/render/PlotPerf.qml | 73 ++++++++++++---- examples/utilities/tools/render/stats.qml | 44 +++++++--- libraries/gpu/src/gpu/Context.h | 2 +- libraries/gpu/src/gpu/GLBackend.cpp | 17 +++- libraries/render/src/render/Engine.cpp | 26 +----- libraries/render/src/render/Engine.h | 52 ----------- libraries/render/src/render/EngineStats.cpp | 50 +++++++++++ libraries/render/src/render/EngineStats.h | 91 ++++++++++++++++++++ 8 files changed, 244 insertions(+), 111 deletions(-) create mode 100644 libraries/render/src/render/EngineStats.cpp create mode 100644 libraries/render/src/render/EngineStats.h diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml index 00b7848936..c907b847a8 100644 --- a/examples/utilities/tools/render/PlotPerf.qml +++ b/examples/utilities/tools/render/PlotPerf.qml @@ -13,6 +13,7 @@ import QtQuick.Controls 1.4 Item { id: root + width: parent.width height: 100 property string title property var config @@ -34,12 +35,15 @@ Item { if (inputs.length > input_VALUE_OFFSET) { for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { var varProps = inputs[i].split("-") - _values.push( { + _values.push( { value: varProps[1], valueMax: 1, + numSamplesConstantMax: 0, valueHistory: new Array(), label: varProps[0], - color: varProps[2] + color: varProps[2], + scale: (varProps.length > 3 ? varProps[3] : 1), + unit: (varProps.length > 4 ? varProps[4] : valueUnit) }) } } @@ -59,25 +63,40 @@ Item { var UPDATE_CANVAS_RATE = 20; tick++; - valueMax = 0 + + var currentValueMax = 0 for (var i = 0; i < _values.length; i++) { - var currentVal = stats.config[_values[i].value]; - if (_values[i].valueMax < currentVal) { - _values[i].valueMax = currentVal; - } + + var currentVal = stats.config[_values[i].value] * _values[i].scale; _values[i].valueHistory.push(currentVal) + _values[i].numSamplesConstantMax++; + if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) { var lostValue = _values[i].valueHistory.shift(); if (lostValue >= _values[i].valueMax) { _values[i].valueMax *= 0.99 + _values[i].numSamplesConstantMax = 0 } } - if (valueMax < _values[i].valueMax) { - valueMax = _values[i].valueMax + if (_values[i].valueMax < currentVal) { + _values[i].valueMax = currentVal; + _values[i].numSamplesConstantMax = 0 + } + + if (_values[i].numSamplesConstantMax > VALUE_HISTORY_SIZE) { + _values[i].numSamplesConstantMax = 0 + _values[i].valueMax *= 0.95 // lower slowly the current max if no new above max since a while + } + + if (currentValueMax < _values[i].valueMax) { + currentValueMax = _values[i].valueMax } } + if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) { + valueMax = currentValueMax; + } if (tick % UPDATE_CANVAS_RATE == 0) { mycanvas.requestPaint() @@ -91,20 +110,23 @@ Item { onPaint: { var lineHeight = 12; - function displayValue(val) { - return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + root.valueUnit + function displayValue(val, unit) { + return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + unit } - function pixelFromVal(val) { + function pixelFromVal(val, valScale) { return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax); } + function valueFromPixel(pixY) { + return ((pixY - lineHeight) / (height - lineHeight) - 1) * valueMax / (-0.9); + } function plotValueHistory(ctx, valHistory, color) { var widthStep= width / (valHistory.length - 1); ctx.beginPath(); ctx.strokeStyle= color; // Green path ctx.lineWidth="2"; - ctx.moveTo(0, pixelFromVal(valHistory[i])); + ctx.moveTo(0, pixelFromVal(valHistory[0])); for (var i = 1; i < valHistory.length; i++) { ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i])); @@ -116,27 +138,40 @@ Item { ctx.fillStyle = val.color; var bestValue = val.valueHistory[val.valueHistory.length -1]; ctx.textAlign = "right"; - ctx.fillText(displayValue(bestValue), width, height - num * lineHeight); + ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); ctx.textAlign = "left"; - ctx.fillText(val.label, 0, height - num * lineHeight); + ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); } function displayTitle(ctx, text, maxVal) { ctx.fillStyle = "grey"; ctx.textAlign = "right"; - ctx.fillText(displayValue(maxVal), width, lineHeight); + ctx.fillText(displayValue(valueFromPixel(lineHeight), root.valueUnit), width, lineHeight); ctx.fillStyle = "white"; ctx.textAlign = "left"; ctx.fillText(text, 0, lineHeight); } + function displayBackground(ctx) { + ctx.fillStyle = Qt.rgba(0, 0, 0, 0.6); + ctx.fillRect(0, 0, width, height); + + ctx.strokeStyle= "grey"; + ctx.lineWidth="2"; + + ctx.beginPath(); + ctx.moveTo(0, lineHeight + 1); + ctx.lineTo(width, lineHeight + 1); + ctx.moveTo(0, height); + ctx.lineTo(width, height); + ctx.stroke(); + } var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - ctx.fillStyle = Qt.rgba(0, 0, 0, 0.4); - ctx.fillRect(0, 0, width, height); - ctx.font="12px Verdana"; + + displayBackground(ctx); for (var i = 0; i < _values.length; i++) { plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 47c0f98568..9c0ac3e14d 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -12,40 +12,58 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -Column { +Item { id: statsUI - width: 300 - spacing: 8 - Column { - spacing: 8 + anchors.fill:parent - property var config: Render.getConfig("Stats") + Column { id: stats + spacing: 8 + anchors.fill:parent + + property var config: Render.getConfig("Stats") + + function evalEvenHeight() { + // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? + return (height - spacing * (children.length - 1)) / children.length + } PlotPerf { title: "Num Buffers" - width:statsUI.width config: stats.config + height: parent.evalEvenHeight() parameters: "1::0:CPU-numBuffers-#00B4EF:GPU-numGPUBuffers-#1AC567" } PlotPerf { - title: "Memory Usage" - width:statsUI.width + title: "gpu::Buffer Memory" config: stats.config + height: parent.evalEvenHeight() parameters: "1048576:Mb:1:CPU-bufferSysmemUsage-#00B4EF:GPU-bufferVidmemUsage-#1AC567" } PlotPerf { title: "Num Textures" - width:statsUI.width config: stats.config - parameters: "1::0:CPU-numTextures-#00B4EF:GPU-numGPUTextures-#1AC567:Frame-numFrameTextures-#E2334D" + height: parent.evalEvenHeight() + parameters: "1::0:CPU-numTextures-#00B4EF:GPU-numGPUTextures-#1AC567:Frame-frameTextureCount-#E2334D" } PlotPerf { - title: "Memory Usage" - width:statsUI.width + title: "gpu::Texture Memory" config: stats.config + height: parent.evalEvenHeight() parameters: "1048576:Mb:1:CPU-textureSysmemUsage-#00B4EF:GPU-textureVidmemUsage-#1AC567" } + PlotPerf { + title: "Drawcalls" + config: stats.config + height: parent.evalEvenHeight() + parameters: "1::0:frame-frameDrawcallCount-#E2334D:rate-frameDrawcallRate-#1AC567-0.001-K/s" + } + PlotPerf { + title: "Triangles" + config: stats.config + height: parent.evalEvenHeight() + parameters: "1000:K:0:frame-frameTriangleCount-#E2334D:rate-frameTriangleRate-#1AC567-0.001-MT/s" + } } } diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index c4ad35020a..c2cd1f239e 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -37,7 +37,7 @@ public: int _DSNumDrawcalls = 0; int _DSNumTriangles = 0; - + ContextStats() {} ContextStats(const ContextStats& stats) = default; }; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index 2c25255a80..e847ad1a42 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -324,7 +324,10 @@ void GLBackend::do_draw(Batch& batch, size_t paramOffset) { uint32 numVertices = batch._params[paramOffset + 1]._uint; uint32 startVertex = batch._params[paramOffset + 0]._uint; glDrawArrays(mode, startVertex, numVertices); - (void) CHECK_GL_ERROR(); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + + (void)CHECK_GL_ERROR(); } void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) { @@ -339,6 +342,9 @@ void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) { GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + _stats._DSNumTriangles += numIndices / 3; + _stats._DSNumDrawcalls++; + (void) CHECK_GL_ERROR(); } @@ -350,6 +356,9 @@ void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) { uint32 startVertex = batch._params[paramOffset + 1]._uint; glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances); + _stats._DSNumTriangles += (numInstances * numVertices) / 3; + _stats._DSNumDrawcalls += numInstances; + (void) CHECK_GL_ERROR(); } @@ -372,6 +381,9 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) { glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, numInstances); Q_UNUSED(startInstance); #endif + _stats._DSNumTriangles += (numInstances * numIndices) / 3; + _stats._DSNumDrawcalls += numInstances; + (void)CHECK_GL_ERROR(); } @@ -382,6 +394,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) { GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; #else // FIXME implement the slow path #endif @@ -396,6 +409,8 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) { GLenum indexType = _elementTypeToGLType[_input._indexBufferType]; glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; + #else // FIXME implement the slow path #endif diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index b4ee713e74..b0329faa3e 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -17,6 +17,7 @@ #include +#include "EngineStats.h" using namespace render; @@ -61,28 +62,3 @@ void Engine::run() { } -#include -void EngineStats::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - const size_t KILO_BYTES = 1024; - // Update the stats - auto config = std::static_pointer_cast(renderContext->jobConfig); - - config->numBuffers = gpu::Buffer::getCurrentNumBuffers(); - config->numGPUBuffers = gpu::Buffer::getCurrentNumGPUBuffers(); - config->bufferSysmemUsage = gpu::Buffer::getCurrentSystemMemoryUsage(); - config->bufferVidmemUsage = gpu::Buffer::getCurrentVideoMemoryUsage(); - - config->numTextures = gpu::Texture::getCurrentNumTextures(); - config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); - config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); - config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); - - gpu::ContextStats gpuStats(_gpuStats); - renderContext->args->_context->getStats(_gpuStats); - - config->numFrameTextures = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded; - - config->numFrameTriangles = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles; - - config->emitDirty(); -} diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 4fd29b5d66..d2bb42e5ff 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -13,7 +13,6 @@ #define hifi_render_Engine_h #include -#include #include "Context.h" #include "Task.h" @@ -49,57 +48,6 @@ namespace render { }; using EnginePointer = std::shared_ptr; - - // A simple job collecting global stats on the Engine / Scene / GPU - class EngineStatsConfig : public Job::Config{ - Q_OBJECT - - Q_PROPERTY(int numBuffers MEMBER numBuffers NOTIFY dirty) - Q_PROPERTY(int numGPUBuffers MEMBER numGPUBuffers NOTIFY dirty) - Q_PROPERTY(qint64 bufferSysmemUsage MEMBER bufferSysmemUsage NOTIFY dirty) - Q_PROPERTY(qint64 bufferVidmemUsage MEMBER bufferVidmemUsage NOTIFY dirty) - - Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) - Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) - Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) - Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) - Q_PROPERTY(int numFrameTextures MEMBER numFrameTextures NOTIFY dirty) - public: - EngineStatsConfig() : Job::Config(true) {} - - int numBuffers{ 0 }; - int numGPUBuffers{ 0 }; - qint64 bufferSysmemUsage{ 0 }; - qint64 bufferVidmemUsage{ 0 }; - - int numTextures{ 0 }; - int numGPUTextures{ 0 }; - qint64 textureSysmemUsage{ 0 }; - qint64 textureVidmemUsage{ 0 }; - - int numFrameTriangles{ 0 }; - int numFrameTextures{ 0 }; - - void emitDirty() { emit dirty(); } - - signals: - void dirty(); - }; - - class EngineStats { - public: - using Config = EngineStatsConfig; - using JobModel = Job::Model; - - EngineStats() {} - - gpu::ContextStats _gpuStats; - - void configure(const Config& configuration) {} - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - }; - - } #endif // hifi_render_Engine_h diff --git a/libraries/render/src/render/EngineStats.cpp b/libraries/render/src/render/EngineStats.cpp new file mode 100644 index 0000000000..63a25229ea --- /dev/null +++ b/libraries/render/src/render/EngineStats.cpp @@ -0,0 +1,50 @@ +// +// EngineStats.cpp +// render/src/render +// +// Created by Sam Gateau on 3/27/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 "EngineStats.h" + +#include + +using namespace render; + +void EngineStats::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + // Tick time + + quint64 msecsElapsed = _frameTimer.restart(); + double frequency = 1000.0 / msecsElapsed; + + + // Update the stats + auto config = std::static_pointer_cast(renderContext->jobConfig); + + config->numBuffers = gpu::Buffer::getCurrentNumBuffers(); + config->numGPUBuffers = gpu::Buffer::getCurrentNumGPUBuffers(); + config->bufferSysmemUsage = gpu::Buffer::getCurrentSystemMemoryUsage(); + config->bufferVidmemUsage = gpu::Buffer::getCurrentVideoMemoryUsage(); + + config->numTextures = gpu::Texture::getCurrentNumTextures(); + config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); + config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); + config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); + + gpu::ContextStats gpuStats(_gpuStats); + renderContext->args->_context->getStats(_gpuStats); + + config->frameDrawcallCount = _gpuStats._DSNumDrawcalls - gpuStats._DSNumDrawcalls; + config->frameDrawcallRate = config->frameDrawcallCount * frequency; + + config->frameTriangleCount = _gpuStats._DSNumTriangles - gpuStats._DSNumTriangles; + config->frameTriangleRate = config->frameTriangleCount * frequency; + + config->frameTextureCount = _gpuStats._RSNumTextureBounded - gpuStats._RSNumTextureBounded; + config->frameTextureRate = config->frameTextureCount * frequency; + + config->emitDirty(); +} diff --git a/libraries/render/src/render/EngineStats.h b/libraries/render/src/render/EngineStats.h new file mode 100644 index 0000000000..d9f7e7ac9a --- /dev/null +++ b/libraries/render/src/render/EngineStats.h @@ -0,0 +1,91 @@ +// +// EngineStats.h +// render/src/render +// +// Created by Sam Gateau on 3/27/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_render_EngineStats_h +#define hifi_render_EngineStats_h + +#include + +#include + +#include "Engine.h" + +namespace render { + + // A simple job collecting global stats on the Engine / Scene / GPU + class EngineStatsConfig : public Job::Config{ + Q_OBJECT + + Q_PROPERTY(int numBuffers MEMBER numBuffers NOTIFY dirty) + Q_PROPERTY(int numGPUBuffers MEMBER numGPUBuffers NOTIFY dirty) + Q_PROPERTY(qint64 bufferSysmemUsage MEMBER bufferSysmemUsage NOTIFY dirty) + Q_PROPERTY(qint64 bufferVidmemUsage MEMBER bufferVidmemUsage NOTIFY dirty) + + Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) + Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) + Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) + Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) + + Q_PROPERTY(int frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty) + Q_PROPERTY(int frameDrawcallRate MEMBER frameDrawcallRate NOTIFY dirty) + + Q_PROPERTY(int frameTriangleCount MEMBER frameTriangleCount NOTIFY dirty) + Q_PROPERTY(int frameTriangleRate MEMBER frameTriangleRate NOTIFY dirty) + + Q_PROPERTY(int frameTextureCount MEMBER frameTextureCount NOTIFY dirty) + Q_PROPERTY(int frameTextureRate MEMBER frameTextureRate NOTIFY dirty) + + + public: + EngineStatsConfig() : Job::Config(true) {} + + int numBuffers{ 0 }; + int numGPUBuffers{ 0 }; + qint64 bufferSysmemUsage{ 0 }; + qint64 bufferVidmemUsage{ 0 }; + + int numTextures{ 0 }; + int numGPUTextures{ 0 }; + qint64 textureSysmemUsage{ 0 }; + qint64 textureVidmemUsage{ 0 }; + + int frameDrawcallCount{ 0 }; + int frameDrawcallRate{ 0 }; + + int frameTriangleCount{ 0 }; + int frameTriangleRate{ 0 }; + + int frameTextureCount{ 0 }; + int frameTextureRate{ 0 }; + + void emitDirty() { emit dirty(); } + + signals: + void dirty(); + }; + + class EngineStats { + public: + using Config = EngineStatsConfig; + using JobModel = Job::Model; + + EngineStats() { _frameTimer.start(); } + + gpu::ContextStats _gpuStats; + + void configure(const Config& configuration) {} + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); + + QElapsedTimer _frameTimer; + }; +} + +#endif \ No newline at end of file From 5190878db21b28047a81b14f77c9528b002ca1cf Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 25 Mar 2016 16:18:04 -0700 Subject: [PATCH 24/61] removing a debug trick --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cb312047c2..b9effa444b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -269,7 +269,7 @@ public: void run() override { while (!_quit) { QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); -#ifdef ____NDEBUG +#ifdef NDEBUG auto now = usecTimestampNow(); auto lastHeartbeatAge = now - _heartbeat; if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { From 73613040841858e85e1b95abab03f3c285c62d89 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 25 Mar 2016 18:38:52 -0700 Subject: [PATCH 25/61] Cleaning up for review --- examples/utilities/tools/render/PlotPerf.qml | 10 ++-- examples/utilities/tools/render/stats.qml | 14 ++--- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 10 ++-- libraries/gpu/src/gpu/GLBackendTexture.cpp | 10 ++-- libraries/gpu/src/gpu/Resource.cpp | 58 +++++++++----------- libraries/gpu/src/gpu/Resource.h | 24 ++++---- libraries/gpu/src/gpu/Texture.cpp | 56 +++++++++---------- libraries/gpu/src/gpu/Texture.h | 25 ++++----- libraries/render/src/render/EngineStats.cpp | 22 +++++--- libraries/render/src/render/EngineStats.h | 56 +++++++++---------- 10 files changed, 137 insertions(+), 148 deletions(-) diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml index c907b847a8..0e100e4e72 100644 --- a/examples/utilities/tools/render/PlotPerf.qml +++ b/examples/utilities/tools/render/PlotPerf.qml @@ -19,7 +19,9 @@ Item { property var config property string parameters - property var trigger: config["numTextures"] + // THis is my hack to get the name of the first property and assign it to a trigger var in order to get + // a signal called whenever the value changed + property var trigger: config[parameters.split(":")[3].split("-")[0]] property var inputs: parameters.split(":") property var valueScale: +inputs[0] @@ -36,11 +38,11 @@ Item { for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { var varProps = inputs[i].split("-") _values.push( { - value: varProps[1], + value: varProps[0], valueMax: 1, numSamplesConstantMax: 0, valueHistory: new Array(), - label: varProps[0], + label: varProps[1], color: varProps[2], scale: (varProps.length > 3 ? varProps[3] : 1), unit: (varProps.length > 4 ? varProps[4] : valueUnit) @@ -67,7 +69,7 @@ Item { var currentValueMax = 0 for (var i = 0; i < _values.length; i++) { - var currentVal = stats.config[_values[i].value] * _values[i].scale; + var currentVal = config[_values[i].value] * _values[i].scale; _values[i].valueHistory.push(currentVal) _values[i].numSamplesConstantMax++; diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 9c0ac3e14d..142b5e25e2 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -32,38 +32,38 @@ Item { title: "Num Buffers" config: stats.config height: parent.evalEvenHeight() - parameters: "1::0:CPU-numBuffers-#00B4EF:GPU-numGPUBuffers-#1AC567" + parameters: "1::0:bufferCPUCount-CPU-#00B4EF:bufferGPUCount-GPU-#1AC567" } PlotPerf { title: "gpu::Buffer Memory" - config: stats.config + config: stats.config height: parent.evalEvenHeight() - parameters: "1048576:Mb:1:CPU-bufferSysmemUsage-#00B4EF:GPU-bufferVidmemUsage-#1AC567" + parameters: "1048576:Mb:1:bufferCPUMemoryUsage-CPU-#00B4EF:bufferGPUMemoryUsage-GPU-#1AC567" } PlotPerf { title: "Num Textures" config: stats.config height: parent.evalEvenHeight() - parameters: "1::0:CPU-numTextures-#00B4EF:GPU-numGPUTextures-#1AC567:Frame-frameTextureCount-#E2334D" + parameters: "1::0:textureCPUCount-CPU-#00B4EF:textureGPUCount-GPU-#1AC567:frameTextureCount-Frame-#E2334D" } PlotPerf { title: "gpu::Texture Memory" config: stats.config height: parent.evalEvenHeight() - parameters: "1048576:Mb:1:CPU-textureSysmemUsage-#00B4EF:GPU-textureVidmemUsage-#1AC567" + parameters: "1048576:Mb:1:textureCPUMemoryUsage-CPU-#00B4EF:textureGPUMemoryUsage-GPU-#1AC567" } PlotPerf { title: "Drawcalls" config: stats.config height: parent.evalEvenHeight() - parameters: "1::0:frame-frameDrawcallCount-#E2334D:rate-frameDrawcallRate-#1AC567-0.001-K/s" + parameters: "1::0:frameDrawcallCount-frame-#E2334D:frameDrawcallRate-rate-#1AC567-0.001-K/s" } PlotPerf { title: "Triangles" config: stats.config height: parent.evalEvenHeight() - parameters: "1000:K:0:frame-frameTriangleCount-#E2334D:rate-frameTriangleRate-#1AC567-0.001-MT/s" + parameters: "1000:K:0:frameTriangleCount-frame-#E2334D:frameTriangleRate-rate-#1AC567-0.001-MT/s" } } } diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 56dd907b2e..8b8af386bb 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -17,15 +17,15 @@ GLBackend::GLBuffer::GLBuffer() : _buffer(0), _size(0) { - Buffer::_numGPUBuffers++; + Buffer::_bufferGPUCount++; } GLBackend::GLBuffer::~GLBuffer() { if (_buffer != 0) { glDeleteBuffers(1, &_buffer); } - Buffer::_bufferVideoMemoryUsage.fetch_sub(_size); - Buffer::_numGPUBuffers--; + Buffer::_bufferGPUMemoryUsage.fetch_sub(_size); + Buffer::_bufferGPUCount--; } void GLBackend::GLBuffer::setSize(GLuint size) { @@ -33,9 +33,9 @@ void GLBackend::GLBuffer::setSize(GLuint size) { return; } if (size > _size) { - Buffer::_bufferVideoMemoryUsage.fetch_add(size - _size); + Buffer::_bufferGPUMemoryUsage.fetch_add(size - _size); } else { - Buffer::_bufferVideoMemoryUsage.fetch_sub(_size - size); + Buffer::_bufferGPUMemoryUsage.fetch_sub(_size - size); } _size = size; diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 6a96c5a651..bc25048a3f 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -20,15 +20,15 @@ GLBackend::GLTexture::GLTexture() : _target(GL_TEXTURE_2D), _size(0) { - Texture::_numGPUTextures++; + Texture::_textureGPUCount++; } GLBackend::GLTexture::~GLTexture() { if (_texture != 0) { glDeleteTextures(1, &_texture); } - Texture::_textureVideoMemoryUsage.fetch_sub(_size); - Texture::_numGPUTextures--; + Texture::_textureGPUMemoryUsage.fetch_sub(_size); + Texture::_textureGPUCount--; } void GLBackend::GLTexture::setSize(GLuint size) { @@ -36,9 +36,9 @@ void GLBackend::GLTexture::setSize(GLuint size) { return; } if (size > _size) { - Texture::_textureVideoMemoryUsage.fetch_add(size - _size); + Texture::_textureGPUMemoryUsage.fetch_add(size - _size); } else { - Texture::_textureVideoMemoryUsage.fetch_sub(_size - size); + Texture::_textureGPUMemoryUsage.fetch_sub(_size - size); } _size = size; diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index d0527d6d3a..f10d95c03b 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -232,43 +232,35 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) { return 0; } -std::atomic Buffer::_numBuffers{ 0 }; -std::atomic Buffer::_numGPUBuffers{ 0 }; -std::atomic Buffer::_bufferSystemMemoryUsage{ 0 }; -std::atomic Buffer::_bufferVideoMemoryUsage{ 0 }; +std::atomic Buffer::_bufferCPUCount{ 0 }; +std::atomic Buffer::_bufferGPUCount{ 0 }; +std::atomic Buffer::_bufferCPUMemoryUsage{ 0 }; +std::atomic Buffer::_bufferGPUMemoryUsage{ 0 }; - -int Buffer::getCurrentNumBuffers() { - return _numBuffers.load(); +uint32_t Buffer::getBufferCPUCount() { + return _bufferCPUCount.load(); } -Buffer::Size Buffer::getCurrentSystemMemoryUsage() { - return _bufferSystemMemoryUsage.load(); +Buffer::Size Buffer::getBufferCPUMemoryUsage() { + return _bufferCPUMemoryUsage.load(); } -int Buffer::getCurrentNumGPUBuffers() { - return _numGPUBuffers.load(); +uint32_t Buffer::getBufferGPUCount() { + return _bufferGPUCount.load(); } -Buffer::Size Buffer::getCurrentVideoMemoryUsage() { - return _bufferVideoMemoryUsage.load(); +Buffer::Size Buffer::getBufferGPUMemoryUsage() { + return _bufferGPUMemoryUsage.load(); } -void Buffer::addSystemMemoryUsage(Size memorySize) { - _bufferSystemMemoryUsage.fetch_add(memorySize); -} -void Buffer::subSystemMemoryUsage(Size memorySize) { - _bufferSystemMemoryUsage.fetch_sub(memorySize); -} - -void Buffer::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { +void Buffer::updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { return; } if (prevObjectSize > newObjectSize) { - subSystemMemoryUsage(prevObjectSize - newObjectSize); + _bufferCPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize); } else { - addSystemMemoryUsage(newObjectSize - prevObjectSize); + _bufferCPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize); } } @@ -276,22 +268,22 @@ void Buffer::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { Buffer::Buffer() : Resource(), _sysmem(new Sysmem()) { - _numBuffers++; + _bufferCPUCount++; } Buffer::Buffer(Size size, const Byte* bytes) : Resource(), _sysmem(new Sysmem(size, bytes)) { - _numBuffers++; - Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); + _bufferCPUCount++; + Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize()); } Buffer::Buffer(const Buffer& buf) : Resource(), _sysmem(new Sysmem(buf.getSysmem())) { - _numBuffers++; - Buffer::updateSystemMemoryUsage(0, _sysmem->getSize()); + _bufferCPUCount++; + Buffer::updateBufferCPUMemoryUsage(0, _sysmem->getSize()); } Buffer& Buffer::operator=(const Buffer& buf) { @@ -300,10 +292,10 @@ Buffer& Buffer::operator=(const Buffer& buf) { } Buffer::~Buffer() { - _numBuffers--; + _bufferCPUCount--; if (_sysmem) { - Buffer::updateSystemMemoryUsage(_sysmem->getSize(), 0); + Buffer::updateBufferCPUMemoryUsage(_sysmem->getSize(), 0); delete _sysmem; _sysmem = NULL; } @@ -312,14 +304,14 @@ Buffer::~Buffer() { Buffer::Size Buffer::resize(Size size) { auto prevSize = editSysmem().getSize(); auto newSize = editSysmem().resize(size); - Buffer::updateSystemMemoryUsage(prevSize, newSize); + Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); return newSize; } Buffer::Size Buffer::setData(Size size, const Byte* data) { auto prevSize = editSysmem().getSize(); auto newSize = editSysmem().setData(size, data); - Buffer::updateSystemMemoryUsage(prevSize, newSize); + Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); return newSize; } @@ -330,7 +322,7 @@ Buffer::Size Buffer::setSubData(Size offset, Size size, const Byte* data) { Buffer::Size Buffer::append(Size size, const Byte* data) { auto prevSize = editSysmem().getSize(); auto newSize = editSysmem().append( size, data); - Buffer::updateSystemMemoryUsage(prevSize, newSize); + Buffer::updateBufferCPUMemoryUsage(prevSize, newSize); return newSize; } diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index d40e9131a1..176e33a428 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -110,21 +110,19 @@ protected: }; class Buffer : public Resource { - static std::atomic _numBuffers; - static std::atomic _bufferSystemMemoryUsage; -public: - static std::atomic _numGPUBuffers; - static std::atomic _bufferVideoMemoryUsage; -private: - static void addSystemMemoryUsage(Size memorySize); - static void subSystemMemoryUsage(Size memorySize); - static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); + static std::atomic _bufferCPUCount; + static std::atomic _bufferCPUMemoryUsage; + static void updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); public: - static int getCurrentNumBuffers(); - static Size getCurrentSystemMemoryUsage(); - static int getCurrentNumGPUBuffers(); - static Size getCurrentVideoMemoryUsage(); + static std::atomic _bufferGPUCount; + static std::atomic _bufferGPUMemoryUsage; + +public: + static uint32_t getBufferCPUCount(); + static Size getBufferCPUMemoryUsage(); + static uint32_t getBufferGPUCount(); + static Size getBufferGPUMemoryUsage(); Buffer(); Buffer(Size size, const Byte* bytes); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index cb0ef20c6c..15ad4eea97 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -17,63 +17,57 @@ using namespace gpu; -std::atomic Texture::_numTextures{ 0 }; -std::atomic Texture::_numGPUTextures{ 0 }; -std::atomic Texture::_textureSystemMemoryUsage{ 0 }; -std::atomic Texture::_textureVideoMemoryUsage{ 0 }; +std::atomic Texture::_textureCPUCount{ 0 }; +std::atomic Texture::_textureGPUCount{ 0 }; +std::atomic Texture::_textureCPUMemoryUsage{ 0 }; +std::atomic Texture::_textureGPUMemoryUsage{ 0 }; -int Texture::getCurrentNumTextures() { - return _numTextures.load(); +uint32_t Texture::getTextureCPUCount() { + return _textureCPUCount.load(); } -Texture::Size Texture::getCurrentSystemMemoryUsage() { - return _textureSystemMemoryUsage.load(); +Texture::Size Texture::getTextureCPUMemoryUsage() { + return _textureCPUMemoryUsage.load(); } -int Texture::getCurrentNumGPUTextures() { - return _numGPUTextures.load(); +uint32_t Texture::getTextureGPUCount() { + return _textureGPUCount.load(); } -Texture::Size Texture::getCurrentVideoMemoryUsage() { - return _textureVideoMemoryUsage.load(); +Texture::Size Texture::getTextureGPUMemoryUsage() { + return _textureGPUMemoryUsage.load(); } -void Texture::addSystemMemoryUsage(Size memorySize) { - _textureSystemMemoryUsage.fetch_add(memorySize); -} -void Texture::subSystemMemoryUsage(Size memorySize) { - _textureSystemMemoryUsage.fetch_sub(memorySize); -} - -void Texture::updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize) { +void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { return; } if (prevObjectSize > newObjectSize) { - subSystemMemoryUsage(prevObjectSize - newObjectSize); + _textureCPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize); } else { - addSystemMemoryUsage(newObjectSize - prevObjectSize); + _textureCPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize); } } + uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : _format(format), _sysmem(size, bytes), _isGPULoaded(false) { - Texture::updateSystemMemoryUsage(0, _sysmem.getSize()); + Texture::updateTextureCPUMemoryUsage(0, _sysmem.getSize()); } Texture::Pixels::~Pixels() { - Texture::updateSystemMemoryUsage(_sysmem.getSize(), 0); + Texture::updateTextureCPUMemoryUsage(_sysmem.getSize(), 0); } Texture::Size Texture::Pixels::resize(Size pSize) { auto prevSize = _sysmem.getSize(); auto newSize = _sysmem.resize(pSize); - Texture::updateSystemMemoryUsage(prevSize, newSize); + Texture::updateTextureCPUMemoryUsage(prevSize, newSize); return newSize; } @@ -81,7 +75,7 @@ Texture::Size Texture::Pixels::setData(const Element& format, Size size, const B _format = format; auto prevSize = _sysmem.getSize(); auto newSize = _sysmem.setData(size, bytes); - Texture::updateSystemMemoryUsage(prevSize, newSize); + Texture::updateTextureCPUMemoryUsage(prevSize, newSize); _isGPULoaded = false; return newSize; } @@ -90,7 +84,7 @@ void Texture::Pixels::notifyGPULoaded() { _isGPULoaded = true; auto prevSize = _sysmem.getSize(); auto newSize = _sysmem.resize(0); - Texture::updateSystemMemoryUsage(prevSize, newSize); + Texture::updateTextureCPUMemoryUsage(prevSize, newSize); } void Texture::Storage::assignTexture(Texture* texture) { @@ -232,12 +226,12 @@ Texture* Texture::createFromStorage(Storage* storage) { Texture::Texture(): Resource() { - _numTextures++; + _textureCPUCount++; } Texture::~Texture() { - _numTextures--; + _textureCPUCount--; } Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { @@ -355,7 +349,7 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co } } - // THen check that the mem buffer passed make sense with its format + // THen check that the mem texture passed make sense with its format Size expectedSize = evalStoredMipSize(level, format); if (size == expectedSize) { _storage->assignMipData(level, format, size, bytes); @@ -386,7 +380,7 @@ bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size } } - // THen check that the mem buffer passed make sense with its format + // THen check that the mem texture passed make sense with its format Size expectedSize = evalStoredMipFaceSize(level, format); if (size == expectedSize) { _storage->assignMipFaceData(level, format, size, bytes, face); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 087f305224..c498b5cc22 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -138,22 +138,19 @@ protected: }; class Texture : public Resource { - static std::atomic _numTextures; - static std::atomic _textureSystemMemoryUsage; -public: - static std::atomic _numGPUTextures; - static std::atomic _textureVideoMemoryUsage; -private: - static void addSystemMemoryUsage(Size memorySize); - static void subSystemMemoryUsage(Size memorySize); - static void updateSystemMemoryUsage(Size prevObjectSize, Size newObjectSize); + static std::atomic _textureCPUCount; + static std::atomic _textureCPUMemoryUsage; + static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); public: + static std::atomic _textureGPUCount; + static std::atomic _textureGPUMemoryUsage; - static int getCurrentNumTextures(); - static Size getCurrentSystemMemoryUsage(); - static int getCurrentNumGPUTextures(); - static Size getCurrentVideoMemoryUsage(); +public: + static uint32_t getTextureCPUCount(); + static Size getTextureCPUMemoryUsage(); + static uint32_t getTextureGPUCount(); + static Size getTextureGPUMemoryUsage(); class Usage { public: @@ -475,7 +472,7 @@ typedef std::shared_ptr TexturePointer; typedef std::vector< TexturePointer > Textures; - // TODO: For now TextureView works with Buffer as a place holder for the Texture. + // TODO: For now TextureView works with Texture as a place holder for the Texture. // The overall logic should be about the same except that the Texture will be a real GL Texture under the hood class TextureView { public: diff --git a/libraries/render/src/render/EngineStats.cpp b/libraries/render/src/render/EngineStats.cpp index 63a25229ea..60cb309786 100644 --- a/libraries/render/src/render/EngineStats.cpp +++ b/libraries/render/src/render/EngineStats.cpp @@ -24,15 +24,21 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte // Update the stats auto config = std::static_pointer_cast(renderContext->jobConfig); - config->numBuffers = gpu::Buffer::getCurrentNumBuffers(); - config->numGPUBuffers = gpu::Buffer::getCurrentNumGPUBuffers(); - config->bufferSysmemUsage = gpu::Buffer::getCurrentSystemMemoryUsage(); - config->bufferVidmemUsage = gpu::Buffer::getCurrentVideoMemoryUsage(); + quint32 textureCPUCount{ 0 }; + quint32 textureGPUCount{ 0 }; + qint64 textureCPUMemoryUsage{ 0 }; + qint64 textureGPUMemoryUsage{ 0 }; - config->numTextures = gpu::Texture::getCurrentNumTextures(); - config->numGPUTextures = gpu::Texture::getCurrentNumGPUTextures(); - config->textureSysmemUsage = gpu::Texture::getCurrentSystemMemoryUsage(); - config->textureVidmemUsage = gpu::Texture::getCurrentVideoMemoryUsage(); + + config->bufferCPUCount = gpu::Buffer::getBufferCPUCount(); + config->bufferGPUCount = gpu::Buffer::getBufferGPUCount(); + config->bufferCPUMemoryUsage = gpu::Buffer::getBufferCPUMemoryUsage(); + config->bufferGPUMemoryUsage = gpu::Buffer::getBufferGPUMemoryUsage(); + + config->textureCPUCount = gpu::Texture::getTextureCPUCount(); + config->textureGPUCount = gpu::Texture::getTextureGPUCount(); + config->textureCPUMemoryUsage = gpu::Texture::getTextureCPUMemoryUsage(); + config->textureGPUMemoryUsage = gpu::Texture::getTextureGPUMemoryUsage(); gpu::ContextStats gpuStats(_gpuStats); renderContext->args->_context->getStats(_gpuStats); diff --git a/libraries/render/src/render/EngineStats.h b/libraries/render/src/render/EngineStats.h index d9f7e7ac9a..85946922b0 100644 --- a/libraries/render/src/render/EngineStats.h +++ b/libraries/render/src/render/EngineStats.h @@ -24,47 +24,47 @@ namespace render { class EngineStatsConfig : public Job::Config{ Q_OBJECT - Q_PROPERTY(int numBuffers MEMBER numBuffers NOTIFY dirty) - Q_PROPERTY(int numGPUBuffers MEMBER numGPUBuffers NOTIFY dirty) - Q_PROPERTY(qint64 bufferSysmemUsage MEMBER bufferSysmemUsage NOTIFY dirty) - Q_PROPERTY(qint64 bufferVidmemUsage MEMBER bufferVidmemUsage NOTIFY dirty) + Q_PROPERTY(quint32 bufferCPUCount MEMBER bufferCPUCount NOTIFY dirty) + Q_PROPERTY(quint32 bufferGPUCount MEMBER bufferGPUCount NOTIFY dirty) + Q_PROPERTY(qint64 bufferCPUMemoryUsage MEMBER bufferCPUMemoryUsage NOTIFY dirty) + Q_PROPERTY(qint64 bufferGPUMemoryUsage MEMBER bufferGPUMemoryUsage NOTIFY dirty) - Q_PROPERTY(int numTextures MEMBER numTextures NOTIFY dirty) - Q_PROPERTY(int numGPUTextures MEMBER numGPUTextures NOTIFY dirty) - Q_PROPERTY(qint64 textureSysmemUsage MEMBER textureSysmemUsage NOTIFY dirty) - Q_PROPERTY(qint64 textureVidmemUsage MEMBER textureVidmemUsage NOTIFY dirty) + Q_PROPERTY(quint32 textureCPUCount MEMBER textureCPUCount NOTIFY dirty) + Q_PROPERTY(quint32 textureGPUCount MEMBER textureGPUCount NOTIFY dirty) + Q_PROPERTY(qint64 textureCPUMemoryUsage MEMBER textureCPUMemoryUsage NOTIFY dirty) + Q_PROPERTY(qint64 textureGPUMemoryUsage MEMBER textureGPUMemoryUsage NOTIFY dirty) - Q_PROPERTY(int frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty) - Q_PROPERTY(int frameDrawcallRate MEMBER frameDrawcallRate NOTIFY dirty) + Q_PROPERTY(quint32 frameDrawcallCount MEMBER frameDrawcallCount NOTIFY dirty) + Q_PROPERTY(quint32 frameDrawcallRate MEMBER frameDrawcallRate NOTIFY dirty) - Q_PROPERTY(int frameTriangleCount MEMBER frameTriangleCount NOTIFY dirty) - Q_PROPERTY(int frameTriangleRate MEMBER frameTriangleRate NOTIFY dirty) + Q_PROPERTY(quint32 frameTriangleCount MEMBER frameTriangleCount NOTIFY dirty) + Q_PROPERTY(quint32 frameTriangleRate MEMBER frameTriangleRate NOTIFY dirty) - Q_PROPERTY(int frameTextureCount MEMBER frameTextureCount NOTIFY dirty) - Q_PROPERTY(int frameTextureRate MEMBER frameTextureRate NOTIFY dirty) + Q_PROPERTY(quint32 frameTextureCount MEMBER frameTextureCount NOTIFY dirty) + Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty) public: EngineStatsConfig() : Job::Config(true) {} - int numBuffers{ 0 }; - int numGPUBuffers{ 0 }; - qint64 bufferSysmemUsage{ 0 }; - qint64 bufferVidmemUsage{ 0 }; + quint32 bufferCPUCount{ 0 }; + quint32 bufferGPUCount{ 0 }; + qint64 bufferCPUMemoryUsage{ 0 }; + qint64 bufferGPUMemoryUsage{ 0 }; - int numTextures{ 0 }; - int numGPUTextures{ 0 }; - qint64 textureSysmemUsage{ 0 }; - qint64 textureVidmemUsage{ 0 }; + quint32 textureCPUCount{ 0 }; + quint32 textureGPUCount{ 0 }; + qint64 textureCPUMemoryUsage{ 0 }; + qint64 textureGPUMemoryUsage{ 0 }; - int frameDrawcallCount{ 0 }; - int frameDrawcallRate{ 0 }; + quint32 frameDrawcallCount{ 0 }; + quint32 frameDrawcallRate{ 0 }; - int frameTriangleCount{ 0 }; - int frameTriangleRate{ 0 }; + quint32 frameTriangleCount{ 0 }; + quint32 frameTriangleRate{ 0 }; - int frameTextureCount{ 0 }; - int frameTextureRate{ 0 }; + quint32 frameTextureCount{ 0 }; + quint32 frameTextureRate{ 0 }; void emitDirty() { emit dirty(); } From 5a3896b1de88d5934c12171f2e568031a6ebe055 Mon Sep 17 00:00:00 2001 From: samcake Date: Sun, 27 Mar 2016 09:35:13 -0700 Subject: [PATCH 26/61] FIxing warnigns --- libraries/gpu/src/gpu/GLBackend.h | 7 ++++--- libraries/render/src/render/EngineStats.cpp | 7 ------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index c8e3be81d1..d4efe7fe99 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -74,19 +74,20 @@ public: static GLuint getBufferID(const Buffer& buffer); class GLTexture : public GPUObject { - GLuint _size; public: Stamp _storageStamp; Stamp _contentStamp; GLuint _texture; GLenum _target; + GLTexture(); + ~GLTexture(); void setSize(GLuint size); GLuint size() const { return _size; } - GLTexture(); - ~GLTexture(); + private: + GLuint _size; }; static GLTexture* syncGPUObject(const Texture& texture); static GLuint getTextureID(const TexturePointer& texture, bool sync = true); diff --git a/libraries/render/src/render/EngineStats.cpp b/libraries/render/src/render/EngineStats.cpp index 60cb309786..ee96e0cd86 100644 --- a/libraries/render/src/render/EngineStats.cpp +++ b/libraries/render/src/render/EngineStats.cpp @@ -20,16 +20,9 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte quint64 msecsElapsed = _frameTimer.restart(); double frequency = 1000.0 / msecsElapsed; - // Update the stats auto config = std::static_pointer_cast(renderContext->jobConfig); - quint32 textureCPUCount{ 0 }; - quint32 textureGPUCount{ 0 }; - qint64 textureCPUMemoryUsage{ 0 }; - qint64 textureGPUMemoryUsage{ 0 }; - - config->bufferCPUCount = gpu::Buffer::getBufferCPUCount(); config->bufferGPUCount = gpu::Buffer::getBufferGPUCount(); config->bufferCPUMemoryUsage = gpu::Buffer::getBufferCPUMemoryUsage(); From d6640ac5207c9077110a054032524220b48f4e86 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sun, 27 Mar 2016 16:38:45 -0700 Subject: [PATCH 27/61] Update Model::_hasTransparentTextures --- libraries/render-utils/src/Model.cpp | 4 +++- libraries/render-utils/src/Model.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 67d7d5df8f..545d239549 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -79,7 +79,9 @@ bool Model::needsFixupInScene() const { // Once textures are loaded, fixup if they are now transparent if (_needsUpdateTransparentTextures && _geometry->getGeometry()->areTexturesLoaded()) { _needsUpdateTransparentTextures = false; - if (_hasTransparentTextures != _geometry->getGeometry()->hasTransparentTextures()) { + bool hasTransparentTextures = _geometry->getGeometry()->hasTransparentTextures(); + if (_hasTransparentTextures != hasTransparentTextures) { + _hasTransparentTextures = hasTransparentTextures; return true; } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 632e8089a8..744a4ce605 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -379,7 +379,7 @@ protected: bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; mutable bool _needsUpdateTransparentTextures { true }; - bool _hasTransparentTextures { false }; + mutable bool _hasTransparentTextures { false }; bool _showCollisionHull { false }; friend class ModelMeshPartPayload; From 77bb8bafbb797c3878483a0986c17721440a3a55 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Sun, 27 Mar 2016 17:56:44 -0700 Subject: [PATCH 28/61] Catch and report GL errors in QML render --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 54 ++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index e224adad07..818b3c6ca8 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -190,25 +190,21 @@ void OffscreenQmlRenderThread::setupFbo() { using namespace oglplus; _textures.setSize(_size); - // Before making any ogl calls, clear any outstanding errors - // FIXME: Something upstream is polluting the context with a GL_INVALID_ENUM, - // likely from glewExperimental = true - GLenum err = glGetError(); - if (err != GL_NO_ERROR) { - qDebug() << "Clearing outstanding GL error to set up QML FBO:" << glewGetErrorString(err); + try { + _depthStencil.reset(new Renderbuffer()); + Context::Bound(Renderbuffer::Target::Renderbuffer, *_depthStencil) + .Storage( + PixelDataInternalFormat::DepthComponent, + _size.x, _size.y); + + _fbo.reset(new Framebuffer()); + _fbo->Bind(Framebuffer::Target::Draw); + _fbo->AttachRenderbuffer(Framebuffer::Target::Draw, + FramebufferAttachment::Depth, *_depthStencil); + DefaultFramebuffer().Bind(Framebuffer::Target::Draw); + } catch (oglplus::Error& error) { + qWarning() << "OpenGL error in QML render setup: " << error.what(); } - - _depthStencil.reset(new Renderbuffer()); - Context::Bound(Renderbuffer::Target::Renderbuffer, *_depthStencil) - .Storage( - PixelDataInternalFormat::DepthComponent, - _size.x, _size.y); - - _fbo.reset(new Framebuffer()); - _fbo->Bind(Framebuffer::Target::Draw); - _fbo->AttachRenderbuffer(Framebuffer::Target::Draw, - FramebufferAttachment::Depth, *_depthStencil); - DefaultFramebuffer().Bind(Framebuffer::Target::Draw); } void OffscreenQmlRenderThread::init() { @@ -299,10 +295,21 @@ void OffscreenQmlRenderThread::render() { try { PROFILE_RANGE("qml_render") - TexturePtr texture = _textures.getNextTexture(); - _fbo->Bind(Framebuffer::Target::Draw); - _fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0); - _fbo->Complete(Framebuffer::Target::Draw); + + TexturePtr texture = _textures.getNextTexture(); + + try { + _fbo->Bind(Framebuffer::Target::Draw); + _fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0); + _fbo->Complete(Framebuffer::Target::Draw); + } catch (oglplus::Error& error) { + qWarning() << "OpenGL error in QML render: " << error.what(); + + // In case we are failing from a failed setupFbo, reset fbo before next render + setupFbo(); + throw; + } + { PROFILE_RANGE("qml_render->rendercontrol") _renderControl->render(); @@ -311,13 +318,14 @@ void OffscreenQmlRenderThread::render() { // for now just clear the errors glGetError(); } + // FIXME probably unecessary DefaultFramebuffer().Bind(Framebuffer::Target::Draw); _quickWindow->resetOpenGLState(); _escrow.submit(GetName(*texture)); _lastRenderTime = usecTimestampNow(); } catch (std::runtime_error& error) { - qWarning() << "Failed to render QML " << error.what(); + qWarning() << "Failed to render QML: " << error.what(); } } From 3e4b4a0fc7ff74221f4b464553243c9163ab4c8f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Mar 2016 10:03:05 -0700 Subject: [PATCH 29/61] cleanup un-used public keys in ice-server --- ice-server/src/IceServer.cpp | 37 ++++++++++++++------ ice-server/src/IceServer.h | 5 ++- libraries/networking/src/udt/PacketQueue.cpp | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index f38923b873..f9d244befa 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -11,7 +11,6 @@ #include "IceServer.h" -#include #include #include @@ -161,15 +160,12 @@ SharedNetworkPeer IceServer::addOrUpdateHeartbeatingPeer(NLPacket& packet) { } bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& plaintext, const QByteArray& signature) { - // check if we have a private key for this domain ID - if we do not then fire off the request for it + // check if we have a public key for this domain ID - if we do not then fire off the request for it auto it = _domainPublicKeys.find(domainID); if (it != _domainPublicKeys.end()) { // attempt to verify the signature for this heartbeat - const unsigned char* publicKeyData = reinterpret_cast(it->second.constData()); - - // first load up the public key into an RSA struct - RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, it->second.size()); + const auto rsaPublicKey = it->second.get(); if (rsaPublicKey) { auto hashedPlaintext = QCryptographicHash::hash(plaintext, QCryptographicHash::Sha256); @@ -180,9 +176,6 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla signature.size(), rsaPublicKey); - // free up the public key and remove connection token before we return - RSA_free(rsaPublicKey); - if (verificationResult == 1) { // this is the only success case - we return true here to indicate that the heartbeat is verified return true; @@ -192,7 +185,7 @@ bool IceServer::isVerifiedHeartbeat(const QUuid& domainID, const QByteArray& pla } else { // we can't let this user in since we couldn't convert their public key to an RSA key we could use - qWarning() << "Could not convert in-memory public key for" << domainID << "to usable RSA public key."; + qWarning() << "Public key for" << domainID << "is not a usable RSA* public key."; qWarning() << "Re-requesting public key from API"; } } @@ -240,7 +233,22 @@ void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { if (responseObject[STATUS_KEY].toString() == SUCCESS_VALUE) { auto dataObject = responseObject[DATA_KEY].toObject(); if (dataObject.contains(PUBLIC_KEY_KEY)) { - _domainPublicKeys[domainID] = QByteArray::fromBase64(dataObject[PUBLIC_KEY_KEY].toString().toUtf8()); + + // grab the base 64 public key from the API response + auto apiPublicKey = QByteArray::fromBase64(dataObject[PUBLIC_KEY_KEY].toString().toUtf8()); + + // convert the downloaded public key to an RSA struct, if possible + const unsigned char* publicKeyData = reinterpret_cast(apiPublicKey.constData()); + + RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, apiPublicKey.size()); + + if (rsaPublicKey) { + _domainPublicKeys[domainID] = { rsaPublicKey, [](RSA* rsa) { RSA_free(rsa); }}; + } else { + qWarning() << "Could not convert in-memory public key for" << domainID << "to usable RSA public key."; + qWarning() << "Public key will be re-requested on next heartbeat."; + } + } else { qWarning() << "There was no public key present in response for domain with ID" << domainID; } @@ -254,6 +262,8 @@ void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { qWarning() << "Error retreiving public key for domain with ID" << domainID << "-" << reply->errorString(); } + + reply->deleteLater(); } void IceServer::sendPeerInformationPacket(const NetworkPeer& peer, const HifiSockAddr* destinationSockAddr) { @@ -274,6 +284,11 @@ void IceServer::clearInactivePeers() { if ((usecTimestampNow() - peer->getLastHeardMicrostamp()) > (PEER_SILENCE_THRESHOLD_MSECS * 1000)) { qDebug() << "Removing peer from memory for inactivity -" << *peer; + + // if we had a public key for this domain, remove it now + _domainPublicKeys.erase(peer->getUUID()); + + // remove the peer object peerItem = _activePeers.erase(peerItem); } else { // we didn't kill this peer, push the iterator forwards diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 81234b2c3c..ebf1a9ac52 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include @@ -52,7 +54,8 @@ private: HTTPManager _httpManager; - using DomainPublicKeyHash = std::unordered_map; + using RSAUniquePtr = std::unique_ptr>; + using DomainPublicKeyHash = std::unordered_map; DomainPublicKeyHash _domainPublicKeys; }; diff --git a/libraries/networking/src/udt/PacketQueue.cpp b/libraries/networking/src/udt/PacketQueue.cpp index 8ff2333a20..4b8c0b187c 100644 --- a/libraries/networking/src/udt/PacketQueue.cpp +++ b/libraries/networking/src/udt/PacketQueue.cpp @@ -51,7 +51,7 @@ PacketQueue::PacketPointer PacketQueue::takePacket() { --_currentIndex; } - return std::move(packet); + return packet; } unsigned int PacketQueue::nextIndex() { From ae82298e1b5f352f045592ffefebd6b0d3da8d07 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 25 Mar 2016 12:26:39 -0700 Subject: [PATCH 30/61] Working on the App JS <-> HTML JS communication --- examples/edit.js | 10 +- examples/html/eventBridgeLoader.js | 50 +--- examples/html/qmlWebTest.html | 10 +- examples/libraries/entityList.js | 8 +- examples/libraries/gridTool.js | 4 +- .../particle_explorer/particleExplorerTool.js | 2 +- examples/tests/qmlWebTest.js | 32 +-- interface/resources/qml/QmlWebWindow.qml | 14 ++ interface/resources/qml/QmlWindow.qml | 1 + interface/resources/qml/ToolWindow.qml | 62 +++-- interface/resources/qml/controls/WebView.qml | 5 +- libraries/ui/src/QmlWebWindowClass.cpp | 37 +-- libraries/ui/src/QmlWebWindowClass.h | 11 +- libraries/ui/src/QmlWindowClass.cpp | 237 +++++------------- libraries/ui/src/QmlWindowClass.h | 44 +--- 15 files changed, 197 insertions(+), 330 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index eb853fd359..e22bb28cd7 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1484,10 +1484,10 @@ PropertiesTool = function(opts) { selections.push(entity); } data.selections = selections; - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + webView.emitScriptEvent(JSON.stringify(data)); }); - webView.eventBridge.webEventReceived.connect(function(data) { + webView.webEventReceived.connect(function(data) { data = JSON.parse(data); if (data.type == "print") { if (data.message) { @@ -1802,7 +1802,7 @@ var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace"); propertiesTool = PropertiesTool(); var particleExplorerTool = ParticleExplorerTool(); var selectedParticleEntity = 0; -entityListTool.webView.eventBridge.webEventReceived.connect(function(data) { +entityListTool.webView.webEventReceived.connect(function(data) { var data = JSON.parse(data); if (data.type == "selectionUpdate") { var ids = data.entityIds; @@ -1823,10 +1823,10 @@ entityListTool.webView.eventBridge.webEventReceived.connect(function(data) { selectedParticleEntity = ids[0]; particleExplorerTool.setActiveParticleEntity(ids[0]); - particleExplorerTool.webView.eventBridge.webEventReceived.connect(function(data) { + particleExplorerTool.webView.webEventReceived.connect(function(data) { var data = JSON.parse(data); if (data.messageType === "page_loaded") { - particleExplorerTool.webView.eventBridge.emitScriptEvent(JSON.stringify(particleData)); + particleExplorerTool.webView.emitScriptEvent(JSON.stringify(particleData)); } }); } else { diff --git a/examples/html/eventBridgeLoader.js b/examples/html/eventBridgeLoader.js index ebfb6dc740..0e95345b40 100644 --- a/examples/html/eventBridgeLoader.js +++ b/examples/html/eventBridgeLoader.js @@ -9,51 +9,11 @@ // var EventBridge; - -EventBridgeConnectionProxy = function(parent) { - this.parent = parent; - this.realSignal = this.parent.realBridge.scriptEventReceived - this.webWindowId = this.parent.webWindow.windowId; -} - -EventBridgeConnectionProxy.prototype.connect = function(callback) { - var that = this; - this.realSignal.connect(function(id, message) { - if (id === that.webWindowId) { callback(message); } - }); -} - -EventBridgeProxy = function(webWindow) { - this.webWindow = webWindow; - this.realBridge = this.webWindow.eventBridge; - this.scriptEventReceived = new EventBridgeConnectionProxy(this); -} - -EventBridgeProxy.prototype.emitWebEvent = function(data) { - this.realBridge.emitWebEvent(data); -} +var WebChannel; openEventBridge = function(callback) { - EVENT_BRIDGE_URI = "ws://localhost:51016"; - socket = new WebSocket(this.EVENT_BRIDGE_URI); - - socket.onclose = function() { - console.error("web channel closed"); - }; - - socket.onerror = function(error) { - console.error("web channel error: " + error); - }; - - socket.onopen = function() { - channel = new QWebChannel(socket, function(channel) { - console.log("Document url is " + document.URL); - var webWindow = channel.objects[document.URL.toLowerCase()]; - console.log("WebWindow is " + webWindow) - eventBridgeProxy = new EventBridgeProxy(webWindow); - EventBridge = eventBridgeProxy; - if (callback) { callback(eventBridgeProxy); } - }); - } + WebChannel = new QWebChannel(qt.webChannelTransport, function (channel) { + EventBridge = WebChannel.objects.eventBridgeWrapper.eventBridge; + callback(EventBridge); + }); } - diff --git a/examples/html/qmlWebTest.html b/examples/html/qmlWebTest.html index e59535701d..553ce83417 100644 --- a/examples/html/qmlWebTest.html +++ b/examples/html/qmlWebTest.html @@ -4,21 +4,17 @@ - diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index 6c6c0aaecb..06f6f0e88f 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -38,14 +38,14 @@ EntityListTool = function(opts) { type: 'selectionUpdate', selectedIDs: selectedIDs, }; - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + webView.emitScriptEvent(JSON.stringify(data)); }); that.clearEntityList = function () { var data = { type: 'clearEntityList' } - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + webView.emitScriptEvent(JSON.stringify(data)); }; that.sendUpdate = function() { @@ -72,11 +72,11 @@ EntityListTool = function(opts) { entities: entities, selectedIDs: selectedIDs, }; - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + webView.emitScriptEvent(JSON.stringify(data)); } - webView.eventBridge.webEventReceived.connect(function(data) { + webView.webEventReceived.connect(function(data) { data = JSON.parse(data); if (data.type == "selectionUpdate") { var ids = data.entityIds; diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index fbd2ec7ea0..c002aec3b1 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -234,11 +234,11 @@ GridTool = function(opts) { }); horizontalGrid.addListener(function(data) { - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + webView.emitScriptEvent(JSON.stringify(data)); selectionDisplay.updateHandles(); }); - webView.eventBridge.webEventReceived.connect(function(data) { + webView.webEventReceived.connect(function(data) { data = JSON.parse(data); if (data.type == "init") { horizontalGrid.emitUpdate(); diff --git a/examples/particle_explorer/particleExplorerTool.js b/examples/particle_explorer/particleExplorerTool.js index 007eb717ec..8a28445c33 100644 --- a/examples/particle_explorer/particleExplorerTool.js +++ b/examples/particle_explorer/particleExplorerTool.js @@ -26,7 +26,7 @@ ParticleExplorerTool = function() { }); that.webView.setVisible(true); - that.webView.eventBridge.webEventReceived.connect(that.webEventReceived); + that.webView.webEventReceived.connect(that.webEventReceived); } diff --git a/examples/tests/qmlWebTest.js b/examples/tests/qmlWebTest.js index 5faa68668d..ac40e54b85 100644 --- a/examples/tests/qmlWebTest.js +++ b/examples/tests/qmlWebTest.js @@ -2,32 +2,18 @@ print("Launching web window"); var htmlUrl = Script.resolvePath("..//html/qmlWebTest.html") webWindow = new OverlayWebWindow('Test Event Bridge', htmlUrl, 320, 240, false); -print("JS Side window: " + webWindow); -print("JS Side bridge: " + webWindow.eventBridge); -webWindow.eventBridge.webEventReceived.connect(function(data) { +webWindow.webEventReceived.connect(function(data) { print("JS Side event received: " + data); }); -var titles = ["A", "B", "C"]; -var titleIndex = 0; - Script.setInterval(function() { - webWindow.eventBridge.emitScriptEvent("JS Event sent"); - var size = webWindow.size; - var position = webWindow.position; - print("Window url: " + webWindow.url) - print("Window visible: " + webWindow.visible) - print("Window size: " + size.x + "x" + size.y) - print("Window pos: " + position.x + "x" + position.y) - webWindow.setVisible(!webWindow.visible); - webWindow.setTitle(titles[titleIndex]); - webWindow.setSize(320 + Math.random() * 100, 240 + Math.random() * 100); - titleIndex += 1; - titleIndex %= titles.length; -}, 2 * 1000); + var message = [ Math.random(), Math.random() ]; + print("JS Side sending: " + message); + webWindow.emitScriptEvent(message); +}, 5 * 1000); -Script.setTimeout(function() { - print("Closing script"); +Script.scriptEnding.connect(function(){ webWindow.close(); - Script.stop(); -}, 15 * 1000) + webWindow.deleteLater(); +}); + diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index fd4e629568..70c8afd298 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -1,6 +1,7 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 import QtWebEngine 1.1 +import QtWebChannel 1.0 import "windows" as Windows import "controls" as Controls @@ -15,11 +16,24 @@ Windows.Window { // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false property alias source: webview.url + property alias eventBridge: eventBridgeWrapper.eventBridge; + + QtObject { + id: eventBridgeWrapper + WebChannel.id: "eventBridgeWrapper" + property var eventBridge; + } + + // This is for JS/QML communication, which is unused in a WebWindow, + // but not having this here results in spurious warnings about a + // missing signal + signal sendToScript(var message); Controls.WebView { id: webview url: "about:blank" anchors.fill: parent focus: true + webChannel.registeredObjects: [eventBridgeWrapper] } } // dialog diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index ed8ff93f19..0420cd2e88 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -20,6 +20,7 @@ Windows.Window { // Don't destroy on close... otherwise the JS/C++ will have a dangling pointer destroyOnCloseButton: false property var source; + property var eventBridge; property var component; property var dynamicContent; onSourceChanged: { diff --git a/interface/resources/qml/ToolWindow.qml b/interface/resources/qml/ToolWindow.qml index 75aa50aa34..7398057722 100644 --- a/interface/resources/qml/ToolWindow.qml +++ b/interface/resources/qml/ToolWindow.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtWebEngine 1.1 - +import QtWebChannel 1.0 import Qt.labs.settings 1.0 import "windows" as Windows @@ -37,14 +37,26 @@ Windows.Window { Repeater { model: 4 Tab { + // Force loading of the content even if the tab is not visible + // (required for letting the C++ code access the webview) active: true - enabled: false; - // we need to store the original url here for future identification + enabled: false property string originalUrl: ""; - onEnabledChanged: toolWindow.updateVisiblity(); + Controls.WebView { id: webView; anchors.fill: parent + enabled: false + property alias eventBridgeWrapper: eventBridgeWrapper + + QtObject { + id: eventBridgeWrapper + WebChannel.id: "eventBridgeWrapper" + property var eventBridge; + } + + webChannel.registeredObjects: [eventBridgeWrapper] + onEnabledChanged: toolWindow.updateVisiblity(); } } } @@ -113,20 +125,23 @@ Windows.Window { var tab = tabView.getTab(index); tab.title = ""; - tab.originalUrl = ""; tab.enabled = false; + tab.originalUrl = ""; + tab.item.url = "about:blank"; + tab.item.enabled = false; } function addWebTab(properties) { if (!properties.source) { - console.warn("Attempted to open Web Tool Pane without URL") + console.warn("Attempted to open Web Tool Pane without URL"); return; } var existingTabIndex = findIndexForUrl(properties.source); if (existingTabIndex >= 0) { - console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source) - return tabView.getTab(existingTabIndex); + console.log("Existing tab " + existingTabIndex + " found with URL " + properties.source); + var tab = tabView.getTab(existingTabIndex); + return tab.item; } var freeTabIndex = findFreeTab(); @@ -135,25 +150,28 @@ Windows.Window { return; } - var newTab = tabView.getTab(freeTabIndex); - newTab.title = properties.title || "Unknown"; - newTab.originalUrl = properties.source; - newTab.item.url = properties.source; - newTab.active = true; - if (properties.width) { - tabView.width = Math.min(Math.max(tabView.width, properties.width), - toolWindow.maxSize.x); + tabView.width = Math.min(Math.max(tabView.width, properties.width), toolWindow.maxSize.x); } if (properties.height) { - tabView.height = Math.min(Math.max(tabView.height, properties.height), - toolWindow.maxSize.y); + tabView.height = Math.min(Math.max(tabView.height, properties.height), toolWindow.maxSize.y); } - console.log("Updating visibility based on child tab added"); - newTab.enabledChanged.connect(updateVisiblity) - updateVisiblity(); - return newTab + var tab = tabView.getTab(freeTabIndex); + tab.title = properties.title || "Unknown"; + tab.enabled = true; + console.log("New tab URL: " + properties.source) + tab.originalUrl = properties.source; + + var eventBridge = properties.eventBridge; + console.log("Event bridge: " + eventBridge); + + var result = tab.item; + result.enabled = true; + console.log("Setting event bridge: " + eventBridge); + result.eventBridgeWrapper.eventBridge = eventBridge; + result.url = properties.source; + return result; } } diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 18080cd448..1361e6e322 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -59,6 +59,7 @@ WebEngineView { request.openIn(newWindow.webView) } - - profile: desktop.browserProfile + // This breaks the webchannel used for passing messages. Fixed in Qt 5.6 + // See https://bugreports.qt.io/browse/QTBUG-49521 + //profile: desktop.browserProfile } diff --git a/libraries/ui/src/QmlWebWindowClass.cpp b/libraries/ui/src/QmlWebWindowClass.cpp index 0228f77f4f..b964f305a4 100644 --- a/libraries/ui/src/QmlWebWindowClass.cpp +++ b/libraries/ui/src/QmlWebWindowClass.cpp @@ -8,35 +8,44 @@ #include "QmlWebWindowClass.h" -#include -#include #include -#include - #include #include -#include - -#include -#include -#include -#include - #include "OffscreenUi.h" static const char* const URL_PROPERTY = "source"; // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { - return QmlWindowClass::internalConstructor("QmlWebWindow.qml", context, engine, - [&](QObject* object) { return new QmlWebWindowClass(object); }); + auto properties = parseArguments(context); + QmlWebWindowClass* retVal { nullptr }; + auto offscreenUi = DependencyManager::get(); + offscreenUi->executeOnUiThread([&] { + retVal = new QmlWebWindowClass(); + retVal->initQml(properties); + }, true); + Q_ASSERT(retVal); + connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); + return engine->newQObject(retVal); } -QmlWebWindowClass::QmlWebWindowClass(QObject* qmlWindow) : QmlWindowClass(qmlWindow) { +void QmlWebWindowClass::emitScriptEvent(const QVariant& scriptMessage) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, scriptMessage)); + } else { + emit scriptEventReceived(scriptMessage); + } } +void QmlWebWindowClass::emitWebEvent(const QVariant& webMessage) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, webMessage)); + } else { + emit webEventReceived(webMessage); + } +} QString QmlWebWindowClass::getURL() const { QVariant result = DependencyManager::get()->returnFromUiThread([&]()->QVariant { diff --git a/libraries/ui/src/QmlWebWindowClass.h b/libraries/ui/src/QmlWebWindowClass.h index 27c0e6996d..86d0e9b2c4 100644 --- a/libraries/ui/src/QmlWebWindowClass.h +++ b/libraries/ui/src/QmlWebWindowClass.h @@ -18,14 +18,21 @@ class QmlWebWindowClass : public QmlWindowClass { public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - QmlWebWindowClass(QObject* qmlWindow); -public slots: + public slots: QString getURL() const; void setURL(const QString& url); + void emitScriptEvent(const QVariant& scriptMessage); + void emitWebEvent(const QVariant& webMessage); + signals: void urlChanged(); + void scriptEventReceived(const QVariant& message); + void webEventReceived(const QVariant& message); + +protected: + QString qmlSource() const override { return "QmlWebWindow.qml"; } }; #endif diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index b7fe330a4e..c43433e87c 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -20,203 +20,115 @@ #include #include -#include #include #include #include "OffscreenUi.h" -QWebSocketServer* QmlWindowClass::_webChannelServer { nullptr }; -static QWebChannel webChannel; -static const uint16_t WEB_CHANNEL_PORT = 51016; -static std::atomic nextWindowId; static const char* const SOURCE_PROPERTY = "source"; static const char* const TITLE_PROPERTY = "title"; +static const char* const EVENT_BRIDGE_PROPERTY = "eventBridge"; static const char* const WIDTH_PROPERTY = "width"; static const char* const HEIGHT_PROPERTY = "height"; static const char* const VISIBILE_PROPERTY = "visible"; static const char* const TOOLWINDOW_PROPERTY = "toolWindow"; -void QmlScriptEventBridge::emitWebEvent(const QString& data) { - QMetaObject::invokeMethod(this, "webEventReceived", Qt::QueuedConnection, Q_ARG(QString, data)); -} - -void QmlScriptEventBridge::emitScriptEvent(const QString& data) { - QMetaObject::invokeMethod(this, "scriptEventReceived", Qt::QueuedConnection, - Q_ARG(int, _webWindow->getWindowId()), Q_ARG(QString, data)); -} - -class QmlWebTransport : public QWebChannelAbstractTransport { - Q_OBJECT -public: - QmlWebTransport(QWebSocket* webSocket) : _webSocket(webSocket) { - // Translate from the websocket layer to the webchannel layer - connect(webSocket, &QWebSocket::textMessageReceived, [this](const QString& message) { - QJsonParseError error; - QJsonDocument document = QJsonDocument::fromJson(message.toUtf8(), &error); - if (error.error || !document.isObject()) { - qWarning() << "Unable to parse incoming JSON message" << message; - return; - } - emit messageReceived(document.object(), this); - }); - } - - virtual void sendMessage(const QJsonObject &message) override { - // Translate from the webchannel layer to the websocket layer - _webSocket->sendTextMessage(QJsonDocument(message).toJson(QJsonDocument::Compact)); - } - -private: - QWebSocket* const _webSocket; -}; - - -void QmlWindowClass::setupServer() { - if (!_webChannelServer) { - _webChannelServer = new QWebSocketServer("EventBridge Server", QWebSocketServer::NonSecureMode); - if (!_webChannelServer->listen(QHostAddress::LocalHost, WEB_CHANNEL_PORT)) { - qFatal("Failed to open web socket server."); - } - - QObject::connect(_webChannelServer, &QWebSocketServer::newConnection, [] { - webChannel.connectTo(new QmlWebTransport(_webChannelServer->nextPendingConnection())); - }); - } -} - -QScriptValue QmlWindowClass::internalConstructor(const QString& qmlSource, - QScriptContext* context, QScriptEngine* engine, - std::function builder) -{ +QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { const auto argumentCount = context->argumentCount(); - QString url; QString title; - int width = -1, height = -1; - bool visible = true; - bool toolWindow = false; + QVariantMap properties; if (argumentCount > 1) { - if (!context->argument(0).isUndefined()) { - title = context->argument(0).toString(); + properties[TITLE_PROPERTY] = context->argument(0).toString(); } if (!context->argument(1).isUndefined()) { - url = context->argument(1).toString(); + properties[SOURCE_PROPERTY] = context->argument(1).toString(); } if (context->argument(2).isNumber()) { - width = context->argument(2).toInt32(); + properties[WIDTH_PROPERTY] = context->argument(2).toInt32(); } if (context->argument(3).isNumber()) { - height = context->argument(3).toInt32(); + properties[HEIGHT_PROPERTY] = context->argument(3).toInt32(); } if (context->argument(4).isBool()) { - toolWindow = context->argument(4).toBool(); + properties[TOOLWINDOW_PROPERTY] = context->argument(4).toBool(); } } else { - auto argumentObject = context->argument(0); - if (!argumentObject.property(TITLE_PROPERTY).isUndefined()) { - title = argumentObject.property(TITLE_PROPERTY).toString(); - } - if (!argumentObject.property(SOURCE_PROPERTY).isUndefined()) { - url = argumentObject.property(SOURCE_PROPERTY).toString(); - } - if (argumentObject.property(WIDTH_PROPERTY).isNumber()) { - width = argumentObject.property(WIDTH_PROPERTY).toInt32(); - } - if (argumentObject.property(HEIGHT_PROPERTY).isNumber()) { - height = argumentObject.property(HEIGHT_PROPERTY).toInt32(); - } - if (argumentObject.property(VISIBILE_PROPERTY).isBool()) { - visible = argumentObject.property(VISIBILE_PROPERTY).toBool(); - } - if (argumentObject.property(TOOLWINDOW_PROPERTY).isBool()) { - toolWindow = argumentObject.property(TOOLWINDOW_PROPERTY).toBool(); - } + properties = context->argument(0).toVariant().toMap(); } + QString url = properties[SOURCE_PROPERTY].toString(); if (!url.startsWith("http") && !url.startsWith("file://") && !url.startsWith("about:")) { - url = QUrl::fromLocalFile(url).toString(); + properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url).toString(); } - if (width != -1 || height != -1) { - width = std::max(100, std::min(1280, width)); - height = std::max(100, std::min(720, height)); - } - - QmlWindowClass* retVal{ nullptr }; - auto offscreenUi = DependencyManager::get(); - - if (toolWindow) { - auto toolWindow = offscreenUi->getToolWindow(); - QVariantMap properties; - properties.insert(TITLE_PROPERTY, title); - properties.insert(SOURCE_PROPERTY, url); - if (width != -1 && height != -1) { - properties.insert(WIDTH_PROPERTY, width); - properties.insert(HEIGHT_PROPERTY, height); - } - - // Build the event bridge and wrapper on the main thread - QVariant newTabVar; - bool invokeResult = QMetaObject::invokeMethod(toolWindow, "addWebTab", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QVariant, newTabVar), - Q_ARG(QVariant, QVariant::fromValue(properties))); - - QQuickItem* newTab = qvariant_cast(newTabVar); - if (!invokeResult || !newTab) { - return QScriptValue(); - } - - offscreenUi->returnFromUiThread([&] { - setupServer(); - retVal = builder(newTab); - retVal->_toolWindow = true; - registerObject(url.toLower(), retVal); - return QVariant(); - }); - } else { - // Build the event bridge and wrapper on the main thread - QMetaObject::invokeMethod(offscreenUi.data(), "load", Qt::BlockingQueuedConnection, - Q_ARG(const QString&, qmlSource), - Q_ARG(std::function, [&](QQmlContext* context, QObject* object) { - setupServer(); - retVal = builder(object); - context->engine()->setObjectOwnership(retVal->_qmlWindow, QQmlEngine::CppOwnership); - registerObject(url.toLower(), retVal); - if (!title.isEmpty()) { - retVal->setTitle(title); - } - if (width != -1 && height != -1) { - retVal->setSize(width, height); - } - object->setProperty(SOURCE_PROPERTY, url); - if (visible) { - object->setProperty("visible", true); - } - })); - } - - retVal->_source = url; - connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); - return engine->newQObject(retVal); + return properties; } + // Method called by Qt scripts to create a new web window in the overlay QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { - return internalConstructor("QmlWindow.qml", context, engine, [&](QObject* object){ - return new QmlWindowClass(object); - }); + auto properties = parseArguments(context); + QmlWindowClass* retVal { nullptr }; + auto offscreenUi = DependencyManager::get(); + offscreenUi->executeOnUiThread([&] { + retVal = new QmlWindowClass(); + retVal->initQml(properties); + }, true); + Q_ASSERT(retVal); + connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater); + return engine->newQObject(retVal); } -QmlWindowClass::QmlWindowClass(QObject* qmlWindow) - : _windowId(++nextWindowId), _qmlWindow(qmlWindow) -{ - qDebug() << "Created window with ID " << _windowId; +QmlWindowClass::QmlWindowClass() { + +} + +void QmlWindowClass::initQml(QVariantMap properties) { + auto offscreenUi = DependencyManager::get(); + _toolWindow = properties.contains(TOOLWINDOW_PROPERTY) && properties[TOOLWINDOW_PROPERTY].toBool(); + _source = properties[SOURCE_PROPERTY].toString(); + + if (_toolWindow) { + // Build the event bridge and wrapper on the main thread + _qmlWindow = offscreenUi->getToolWindow(); + properties[EVENT_BRIDGE_PROPERTY] = QVariant::fromValue(this); + QVariant newTabVar; + bool invokeResult = QMetaObject::invokeMethod(_qmlWindow, "addWebTab", Qt::DirectConnection, + Q_RETURN_ARG(QVariant, newTabVar), + Q_ARG(QVariant, QVariant::fromValue(properties))); + Q_ASSERT(invokeResult); + } else { + // Build the event bridge and wrapper on the main thread + offscreenUi->load(qmlSource(), [&](QQmlContext* context, QObject* object) { + _qmlWindow = object; + _qmlWindow->setProperty("eventBridge", QVariant::fromValue(this)); + context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); + context->engine()->setObjectOwnership(object, QQmlEngine::CppOwnership); + if (properties.contains(TITLE_PROPERTY)) { + object->setProperty(TITLE_PROPERTY, properties[TITLE_PROPERTY].toString()); + } + if (properties.contains(HEIGHT_PROPERTY) && properties.contains(WIDTH_PROPERTY)) { + auto height = properties[HEIGHT_PROPERTY].toInt(); + auto width = properties[WIDTH_PROPERTY].toInt(); + if (width != -1 && height != -1) { + width = std::max(100, std::min(1280, width)); + height = std::max(100, std::min(720, height)); + asQuickItem()->setSize(QSize(width, height)); + } + } + + bool visible = !properties.contains(VISIBILE_PROPERTY) || properties[VISIBILE_PROPERTY].toBool(); + object->setProperty(VISIBILE_PROPERTY, visible); + object->setProperty(SOURCE_PROPERTY, _source); + + // Forward messages received from QML on to the script + connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(const QVariant&)), Qt::QueuedConnection); + }); + } Q_ASSERT(_qmlWindow); Q_ASSERT(dynamic_cast(_qmlWindow.data())); - // Forward messages received from QML on to the script - connect(_qmlWindow, SIGNAL(sendToScript(QVariant)), this, SIGNAL(fromQml(const QVariant&)), Qt::QueuedConnection); } void QmlWindowClass::sendToQml(const QVariant& message) { @@ -228,14 +140,6 @@ QmlWindowClass::~QmlWindowClass() { close(); } -void QmlWindowClass::registerObject(const QString& name, QObject* object) { - webChannel.registerObject(name, object); -} - -void QmlWindowClass::deregisterObject(QObject* object) { - webChannel.deregisterObject(object); -} - QQuickItem* QmlWindowClass::asQuickItem() const { if (_toolWindow) { return DependencyManager::get()->getToolWindow(); @@ -248,7 +152,6 @@ void QmlWindowClass::setVisible(bool visible) { if (_toolWindow) { // For tool window tabs we special case visibility as a function call on the tab parent // The tool window itself has special logic based on whether any tabs are visible - auto offscreenUi = DependencyManager::get(); QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible)); } else { DependencyManager::get()->executeOnUiThread([=] { @@ -359,5 +262,3 @@ void QmlWindowClass::raise() { } }); } - -#include "QmlWindowClass.moc" diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index fb7dbf1253..bf3f37aae3 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -13,45 +13,23 @@ #include #include #include -#include #include class QScriptEngine; class QScriptContext; -class QmlWindowClass; -class QWebSocketServer; -class QWebSocket; -class QmlScriptEventBridge : public QObject { - Q_OBJECT -public: - QmlScriptEventBridge(const QmlWindowClass* webWindow) : _webWindow(webWindow) {} - -public slots : - void emitWebEvent(const QString& data); - void emitScriptEvent(const QString& data); - -signals: - void webEventReceived(const QString& data); - void scriptEventReceived(int windowId, const QString& data); - -private: - const QmlWindowClass* _webWindow { nullptr }; - QWebSocket *_socket { nullptr }; -}; // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWindowClass : public QObject { Q_OBJECT - Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) - Q_PROPERTY(int windowId READ getWindowId CONSTANT) +// Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) public: static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - QmlWindowClass(QObject* qmlWindow); + QmlWindowClass(); ~QmlWindowClass(); public slots: @@ -69,8 +47,7 @@ public slots: Q_INVOKABLE void raise(); Q_INVOKABLE void close(); - Q_INVOKABLE int getWindowId() const { return _windowId; }; - Q_INVOKABLE QmlScriptEventBridge* getEventBridge() const { return _eventBridge; }; + Q_INVOKABLE QObject* getEventBridge() { return this; }; // Scripts can use this to send a message to the QML object void sendToQml(const QVariant& message); @@ -89,21 +66,18 @@ protected slots: void hasClosed(); protected: - static QScriptValue internalConstructor(const QString& qmlSource, - QScriptContext* context, QScriptEngine* engine, - std::function function); - static void setupServer(); - static void registerObject(const QString& name, QObject* object); - static void deregisterObject(QObject* object); - static QWebSocketServer* _webChannelServer; + static QVariantMap parseArguments(QScriptContext* context); + static QScriptValue internalConstructor(QScriptContext* context, QScriptEngine* engine, + std::function function); + virtual QString qmlSource() const { return "QmlWindow.qml"; } + + virtual void initQml(QVariantMap properties); QQuickItem* asQuickItem() const; - QmlScriptEventBridge* const _eventBridge { new QmlScriptEventBridge(this) }; // FIXME needs to be initialized in the ctor once we have support // for tool window panes in QML bool _toolWindow { false }; - const int _windowId; QPointer _qmlWindow; QString _source; }; From 5343dfef24f364ecb55dbe2a4f04004b84b095f0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 28 Mar 2016 10:19:38 -0700 Subject: [PATCH 31/61] PR feedback on 7480 --- libraries/ui/src/QmlWindowClass.cpp | 12 +++++------- libraries/ui/src/QmlWindowClass.h | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index c43433e87c..d18ada1f5a 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -32,6 +32,8 @@ static const char* const WIDTH_PROPERTY = "width"; static const char* const HEIGHT_PROPERTY = "height"; static const char* const VISIBILE_PROPERTY = "visible"; static const char* const TOOLWINDOW_PROPERTY = "toolWindow"; +static const uvec2 MAX_QML_WINDOW_SIZE { 1280, 720 }; +static const uvec2 MIN_QML_WINDOW_SIZE { 120, 80 }; QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) { const auto argumentCount = context->argumentCount(); @@ -110,13 +112,9 @@ void QmlWindowClass::initQml(QVariantMap properties) { object->setProperty(TITLE_PROPERTY, properties[TITLE_PROPERTY].toString()); } if (properties.contains(HEIGHT_PROPERTY) && properties.contains(WIDTH_PROPERTY)) { - auto height = properties[HEIGHT_PROPERTY].toInt(); - auto width = properties[WIDTH_PROPERTY].toInt(); - if (width != -1 && height != -1) { - width = std::max(100, std::min(1280, width)); - height = std::max(100, std::min(720, height)); - asQuickItem()->setSize(QSize(width, height)); - } + uvec2 requestedSize { properties[WIDTH_PROPERTY].toUInt(), properties[HEIGHT_PROPERTY].toUInt() }; + requestedSize = glm::clamp(requestedSize, MIN_QML_WINDOW_SIZE, MAX_QML_WINDOW_SIZE); + asQuickItem()->setSize(QSize(requestedSize.x, requestedSize.y)); } bool visible = !properties.contains(VISIBILE_PROPERTY) || properties[VISIBILE_PROPERTY].toBool(); diff --git a/libraries/ui/src/QmlWindowClass.h b/libraries/ui/src/QmlWindowClass.h index bf3f37aae3..242f9b0dd4 100644 --- a/libraries/ui/src/QmlWindowClass.h +++ b/libraries/ui/src/QmlWindowClass.h @@ -22,7 +22,6 @@ class QScriptContext; // FIXME refactor this class to be a QQuickItem derived type and eliminate the needless wrapping class QmlWindowClass : public QObject { Q_OBJECT -// Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT) Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibilityChanged) From cffeece08e538ad094dc44bc90b430b01481ef69 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Mar 2016 10:51:15 -0700 Subject: [PATCH 32/61] use time since last packet as short-term status check --- ice-server/src/IceServer.cpp | 13 +++++++++++-- ice-server/src/IceServer.h | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index f9d244befa..86b400fe81 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -67,7 +67,9 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) { } void IceServer::processPacket(std::unique_ptr packet) { - + + _lastPacketTimestamp = QDateTime::currentMSecsSinceEpoch(); + auto nlPacket = NLPacket::fromBase(std::move(packet)); // make sure that this packet at least looks like something we can read @@ -303,7 +305,14 @@ bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, b if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/status") { - connection->respond(HTTPConnection::StatusCode200, QByteArray::number(_activePeers.size())); + // figure out if we respond with 0 (we're good) or 1 (we think we're in trouble) + + const quint64 MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET = 10 * 1000; + + int statusNumber = (QDateTime::currentMSecsSinceEpoch() - _lastPacketTimestamp > MAX_PACKET_GAP_MS_FOR_STUCK_SOCKET) + ? 1 : 0; + + connection->respond(HTTPConnection::StatusCode200, QByteArray::number(statusNumber)); } } return true; diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index ebf1a9ac52..6cc33fd8fc 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -57,6 +57,8 @@ private: using RSAUniquePtr = std::unique_ptr>; using DomainPublicKeyHash = std::unordered_map; DomainPublicKeyHash _domainPublicKeys; + + quint64 _lastPacketTimestamp; }; #endif // hifi_IceServer_h From 869529a43519ebacbc8c3625e6de70000986a46f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Mar 2016 10:51:47 -0700 Subject: [PATCH 33/61] register RSA_free directly as custom deleter --- ice-server/src/IceServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 86b400fe81..d7fba12f26 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -245,7 +245,7 @@ void IceServer::publicKeyReplyFinished(QNetworkReply* reply) { RSA* rsaPublicKey = d2i_RSA_PUBKEY(NULL, &publicKeyData, apiPublicKey.size()); if (rsaPublicKey) { - _domainPublicKeys[domainID] = { rsaPublicKey, [](RSA* rsa) { RSA_free(rsa); }}; + _domainPublicKeys[domainID] = { rsaPublicKey, RSA_free }; } else { qWarning() << "Could not convert in-memory public key for" << domainID << "to usable RSA public key."; qWarning() << "Public key will be re-requested on next heartbeat."; From c0b92486f96a72cf6157d7d9350fdac61a773aa5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 28 Mar 2016 11:09:32 -0700 Subject: [PATCH 34/61] fix incorrect next packet delta --- libraries/networking/src/udt/SendQueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 8933c984d5..d9cd329bdd 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -404,8 +404,8 @@ int SendQueue::maybeSendNewPacket() { _socket->writeBasePacket(*pairTailPacket, _destination); } - // we attempted to send two packets, return 2 - return 2; + // return the number of attempted packet sends + return shouldSendPairTail ? 2 : 1; } else { // we attempted to send a single packet, return 1 return 1; From 776893a5ab88cb77e14904073a5bfe7121bab0aa Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 11:22:56 -0700 Subject: [PATCH 35/61] Improve logging for oculus errors --- .../oculus/src/OculusBaseDisplayPlugin.cpp | 2 +- plugins/oculus/src/OculusDisplayPlugin.cpp | 2 +- plugins/oculus/src/OculusHelpers.cpp | 26 ++++++++++++++++--- plugins/oculus/src/OculusHelpers.h | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 29fc014a64..1ed5c9f22a 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -65,7 +65,7 @@ void OculusBaseDisplayPlugin::internalActivate() { if (!OVR_SUCCESS(ovr_ConfigureTracking(_session, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { - qWarning() << "Could not attach to sensor device"; + logWarning("Failed to attach to sensor device"); } // Parent class relies on our _session intialization, so it must come after that. diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 71a858e1e8..8c3a676c61 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -67,7 +67,7 @@ void OculusDisplayPlugin::hmdPresent() { ovrLayerHeader* layers = &_sceneLayer.Header; ovrResult result = ovr_SubmitFrame(_session, _currentRenderFrameIndex, &_viewScaleDesc, &layers, 1); if (!OVR_SUCCESS(result)) { - qDebug() << result; + logWarning("Failed to present"); } } _sceneFbo->Increment(); diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index db65c72aac..170be05952 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -10,16 +10,34 @@ #include #include + using Mutex = std::mutex; using Lock = std::unique_lock; - Q_DECLARE_LOGGING_CATEGORY(oculus) Q_LOGGING_CATEGORY(oculus, "hifi.plugins.oculus") static std::atomic refCount { 0 }; static ovrSession session { nullptr }; +inline ovrErrorInfo getError() { + ovrErrorInfo error; + ovr_GetLastErrorInfo(&error); + return error; +} + +void logWarning(const char* what) { + qWarning(oculus) << what << ":" << getError().ErrorString; +} + +void logFatal(const char* what) { + std::string error("[oculus] "); + error += what; + error += ": "; + error += getError().ErrorString; + qFatal(error.c_str()); +} + bool oculusAvailable() { ovrDetectResult detect = ovr_Detect(0); return (detect.IsOculusServiceRunning && detect.IsOculusHMDConnected); @@ -37,14 +55,14 @@ ovrSession acquireOculusSession() { init.ConnectionTimeoutMS = 0; init.LogCallback = nullptr; if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { - qCWarning(oculus) << "Failed to initialize Oculus SDK"; + logWarning("Failed to initialize Oculus SDK"); return session; } Q_ASSERT(0 == refCount); ovrGraphicsLuid luid; if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { - qCWarning(oculus) << "Failed to acquire Oculus session"; + logWarning("Failed to acquire Oculus session"); return session; } } @@ -105,7 +123,7 @@ void SwapFramebufferWrapper::initColor() { destroyColor(); if (!OVR_SUCCESS(ovr_CreateSwapTextureSetGL(_session, GL_SRGB8_ALPHA8, size.x, size.y, &color))) { - qFatal("Unable to create swap textures"); + logFatal("Failed to create swap textures"); } for (int i = 0; i < color->TextureCount; ++i) { diff --git a/plugins/oculus/src/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h index cd527b184b..e10e058ad2 100644 --- a/plugins/oculus/src/OculusHelpers.h +++ b/plugins/oculus/src/OculusHelpers.h @@ -14,6 +14,8 @@ #include +void logWarning(const char* what); +void logFatal(const char* what); bool oculusAvailable(); ovrSession acquireOculusSession(); void releaseOculusSession(); From b5028acde1a878098ab5eba8962af2ad878a51be Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 28 Mar 2016 11:45:07 -0700 Subject: [PATCH 36/61] CLeaning up the location of the global variables, moved them to the gpu::COntext class as static --- libraries/gpu/src/gpu/Context.cpp | 65 ++++++++++++++++++++++ libraries/gpu/src/gpu/Context.h | 36 ++++++++++++ libraries/gpu/src/gpu/GLBackendBuffer.cpp | 16 ++---- libraries/gpu/src/gpu/GLBackendTexture.cpp | 16 ++---- libraries/gpu/src/gpu/Resource.cpp | 35 ++++++------ libraries/gpu/src/gpu/Resource.h | 4 -- libraries/gpu/src/gpu/Texture.cpp | 42 +++++++------- libraries/gpu/src/gpu/Texture.h | 5 -- 8 files changed, 146 insertions(+), 73 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 6148994a1b..b14c461bc5 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -107,3 +107,68 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S return result; } + +// Counters for Buffer and Texture usage in GPU/Context +std::atomic Context::_bufferGPUCount{ 0 }; +std::atomic Context::_bufferGPUMemoryUsage{ 0 }; + +std::atomic Context::_textureGPUCount{ 0 }; +std::atomic Context::_textureGPUMemoryUsage{ 0 }; + +void Context::incrementBufferGPUCount() { + _bufferGPUCount++; +} +void Context::decrementBufferGPUCount() { + _bufferGPUCount--; +} +void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (newObjectSize > prevObjectSize) { + _bufferGPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize); + } else { + _bufferGPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize); + } +} + +void Context::incrementTextureGPUCount() { + _textureGPUCount++; +} +void Context::decrementTextureGPUCount() { + _textureGPUCount--; +} +void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { + if (prevObjectSize == newObjectSize) { + return; + } + if (newObjectSize > prevObjectSize) { + _textureGPUMemoryUsage.fetch_add(newObjectSize - prevObjectSize); + } else { + _textureGPUMemoryUsage.fetch_sub(prevObjectSize - newObjectSize); + } +} + +uint32_t Context::getBufferGPUCount() { + return _bufferGPUCount.load(); +} + +Context::Size Context::getBufferGPUMemoryUsage() { + return _bufferGPUMemoryUsage.load(); +} + +uint32_t Context::getTextureGPUCount() { + return _textureGPUCount.load(); +} + +Context::Size Context::getTextureGPUMemoryUsage() { + return _textureGPUMemoryUsage.load(); +} + +void Backend::incrementBufferGPUCount() { Context::incrementBufferGPUCount(); } +void Backend::decrementBufferGPUCount() { Context::decrementBufferGPUCount(); } +void Backend::updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateBufferGPUMemoryUsage(prevObjectSize, newObjectSize); } +void Backend::incrementTextureGPUCount() { Context::incrementTextureGPUCount(); } +void Backend::decrementTextureGPUCount() { Context::decrementTextureGPUCount(); } +void Backend::updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize) { Context::updateTextureGPUMemoryUsage(prevObjectSize, newObjectSize); } + diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index c2cd1f239e..b898bddef9 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -117,6 +117,17 @@ public: void getStats(ContextStats& stats) const { stats = _stats; } + + + // These should only be accessed by Backend implementation to repport the buffer and texture allocations, + // they are NOT public calls + static void incrementBufferGPUCount(); + static void decrementBufferGPUCount(); + static void updateBufferGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); + static void incrementTextureGPUCount(); + static void decrementTextureGPUCount(); + static void updateTextureGPUMemoryUsage(Resource::Size prevObjectSize, Resource::Size newObjectSize); + protected: StereoState _stereo; ContextStats _stats; @@ -124,6 +135,7 @@ protected: class Context { public: + using Size = Resource::Size; typedef Backend* (*CreateBackend)(); typedef bool (*MakeProgram)(Shader& shader, const Shader::BindingSet& bindings); @@ -158,6 +170,13 @@ public: // Repporting stats of the context void getStats(ContextStats& stats) const; + + static uint32_t getBufferGPUCount(); + static Size getBufferGPUMemoryUsage(); + + static uint32_t getTextureGPUCount(); + static Size getTextureGPUMemoryUsage(); + protected: Context(const Context& context); @@ -174,6 +193,23 @@ protected: static std::once_flag _initialized; friend class Shader; + + // These should only be accessed by the Backend, they are NOT public calls + static void incrementBufferGPUCount(); + static void decrementBufferGPUCount(); + static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); + static void incrementTextureGPUCount(); + static void decrementTextureGPUCount(); + static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); + + // Buffer and Texture Counters + static std::atomic _bufferGPUCount; + static std::atomic _bufferGPUMemoryUsage; + + static std::atomic _textureGPUCount; + static std::atomic _textureGPUMemoryUsage; + + friend class Backend; }; typedef std::shared_ptr ContextPointer; diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 8b8af386bb..080d743104 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -17,27 +17,19 @@ GLBackend::GLBuffer::GLBuffer() : _buffer(0), _size(0) { - Buffer::_bufferGPUCount++; + Backend::incrementBufferGPUCount(); } GLBackend::GLBuffer::~GLBuffer() { if (_buffer != 0) { glDeleteBuffers(1, &_buffer); } - Buffer::_bufferGPUMemoryUsage.fetch_sub(_size); - Buffer::_bufferGPUCount--; + Backend::updateBufferGPUMemoryUsage(_size, 0); + Backend::decrementBufferGPUCount(); } void GLBackend::GLBuffer::setSize(GLuint size) { - if (_size == size) { - return; - } - if (size > _size) { - Buffer::_bufferGPUMemoryUsage.fetch_add(size - _size); - } else { - Buffer::_bufferGPUMemoryUsage.fetch_sub(_size - size); - } - + Backend::updateBufferGPUMemoryUsage(_size, size); _size = size; } diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index bc25048a3f..09714b5542 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -20,27 +20,19 @@ GLBackend::GLTexture::GLTexture() : _target(GL_TEXTURE_2D), _size(0) { - Texture::_textureGPUCount++; + Backend::incrementTextureGPUCount(); } GLBackend::GLTexture::~GLTexture() { if (_texture != 0) { glDeleteTextures(1, &_texture); } - Texture::_textureGPUMemoryUsage.fetch_sub(_size); - Texture::_textureGPUCount--; + Backend::updateTextureGPUMemoryUsage(_size, 0); + Backend::decrementTextureGPUCount(); } void GLBackend::GLTexture::setSize(GLuint size) { - if (_size == size) { - return; - } - if (size > _size) { - Texture::_textureGPUMemoryUsage.fetch_add(size - _size); - } else { - Texture::_textureGPUMemoryUsage.fetch_sub(_size - size); - } - + Backend::updateTextureGPUMemoryUsage(_size, size); _size = size; } diff --git a/libraries/gpu/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp index f10d95c03b..c793a92b72 100644 --- a/libraries/gpu/src/gpu/Resource.cpp +++ b/libraries/gpu/src/gpu/Resource.cpp @@ -16,6 +16,8 @@ #include #include +#include "Context.h" + using namespace gpu; class AllocationDebugger { @@ -233,25 +235,7 @@ Resource::Size Resource::Sysmem::append(Size size, const Byte* bytes) { } std::atomic Buffer::_bufferCPUCount{ 0 }; -std::atomic Buffer::_bufferGPUCount{ 0 }; std::atomic Buffer::_bufferCPUMemoryUsage{ 0 }; -std::atomic Buffer::_bufferGPUMemoryUsage{ 0 }; - -uint32_t Buffer::getBufferCPUCount() { - return _bufferCPUCount.load(); -} - -Buffer::Size Buffer::getBufferCPUMemoryUsage() { - return _bufferCPUMemoryUsage.load(); -} - -uint32_t Buffer::getBufferGPUCount() { - return _bufferGPUCount.load(); -} - -Buffer::Size Buffer::getBufferGPUMemoryUsage() { - return _bufferGPUMemoryUsage.load(); -} void Buffer::updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { @@ -264,6 +248,21 @@ void Buffer::updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) } } +uint32_t Buffer::getBufferCPUCount() { + return _bufferCPUCount.load(); +} + +Buffer::Size Buffer::getBufferCPUMemoryUsage() { + return _bufferCPUMemoryUsage.load(); +} + +uint32_t Buffer::getBufferGPUCount() { + return Context::getBufferGPUCount(); +} + +Buffer::Size Buffer::getBufferGPUMemoryUsage() { + return Context::getBufferGPUMemoryUsage(); +} Buffer::Buffer() : Resource(), diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 176e33a428..98ad0a2d28 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -114,10 +114,6 @@ class Buffer : public Resource { static std::atomic _bufferCPUMemoryUsage; static void updateBufferCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); -public: - static std::atomic _bufferGPUCount; - static std::atomic _bufferGPUMemoryUsage; - public: static uint32_t getBufferCPUCount(); static Size getBufferCPUMemoryUsage(); diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 15ad4eea97..df93cd76a5 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -13,31 +13,13 @@ #include #include "GPULogging.h" -//#include +#include "Context.h" using namespace gpu; std::atomic Texture::_textureCPUCount{ 0 }; -std::atomic Texture::_textureGPUCount{ 0 }; std::atomic Texture::_textureCPUMemoryUsage{ 0 }; -std::atomic Texture::_textureGPUMemoryUsage{ 0 }; - -uint32_t Texture::getTextureCPUCount() { - return _textureCPUCount.load(); -} - -Texture::Size Texture::getTextureCPUMemoryUsage() { - return _textureCPUMemoryUsage.load(); -} - -uint32_t Texture::getTextureGPUCount() { - return _textureGPUCount.load(); -} - -Texture::Size Texture::getTextureGPUMemoryUsage() { - return _textureGPUMemoryUsage.load(); -} void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { @@ -50,6 +32,22 @@ void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSiz } } +uint32_t Texture::getTextureCPUCount() { + return _textureCPUCount.load(); +} + +Texture::Size Texture::getTextureCPUMemoryUsage() { + return _textureCPUMemoryUsage.load(); +} + +uint32_t Texture::getTextureGPUCount() { + return Context::getTextureGPUCount(); +} + +Texture::Size Texture::getTextureGPUMemoryUsage() { + return Context::getTextureGPUMemoryUsage(); + +} uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = {1, 1, 1, 6}; @@ -118,9 +116,9 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa void Texture::Storage::notifyMipFaceGPULoaded(uint16 level, uint8 face) const { PixelsPointer mipFace = getMipFace(level, face); - // if (mipFace && (_type != TEX_CUBE)) { - if (mipFace) { - mipFace->notifyGPULoaded(); + // Free the mips + if (mipFace) { + mipFace->notifyGPULoaded(); } } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index c498b5cc22..80fbc867e3 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -141,11 +141,6 @@ class Texture : public Resource { static std::atomic _textureCPUCount; static std::atomic _textureCPUMemoryUsage; static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); - -public: - static std::atomic _textureGPUCount; - static std::atomic _textureGPUMemoryUsage; - public: static uint32_t getTextureCPUCount(); static Size getTextureCPUMemoryUsage(); From aa085f69559e020e82632bd68918abae9a6579c0 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 28 Mar 2016 11:52:31 -0700 Subject: [PATCH 37/61] Putting members of the ENgineStats class NOT public so they can keep their name proudly --- libraries/render/src/render/EngineStats.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/render/src/render/EngineStats.h b/libraries/render/src/render/EngineStats.h index 85946922b0..478d94855e 100644 --- a/libraries/render/src/render/EngineStats.h +++ b/libraries/render/src/render/EngineStats.h @@ -73,18 +73,16 @@ namespace render { }; class EngineStats { + gpu::ContextStats _gpuStats; + QElapsedTimer _frameTimer; public: using Config = EngineStatsConfig; using JobModel = Job::Model; EngineStats() { _frameTimer.start(); } - gpu::ContextStats _gpuStats; - void configure(const Config& configuration) {} void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); - - QElapsedTimer _frameTimer; }; } From 931cad34d166f5ebc33b04d262e7678f45971b84 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 12:05:58 -0700 Subject: [PATCH 38/61] Check plugin activation success --- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 6 +++--- .../display-plugins/Basic2DWindowOpenGLDisplayPlugin.h | 2 +- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 9 ++++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 5 +++-- .../src/display-plugins/hmd/HmdDisplayPlugin.cpp | 5 +++-- .../src/display-plugins/hmd/HmdDisplayPlugin.h | 2 +- .../src/display-plugins/stereo/StereoDisplayPlugin.cpp | 5 +++-- .../src/display-plugins/stereo/StereoDisplayPlugin.h | 2 +- libraries/plugins/src/plugins/DisplayPlugin.cpp | 4 ++-- libraries/plugins/src/plugins/DisplayPlugin.h | 2 +- libraries/plugins/src/plugins/Plugin.h | 4 +++- plugins/hifiNeuron/src/NeuronPlugin.cpp | 8 ++++++-- plugins/hifiNeuron/src/NeuronPlugin.h | 2 +- plugins/hifiSdl2/src/SDL2Manager.cpp | 8 ++++++-- plugins/hifiSdl2/src/SDL2Manager.h | 4 +--- plugins/hifiSixense/src/SixenseManager.cpp | 5 ++++- plugins/hifiSixense/src/SixenseManager.h | 2 +- plugins/oculus/src/OculusBaseDisplayPlugin.cpp | 7 +++++-- plugins/oculus/src/OculusBaseDisplayPlugin.h | 2 +- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 10 ++++++++-- plugins/openvr/src/OpenVrDisplayPlugin.h | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 5 ++++- plugins/openvr/src/ViveControllerManager.h | 4 +--- 23 files changed, 66 insertions(+), 39 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 63cb1b80a4..3e3efec4a2 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -19,9 +19,7 @@ const QString Basic2DWindowOpenGLDisplayPlugin::NAME("Desktop"); static const QString FULLSCREEN = "Fullscreen"; -void Basic2DWindowOpenGLDisplayPlugin::internalActivate() { - Parent::internalActivate(); - +bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() { _framerateActions.clear(); _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN, [this](bool clicked) { @@ -33,6 +31,8 @@ void Basic2DWindowOpenGLDisplayPlugin::internalActivate() { }, true, false); updateFramerate(); + + return Parent::internalActivate(); } void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) { diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 90b32a1924..40c6eb4381 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -22,7 +22,7 @@ public: virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; } - virtual void internalActivate() override; + virtual bool internalActivate() override; virtual void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index d842dc553b..8049e2d5a5 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -219,7 +219,7 @@ void OpenGLDisplayPlugin::cleanupForSceneTexture(const gpu::TexturePointer& scen } -void OpenGLDisplayPlugin::activate() { +bool OpenGLDisplayPlugin::activate() { if (!_cursorsData.size()) { auto& cursorManager = Cursor::Manager::instance(); for (const auto iconId : cursorManager.registeredIcons()) { @@ -238,7 +238,9 @@ void OpenGLDisplayPlugin::activate() { // Child classes may override this in order to do things like initialize // libraries, etc - internalActivate(); + if (!internalActivate()) { + return false; + } #if THREADED_PRESENT @@ -263,7 +265,8 @@ void OpenGLDisplayPlugin::activate() { customizeContext(); _container->makeRenderingContextCurrent(); #endif - DisplayPlugin::activate(); + + return DisplayPlugin::activate(); } void OpenGLDisplayPlugin::deactivate() { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 7295b07ad3..b9628deb6c 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -32,7 +32,7 @@ public: // These must be final to ensure proper ordering of operations // between the main thread and the presentation thread - void activate() override final; + bool activate() override final; void deactivate() override final; bool eventFilter(QObject* receiver, QEvent* event) override; @@ -77,7 +77,8 @@ protected: virtual void customizeContext(); virtual void uncustomizeContext(); - virtual void internalActivate() {} + // Returns true on successful activation + virtual bool internalActivate() { return true; } virtual void internalDeactivate() {} virtual void cleanupForSceneTexture(const gpu::TexturePointer& sceneTexture); // Plugin specific functionality to send the composed scene to the output window or device diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index b022b10887..5be3f0d96a 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -32,7 +32,7 @@ glm::uvec2 HmdDisplayPlugin::getRecommendedUiSize() const { return CompositorHelper::VIRTUAL_SCREEN_SIZE; } -void HmdDisplayPlugin::internalActivate() { +bool HmdDisplayPlugin::internalActivate() { _monoPreview = _container->getBoolSetting("monoPreview", DEFAULT_MONO_VIEW); _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW, @@ -41,7 +41,8 @@ void HmdDisplayPlugin::internalActivate() { _container->setBoolSetting("monoPreview", _monoPreview); }, true, _monoPreview); _container->removeMenu(FRAMERATE); - Parent::internalActivate(); + + return Parent::internalActivate(); } void HmdDisplayPlugin::customizeContext() { diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index fede16c3a5..080a44bc66 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -33,7 +33,7 @@ protected: virtual bool isHmdMounted() const = 0; virtual void postPreview() {}; - void internalActivate() override; + bool internalActivate() override; void compositeOverlay() override; void compositePointer() override; void internalPresent() override; diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index ae9f18e20d..66a4ba4835 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -58,7 +58,7 @@ glm::mat4 StereoDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& basePr static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; std::vector _screenActions; -void StereoDisplayPlugin::internalActivate() { +bool StereoDisplayPlugin::internalActivate() { auto screens = qApp->screens(); _screenActions.resize(screens.size()); for (int i = 0; i < screens.size(); ++i) { @@ -77,7 +77,8 @@ void StereoDisplayPlugin::internalActivate() { _screen = qApp->primaryScreen(); _container->setFullscreen(_screen); - Parent::internalActivate(); + + return Parent::internalActivate(); } void StereoDisplayPlugin::updateScreen() { diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h index 6563c2ae89..3b481dce97 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.h @@ -29,7 +29,7 @@ public: // virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; protected: - virtual void internalActivate() override; + virtual bool internalActivate() override; virtual void internalDeactivate() override; void updateScreen(); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.cpp b/libraries/plugins/src/plugins/DisplayPlugin.cpp index 3860639614..c7fa5f5671 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.cpp +++ b/libraries/plugins/src/plugins/DisplayPlugin.cpp @@ -4,11 +4,11 @@ #include "PluginContainer.h" -void DisplayPlugin::activate() { - Parent::activate(); +bool DisplayPlugin::activate() { if (isHmd() && (getHmdScreen() >= 0)) { _container->showDisplayPluginsTools(); } + return Parent::activate(); } void DisplayPlugin::deactivate() { diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index e5ac78036e..f4f28176c7 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -59,7 +59,7 @@ class DisplayPlugin : public Plugin { Q_OBJECT using Parent = Plugin; public: - void activate() override; + bool activate() override; void deactivate() override; virtual bool isHmd() const { return false; } virtual int getHmdScreen() const { return -1; } diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h index ee10ce331c..fb5bf0ba55 100644 --- a/libraries/plugins/src/plugins/Plugin.h +++ b/libraries/plugins/src/plugins/Plugin.h @@ -38,8 +38,10 @@ public: virtual void deinit(); /// Called when a plugin is being activated for use. May be called multiple times. - virtual void activate() { + /// Returns true if plugin was successfully activated. + virtual bool activate() { _active = true; + return _active; } /// Called when a plugin is no longer being used. May be called multiple times. diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index e2143dbdcf..f2b8c04827 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -451,10 +451,10 @@ bool NeuronPlugin::isSupported() const { #endif } -void NeuronPlugin::activate() { -#ifdef HAVE_NEURON +bool NeuronPlugin::activate() { InputPlugin::activate(); +#ifdef HAVE_NEURON // register with userInputMapper auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); @@ -473,11 +473,15 @@ void NeuronPlugin::activate() { if (!_socketRef) { // error qCCritical(inputplugins) << "NeuronPlugin: error connecting to " << _serverAddress.c_str() << ":" << _serverPort << ", error = " << BRGetLastErrorMessage(); + return false; } else { qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort; BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode); + return true; } +#else + return false; #endif } diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index afe8530b07..99859dcacb 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -31,7 +31,7 @@ public: virtual const QString& getName() const override { return NAME; } const QString& getID() const override { return NEURON_ID_STRING; } - virtual void activate() override; + virtual bool activate() override; virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } diff --git a/plugins/hifiSdl2/src/SDL2Manager.cpp b/plugins/hifiSdl2/src/SDL2Manager.cpp index 58da2c5df0..7091b20d21 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.cpp +++ b/plugins/hifiSdl2/src/SDL2Manager.cpp @@ -99,15 +99,19 @@ void SDL2Manager::deinit() { #endif } -void SDL2Manager::activate() { +bool SDL2Manager::activate() { + InputPlugin::activate(); + #ifdef HAVE_SDL2 auto userInputMapper = DependencyManager::get(); for (auto joystick : _openJoysticks) { userInputMapper->registerDevice(joystick); emit joystickAdded(joystick.get()); } + return true; +#else + return false; #endif - InputPlugin::activate(); } void SDL2Manager::deactivate() { diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index a88e41128d..5e3e16d090 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -34,9 +34,7 @@ public: virtual void init() override; virtual void deinit() override; - /// Called when a plugin is being activated for use. May be called multiple times. - virtual void activate() override; - /// Called when a plugin is no longer being used. May be called multiple times. + virtual bool activate() override; virtual void deactivate() override; virtual void pluginFocusOutEvent() override; diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index 9fdce3add4..eb55d84664 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -79,7 +79,7 @@ bool SixenseManager::isSupported() const { #endif } -void SixenseManager::activate() { +bool SixenseManager::activate() { InputPlugin::activate(); #ifdef HAVE_SIXENSE @@ -101,6 +101,9 @@ void SixenseManager::activate() { loadSettings(); _sixenseLoaded = (sixenseInit() == SIXENSE_SUCCESS); + return _sixenseLoaded; +#else + return false; #endif } diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index 5106c87836..a46614b17a 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -32,7 +32,7 @@ public: virtual const QString& getName() const override { return NAME; } virtual const QString& getID() const override { return HYDRA_ID_STRING; } - virtual void activate() override; + virtual bool activate() override; virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 1ed5c9f22a..e23d8cade6 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -34,8 +34,11 @@ void OculusBaseDisplayPlugin::customizeContext() { Parent::customizeContext(); } -void OculusBaseDisplayPlugin::internalActivate() { +bool OculusBaseDisplayPlugin::internalActivate() { _session = acquireOculusSession(); + if (!_session) { + return false; + } _hmdDesc = ovr_GetHmdDesc(_session); @@ -81,7 +84,7 @@ void OculusBaseDisplayPlugin::internalActivate() { // This must come after the initialization, so that the values calculated // above are available during the customizeContext call (when not running // in threaded present mode) - Parent::internalActivate(); + return Parent::internalActivate(); } void OculusBaseDisplayPlugin::internalDeactivate() { diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 5455b61a60..d21b0561bc 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -24,7 +24,7 @@ public: protected: void customizeContext() override; - void internalActivate() override; + bool internalActivate() override; void internalDeactivate() override; protected: diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 0e7541066e..c4d8b252f0 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -41,14 +41,18 @@ bool OpenVrDisplayPlugin::isSupported() const { return !isOculusPresent() && vr::VR_IsHmdPresent(); } -void OpenVrDisplayPlugin::internalActivate() { +bool OpenVrDisplayPlugin::internalActivate() { Parent::internalActivate(); + _container->setIsOptionChecked(StandingHMDSensorMode, true); if (!_system) { _system = acquireOpenVrSystem(); } - Q_ASSERT(_system); + if (!_system) { + qWarning() << "Failed to initialize OpenVR"; + return false; + } _system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y); // Recommended render target size is per-eye, so double the X size for @@ -86,6 +90,8 @@ void OpenVrDisplayPlugin::internalActivate() { } else { qDebug() << "OpenVR: error could not get chaperone pointer"; } + + return true; } void OpenVrDisplayPlugin::internalDeactivate() { diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 78b76cb78d..022af5b06d 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -30,7 +30,7 @@ public: virtual void updateHeadPose(uint32_t frameIndex) override; protected: - void internalActivate() override; + bool internalActivate() override; void internalDeactivate() override; void hmdPresent() override; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 2e2c0face0..c1ed5aa880 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -53,8 +53,9 @@ bool ViveControllerManager::isSupported() const { return !isOculusPresent() && vr::VR_IsHmdPresent(); } -void ViveControllerManager::activate() { +bool ViveControllerManager::activate() { InputPlugin::activate(); + _container->addMenu(MENU_PATH); _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS, [this] (bool clicked) { this->setRenderControllers(clicked); }, @@ -122,6 +123,8 @@ void ViveControllerManager::activate() { auto userInputMapper = DependencyManager::get(); userInputMapper->registerDevice(_inputDevice); _registeredWithInputMapper = true; + + return true; } void ViveControllerManager::deactivate() { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 480fbfeb90..d3645304c5 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -37,7 +37,7 @@ public: virtual bool isJointController() const override { return true; } const QString& getName() const override { return NAME; } - virtual void activate() override; + virtual bool activate() override; virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } @@ -111,8 +111,6 @@ private: std::shared_ptr _inputDevice { std::make_shared(_system) }; static const QString NAME; - - }; #endif // hifi__ViveControllerManager From 37a725b06dc8b9bc183609a2077ec54602c939bf Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 12:12:52 -0700 Subject: [PATCH 39/61] Fallback to desktop if display plugin fails --- interface/src/Application.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9bef698167..7f2d1d2af5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4892,7 +4892,17 @@ void Application::updateDisplayMode() { // FIXME probably excessive and useless context switching _offscreenContext->makeCurrent(); - newDisplayPlugin->activate(); + + // If the new plugin fails to activate, fallback to first item on the list + if (!newDisplayPlugin->activate()) { + qWarning() << "Failed to activate plugin: " << newDisplayPlugin->getName(); + newDisplayPlugin = displayPlugins.at(0); + qWarning() << "Activating fallback plugin: " << newDisplayPlugin->getName(); + if (!newDisplayPlugin->activate()) { + qFatal("Failed to activate fallback plugin"); + } + } + _offscreenContext->makeCurrent(); offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); _offscreenContext->makeCurrent(); From b94e244844c99a8acf402634a31c0d8a62b115cc Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 12:24:31 -0700 Subject: [PATCH 40/61] Update oculus legacy plugin --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 6 +++++- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 73e18aa697..396f55b932 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -68,18 +68,20 @@ bool OculusLegacyDisplayPlugin::isSupported() const { return result; } -void OculusLegacyDisplayPlugin::internalActivate() { +bool OculusLegacyDisplayPlugin::internalActivate() { Parent::internalActivate(); if (!(ovr_Initialize(nullptr))) { Q_ASSERT(false); qFatal("Failed to Initialize SDK"); + return false; } _hswDismissed = false; _hmd = ovrHmd_Create(0); if (!_hmd) { qFatal("Failed to acquire HMD"); + return false; } _ipd = ovrHmd_GetFloat(_hmd, OVR_KEY_IPD, _ipd); @@ -107,6 +109,8 @@ void OculusLegacyDisplayPlugin::internalActivate() { ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) { qFatal("Could not attach to sensor device"); } + + return true; } void OculusLegacyDisplayPlugin::internalDeactivate() { diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index bf4ae26205..187c0681e9 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -31,7 +31,7 @@ public: virtual float getTargetFrameRate() override; protected: - virtual void internalActivate() override; + virtual bool internalActivate() override; virtual void internalDeactivate() override; virtual void customizeContext() override; From 34a77b47a34a2f59d9fff4f0e4a6b78a0c3f4750 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 12:25:56 -0700 Subject: [PATCH 41/61] Restore SDL2 comments --- plugins/hifiSdl2/src/SDL2Manager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index 5e3e16d090..f69e23ee98 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -34,7 +34,9 @@ public: virtual void init() override; virtual void deinit() override; + /// Called when a plugin is being activated for use. May be called multiple times. virtual bool activate() override; + /// Called when a plugin is no longer being used. May be called multiple times. virtual void deactivate() override; virtual void pluginFocusOutEvent() override; From 7bcef1d3194cbfd7e7dc995b067df3d2db7a1df7 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 12:54:38 -0700 Subject: [PATCH 42/61] Fallback display to last, then desktop --- interface/src/Application.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7f2d1d2af5..7eb19557e5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4886,6 +4886,7 @@ void Application::updateDisplayMode() { { std::unique_lock lock(_displayPluginLock); + auto oldDisplayPlugin = _displayPlugin; if (_displayPlugin) { _displayPlugin->deactivate(); } @@ -4893,12 +4894,27 @@ void Application::updateDisplayMode() { // FIXME probably excessive and useless context switching _offscreenContext->makeCurrent(); - // If the new plugin fails to activate, fallback to first item on the list - if (!newDisplayPlugin->activate()) { - qWarning() << "Failed to activate plugin: " << newDisplayPlugin->getName(); - newDisplayPlugin = displayPlugins.at(0); - qWarning() << "Activating fallback plugin: " << newDisplayPlugin->getName(); - if (!newDisplayPlugin->activate()) { + bool active = newDisplayPlugin->activate(); + + if (!active) { + // If the new plugin fails to activate, fallback to last display + qWarning() << "Failed to activate display: " << newDisplayPlugin->getName(); + newDisplayPlugin = oldDisplayPlugin; + + if (newDisplayPlugin) { + qWarning() << "Falling back to last display: " << newDisplayPlugin->getName(); + active = newDisplayPlugin->activate(); + } + + // If there is no last display, or + // If the last display fails to activate, fallback to desktop + if (!active) { + newDisplayPlugin = displayPlugins.at(0); + qWarning() << "Falling back to display: " << newDisplayPlugin->getName(); + active = newDisplayPlugin->activate(); + } + + if (!active) { qFatal("Failed to activate fallback plugin"); } } From 103c6d89f2fe1f1da0b73fcc342dcd72ed63dafb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 28 Mar 2016 13:11:44 -0700 Subject: [PATCH 43/61] Add Socket include to see debug macro --- libraries/networking/src/udt/Packet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 088de49981..2129202cb6 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -15,6 +15,8 @@ #include +#include "Socket.h" + using namespace udt; static int packetMetaTypeId = qRegisterMetaType("Packet*"); From 659d7e7335f1d10bd9377ac5a3264d2599c46fa9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 25 Mar 2016 17:55:06 -0700 Subject: [PATCH 44/61] Fix segfault with gxx --- libraries/networking/src/udt/Packet.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/udt/Packet.cpp b/libraries/networking/src/udt/Packet.cpp index 2129202cb6..d46cae2404 100644 --- a/libraries/networking/src/udt/Packet.cpp +++ b/libraries/networking/src/udt/Packet.cpp @@ -30,15 +30,10 @@ static const std::array KEYS {{ }}; void xorHelper(char* start, int size, Key key) { - const auto end = start + size; - - auto p = start; - for (; p + sizeof(Key) < end; p += sizeof(Key)) { - *reinterpret_cast(p) ^= key; - } - - for (int i = 0; p < end; ++p || ++i) { - *p ^= *(reinterpret_cast(&key) + i); + auto current = start; + auto xorValue = reinterpret_cast(&key); + for (int i = 0; i < size; ++i) { + *(current++) ^= *(xorValue + (i % sizeof(Key))); } } From 95418e25c07a2dde5fb2c7032959a0108167b02c Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 28 Mar 2016 17:46:19 -0700 Subject: [PATCH 45/61] Try to fix the iinclude for the PerfPlot/qml --- examples/utilities/tools/render/stats.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 142b5e25e2..7e7684800b 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 - +import "." Item { id: statsUI From 807698f0bbec99602221b6a2d086d0d8690a4592 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 28 Mar 2016 17:39:43 -0700 Subject: [PATCH 46/61] Make svo loading use ResourceManager --- interface/src/Application.cpp | 9 +------ libraries/octree/src/Octree.cpp | 44 +++++++++++++-------------------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7eb19557e5..c6669303a8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2893,14 +2893,7 @@ void Application::saveSettings() { bool Application::importEntities(const QString& urlOrFilename) { _entityClipboard->eraseAllOctreeElements(); - QUrl url(urlOrFilename); - - // if the URL appears to be invalid or relative, then it is probably a local file - if (!url.isValid() || url.isRelative()) { - url = QUrl::fromLocalFile(urlOrFilename); - } - - bool success = _entityClipboard->readFromURL(url.toString()); + bool success = _entityClipboard->readFromURL(urlOrFilename); if (success) { _entityClipboard->remapIDs(); _entityClipboard->reaverageOctreeElements(); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 4d89464460..ffbc2e6709 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1674,35 +1675,24 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) { } bool Octree::readFromURL(const QString& urlString) { - bool readOk = false; + auto request = std::unique_ptr(ResourceManager::createResourceRequest(this, urlString)); - // determine if this is a local file or a network resource - QUrl url(urlString); - - if (url.isLocalFile()) { - readOk = readFromFile(qPrintable(url.toLocalFile())); - } else { - QNetworkRequest request; - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - request.setUrl(url); - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkReply* reply = networkAccessManager.get(request); - - qCDebug(octree) << "Downloading svo at" << qPrintable(urlString); - - QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); - - if (reply->error() == QNetworkReply::NoError) { - int resourceSize = reply->bytesAvailable(); - QDataStream inputStream(reply); - readOk = readFromStream(resourceSize, inputStream); - } - delete reply; + if (!request) { + return false; } - return readOk; + + QEventLoop loop; + connect(request.get(), &ResourceRequest::finished, &loop, &QEventLoop::quit); + request->send(); + loop.exec(); + + if (request->getResult() != ResourceRequest::Success) { + return false; + } + + auto data = request->getData(); + QDataStream inputStream(data); + return readFromStream(data.size(), inputStream); } From a815c50fcacfcdd951761667ceb0071d1c9d3b56 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 28 Mar 2016 18:36:17 -0700 Subject: [PATCH 47/61] fixing the qml component --- .../tools/render/plotperf/PlotPerf.qml | 186 ++++++++++++++++++ .../utilities/tools/render/plotperf/qmldir | 1 + examples/utilities/tools/render/stats.qml | 2 +- 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 examples/utilities/tools/render/plotperf/PlotPerf.qml create mode 100644 examples/utilities/tools/render/plotperf/qmldir diff --git a/examples/utilities/tools/render/plotperf/PlotPerf.qml b/examples/utilities/tools/render/plotperf/PlotPerf.qml new file mode 100644 index 0000000000..0e100e4e72 --- /dev/null +++ b/examples/utilities/tools/render/plotperf/PlotPerf.qml @@ -0,0 +1,186 @@ +// +// PlotPerf.qml +// examples/utilities/tools/render +// +// Created by Sam Gateau on 3//2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +Item { + id: root + width: parent.width + height: 100 + property string title + property var config + property string parameters + + // THis is my hack to get the name of the first property and assign it to a trigger var in order to get + // a signal called whenever the value changed + property var trigger: config[parameters.split(":")[3].split("-")[0]] + + property var inputs: parameters.split(":") + property var valueScale: +inputs[0] + property var valueUnit: inputs[1] + property var valueNumDigits: inputs[2] + property var input_VALUE_OFFSET: 3 + property var valueMax : 1 + + property var _values : new Array() + property var tick : 0 + + function createValues() { + if (inputs.length > input_VALUE_OFFSET) { + for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { + var varProps = inputs[i].split("-") + _values.push( { + value: varProps[0], + valueMax: 1, + numSamplesConstantMax: 0, + valueHistory: new Array(), + label: varProps[1], + color: varProps[2], + scale: (varProps.length > 3 ? varProps[3] : 1), + unit: (varProps.length > 4 ? varProps[4] : valueUnit) + }) + } + } + print("in creator" + JSON.stringify(_values)); + + } + + Component.onCompleted: { + createValues(); + print(JSON.stringify(_values)); + + } + + function pullFreshValues() { + //print("pullFreshValues"); + var VALUE_HISTORY_SIZE = 100; + var UPDATE_CANVAS_RATE = 20; + tick++; + + + var currentValueMax = 0 + for (var i = 0; i < _values.length; i++) { + + var currentVal = config[_values[i].value] * _values[i].scale; + _values[i].valueHistory.push(currentVal) + _values[i].numSamplesConstantMax++; + + if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) { + var lostValue = _values[i].valueHistory.shift(); + if (lostValue >= _values[i].valueMax) { + _values[i].valueMax *= 0.99 + _values[i].numSamplesConstantMax = 0 + } + } + + if (_values[i].valueMax < currentVal) { + _values[i].valueMax = currentVal; + _values[i].numSamplesConstantMax = 0 + } + + if (_values[i].numSamplesConstantMax > VALUE_HISTORY_SIZE) { + _values[i].numSamplesConstantMax = 0 + _values[i].valueMax *= 0.95 // lower slowly the current max if no new above max since a while + } + + if (currentValueMax < _values[i].valueMax) { + currentValueMax = _values[i].valueMax + } + } + + if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) { + valueMax = currentValueMax; + } + + if (tick % UPDATE_CANVAS_RATE == 0) { + mycanvas.requestPaint() + } + } + onTriggerChanged: pullFreshValues() + + Canvas { + id: mycanvas + anchors.fill:parent + onPaint: { + var lineHeight = 12; + + function displayValue(val, unit) { + return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + unit + } + + function pixelFromVal(val, valScale) { + return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax); + } + function valueFromPixel(pixY) { + return ((pixY - lineHeight) / (height - lineHeight) - 1) * valueMax / (-0.9); + } + function plotValueHistory(ctx, valHistory, color) { + var widthStep= width / (valHistory.length - 1); + + ctx.beginPath(); + ctx.strokeStyle= color; // Green path + ctx.lineWidth="2"; + ctx.moveTo(0, pixelFromVal(valHistory[0])); + + for (var i = 1; i < valHistory.length; i++) { + ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i])); + } + + ctx.stroke(); + } + function displayValueLegend(ctx, val, num) { + ctx.fillStyle = val.color; + var bestValue = val.valueHistory[val.valueHistory.length -1]; + ctx.textAlign = "right"; + ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); + ctx.textAlign = "left"; + ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); + } + + function displayTitle(ctx, text, maxVal) { + ctx.fillStyle = "grey"; + ctx.textAlign = "right"; + ctx.fillText(displayValue(valueFromPixel(lineHeight), root.valueUnit), width, lineHeight); + + ctx.fillStyle = "white"; + ctx.textAlign = "left"; + ctx.fillText(text, 0, lineHeight); + } + function displayBackground(ctx) { + ctx.fillStyle = Qt.rgba(0, 0, 0, 0.6); + ctx.fillRect(0, 0, width, height); + + ctx.strokeStyle= "grey"; + ctx.lineWidth="2"; + + ctx.beginPath(); + ctx.moveTo(0, lineHeight + 1); + ctx.lineTo(width, lineHeight + 1); + ctx.moveTo(0, height); + ctx.lineTo(width, height); + ctx.stroke(); + } + + var ctx = getContext("2d"); + ctx.clearRect(0, 0, width, height); + ctx.font="12px Verdana"; + + displayBackground(ctx); + + for (var i = 0; i < _values.length; i++) { + plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) + displayValueLegend(ctx, _values[i], i) + } + + displayTitle(ctx, title, valueMax) + } + } +} diff --git a/examples/utilities/tools/render/plotperf/qmldir b/examples/utilities/tools/render/plotperf/qmldir new file mode 100644 index 0000000000..5668f5034c --- /dev/null +++ b/examples/utilities/tools/render/plotperf/qmldir @@ -0,0 +1 @@ +PlotPerf 1.0 PlotPerf.qml \ No newline at end of file diff --git a/examples/utilities/tools/render/stats.qml b/examples/utilities/tools/render/stats.qml index 7e7684800b..aacc896444 100644 --- a/examples/utilities/tools/render/stats.qml +++ b/examples/utilities/tools/render/stats.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 import QtQuick.Controls 1.4 -import "." +import "plotperf" Item { id: statsUI From 884a3e691d0ac7e7d79ee8981b7c8ac3bcca1639 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 28 Mar 2016 18:38:34 -0700 Subject: [PATCH 48/61] Cleaning up moved files --- examples/utilities/tools/render/PlotPerf.qml | 186 ------------------- 1 file changed, 186 deletions(-) delete mode 100644 examples/utilities/tools/render/PlotPerf.qml diff --git a/examples/utilities/tools/render/PlotPerf.qml b/examples/utilities/tools/render/PlotPerf.qml deleted file mode 100644 index 0e100e4e72..0000000000 --- a/examples/utilities/tools/render/PlotPerf.qml +++ /dev/null @@ -1,186 +0,0 @@ -// -// PlotPerf.qml -// examples/utilities/tools/render -// -// Created by Sam Gateau on 3//2016 -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html -// -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -Item { - id: root - width: parent.width - height: 100 - property string title - property var config - property string parameters - - // THis is my hack to get the name of the first property and assign it to a trigger var in order to get - // a signal called whenever the value changed - property var trigger: config[parameters.split(":")[3].split("-")[0]] - - property var inputs: parameters.split(":") - property var valueScale: +inputs[0] - property var valueUnit: inputs[1] - property var valueNumDigits: inputs[2] - property var input_VALUE_OFFSET: 3 - property var valueMax : 1 - - property var _values : new Array() - property var tick : 0 - - function createValues() { - if (inputs.length > input_VALUE_OFFSET) { - for (var i = input_VALUE_OFFSET; i < inputs.length; i++) { - var varProps = inputs[i].split("-") - _values.push( { - value: varProps[0], - valueMax: 1, - numSamplesConstantMax: 0, - valueHistory: new Array(), - label: varProps[1], - color: varProps[2], - scale: (varProps.length > 3 ? varProps[3] : 1), - unit: (varProps.length > 4 ? varProps[4] : valueUnit) - }) - } - } - print("in creator" + JSON.stringify(_values)); - - } - - Component.onCompleted: { - createValues(); - print(JSON.stringify(_values)); - - } - - function pullFreshValues() { - //print("pullFreshValues"); - var VALUE_HISTORY_SIZE = 100; - var UPDATE_CANVAS_RATE = 20; - tick++; - - - var currentValueMax = 0 - for (var i = 0; i < _values.length; i++) { - - var currentVal = config[_values[i].value] * _values[i].scale; - _values[i].valueHistory.push(currentVal) - _values[i].numSamplesConstantMax++; - - if (_values[i].valueHistory.length > VALUE_HISTORY_SIZE) { - var lostValue = _values[i].valueHistory.shift(); - if (lostValue >= _values[i].valueMax) { - _values[i].valueMax *= 0.99 - _values[i].numSamplesConstantMax = 0 - } - } - - if (_values[i].valueMax < currentVal) { - _values[i].valueMax = currentVal; - _values[i].numSamplesConstantMax = 0 - } - - if (_values[i].numSamplesConstantMax > VALUE_HISTORY_SIZE) { - _values[i].numSamplesConstantMax = 0 - _values[i].valueMax *= 0.95 // lower slowly the current max if no new above max since a while - } - - if (currentValueMax < _values[i].valueMax) { - currentValueMax = _values[i].valueMax - } - } - - if ((valueMax < currentValueMax) || (tick % VALUE_HISTORY_SIZE == 0)) { - valueMax = currentValueMax; - } - - if (tick % UPDATE_CANVAS_RATE == 0) { - mycanvas.requestPaint() - } - } - onTriggerChanged: pullFreshValues() - - Canvas { - id: mycanvas - anchors.fill:parent - onPaint: { - var lineHeight = 12; - - function displayValue(val, unit) { - return (val / root.valueScale).toFixed(root.valueNumDigits) + " " + unit - } - - function pixelFromVal(val, valScale) { - return lineHeight + (height - lineHeight) * (1 - (0.9) * val / valueMax); - } - function valueFromPixel(pixY) { - return ((pixY - lineHeight) / (height - lineHeight) - 1) * valueMax / (-0.9); - } - function plotValueHistory(ctx, valHistory, color) { - var widthStep= width / (valHistory.length - 1); - - ctx.beginPath(); - ctx.strokeStyle= color; // Green path - ctx.lineWidth="2"; - ctx.moveTo(0, pixelFromVal(valHistory[0])); - - for (var i = 1; i < valHistory.length; i++) { - ctx.lineTo(i * widthStep, pixelFromVal(valHistory[i])); - } - - ctx.stroke(); - } - function displayValueLegend(ctx, val, num) { - ctx.fillStyle = val.color; - var bestValue = val.valueHistory[val.valueHistory.length -1]; - ctx.textAlign = "right"; - ctx.fillText(displayValue(bestValue, val.unit), width, (num + 2) * lineHeight * 1.5); - ctx.textAlign = "left"; - ctx.fillText(val.label, 0, (num + 2) * lineHeight * 1.5); - } - - function displayTitle(ctx, text, maxVal) { - ctx.fillStyle = "grey"; - ctx.textAlign = "right"; - ctx.fillText(displayValue(valueFromPixel(lineHeight), root.valueUnit), width, lineHeight); - - ctx.fillStyle = "white"; - ctx.textAlign = "left"; - ctx.fillText(text, 0, lineHeight); - } - function displayBackground(ctx) { - ctx.fillStyle = Qt.rgba(0, 0, 0, 0.6); - ctx.fillRect(0, 0, width, height); - - ctx.strokeStyle= "grey"; - ctx.lineWidth="2"; - - ctx.beginPath(); - ctx.moveTo(0, lineHeight + 1); - ctx.lineTo(width, lineHeight + 1); - ctx.moveTo(0, height); - ctx.lineTo(width, height); - ctx.stroke(); - } - - var ctx = getContext("2d"); - ctx.clearRect(0, 0, width, height); - ctx.font="12px Verdana"; - - displayBackground(ctx); - - for (var i = 0; i < _values.length; i++) { - plotValueHistory(ctx, _values[i].valueHistory, _values[i].color) - displayValueLegend(ctx, _values[i], i) - } - - displayTitle(ctx, title, valueMax) - } - } -} From 29dedd55241e08bc7f6458dbfbed5e7b15f856b6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 28 Mar 2016 19:19:16 -0700 Subject: [PATCH 49/61] Update model URL on render thread --- .../src/EntityTreeRenderer.cpp | 34 ++++-------- .../src/RenderableModelEntityItem.cpp | 53 +++++++++---------- libraries/render-utils/src/Model.h | 4 +- 3 files changed, 38 insertions(+), 53 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 07d19dbd92..65ac5197c8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -460,14 +460,17 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) { ModelPointer model = nullptr; - // Make sure we only create and delete models on the thread that owns the EntityTreeRenderer + + // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ModelPointer, model), - Q_ARG(const QString&, url)); + Q_ARG(const QString&, url), + Q_ARG(const QString&, collisionUrl)); return model; } + model = std::make_shared(std::make_shared()); model->init(); model->setURL(QUrl(url)); @@ -475,37 +478,20 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString return model; } -ModelPointer EntityTreeRenderer::updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl) { - ModelPointer model = nullptr; - - // The caller shouldn't call us if the URL doesn't need to change. But if they - // do, we just return their original back to them. - if (!original || (QUrl(newUrl) == original->getURL())) { - return original; - } - - // Before we do any creating or deleting, make sure we're on our renderer thread +ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& newUrl, const QString& collisionUrl) { + // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ModelPointer, model), - Q_ARG(ModelPointer, original), - Q_ARG(const QString&, newUrl)); + Q_ARG(ModelPointer, model), + Q_ARG(const QString&, newUrl), + Q_ARG(const QString&, collisionUrl)); return model; } - // at this point we know we need to replace the model, and we know we're on the - // correct thread, so we can do all our work. - if (original) { - original.reset(); // delete the old model... - } - - // create the model and correctly initialize it with the new url - model = std::make_shared(std::make_shared()); - model->init(); model->setURL(QUrl(newUrl)); model->setCollisionModelURL(QUrl(collisionUrl)); - return model; } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ae29d1faf7..e2db598d40 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -69,14 +69,10 @@ void RenderableModelEntityItem::loader() { _needsModelReload = true; EntityTreeRenderer* renderer = DependencyManager::get().data(); assert(renderer); - if (!_model || _needsModelReload) { + { PerformanceTimer perfTimer("getModel"); getModel(renderer); } - if (_model) { - _model->setURL(getParsedModelURL()); - _model->setCollisionModelURL(QUrl(getCompoundShapeURL())); - } } void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { @@ -364,13 +360,6 @@ void RenderableModelEntityItem::render(RenderArgs* args) { if (hasModel()) { if (_model) { - // check if the URL has changed - auto& currentURL = getParsedModelURL(); - if (currentURL != _model->getURL()) { - qCDebug(entitiesrenderer).noquote() << "Updating model URL: " << currentURL.toDisplayString(); - _model->setURL(currentURL); - } - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); // check to see if when we added our models to the scene they were ready, if they were not ready, then @@ -435,6 +424,15 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } }); updateModelBounds(); + + // Check if the URL has changed + // Do this last as the getModel is queued for the next frame, + // and we need to keep state directing the model to reinitialize + auto& currentURL = getParsedModelURL(); + if (currentURL != _model->getURL()) { + // Defer setting the url to the render thread + getModel(_myRenderer); + } } } } else { @@ -450,10 +448,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { - ModelPointer result = nullptr; - if (!renderer) { - return result; + return nullptr; } // make sure our renderer is setup @@ -468,21 +464,22 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { _needsModelReload = false; // this is the reload - // if we have a URL, then we will want to end up returning a model... + // If we have a URL, then we will want to end up returning a model... if (!getModelURL().isEmpty()) { - - // if we have a previously allocated model, but its URL doesn't match - // then we need to let our renderer update our model for us. - if (_model && (QUrl(getModelURL()) != _model->getURL() || - QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) { - result = _model = _myRenderer->updateModel(_model, getModelURL(), getCompoundShapeURL()); + // If we don't have a model, allocate one *immediately* + if (!_model) { + _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL()); _needsInitialSimulation = true; - } else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one - result = _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL()); + // If we need to change URLs, update it *after rendering* (to avoid access violations) + } else if ((QUrl(getModelURL()) != _model->getURL() || QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) { + QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, + Q_ARG(ModelPointer, _model), + Q_ARG(const QString&, getModelURL()), + Q_ARG(const QString&, getCompoundShapeURL())); _needsInitialSimulation = true; - } else { // we already have the model we want... - result = _model; } + // Else we can just return the _model + // If we have no URL, then we can delete any model we do have... } else if (_model) { // remove from scene render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); @@ -492,11 +489,11 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { // release interest _myRenderer->releaseModel(_model); - result = _model = nullptr; + _model = nullptr; _needsInitialSimulation = true; } - return result; + return _model; } bool RenderableModelEntityItem::needsToCallUpdate() const { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 744a4ce605..785b902b3a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -73,6 +73,7 @@ public: } /// Sets the URL of the model to render. + // Should only be called from the model's rendering thread to avoid access violations of changed geometry. Q_INVOKABLE void setURL(const QUrl& url); const QUrl& getURL() const { return _url; } @@ -133,7 +134,8 @@ public: /// Provided as a convenience, will crash if !isCollisionLoaded() const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return getCollisionGeometry()->getGeometry()->getGeometry(); } - // Set the model to use for collisions + // Set the model to use for collisions. + // Should only be called from the model's rendering thread to avoid access violations of changed geometry. Q_INVOKABLE void setCollisionModelURL(const QUrl& url); const QUrl& getCollisionURL() const { return _collisionUrl; } From cbb6c5fe98ecfa0bbe55493ff77195c8826e1453 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 10:07:04 -0700 Subject: [PATCH 50/61] added portkey to posters --- .../Home/kineticObjects/postersCell.json | 29 +++++++++++++ .../DomainContent/Home/switches/portkey.js | 42 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 unpublishedScripts/DomainContent/Home/switches/portkey.js diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json b/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json index ec26cf66ac..6774e87b9b 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json @@ -60,6 +60,35 @@ "shapeType": "compound", "type": "Model", "userData": "{\"hifiHomeKey\":{\"reset\":true}}" + }, + { + "color": { + "blue": 255, + "green": 0, + "red": 255 + }, + "name": "home_sphere_cellsciencePortkey", + "href": "hifi://cellscience", + "script": "atp:/switches/portkey.js", + "visible": false, + "dimensions": { + "x": 0.111, + "y": 0.111, + "z": 0.111 + }, + "position": { + "x": 0.0, + "y": -0.2, + "z": 0.0 + }, + "queryAACube": { + "scale": 0.25831151008605957, + "x": -0.12915575504302979, + "y": -0.12915575504302979, + "z": -0.10074388980865479 + }, + "type": "Sphere", + "userData": "{\"hifiHomeKey\":{\"reset\":true}, \"grabbableKey\": {\"wantsTrigger\": true}}" }], "Version": 57 } \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/Home/switches/portkey.js b/unpublishedScripts/DomainContent/Home/switches/portkey.js new file mode 100644 index 0000000000..e6065e24ea --- /dev/null +++ b/unpublishedScripts/DomainContent/Home/switches/portkey.js @@ -0,0 +1,42 @@ +// +// portkey.js +// +// +// Created by Eric Levin on 3/28/2016 +// Copyright 2016 High Fidelity, Inc. +// +// This entity script is designed to teleport a user to an in-world location specified in object's userdata +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +(function() { + + Script.include("atp:/utils.js"); + var _this = this; + + + this.startFarTrigger = function() { + _this.teleport(); + } + + this.startNearTrigger = function() { + _this.teleport(); + } + + this.startNearGrab = function() { + _this.teleport(); + } + + this.teleport = function() { + Window.location = _this.portkeyLink; + } + + this.preload = function(entityID) { + _this.entityID = entityID; + _this.portkeyLink = Entities.getEntityProperties(_this.entityID, "href").href; + } + +}); \ No newline at end of file From 1597ee57e2fd46a0dd7a68373099394c1356e609 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 10:18:00 -0700 Subject: [PATCH 51/61] added json --- .../Home/kineticObjects/postersPlaya.json | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json b/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json index 68594aaf3f..2d4bf1da0b 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json @@ -66,6 +66,35 @@ }, "type": "Box", "userData": "{\"hifiHomeKey\":{\"reset\":true}}" + }, + { + "color": { + "blue": 255, + "green": 0, + "red": 255 + }, + "name": "home_sphere_playaPortkey", + "href": "hifi://playa", + "script": "atp:/switches/portkey.js", + "visible": true, + "dimensions": { + "x": 0.111, + "y": 0.111, + "z": 0.111 + }, + "position": { + "x": 0.0, + "y": -0.2, + "z": 0.0 + }, + "queryAACube": { + "scale": 0.25831151008605957, + "x": -0.12915575504302979, + "y": -0.12915575504302979, + "z": -0.10074388980865479 + }, + "type": "Sphere", + "userData": "{\"hifiHomeKey\":{\"reset\":true}, \"grabbableKey\": {\"wantsTrigger\": true}}" }], "Version": 57 } \ No newline at end of file From 6d4c0e940a0abd4eb6b4d9fcc9d3367d414a8289 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 10:26:17 -0700 Subject: [PATCH 52/61] json changes to posters --- .../DomainContent/Home/kineticObjects/postersCell.json | 7 +------ .../DomainContent/Home/kineticObjects/postersPlaya.json | 9 ++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json b/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json index 6774e87b9b..25aa606a50 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/postersCell.json @@ -41,12 +41,7 @@ "y": 1.1607639789581299, "z": 0.87844705581665039 }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -5, - "z": 0 - }, + "dynamic": 0, "id": "{9eec1faa-9e1a-4d76-abeb-a1b1175a44d5}", "modelURL": "atp:/kineticObjects/posters/Cellscience-Poster-2.fbx", "name": "hifi-home-poster-cell", diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json b/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json index 2d4bf1da0b..37a2b90e8f 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/postersPlaya.json @@ -8,12 +8,7 @@ "y": 1.2243480682373047, "z": 0.92656642198562622 }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -2, - "z": 0 - }, + "dynamic": 0, "name": "hifi-home-poster-playa", "id": "{2b5ca0a0-9115-4916-bee6-63f88d3909b1}", "modelURL": "atp:/kineticObjects/posters/Playa-Poster.fbx", @@ -76,7 +71,7 @@ "name": "home_sphere_playaPortkey", "href": "hifi://playa", "script": "atp:/switches/portkey.js", - "visible": true, + "visible": false, "dimensions": { "x": 0.111, "y": 0.111, From 286bc5de1d2598f6ad8ddb2b2518610b948e14d8 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 14:06:51 -0700 Subject: [PATCH 53/61] changed json desk lamp to work with parenting --- .../cuckooClockMinuteHandEntityScript.js | 20 +- .../Home/kineticObjects/deskLamp.json | 249 +++++++++--------- .../DomainContent/Home/reset.js | 6 - 3 files changed, 131 insertions(+), 144 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/cuckooClock/cuckooClockMinuteHandEntityScript.js b/unpublishedScripts/DomainContent/Home/cuckooClock/cuckooClockMinuteHandEntityScript.js index 3b6c4519eb..3689495d84 100644 --- a/unpublishedScripts/DomainContent/Home/cuckooClock/cuckooClockMinuteHandEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/cuckooClock/cuckooClockMinuteHandEntityScript.js @@ -80,16 +80,16 @@ print("WE DONT HAVE A SECOND HAND! RETURNING"); return; } - + var clockRotation = Entities.getEntityProperties(_this.clockBody, "rotation").rotation; var DEGREES_FOR_SECOND = 6; var myDate = new Date(); var seconds = myDate.getSeconds(); secondRollDegrees = -seconds * DEGREES_FOR_SECOND; - // var localClockHandRotation = Quat.fromPitchYawRollDegrees(0, 0, secondRollDegrees); - // var worldClockHandRotation = Quat.multiply(clockRotation, localClockHandRotation); - // Entities.editEntity(_this.secondHand, { - // rotation: worldClockHandRotation - // }); + var localClockHandRotation = Quat.fromPitchYawRollDegrees(0, 0, secondRollDegrees); + var worldClockHandRotation = Quat.multiply(clockRotation, localClockHandRotation); + Entities.editEntity(_this.secondHand, { + rotation: worldClockHandRotation + }); }, @@ -122,12 +122,12 @@ var seconds = date.getSeconds(); var minutes = date.getMinutes(); - // if (seconds === 0 && minutes === 0) { - // _this.popCuckooOut(); - // } - if (seconds % 30 === 0) { + if (seconds === 0 && minutes === 0) { _this.popCuckooOut(); } + // if (seconds % 30 === 0) { + // _this.popCuckooOut(); + // } }, diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json b/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json index 162d7a1355..8a84a7894d 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json @@ -1,103 +1,44 @@ { "Entities": [ { - "angularVelocity": { - "x": -0.026321493089199066, - "y": -0.028931867331266403, - "z": 0.010236549191176891 + "collisionless": 1, + "color": { + "blue": 0, + "green": 0, + "red": 255 }, - "collisionsWillMove": 1, - "compoundShapeURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Shade.obj", - "created": "2016-03-22T22:55:11Z", + "created": "2016-03-24T22:17:16Z", "dimensions": { - "x": 0.35158795118331909, - "y": 0.27823561429977417, - "z": 0.35158795118331909 + "x": 0.15776367485523224, + "y": 0.26723021268844604, + "z": 0.16535492241382599 }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -2, - "z": 0 - }, - "id": "{747a8714-3cc5-4336-bac3-de3c8ec1494d}", - "modelURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Shade.fbx", - "name": "hifi-home-model-bulldog-shade", + "id": "{c7c6108b-4c60-4735-b2bf-5559d7e30e7d}", + "ignoreForCollisions": 1, + "name": "hifi-home-living-room-desk-lamp-trigger", + "parentID": "{f59b50d8-13fb-4ceb-b80a-62cd03428a7c}", "position": { - "x": 0.085205078125, - "y": 0.5194091796875, - "z": 0 + "x": 0.0062166899442672729, + "y": -0.1577162891626358, + "z": -0.0018789069727063179 }, "queryAACube": { - "scale": 0.56977474689483643, - "x": -0.19968229532241821, - "y": 0.23452180624008179, - "z": -0.28488737344741821 - }, - "restitution": 0.20000000298023224, - "rotation": { - "w": 0.98912078142166138, - "x": -0.0035601628478616476, - "y": -0.14705567061901093, - "z": 0.0014477154472842813 - }, - "shapeType": "compound", - "type": "Model", - "userData": "{\"hifiHomeKey\":{\"reset\":true}}", - "velocity": { - "x": 0.0051150284707546234, - "y": 0.00043292529881000519, - "z": 0.00053954275790601969 - } - }, - { - "angularVelocity": { - "x": -0.0016508022090420127, - "y": 0.00053207820747047663, - "z": -0.0033033043146133423 - }, - "collisionsWillMove": 1, - "compoundShapeURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Base.obj", - "created": "2016-03-22T22:50:49Z", - "dimensions": { - "x": 0.26436957716941833, - "y": 0.73171323537826538, - "z": 0.26436954736709595 - }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -9, - "z": 0 - }, - "id": "{5dcc642f-34a6-44a7-8da8-275cbbbef9d6}", - "modelURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Base.fbx", - "name": "hifi-home-model-bulldog-base", - "position": { - "x": 0.08642578125, - "y": 0.306884765625, - "z": 0.00026702880859375 - }, - "queryAACube": { - "scale": 0.82169753313064575, - "x": -0.32442298531532288, - "y": -0.10396400094032288, - "z": -0.41058173775672913 + "scale": 6.92822265625, + "x": 1101.2117919921875, + "y": 456.86856079101562, + "z": -84.708488464355469 }, "rotation": { - "w": 0.84591019153594971, - "x": -6.7644752562046051e-05, - "y": -0.53332537412643433, - "z": 8.2868709796457551e-06 + "w": 0.84585332870483398, + "x": 1.52587890625e-05, + "y": 0.53337907791137695, + "z": -0.0001373291015625 }, - "shapeType": "compound", - "type": "Model", - "userData": "{\"hifiHomeKey\":{\"reset\":true}}", - "velocity": { - "x": 0.0011470125755295157, - "y": 0.0010520070791244507, - "z": -0.0011547321919351816 - } + "script": "atp:/switches/livingRoomDeskLamp.js", + "scriptTimestamp": 1458860464095, + "type": "Box", + "userData": "{\"hifiHomeKey\":{\"reset\":true},\"grabbableKey\":{\"wantsTrigger\":true},\"home-switch\":{\"state\":\"off\"}}", + "visible": 0 }, { "color": { @@ -113,68 +54,120 @@ "z": 4 }, "falloffRadius": 0.30000001192092896, - "id": "{1f15e48e-66cd-4ecd-8d60-a391f050ec8d}", + "id": "{47e2c415-854c-4b6a-b71e-06c760675afd}", "intensity": 20, "isSpotlight": 1, "name": "hifi-home-living-room-desk-lamp-spotlight", + "parentID": "{c7c6108b-4c60-4735-b2bf-5559d7e30e7d}", "position": { - "x": 0, - "y": 0, - "z": 0.727783203125 + "x": -0.10525670647621155, + "y": -0.14917388558387756, + "z": 0.71759903430938721 }, "queryAACube": { - "scale": 6.9282031059265137, - "x": -3.4641015529632568, - "y": -3.4641015529632568, - "z": -2.7363183498382568 + "scale": 20.784608840942383, + "x": 1094.28076171875, + "y": 449.9404296875, + "z": -91.635543823242188 }, "rotation": { - "w": 0.63591969013214111, - "x": 0.26338601112365723, - "y": -0.27760738134384155, - "z": -0.67016100883483887 + "w": 0.6360476016998291, + "x": 0.26325368881225586, + "y": -0.27753552794456482, + "z": -0.67013490200042725 }, "type": "Light", + "userData": "{\"hifiHomeKey\":{\"reset\":true}}", + "visible": 0 + }, + { + "collisionsWillMove": 1, + "compoundShapeURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Shade.obj", + "created": "2016-03-22T22:55:11Z", + "dimensions": { + "x": 0.35158795118331909, + "y": 0.27823561429977417, + "z": 0.35158795118331909 + }, + "dynamic": 1, + "gravity": { + "x": 0, + "y": -2, + "z": 0 + }, + "id": "{6c59ca6f-e3f6-42c1-ae4d-1549b5bdaee1}", + "modelURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Shade.fbx", + "name": "hifi-home-model-bulldog-shade", + "position": { + "x": 0.085205078125, + "y": 0.5194091796875, + "z": 0 + }, + "queryAACube": { + "scale": 0.56977474689483643, + "x": -0.28488737344741821, + "y": -0.072393476963043213, + "z": -0.28485685586929321 + }, + "restitution": 0.20000000298023224, + "rotation": { + "w": 0.98724901676177979, + "x": -0.0033740350045263767, + "y": -0.15913932025432587, + "z": 0.0016243136487901211 + }, + "shapeType": "compound", + "type": "Model", "userData": "{\"hifiHomeKey\":{\"reset\":true}}" }, { - "collisionless": 1, - "color": { - "blue": 0, - "green": 0, - "red": 255 + "angularVelocity": { + "x": 0.0087265009060502052, + "y": 0.005478390958160162, + "z": 0.0057442504912614822 }, - "created": "2016-03-24T22:17:16Z", + "collisionsWillMove": 1, + "compoundShapeURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Base.obj", + "created": "2016-03-22T22:50:49Z", "dimensions": { - "x": 0.15776367485523224, - "y": 0.26723021268844604, - "z": 0.16535492241382599 + "x": 0.26436957716941833, + "y": 0.73171323537826538, + "z": 0.26436954736709595 }, - "id": "{51eb700c-62ba-4e1d-813a-2c23deb02e26}", - "ignoreForCollisions": 1, - "name": "hifi-home-living-room-desk-lamp-trigger", + "dynamic": 1, + "gravity": { + "x": 0, + "y": -9, + "z": 0 + }, + "id": "{f59b50d8-13fb-4ceb-b80a-62cd03428a7c}", + "modelURL": "atp:/kineticObjects/lamp/Lamp-Bulldog-Base.fbx", + "name": "hifi-home-model-bulldog-base", "position": { - "x": 0.09033203125, - "y": 0.149169921875, - "z": 0.00484466552734375 + "x": 0.08642578125, + "y": 0.306884765625, + "z": 0.00026702880859375 }, "queryAACube": { - "scale": 0.35162994265556335, - "x": -0.085482940077781677, - "y": -0.026645049452781677, - "z": -0.17097030580043793 + "scale": 0.82169753313064575, + "x": -0.40962806344032288, + "y": -0.41084876656532288, + "z": -0.41084876656532288 }, "rotation": { - "w": 1, - "x": -1.52587890625e-05, - "y": -1.52587890625e-05, - "z": -1.52587890625e-05 + "w": 0.84690523147583008, + "x": 4.9625090468907729e-05, + "y": -0.53174382448196411, + "z": 4.0798266127239913e-05 }, - "script": "atp:/switches/livingRoomDeskLamp.js", - "scriptTimestamp": 1458860464095, - "type": "Box", - "userData": "{\"hifiHomeKey\":{\"reset\":true},\"grabbableKey\":{\"wantsTrigger\":true},\"home-switch\":{\"state\":\"on\"}}", - "visible": 0 + "shapeType": "compound", + "type": "Model", + "userData": "{\"hifiHomeKey\":{\"reset\":true}}", + "velocity": { + "x": -0.0026286719366908073, + "y": 0.0016162246465682983, + "z": 0.0042029935866594315 + } } ], "Version": 57 diff --git a/unpublishedScripts/DomainContent/Home/reset.js b/unpublishedScripts/DomainContent/Home/reset.js index c1cc8cc12a..34292f7083 100644 --- a/unpublishedScripts/DomainContent/Home/reset.js +++ b/unpublishedScripts/DomainContent/Home/reset.js @@ -274,12 +274,6 @@ z: -73.3 }); - var livingRoomLampTriggerBoxName = "hifi-home-living-room-desk-lamp-trigger"; - var livingRoomLampModelName = "hifi-home-model-bulldog-base"; - Script.setTimeout(function() { - attachChildToParent(livingRoomLampTriggerBoxName, livingRoomLampModelName, MyAvatar.position, 20); - }, 1000); - }, setupDressingRoom: function() { From 182e05e1251c49b8cdf6266042cff02735525a21 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 15:38:21 -0700 Subject: [PATCH 54/61] adding collision hulls to can and bowl --- .../DomainContent/Home/growingPlant/wrapper.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index e535b9b839..ca42d21b98 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -21,6 +21,7 @@ Plant = function(spawnPosition, spawnRotation) { print("EBL ORIENTATION " + JSON.stringify(orientation)); var bowlPosition = spawnPosition; var BOWL_MODEL_URL = "atp:/growingPlant/Flowers-Bowl.fbx"; + var BOWL_COLLISION_HULL_URL = "atp:/growingPlant/bowl.obj"; var bowlDimensions = { x: 0.518, y: 0.1938, @@ -30,6 +31,8 @@ Plant = function(spawnPosition, spawnRotation) { type: "Model", modelURL: BOWL_MODEL_URL, dimensions: bowlDimensions, + shapeType: 'compound', + compundShapeURL: BOWL_COLLISION_HULL_URL, name: "plant bowl", position: bowlPosition, userData: JSON.stringify({ @@ -69,12 +72,13 @@ Plant = function(spawnPosition, spawnRotation) { var WATER_CAN_MODEL_URL = "atp:/growingPlant/waterCan.fbx"; - + var WATER_CAN_COLLIISION_HULL_URL = "atp:/growingPlant/can.obj"; var waterCanPosition = Vec3.sum(plantPosition, Vec3.multiply(0.6, Quat.getRight(orientation))); var waterCanRotation = orientation; var waterCan = Entities.addEntity({ type: "Model", - shapeType: 'box', + shapeType: 'compound', + compundShapeURL: WATER_CAN_COLLIISION_HULL_URL, name: "hifi-water-can", modelURL: WATER_CAN_MODEL_URL, script: WATER_CAN_SCRIPT_URL, From c74b71aa3728502af358cb44e3f342bc86387373 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 16:10:31 -0700 Subject: [PATCH 55/61] updated growing plant --- unpublishedScripts/DomainContent/Home/createTidyGuy.js | 2 +- unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/unpublishedScripts/DomainContent/Home/createTidyGuy.js b/unpublishedScripts/DomainContent/Home/createTidyGuy.js index c54e0ef7b2..968dd85f25 100644 --- a/unpublishedScripts/DomainContent/Home/createTidyGuy.js +++ b/unpublishedScripts/DomainContent/Home/createTidyGuy.js @@ -32,5 +32,5 @@ function createTidyGuy() { var tidyGuy = createTidyGuy(); Script.scriptEnding.connect(function() { - Entities.deleteEntity(tidyGuy); + // Entities.deleteEntity(tidyGuy); }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index ca42d21b98..8adc05b35c 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -12,6 +12,7 @@ var PLANT_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/growingPlantEntityScript.js"); var WATER_CAN_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/waterCanEntityScript.js"); Plant = function(spawnPosition, spawnRotation) { + print("EBL PLANT CONSTRUCTOR!") var orientation; if (spawnRotation !== undefined) { orientation = Quat.fromPitchYawRollDegrees(spawnRotation.x, spawnRotation.y, spawnRotation.z); @@ -31,6 +32,7 @@ Plant = function(spawnPosition, spawnRotation) { type: "Model", modelURL: BOWL_MODEL_URL, dimensions: bowlDimensions, + dynamic: true, shapeType: 'compound', compundShapeURL: BOWL_COLLISION_HULL_URL, name: "plant bowl", @@ -43,6 +45,7 @@ Plant = function(spawnPosition, spawnRotation) { }); + var PLANT_MODEL_URL = "atp:/growingPlant/Flowers-Rock.fbx"; var plantDimensions = { From 665597214a35cc5fd1f0ea52d6cfa842f3c4e188 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 30 Mar 2016 20:04:33 -0700 Subject: [PATCH 56/61] made desk lamp dimensions bigger --- .../DomainContent/Home/kineticObjects/deskLamp.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json b/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json index 8a84a7894d..dfc03840f5 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/deskLamp.json @@ -9,9 +9,9 @@ }, "created": "2016-03-24T22:17:16Z", "dimensions": { - "x": 0.15776367485523224, - "y": 0.26723021268844604, - "z": 0.16535492241382599 + "x": 0.2776367485523224, + "y": 0.27723021268844604, + "z": 0.2535492241382599 }, "id": "{c7c6108b-4c60-4735-b2bf-5559d7e30e7d}", "ignoreForCollisions": 1, From 4cf5f41eed7610f5248cdb3b0c2ac806cd947067 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 31 Mar 2016 14:03:05 -0700 Subject: [PATCH 57/61] changed chair path --- unpublishedScripts/DomainContent/Home/kineticObjects/chair.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/DomainContent/Home/kineticObjects/chair.json b/unpublishedScripts/DomainContent/Home/kineticObjects/chair.json index 1e48a21827..0acd78929c 100644 --- a/unpublishedScripts/DomainContent/Home/kineticObjects/chair.json +++ b/unpublishedScripts/DomainContent/Home/kineticObjects/chair.json @@ -2,7 +2,7 @@ "Entities": [{ "userData": "{\"hifiHomeKey\":{\"reset\":true}}", "name": "hifi-home-model-chair", - "compoundShapeURL": "atp:/collision-hulls/simple-chair2.obj", + "compoundShapeURL": "atp:/kineticObjects/simple-chair2.obj", "created": "2016-03-07T21:07:29Z", "dimensions": { "x": 0.66077238321304321, From aead16da8938aada33e99cbc86c2acb9a4b1d007 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 31 Mar 2016 15:10:43 -0700 Subject: [PATCH 58/61] growing flowers faster --- .../DomainContent/Home/createTidyGuy.js | 2 +- .../growingPlant/growingPlantEntityScript.js | 37 +++---- .../Home/growingPlant/waterCanEntityScript.js | 6 +- .../Home/growingPlant/wrapper.js | 34 ++++--- .../DomainContent/Home/reset.js | 99 ++++++++++--------- 5 files changed, 94 insertions(+), 84 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/createTidyGuy.js b/unpublishedScripts/DomainContent/Home/createTidyGuy.js index 968dd85f25..c54e0ef7b2 100644 --- a/unpublishedScripts/DomainContent/Home/createTidyGuy.js +++ b/unpublishedScripts/DomainContent/Home/createTidyGuy.js @@ -32,5 +32,5 @@ function createTidyGuy() { var tidyGuy = createTidyGuy(); Script.scriptEnding.connect(function() { - // Entities.deleteEntity(tidyGuy); + Entities.deleteEntity(tidyGuy); }) \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js index bd9d5d56af..8c60f97722 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js @@ -19,7 +19,6 @@ function GrowingPlant() { _this = this; _this.flowers = []; - // _this.STARTING_FLOWER_DIMENSIONS = {x: 0.1, y: 0.001, z: 0.1} _this.STARTING_FLOWER_DIMENSIONS = { x: 0.001, y: 0.001, @@ -34,9 +33,9 @@ max: 1000 }; _this.canCreateFlower = true; - // _this.SHADER_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/shaders/flower.fs"; - _this.SHADER_URL = "atp:/shaders/flower.fs"; - // _this.SHADER_URL = "file:///C:/Users/Eric/hifi/unpublishedScripts/DomainContent/Home/plant/flower.fs"; + // _this.SHADER_URL = "atp:/shaders/flower.fs"; + // EBL REMOVE ME + _this.SHADER_URL = Script.resolvePath("flower.fs"); _this.flowerHSLColors = [{ hue: 19 / 360, @@ -77,10 +76,10 @@ // Reduces flower overlap return; } - var xzGrowthRate = randFloat(0.00006, 0.00016); + var xzGrowthRate = randFloat(0.0009, 0.0026); var growthRate = { x: xzGrowthRate, - y: randFloat(0.001, 0.003), + y: randFloat(0.01, 0.03), z: xzGrowthRate }; @@ -92,17 +91,7 @@ }, startingPosition: position, rotation: Quat.rotationBetween(Vec3.UNIT_Y, surfaceNormal), - maxYDimension: randFloat(0.4, 1.1), - // startingHSLColor: { - // hue: 80 / 360, - // saturation: 0.47, - // light: 0.48 - // }, - // endingHSLColor: { - // hue: 19 / 260, - // saturation: 0.92, - // light: 0.41 - // }, + maxYDimension: randFloat(0.8, 1.7), hslColor: Math.random() < 0.5 ? _this.flowerHSLColors[0] : _this.flowerHSLColors[1], growthRate: growthRate }; @@ -121,7 +110,7 @@ }; flower.id = Entities.addEntity({ type: "Sphere", - name: "flower", + name: "home-sphere-flower", lifetime: 3600, position: position, collisionless: true, @@ -136,12 +125,6 @@ } flower.dimensions = Vec3.sum(flower.dimensions, flower.growthRate); flower.position = Vec3.sum(flower.startingPosition, Vec3.multiply(Quat.getUp(flower.rotation), flower.dimensions.y / 2)); - //As we grow we must also move ourselves in direction we grow! - //TODO: Add this color changing back once we fix bug https://app.asana.com/0/inbox/31759584831096/96943843100173/98022172055918 - // var newHue = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.hue, flower.endingHSLColor.hue); - // var newSaturation = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.saturation, flower.endingHSLColor.saturation); - // var newLight = map(flower.dimensions.y, _this.STARTING_FLOWER_DIMENSIONS.y, flower.maxYDimension, flower.startingHSLColor.light, flower.endingHSLColor.light); - // flower.userData.PrsoceduralEntity.uniforms.iHSLColor = [newHue, newSaturation, newLight]; Entities.editEntity(flower.id, { dimensions: flower.dimensions, position: flower.position, @@ -155,6 +138,12 @@ _this.entityID = entityID; }, + unload: function() { + _this.flowers.forEach(function(flower) { + Entities.deleteEntity(flower.id); + }); + } + }; // entity scripts always need to return a newly constructed object of our type diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js index a9f7da9bc2..70448c2b9c 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js @@ -91,12 +91,12 @@ return; } // Check rotation of water can along it's z axis. If it's beyond a threshold, then start spraying water - _this.castRay(); var rotation = Entities.getEntityProperties(_this.entityID, "rotation").rotation; var pitch = Quat.safeEulerAngles(rotation).x; if (pitch < _this.POUR_ANGLE_THRESHOLD) { // Water is pouring var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]); + _this.castRay(); if (!_this.waterPouring) { Entities.editEntity(_this.waterEffect, { isEmitting: true @@ -201,7 +201,9 @@ alpha: 1.0, alphaFinish: 1.0, emitterShouldTrail: true, - textures: "atp:/growingPlant/raindrop.png", + // textures: "atp:/growingPlant/raindrop.png", + //EBL REMOVE ME + textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/images/raindrop.png", userData: JSON.stringify({ 'hifiHomeKey': { 'reset': true diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index 8adc05b35c..c6be7e2e4c 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -9,8 +9,14 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var PLANT_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/growingPlantEntityScript.js"); -var WATER_CAN_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/waterCanEntityScript.js"); + +// +// var PLANT_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/growingPlantEntityScript.js"); +// var WATER_CAN_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/waterCanEntityScript.js"); + +//EBL REMOVE ME +var PLANT_SCRIPT_URL = Script.resolvePath("growingPlantEntityScript.js"); +var WATER_CAN_SCRIPT_URL = Script.resolvePath("waterCanEntityScript.js"); Plant = function(spawnPosition, spawnRotation) { print("EBL PLANT CONSTRUCTOR!") var orientation; @@ -21,8 +27,11 @@ Plant = function(spawnPosition, spawnRotation) { } print("EBL ORIENTATION " + JSON.stringify(orientation)); var bowlPosition = spawnPosition; - var BOWL_MODEL_URL = "atp:/growingPlant/Flowers-Bowl.fbx"; + // var BOWL_MODEL_URL = "atp:/growingPlant/Flowers-Bowl.fbx"; var BOWL_COLLISION_HULL_URL = "atp:/growingPlant/bowl.obj"; + +//EBL REMOVE ME + var BOWL_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Bowl.fbx"; var bowlDimensions = { x: 0.518, y: 0.1938, @@ -32,9 +41,9 @@ Plant = function(spawnPosition, spawnRotation) { type: "Model", modelURL: BOWL_MODEL_URL, dimensions: bowlDimensions, - dynamic: true, - shapeType: 'compound', - compundShapeURL: BOWL_COLLISION_HULL_URL, + // dynamic: true, + shapeType: 'box', + // compoundShapeURL: BOWL_COLLISION_HULL_URL, name: "plant bowl", position: bowlPosition, userData: JSON.stringify({ @@ -46,8 +55,9 @@ Plant = function(spawnPosition, spawnRotation) { - var PLANT_MODEL_URL = "atp:/growingPlant/Flowers-Rock.fbx"; - + //var PLANT_MODEL_URL = "atp:/growingPlant/Flowers-Rock.fbx"; + //EBL REMOVE ME + var PLANT_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Moss-Rock.fbx"; var plantDimensions = { x: 0.52, y: 0.2600, @@ -74,14 +84,16 @@ Plant = function(spawnPosition, spawnRotation) { }); - var WATER_CAN_MODEL_URL = "atp:/growingPlant/waterCan.fbx"; + // var WATER_CAN_MODEL_URL = "atp:/growingPlant/waterCan.fbx"; + // EBL REMOVE ME + var WATER_CAN_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/waterCan.fbx?v1" + Math.random(); var WATER_CAN_COLLIISION_HULL_URL = "atp:/growingPlant/can.obj"; var waterCanPosition = Vec3.sum(plantPosition, Vec3.multiply(0.6, Quat.getRight(orientation))); var waterCanRotation = orientation; var waterCan = Entities.addEntity({ type: "Model", - shapeType: 'compound', - compundShapeURL: WATER_CAN_COLLIISION_HULL_URL, + shapeType: 'box', + // compoundShapeURL: WATER_CAN_COLLIISION_HULL_URL, name: "hifi-water-can", modelURL: WATER_CAN_MODEL_URL, script: WATER_CAN_SCRIPT_URL, diff --git a/unpublishedScripts/DomainContent/Home/reset.js b/unpublishedScripts/DomainContent/Home/reset.js index 34292f7083..86c893b266 100644 --- a/unpublishedScripts/DomainContent/Home/reset.js +++ b/unpublishedScripts/DomainContent/Home/reset.js @@ -28,7 +28,11 @@ var whiteboardPath = Script.resolvePath("atp:/whiteboard/wrapper.js"); - var plantPath = Script.resolvePath("atp:/growingPlant/wrapper.js"); + // var plantPath = Script.resolvePath("atp:/growingPlant/wrapper.js"); + + //EBL REMOVE ME + var myPlant; + var plantPath = Script.resolvePath("growingPlant/wrapper.js?v1" + Math.random()); var cuckooClockPath = Script.resolvePath("atp:/cuckooClock/wrapper.js"); @@ -109,16 +113,16 @@ _this.showTidyingButton(); _this.playTidyingSound(); - _this.findAndDeleteHomeEntities(); + // _this.findAndDeleteHomeEntities(); Script.setTimeout(function() { _this.showTidyButton(); _this.tidying = false; }, 2500); Script.setTimeout(function() { - _this.createKineticEntities(); + // _this.createKineticEntities(); _this.createDynamicEntities(); - _this.setupDressingRoom(); + // _this.setupDressingRoom(); }, 750) @@ -138,33 +142,33 @@ }, createDynamicEntities: function() { - var fishTank = new FishTank({ - x: 1099.2200, - y: 460.5460, - z: -78.2363 - }, { - x: 0, - y: 0, - z: 0 - }); + // var fishTank = new FishTank({ + // x: 1099.2200, + // y: 460.5460, + // z: -78.2363 + // }, { + // x: 0, + // y: 0, + // z: 0 + // }); - var tiltMaze = new TiltMaze({ - x: 1105.5768, - y: 460.3298, - z: -80.4891 - }); + // var tiltMaze = new TiltMaze({ + // x: 1105.5768, + // y: 460.3298, + // z: -80.4891 + // }); - var whiteboard = new Whiteboard({ - x: 1104, - y: 460.5, - z: -77 - }, { - x: 0, - y: -133, - z: 0 - }); + // var whiteboard = new Whiteboard({ + // x: 1104, + // y: 460.5, + // z: -77 + // }, { + // x: 0, + // y: -133, + // z: 0 + // }); - var myPlant = new Plant({ + myPlant = new Plant({ x: 1099.8785, y: 460.3115, z: -84.7736 @@ -174,24 +178,24 @@ z: 0 }); - var pingPongGun = new HomePingPongGun({ - x: 1101.2123, - y: 460.2328, - z: -65.8513 - }, { - x: 97.3683, - y: 179.0293, - z: 89.9698 - }); - var cuckooClock = new MyCuckooClock({ - x: 1105.267, - y: 461.44, - z: -81.9495 - }, { - x: 0, - y: -57, - z: 0 - }); + // var pingPongGun = new HomePingPongGun({ + // x: 1101.2123, + // y: 460.2328, + // z: -65.8513 + // }, { + // x: 97.3683, + // y: 179.0293, + // z: 89.9698 + // }); + // var cuckooClock = new MyCuckooClock({ + // x: 1105.267, + // y: 461.44, + // z: -81.9495 + // }, { + // x: 0, + // y: -57, + // z: 0 + // }); //v2.0 // var musicBox = new MusicBox(); @@ -457,6 +461,9 @@ unload: function() { // this.findAndDeleteHomeEntities(); + //REMOVE ME + myPlant.cleanup(); + } } From 50e1a11f6c00c3cbc91016255d900936afcf0063 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 31 Mar 2016 15:16:57 -0700 Subject: [PATCH 59/61] change flower name --- .../Home/growingPlant/waterCanEntityScript.js | 16 +--------------- .../DomainContent/Home/growingPlant/wrapper.js | 9 +++++---- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js index 70448c2b9c..200c2df6df 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js @@ -21,7 +21,7 @@ _this.waterSound = SoundCache.getSound("atp:/growingPlant/watering_can_pour.L.wav"); _this.POUR_ANGLE_THRESHOLD = 0; _this.waterPouring = false; - _this.WATER_SPOUT_NAME = "hifi-water-spout"; + _this.WATER_SPOUT_NAME = "home_box_waterSpout"; _this.GROWABLE_ENTITIES_SEARCH_RANGE = 100; }; @@ -229,20 +229,6 @@ print("EBL PRELOADING WATER CAN") _this.entityID = entityID; _this.position = Entities.getEntityProperties(_this.entityID, "position").position; - // Wait a a bit for spout to spawn for case where preload is initial spawn, then save it - Script.setTimeout(function() { - var entities = Entities.findEntities(_this.position, 2); - print("EBL SEARCHING FOR SPOUT"); - entities.forEach(function(entity) { - var name = Entities.getEntityProperties(entity, "name").name; - if (name === _this.WATER_SPOUT_NAME) { - print("EBL FOUND SPOUT"); - _this.waterSpout = entity; - } - }); - - }, 2000); - }, diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index c6be7e2e4c..840dd3b2e4 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -44,7 +44,7 @@ Plant = function(spawnPosition, spawnRotation) { // dynamic: true, shapeType: 'box', // compoundShapeURL: BOWL_COLLISION_HULL_URL, - name: "plant bowl", + name: "home_model_plantNowl", position: bowlPosition, userData: JSON.stringify({ 'hifiHomeKey': { @@ -71,7 +71,7 @@ Plant = function(spawnPosition, spawnRotation) { var plant = Entities.addEntity({ type: "Model", modelURL: PLANT_MODEL_URL, - name: "hifi-growable-plant", + name: "home_model_growablePlant", dimensions: plantDimensions, position: plantPosition, script: PLANT_SCRIPT_URL, @@ -94,7 +94,7 @@ Plant = function(spawnPosition, spawnRotation) { type: "Model", shapeType: 'box', // compoundShapeURL: WATER_CAN_COLLIISION_HULL_URL, - name: "hifi-water-can", + name: "home_model_waterCan", modelURL: WATER_CAN_MODEL_URL, script: WATER_CAN_SCRIPT_URL, dimensions: { @@ -151,9 +151,10 @@ Plant = function(spawnPosition, spawnRotation) { var waterSpoutPosition = Vec3.sum(waterCanPosition, Vec3.multiply(0.2, Quat.getFront(orientation))) var waterSpoutRotation = Quat.multiply(waterCanRotation, Quat.fromPitchYawRollDegrees(10, 0, 0)); + var WATER_SPOUT_NAME = "home_box_waterSpout"; var waterSpout = Entities.addEntity({ type: "Box", - name: "hifi-water-spout", + name: WATER_SPOUT_NAME, dimensions: { x: 0.02, y: 0.02, From 724d403fc7b57cbffa3986d64107f54b551ba98c Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 31 Mar 2016 16:08:06 -0700 Subject: [PATCH 60/61] behavior as expected --- .../Home/growingPlant/waterCanEntityScript.js | 71 +++++++++++-------- .../Home/growingPlant/wrapper.js | 2 +- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js index 200c2df6df..93ea4a33cc 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js @@ -19,7 +19,7 @@ function WaterSpout() { _this = this; _this.waterSound = SoundCache.getSound("atp:/growingPlant/watering_can_pour.L.wav"); - _this.POUR_ANGLE_THRESHOLD = 0; + _this.POUR_ANGLE_THRESHOLD = -0.1; _this.waterPouring = false; _this.WATER_SPOUT_NAME = "home_box_waterSpout"; _this.GROWABLE_ENTITIES_SEARCH_RANGE = 100; @@ -37,6 +37,7 @@ }, startHold: function() { + print("EBL START HOLD") var entities = Entities.findEntities(_this.position, 2); print("EBL SEARCHING FOR SPOUT"); entities.forEach(function(entity) { @@ -62,22 +63,12 @@ releaseHold: function() { _this.stopPouring(); + var waterEffectToDelete = _this.waterEffect; Script.setTimeout(function() { - Entities.deleteEntity(_this.waterEffect); + Entities.deleteEntity(waterEffectToDelete); }, 2000); }, - stopPouring: function() { - Entities.editEntity(_this.waterEffect, { - isEmitting: false - }); - _this.waterPouring = false; - //water no longer pouring... - if (_this.waterInjector) { - _this.waterInjector.stop(); - } - Entities.callEntityMethod(_this.mostRecentIntersectedGrowableEntity, 'stopWatering'); - }, continueEquip: function() { _this.continueHolding(); }, @@ -92,36 +83,58 @@ } // Check rotation of water can along it's z axis. If it's beyond a threshold, then start spraying water var rotation = Entities.getEntityProperties(_this.entityID, "rotation").rotation; - var pitch = Quat.safeEulerAngles(rotation).x; - if (pitch < _this.POUR_ANGLE_THRESHOLD) { + var forwardVec = Quat.getFront(rotation); + if (forwardVec.y < _this.POUR_ANGLE_THRESHOLD) { // Water is pouring var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]); _this.castRay(); if (!_this.waterPouring) { - Entities.editEntity(_this.waterEffect, { - isEmitting: true - }); - _this.waterPouring = true; - if (!_this.waterInjector) { - _this.waterInjector = Audio.playSound(_this.waterSound, { - position: spoutProps.position, - loop: true - }); - - } else { - _this.waterInjector.restart(); - } + _this.startPouring(); } _this.waterSpoutRotation = spoutProps.rotation; var waterEmitOrientation = Quat.multiply(_this.waterSpoutRotation, Quat.fromPitchYawRollDegrees(0, 180, 0)); Entities.editEntity(_this.waterEffect, { emitOrientation: waterEmitOrientation }); - } else if (pitch > _this.POUR_ANGLE_THRESHOLD && _this.waterPouring) { + } else if (forwardVec.y > _this.POUR_ANGLE_THRESHOLD && _this.waterPouring) { _this.stopPouring(); } }, + + stopPouring: function() { + print("EBL STOP POURING") + Entities.editEntity(_this.waterEffect, { + isEmitting: false + }); + _this.waterPouring = false; + //water no longer pouring... + if (_this.waterInjector) { + _this.waterInjector.stop(); + } + Entities.callEntityMethod(_this.mostRecentIntersectedGrowableEntity, 'stopWatering'); + }, + + startPouring: function() { + print("EBL START POURING") + Script.setTimeout(function() { + Entities.editEntity(_this.waterEffect, { + isEmitting: true + }); + }, 100); + _this.waterPouring = true; + if (!_this.waterInjector) { + _this.waterInjector = Audio.playSound(_this.waterSound, { + position: spoutProps.position, + loop: true + }); + + } else { + _this.waterInjector.restart(); + } + + }, + castRay: function() { var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["position, rotation"]); var direction = Quat.getFront(spoutProps.rotation) diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index 840dd3b2e4..0a4d97103b 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -149,7 +149,7 @@ Plant = function(spawnPosition, spawnRotation) { }); - var waterSpoutPosition = Vec3.sum(waterCanPosition, Vec3.multiply(0.2, Quat.getFront(orientation))) + var waterSpoutPosition = Vec3.sum(waterCanPosition, Vec3.multiply(0.21, Quat.getFront(orientation))) var waterSpoutRotation = Quat.multiply(waterCanRotation, Quat.fromPitchYawRollDegrees(10, 0, 0)); var WATER_SPOUT_NAME = "home_box_waterSpout"; var waterSpout = Entities.addEntity({ From 9ff4540697a9a5ca40fc7bbcb1d2ddd7ad08d33e Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 31 Mar 2016 16:45:12 -0700 Subject: [PATCH 61/61] growing plant fixes --- .../growingPlant/growingPlantEntityScript.js | 4 +- .../Home/growingPlant/waterCanEntityScript.js | 10 +- .../Home/growingPlant/wrapper.js | 30 ++---- .../DomainContent/Home/reset.js | 97 +++++++++---------- 4 files changed, 62 insertions(+), 79 deletions(-) diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js index 8c60f97722..7c3d89d585 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/growingPlantEntityScript.js @@ -33,9 +33,7 @@ max: 1000 }; _this.canCreateFlower = true; - // _this.SHADER_URL = "atp:/shaders/flower.fs"; - // EBL REMOVE ME - _this.SHADER_URL = Script.resolvePath("flower.fs"); + _this.SHADER_URL = "atp:/shaders/flower.fs"; _this.flowerHSLColors = [{ hue: 19 / 360, diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js index 93ea4a33cc..972b7f2d77 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/waterCanEntityScript.js @@ -86,12 +86,12 @@ var forwardVec = Quat.getFront(rotation); if (forwardVec.y < _this.POUR_ANGLE_THRESHOLD) { // Water is pouring - var spoutProps = Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]); + _this.spoutProps= Entities.getEntityProperties(_this.waterSpout, ["rotation", "position"]); _this.castRay(); if (!_this.waterPouring) { _this.startPouring(); } - _this.waterSpoutRotation = spoutProps.rotation; + _this.waterSpoutRotation = _this.spoutProps.rotation; var waterEmitOrientation = Quat.multiply(_this.waterSpoutRotation, Quat.fromPitchYawRollDegrees(0, 180, 0)); Entities.editEntity(_this.waterEffect, { emitOrientation: waterEmitOrientation @@ -125,7 +125,7 @@ _this.waterPouring = true; if (!_this.waterInjector) { _this.waterInjector = Audio.playSound(_this.waterSound, { - position: spoutProps.position, + position: _this.spoutProps.position, loop: true }); @@ -214,9 +214,7 @@ alpha: 1.0, alphaFinish: 1.0, emitterShouldTrail: true, - // textures: "atp:/growingPlant/raindrop.png", - //EBL REMOVE ME - textures: "https://s3-us-west-1.amazonaws.com/hifi-content/eric/images/raindrop.png", + textures: "atp:/growingPlant/raindrop.png", userData: JSON.stringify({ 'hifiHomeKey': { 'reset': true diff --git a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js index 0a4d97103b..31f46eb43f 100644 --- a/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js +++ b/unpublishedScripts/DomainContent/Home/growingPlant/wrapper.js @@ -11,12 +11,9 @@ // // -// var PLANT_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/growingPlantEntityScript.js"); -// var WATER_CAN_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/waterCanEntityScript.js"); +var PLANT_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/growingPlantEntityScript.js"); +var WATER_CAN_SCRIPT_URL = Script.resolvePath("atp:/growingPlant/waterCanEntityScript.js"); -//EBL REMOVE ME -var PLANT_SCRIPT_URL = Script.resolvePath("growingPlantEntityScript.js"); -var WATER_CAN_SCRIPT_URL = Script.resolvePath("waterCanEntityScript.js"); Plant = function(spawnPosition, spawnRotation) { print("EBL PLANT CONSTRUCTOR!") var orientation; @@ -27,11 +24,8 @@ Plant = function(spawnPosition, spawnRotation) { } print("EBL ORIENTATION " + JSON.stringify(orientation)); var bowlPosition = spawnPosition; - // var BOWL_MODEL_URL = "atp:/growingPlant/Flowers-Bowl.fbx"; - var BOWL_COLLISION_HULL_URL = "atp:/growingPlant/bowl.obj"; + var BOWL_MODEL_URL = "atp:/growingPlant/Flowers-Bowl.fbx"; -//EBL REMOVE ME - var BOWL_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Bowl.fbx"; var bowlDimensions = { x: 0.518, y: 0.1938, @@ -41,9 +35,9 @@ Plant = function(spawnPosition, spawnRotation) { type: "Model", modelURL: BOWL_MODEL_URL, dimensions: bowlDimensions, - // dynamic: true, - shapeType: 'box', - // compoundShapeURL: BOWL_COLLISION_HULL_URL, + dynamic: true, + shapeType: 'compound', + compoundShapeURL: BOWL_COLLISION_HULL_URL, name: "home_model_plantNowl", position: bowlPosition, userData: JSON.stringify({ @@ -55,9 +49,7 @@ Plant = function(spawnPosition, spawnRotation) { - //var PLANT_MODEL_URL = "atp:/growingPlant/Flowers-Rock.fbx"; - //EBL REMOVE ME - var PLANT_MODEL_URL = "http://hifi-content.s3.amazonaws.com/alan/dev/Flowers--Moss-Rock.fbx"; + var PLANT_MODEL_URL = "atp:/growingPlant/Flowers-Rock.fbx"; var plantDimensions = { x: 0.52, y: 0.2600, @@ -84,16 +76,14 @@ Plant = function(spawnPosition, spawnRotation) { }); - // var WATER_CAN_MODEL_URL = "atp:/growingPlant/waterCan.fbx"; - // EBL REMOVE ME - var WATER_CAN_MODEL_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/waterCan.fbx?v1" + Math.random(); + var WATER_CAN_MODEL_URL = "atp:/growingPlant/waterCan.fbx"; var WATER_CAN_COLLIISION_HULL_URL = "atp:/growingPlant/can.obj"; var waterCanPosition = Vec3.sum(plantPosition, Vec3.multiply(0.6, Quat.getRight(orientation))); var waterCanRotation = orientation; var waterCan = Entities.addEntity({ type: "Model", - shapeType: 'box', - // compoundShapeURL: WATER_CAN_COLLIISION_HULL_URL, + shapeType: 'compound', + compoundShapeURL: WATER_CAN_COLLIISION_HULL_URL, name: "home_model_waterCan", modelURL: WATER_CAN_MODEL_URL, script: WATER_CAN_SCRIPT_URL, diff --git a/unpublishedScripts/DomainContent/Home/reset.js b/unpublishedScripts/DomainContent/Home/reset.js index 86c893b266..7362932f99 100644 --- a/unpublishedScripts/DomainContent/Home/reset.js +++ b/unpublishedScripts/DomainContent/Home/reset.js @@ -28,11 +28,10 @@ var whiteboardPath = Script.resolvePath("atp:/whiteboard/wrapper.js"); - // var plantPath = Script.resolvePath("atp:/growingPlant/wrapper.js"); + var plantPath = Script.resolvePath("atp:/growingPlant/wrapper.js"); //EBL REMOVE ME var myPlant; - var plantPath = Script.resolvePath("growingPlant/wrapper.js?v1" + Math.random()); var cuckooClockPath = Script.resolvePath("atp:/cuckooClock/wrapper.js"); @@ -113,16 +112,16 @@ _this.showTidyingButton(); _this.playTidyingSound(); - // _this.findAndDeleteHomeEntities(); + _this.findAndDeleteHomeEntities(); Script.setTimeout(function() { _this.showTidyButton(); _this.tidying = false; }, 2500); Script.setTimeout(function() { - // _this.createKineticEntities(); + _this.createKineticEntities(); _this.createDynamicEntities(); - // _this.setupDressingRoom(); + _this.setupDressingRoom(); }, 750) @@ -142,31 +141,31 @@ }, createDynamicEntities: function() { - // var fishTank = new FishTank({ - // x: 1099.2200, - // y: 460.5460, - // z: -78.2363 - // }, { - // x: 0, - // y: 0, - // z: 0 - // }); + var fishTank = new FishTank({ + x: 1099.2200, + y: 460.5460, + z: -78.2363 + }, { + x: 0, + y: 0, + z: 0 + }); - // var tiltMaze = new TiltMaze({ - // x: 1105.5768, - // y: 460.3298, - // z: -80.4891 - // }); + var tiltMaze = new TiltMaze({ + x: 1105.5768, + y: 460.3298, + z: -80.4891 + }); - // var whiteboard = new Whiteboard({ - // x: 1104, - // y: 460.5, - // z: -77 - // }, { - // x: 0, - // y: -133, - // z: 0 - // }); + var whiteboard = new Whiteboard({ + x: 1104, + y: 460.5, + z: -77 + }, { + x: 0, + y: -133, + z: 0 + }); myPlant = new Plant({ x: 1099.8785, @@ -178,26 +177,26 @@ z: 0 }); - // var pingPongGun = new HomePingPongGun({ - // x: 1101.2123, - // y: 460.2328, - // z: -65.8513 - // }, { - // x: 97.3683, - // y: 179.0293, - // z: 89.9698 - // }); - // var cuckooClock = new MyCuckooClock({ - // x: 1105.267, - // y: 461.44, - // z: -81.9495 - // }, { - // x: 0, - // y: -57, - // z: 0 - // }); + var pingPongGun = new HomePingPongGun({ + x: 1101.2123, + y: 460.2328, + z: -65.8513 + }, { + x: 97.3683, + y: 179.0293, + z: 89.9698 + }); + var cuckooClock = new MyCuckooClock({ + x: 1105.267, + y: 461.44, + z: -81.9495 + }, { + x: 0, + y: -57, + z: 0 + }); - //v2.0 + // v2.0 // var musicBox = new MusicBox(); // var doppelganger = new Doppelganger(); @@ -460,9 +459,7 @@ }, unload: function() { - // this.findAndDeleteHomeEntities(); - //REMOVE ME - myPlant.cleanup(); + this.findAndDeleteHomeEntities(); }