From 468281f92dbeab9b427751dde29963fb7d728d6d Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 29 Sep 2016 06:58:14 -0700 Subject: [PATCH 01/13] Fix the Debug build of Interface on Windows --- cmake/macros/PackageLibrariesForDeployment.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/macros/PackageLibrariesForDeployment.cmake b/cmake/macros/PackageLibrariesForDeployment.cmake index 7f826c1f8c..da0ee35769 100644 --- a/cmake/macros/PackageLibrariesForDeployment.cmake +++ b/cmake/macros/PackageLibrariesForDeployment.cmake @@ -49,6 +49,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT) TARGET ${TARGET_NAME} POST_BUILD COMMAND if exist ${QTAUDIO_PATH}/qtaudio_windows.dll ( ${CMAKE_COMMAND} -E remove ${QTAUDIO_PATH}/qtaudio_windows.dll && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapi.dll ${QTAUDIO_PATH} && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapi.pdb ${QTAUDIO_PATH} ) + COMMAND if exist ${QTAUDIO_PATH}/qtaudio_windowsd.dll ( ${CMAKE_COMMAND} -E remove ${QTAUDIO_PATH}/qtaudio_windowsd.dll && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapid.dll ${QTAUDIO_PATH} && ${CMAKE_COMMAND} -E copy ${WASAPI_DLL_PATH}/qtaudio_wasapid.pdb ${QTAUDIO_PATH} ) ) endif () From f42c0dbd7c51a18ddd3e7ad43b3319e156c683ad Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 29 Sep 2016 13:01:15 -0700 Subject: [PATCH 02/13] Fix cmake checksum, for updated qtaudio_wasapi.zip with release and debug plugins --- cmake/externals/wasapi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt index 019920df77..1cb63531b8 100644 --- a/cmake/externals/wasapi/CMakeLists.txt +++ b/cmake/externals/wasapi/CMakeLists.txt @@ -7,7 +7,7 @@ if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi.zip - URL_MD5 11c8a7728d6eda7223df800e10b70723 + URL_MD5 272b27bd6c211c45c0c23d4701b63b5e CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" From d925a22fd4769d16ac00cef169760f3a5cefb9cf Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 29 Sep 2016 14:09:38 -0700 Subject: [PATCH 03/13] Use new filename for the external as a simple form of versioning --- cmake/externals/wasapi/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/wasapi/CMakeLists.txt b/cmake/externals/wasapi/CMakeLists.txt index 1cb63531b8..8ec327600f 100644 --- a/cmake/externals/wasapi/CMakeLists.txt +++ b/cmake/externals/wasapi/CMakeLists.txt @@ -6,7 +6,7 @@ if (WIN32) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi.zip + URL http://hifi-public.s3.amazonaws.com/dependencies/qtaudio_wasapi2.zip URL_MD5 272b27bd6c211c45c0c23d4701b63b5e CONFIGURE_COMMAND "" BUILD_COMMAND "" From 42e28fa010a4dd4615e430b3aa1e4a51000e9f23 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 30 Sep 2016 15:48:10 -0700 Subject: [PATCH 04/13] Fix crash in initializing texture transfer thread --- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 13 ++++++++++++- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 75af08d9a3..45403f4d4d 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -18,7 +18,6 @@ std::unordered_map _map; #endif -//#define TEXTURE_TRANSFER_PBOS #ifdef TEXTURE_TRANSFER_PBOS #define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024) @@ -62,11 +61,16 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture void GLTextureTransferHelper::setup() { #ifdef THREADED_TEXTURE_TRANSFER _context.makeCurrent(); + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + // FIXME don't use opengl 4.5 DSA functionality without verifying it's present glCreateRenderbuffers(1, &_drawRenderbuffer); glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128); glCreateFramebuffers(1, &_drawFramebuffer); glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer); glCreateFramebuffers(1, &_readFramebuffer); +#endif + #ifdef TEXTURE_TRANSFER_PBOS std::array pbos; glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]); @@ -84,7 +88,9 @@ void GLTextureTransferHelper::setup() { void GLTextureTransferHelper::shutdown() { #ifdef THREADED_TEXTURE_TRANSFER _context.makeCurrent(); +#endif +#ifdef TEXTURE_TRANSFER_FORCE_DRAW glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0); glDeleteFramebuffers(1, &_drawFramebuffer); _drawFramebuffer = 0; @@ -165,6 +171,11 @@ bool GLTextureTransferHelper::process() { } gltexture->finishTransfer(); + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW + // FIXME force a draw on the texture transfer thread before passing the texture to the main thread for use +#endif + #ifdef THREADED_TEXTURE_TRANSFER clientWait(); #endif diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h index 289aec40bb..a23c282fd4 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -21,6 +21,14 @@ #define THREADED_TEXTURE_TRANSFER #endif +#ifdef THREADED_TEXTURE_TRANSFER +// FIXME when sparse textures are enabled, it's harder to force a draw on the transfer thread +// also, the current draw code is implicitly using OpenGL 4.5 functionality +//#define TEXTURE_TRANSFER_FORCE_DRAW +// FIXME PBO's increase the complexity and don't seem to work reliably +//#define TEXTURE_TRANSFER_PBOS +#endif + namespace gpu { namespace gl { using TextureList = std::list; @@ -43,11 +51,15 @@ public: private: #ifdef THREADED_TEXTURE_TRANSFER ::gl::OffscreenContext _context; +#endif + +#ifdef TEXTURE_TRANSFER_FORCE_DRAW // Framebuffers / renderbuffers for forcing access to the texture on the transfer thread GLuint _drawRenderbuffer { 0 }; GLuint _drawFramebuffer { 0 }; GLuint _readFramebuffer { 0 }; #endif + // A mutex for protecting items access on the render and transfer threads Mutex _mutex; // Commands that have been submitted for execution on the texture transfer thread From c806f6cad2166518466eb30cb0b9089cfa067cc8 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 30 Sep 2016 16:05:39 -0700 Subject: [PATCH 05/13] better shutdown check for timer firings --- libraries/script-engine/src/ScriptEngine.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e4d1cd7307..160ad77197 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -1017,9 +1017,12 @@ void ScriptEngine::updateMemoryCost(const qint64& deltaSize) { } void ScriptEngine::timerFired() { - if (DependencyManager::get()->isStopped()) { - qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename(); - return; // bail early + { + auto engine = DependencyManager::get(); + if (!engine || engine->isStopped()) { + qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename(); + return; // bail early + } } QTimer* callingTimer = reinterpret_cast(sender()); From 0f06d0e4cc9f974fe4ec90d80a65cd0fb86283e2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 1 Oct 2016 10:40:31 -0700 Subject: [PATCH 06/13] Don't use GL functions before making the context current --- libraries/gl/src/gl/GLWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index f2b823a65e..23bdcff640 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -67,8 +67,8 @@ void GLWidget::createContext() { _context = new gl::Context(); _context->setWindow(windowHandle()); _context->create(); - _context->clear(); _context->makeCurrent(); + _context->clear(); } bool GLWidget::makeCurrent() { From 2cba3db2b6471d9e9b3adb5f9b3d5dfa4c15365b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 30 Sep 2016 17:43:26 -0700 Subject: [PATCH 07/13] fix crash when bouncing to escotology, which may or may not be related --- .../src/model-networking/ModelCache.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 306a19c308..6eacbab46a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -377,8 +377,10 @@ void GeometryResource::deleter() { } void GeometryResource::setTextures() { - for (const FBXMaterial& material : _fbxGeometry->materials) { - _materials.push_back(std::make_shared(material, _textureBaseUrl)); + if (_fbxGeometry) { + for (const FBXMaterial& material : _fbxGeometry->materials) { + _materials.push_back(std::make_shared(material, _textureBaseUrl)); + } } } @@ -457,7 +459,9 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, c _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); - map->setTextureSource(texture->_textureSource); + if (texture) { + map->setTextureSource(texture->_textureSource); + } map->setTextureTransform(fbxTexture.transform); return map; From 265996156c5376c6c9846ea65ac4d81b7f1ca0e9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 27 Sep 2016 11:44:51 -0700 Subject: [PATCH 08/13] Remove unused header and typedef --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index ef15861843..74f8cdbc10 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -8,6 +8,7 @@ #pragma once #include "DisplayPlugin.h" +#include #include #include @@ -18,7 +19,6 @@ #include #include -#include #include namespace gpu { @@ -35,7 +35,6 @@ protected: using Mutex = std::mutex; using Lock = std::unique_lock; using Condition = std::condition_variable; - using TextureEscrow = GLEscrow; public: // These must be final to ensure proper ordering of operations // between the main thread and the presentation thread From 933388bc61c136312f4bd31fa655b0813fc5361b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 27 Sep 2016 11:45:35 -0700 Subject: [PATCH 09/13] Remove oglplus usage from offscreen UI --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 194 +++++++++++++++----- 1 file changed, 143 insertions(+), 51 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index bdfa359b8b..d1c884f264 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -6,7 +6,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OffscreenQmlSurface.h" -#include "OglplusHelpers.h" +#include "Config.h" + +#include +#include +#include #include #include @@ -116,6 +120,108 @@ static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2); static const QEvent::Type RESIZE = QEvent::Type(QEvent::User + 3); static const QEvent::Type STOP = QEvent::Type(QEvent::User + 4); +class RawTextureRecycler { +public: + using TexturePtr = GLuint; + RawTextureRecycler(bool useMipmaps) : _useMipmaps(useMipmaps) {} + void setSize(const uvec2& size); + void clear(); + TexturePtr getNextTexture(); + void recycleTexture(GLuint texture); + +private: + + struct TexInfo { + TexturePtr _tex { 0 }; + uvec2 _size; + bool _active { false }; + + TexInfo() {} + TexInfo(TexturePtr tex, const uvec2& size) : _tex(tex), _size(size) {} + }; + + using Map = std::map; + using Queue = std::queue; + + Map _allTextures; + Queue _readyTextures; + uvec2 _size { 1920, 1080 }; + bool _useMipmaps; +}; + + +void RawTextureRecycler::setSize(const uvec2& size) { + if (size == _size) { + return; + } + _size = size; + while (!_readyTextures.empty()) { + _readyTextures.pop(); + } + std::set toDelete; + std::for_each(_allTextures.begin(), _allTextures.end(), [&](Map::const_reference item) { + if (!item.second._active && item.second._size != _size) { + toDelete.insert(item.first); + } + }); + std::for_each(toDelete.begin(), toDelete.end(), [&](Map::key_type key) { + _allTextures.erase(key); + }); +} + +void RawTextureRecycler::clear() { + while (!_readyTextures.empty()) { + _readyTextures.pop(); + } + _allTextures.clear(); +} + +RawTextureRecycler::TexturePtr RawTextureRecycler::getNextTexture() { + if (_readyTextures.empty()) { + TexturePtr newTexture; + glGenTextures(1, &newTexture); + + glBindTexture(GL_TEXTURE_2D, newTexture); + if (_useMipmaps) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.2f); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _size.x, _size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + _allTextures[newTexture] = TexInfo { newTexture, _size }; + _readyTextures.push(newTexture); + } + + TexturePtr result = _readyTextures.front(); + _readyTextures.pop(); + auto& item = _allTextures[result]; + item._active = true; + return result; +} + +void RawTextureRecycler::recycleTexture(GLuint texture) { + Q_ASSERT(_allTextures.count(texture)); + auto& item = _allTextures[texture]; + Q_ASSERT(item._active); + item._active = false; + if (item._size != _size) { + // Buh-bye + _allTextures.erase(texture); + return; + } + + _readyTextures.push(item._tex); +} + + class OffscreenQmlRenderThread : public QThread { public: OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext); @@ -165,9 +271,9 @@ private: OffscreenQmlSurface* _surface{ nullptr }; QQuickWindow* _quickWindow{ nullptr }; QMyQuickRenderControl* _renderControl{ nullptr }; - FramebufferPtr _fbo; - RenderbufferPtr _depthStencil; - TextureRecycler _textures { true }; + GLuint _fbo { 0 }; + GLuint _depthStencil { 0 }; + RawTextureRecycler _textures { true }; GLTextureEscrow _escrow; uint64_t _lastRenderTime{ 0 }; @@ -253,24 +359,23 @@ bool OffscreenQmlRenderThread::event(QEvent *e) { } void OffscreenQmlRenderThread::setupFbo() { - using namespace oglplus; _textures.setSize(_size); - - 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(); + if (_depthStencil) { + glDeleteRenderbuffers(1, &_depthStencil); + _depthStencil = 0; } + glGenRenderbuffers(1, &_depthStencil); + glBindRenderbuffer(GL_RENDERBUFFER, _depthStencil); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _size.x, _size.y); + + if (_fbo) { + glDeleteFramebuffers(1, &_fbo); + _fbo = 0; + } + glGenFramebuffers(1, &_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } QJsonObject OffscreenQmlRenderThread::getGLContextData() { @@ -309,8 +414,15 @@ void OffscreenQmlRenderThread::init() { void OffscreenQmlRenderThread::cleanup() { _renderControl->invalidate(); - _fbo.reset(); - _depthStencil.reset(); + if (_depthStencil) { + glDeleteRenderbuffers(1, &_depthStencil); + _depthStencil = 0; + } + if (_fbo) { + glDeleteFramebuffers(1, &_fbo); + _fbo = 0; + } + _textures.clear(); _canvas.doneCurrent(); @@ -371,42 +483,22 @@ void OffscreenQmlRenderThread::render() { releaseMainThread.trigger(); } - using namespace oglplus; - - _quickWindow->setRenderTarget(GetName(*_fbo), QSize(_size.x, _size.y)); + _quickWindow->setRenderTarget(_fbo, QSize(_size.x, _size.y)); try { - PROFILE_RANGE("qml_render") - - 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; - } - - { + GLuint texture = _textures.getNextTexture(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo); + glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); PROFILE_RANGE("qml_render->rendercontrol") _renderControl->render(); - // FIXME The web browsers seem to be leaving GL in an error state. - // Need a debug context with sync logging to figure out why. - // for now just clear the errors - glGetError(); - } - Context::Bound(oglplus::Texture::Target::_2D, *texture).GenerateMipmap(); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, texture); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); - // FIXME probably unecessary - DefaultFramebuffer().Bind(Framebuffer::Target::Draw); _quickWindow->resetOpenGLState(); - _escrow.submit(GetName(*texture)); + _escrow.submit(texture); _lastRenderTime = usecTimestampNow(); } catch (std::runtime_error& error) { qWarning() << "Failed to render QML: " << error.what(); From 04f654794069b451039f04bd139af994758e0103 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 1 Oct 2016 12:15:03 -0700 Subject: [PATCH 10/13] add guards to getShapeKey --- libraries/render-utils/src/MeshPartPayload.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 50c0c869ff..2644bc6096 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -429,7 +429,12 @@ ItemKey ModelMeshPartPayload::getKey() const { } ShapeKey ModelMeshPartPayload::getShapeKey() const { - assert(_model->isLoaded()); + + // guard against partially loaded meshes + if (!_model || !_model->isLoaded() || !_model->getGeometry()) { + return ShapeKey::Builder::invalid(); + } + const FBXGeometry& geometry = _model->getFBXGeometry(); const auto& networkMeshes = _model->getGeometry()->getMeshes(); From a79485f8c2bf84f0140b479959ffea2362a72b88 Mon Sep 17 00:00:00 2001 From: Anthony Thibault Date: Sat, 1 Oct 2016 13:37:42 -0700 Subject: [PATCH 11/13] Fix for crash bug in web entities Guard against nullptrs in RenderableWebEntitItem and WebEntityAPIHelper. These pointers can go null if the webEntity is deleted on the main thread. Also, the backing offscreen qml surface can be destroyed if the webEntity has not been rendered for 30 seconds due to frustum culling. --- .../src/RenderableWebEntityItem.cpp | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 1c177cffc4..86bce87ba2 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -58,9 +58,13 @@ void WebEntityAPIHelper::emitWebEvent(const QVariant& message) { } else { // special case to handle raising and lowering the virtual keyboard if (message.type() == QVariant::String && message.toString() == "_RAISE_KEYBOARD" && _renderableWebEntityItem) { - _renderableWebEntityItem->setKeyboardRaised(true); + if (_renderableWebEntityItem) { + _renderableWebEntityItem->setKeyboardRaised(true); + } } else if (message.type() == QVariant::String && message.toString() == "_LOWER_KEYBOARD" && _renderableWebEntityItem) { - _renderableWebEntityItem->setKeyboardRaised(false); + if (_renderableWebEntityItem) { + _renderableWebEntityItem->setKeyboardRaised(false); + } } else { emit webEventReceived(message); } @@ -343,7 +347,7 @@ void RenderableWebEntityItem::destroyWebSurface() { // The lifetime of the QML surface MUST be managed by the main thread // Additionally, we MUST use local variables copied by value, rather than - // member variables, since they would implicitly refer to a this that + // member variables, since they would implicitly refer to a this that // is no longer valid auto webSurface = _webSurface; AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] { @@ -388,35 +392,40 @@ static bool equals(const QByteArray& byteArray, const uint8_t* ptr) { } void RenderableWebEntityItem::synthesizeKeyPress(QString key) { - auto utf8Key = key.toUtf8(); + auto eventHandler = getEventHandler(); + if (eventHandler) { + auto utf8Key = key.toUtf8(); - int scanCode = (int)utf8Key[0]; - QString keyString = key; - if (equals(utf8Key, UPWARDS_WHITE_ARROW_FROM_BAR) || equals(utf8Key, ASTERISIM) || - equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) { - return; // ignore - } else if (equals(utf8Key, LEFT_ARROW)) { - scanCode = Qt::Key_Backspace; - keyString = "\x08"; - } else if (equals(utf8Key, RETURN_SYMBOL)) { - scanCode = Qt::Key_Return; - keyString = "\x0d"; - } else if (equals(utf8Key, LEFTWARD_WHITE_ARROW)) { - scanCode = Qt::Key_Left; - keyString = ""; - } else if (equals(utf8Key, RIGHTWARD_WHITE_ARROW)) { - scanCode = Qt::Key_Right; - keyString = ""; + int scanCode = (int)utf8Key[0]; + QString keyString = key; + if (equals(utf8Key, UPWARDS_WHITE_ARROW_FROM_BAR) || equals(utf8Key, ASTERISIM) || + equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) { + return; // ignore + } else if (equals(utf8Key, LEFT_ARROW)) { + scanCode = Qt::Key_Backspace; + keyString = "\x08"; + } else if (equals(utf8Key, RETURN_SYMBOL)) { + scanCode = Qt::Key_Return; + keyString = "\x0d"; + } else if (equals(utf8Key, LEFTWARD_WHITE_ARROW)) { + scanCode = Qt::Key_Left; + keyString = ""; + } else if (equals(utf8Key, RIGHTWARD_WHITE_ARROW)) { + scanCode = Qt::Key_Right; + keyString = ""; + } + + QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, scanCode, Qt::NoModifier, keyString); + QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, scanCode, Qt::NoModifier, keyString); + QCoreApplication::postEvent(eventHandler, pressEvent); + QCoreApplication::postEvent(eventHandler, releaseEvent); } - - QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, scanCode, Qt::NoModifier, keyString); - QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, scanCode, Qt::NoModifier, keyString); - QCoreApplication::postEvent(getEventHandler(), pressEvent); - QCoreApplication::postEvent(getEventHandler(), releaseEvent); } void RenderableWebEntityItem::emitScriptEvent(const QVariant& message) { - _webEntityAPIHelper->emitScriptEvent(message); + if (_webEntityAPIHelper) { + _webEntityAPIHelper->emitScriptEvent(message); + } } void RenderableWebEntityItem::setKeyboardRaised(bool raised) { @@ -424,5 +433,10 @@ void RenderableWebEntityItem::setKeyboardRaised(bool raised) { // raise the keyboard only while in HMD mode and it's being requested. bool value = AbstractViewStateInterface::instance()->isHMDMode() && raised; - _webSurface->getRootItem()->setProperty("keyboardRaised", QVariant(value)); + if (_webSurface) { + auto rootItem = _webSurface->getRootItem(); + if (rootItem) { + rootItem->setProperty("keyboardRaised", QVariant(value)); + } + } } From 7fe16442faea5bac5dc4107ad20763c914ad91c1 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 1 Oct 2016 15:45:59 -0700 Subject: [PATCH 12/13] make calculateTextureInfo thread safe --- libraries/model/src/model/Material.cpp | 42 +++++++++++++++++++ libraries/model/src/model/Material.h | 17 +++++++- .../render-utils/src/MeshPartPayload.cpp | 32 -------------- libraries/render-utils/src/MeshPartPayload.h | 10 ++--- libraries/render-utils/src/Model.cpp | 3 +- 5 files changed, 62 insertions(+), 42 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 6e7968a571..4e01c4b866 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -44,8 +44,11 @@ Material::Material(const Material& material) : } Material& Material::operator= (const Material& material) { + QMutexLocker locker(&_textureMapsMutex); + _key = (material._key); _textureMaps = (material._textureMaps); + _hasCalculatedTextureInfo = false; // copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer Schema schema; @@ -112,6 +115,8 @@ void Material::setScattering(float scattering) { } void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { + QMutexLocker locker(&_textureMapsMutex); + if (textureMap) { _key.setMapChannel(channel, (true)); _textureMaps[channel] = textureMap; @@ -119,6 +124,7 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _key.setMapChannel(channel, (false)); _textureMaps.erase(channel); } + _hasCalculatedTextureInfo = false; _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); @@ -173,6 +179,8 @@ void Material::resetOpacityMap() const { const TextureMapPointer Material::getTextureMap(MapChannel channel) const { + QMutexLocker locker(&_textureMapsMutex); + auto result = _textureMaps.find(channel); if (result != _textureMaps.end()) { return (result->second); @@ -180,3 +188,37 @@ const TextureMapPointer Material::getTextureMap(MapChannel channel) const { return TextureMapPointer(); } } + + +bool Material::calculateMaterialInfo() const { + if (!_hasCalculatedTextureInfo) { + QMutexLocker locker(&_textureMapsMutex); + + bool allTextures = true; // assume we got this... + _textureSize = 0; + _textureCount = 0; + + for (auto const &textureMapItem : _textureMaps) { + auto textureMap = textureMapItem.second; + if (textureMap) { + auto textureSoure = textureMap->getTextureSource(); + if (textureSoure) { + auto texture = textureSoure->getGPUTexture(); + if (texture) { + auto size = texture->getSize(); + _textureSize += size; + _textureCount++; + } else { + allTextures = false; + } + } else { + allTextures = false; + } + } else { + allTextures = false; + } + } + _hasCalculatedTextureInfo = allTextures; + } + return _hasCalculatedTextureInfo; +} diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 304ef2e93b..8851ef4ce9 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -11,6 +11,8 @@ #ifndef hifi_model_Material_h #define hifi_model_Material_h +#include + #include #include @@ -324,7 +326,7 @@ public: // The texture map to channel association void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap); - const TextureMaps& getTextureMaps() const { return _textureMaps; } + const TextureMaps& getTextureMaps() const { return _textureMaps; } // FIXME - not thread safe... const TextureMapPointer getTextureMap(MapChannel channel) const; // Albedo maps cannot have opacity detected until they are loaded @@ -344,12 +346,25 @@ public: }; const UniformBufferView& getTexMapArrayBuffer() const { return _texMapArrayBuffer; } + + int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } + size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } + bool hasTextureInfo() const { return _hasCalculatedTextureInfo; } + private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _texMapArrayBuffer; TextureMaps _textureMaps; + + mutable QMutex _textureMapsMutex { QMutex::Recursive }; + mutable size_t _textureSize { 0 }; + mutable int _textureCount { 0 }; + mutable bool _hasCalculatedTextureInfo { false }; + bool calculateMaterialInfo() const; + + }; typedef std::shared_ptr< Material > MaterialPointer; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 50c0c869ff..2994c7fa5b 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -71,39 +71,8 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; - calculateMaterialSize(); } -bool MeshPartPayload::calculateMaterialSize() { - bool allTextures = true; // assume we got this... - _materialTextureSize = 0; - _materialTextureCount = 0; - auto textureMaps = _drawMaterial->getTextureMaps(); - for (auto const &textureMapItem : textureMaps) { - auto textureMap = textureMapItem.second; - if (textureMap) { - auto textureSoure = textureMap->getTextureSource(); - if (textureSoure) { - auto texture = textureSoure->getGPUTexture(); - if (texture) { - //auto storedSize = texture->getStoredSize(); - auto size = texture->getSize(); - _materialTextureSize += size; - _materialTextureCount++; - } else { - allTextures = false; - } - } else { - allTextures = false; - } - } else { - allTextures = false; - } - } - return allTextures; -} - - ItemKey MeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -378,7 +347,6 @@ void ModelMeshPartPayload::initCache() { auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID); if (networkMaterial) { _drawMaterial = networkMaterial; - calculateMaterialSize(); } } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 3ecd8da03e..04b63874cd 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -66,13 +66,9 @@ public: bool _hasColorAttrib = false; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } - size_t getMaterialTextureSize() { return _materialTextureSize; } - int getMaterialTextureCount() { return _materialTextureCount; } - bool calculateMaterialSize(); - -protected: - size_t _materialTextureSize { 0 }; - int _materialTextureCount { 0 }; + size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } + int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; } + bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; } }; namespace render { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f6caa7c3d3..28a1c3d579 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -168,10 +168,9 @@ void Model::calculateTextureInfo() { bool allTexturesLoaded = true; foreach(auto renderItem, _modelMeshRenderItemsSet) { auto meshPart = renderItem.get(); - bool allTexturesForThisMesh = meshPart->calculateMaterialSize(); - allTexturesLoaded = allTexturesLoaded & allTexturesForThisMesh; textureSize += meshPart->getMaterialTextureSize(); textureCount += meshPart->getMaterialTextureCount(); + allTexturesLoaded = allTexturesLoaded & meshPart->hasTextureInfo(); } _renderInfoTextureSize = textureSize; _renderInfoTextureCount = textureCount; From 546d4ff986da4e8d47a395a1d4ff8ce00e01e2bf Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 1 Oct 2016 22:23:56 -0700 Subject: [PATCH 13/13] remove mic and window resize notifications --- scripts/system/notifications.js | 41 ++++----------------------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index f3ba466342..d89b532f31 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -17,11 +17,9 @@ // keystroke: // // CTRL/s for snapshot. -// CTRL/m for mic mute and unmute. // System generated notifications: -// If Screen is resized. -// If mic is muted for any reason. +// Connection refused. // // To add a new System notification type: // @@ -92,16 +90,12 @@ var lodTextID = false; var NotificationType = { UNKNOWN: 0, - MUTE_TOGGLE: 1, - SNAPSHOT: 2, - WINDOW_RESIZE: 3, - LOD_WARNING: 4, - CONNECTION_REFUSED: 5, - EDIT_ERROR: 6, + SNAPSHOT: 1, + LOD_WARNING: 2, + CONNECTION_REFUSED: 3, + EDIT_ERROR: 4, properties: [ - { text: "Mute Toggle" }, { text: "Snapshot" }, - { text: "Window Resize" }, { text: "Level of Detail" }, { text: "Connection Refused" }, { text: "Edit error" } @@ -446,19 +440,6 @@ function wordWrap(str) { return stringDivider(str, 43.0, "\n"); } -// This fires a notification on window resize -function checkSize() { - if ((Window.innerWidth !== ourWidth) || (Window.innerHeight !== ourHeight)) { - var windowResize = "Window has been resized"; - ourWidth = Window.innerWidth; - ourHeight = Window.innerHeight; - windowDimensions = Controller.getViewportDimensions(); - overlayLocationX = (windowDimensions.x - (width + 60.0)); - buttonLocationX = overlayLocationX + (width - 35.0); - createNotification(windowResize, NotificationType.WINDOW_RESIZE); - } -} - function update() { var nextOverlay, noticeOut, @@ -480,7 +461,6 @@ function update() { frame += 1; if ((frame % 60.0) === 0) { // only update once a second - checkSize(); // checks for size change to trigger windowResize notification locationY = 20.0; for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY }); @@ -533,16 +513,6 @@ function isStartingUp() { return startingUp; } -// Triggers mic mute notification -function onMuteStateChanged() { - var muteState, - muteString; - - muteState = AudioDevice.getMuted() ? "muted" : "unmuted"; - muteString = "Microphone is now " + muteState; - createNotification(muteString, NotificationType.MUTE_TOGGLE); -} - function onDomainConnectionRefused(reason) { createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); } @@ -653,7 +623,6 @@ LODManager.LODDecreased.connect(function() { } }); -AudioDevice.muteToggled.connect(onMuteStateChanged); Controller.keyPressEvent.connect(keyPressEvent); Controller.mousePressEvent.connect(mousePressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent);