Merge branch 'master' of https://github.com/highfidelity/hifi into color

This commit is contained in:
samcake 2016-10-03 10:17:46 -07:00
commit afcb5b8557
16 changed files with 300 additions and 170 deletions

View file

@ -6,8 +6,8 @@ if (WIN32)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add( ExternalProject_Add(
${EXTERNAL_NAME} ${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 11c8a7728d6eda7223df800e10b70723 URL_MD5 272b27bd6c211c45c0c23d4701b63b5e
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
INSTALL_COMMAND "" INSTALL_COMMAND ""

View file

@ -49,6 +49,7 @@ macro(PACKAGE_LIBRARIES_FOR_DEPLOYMENT)
TARGET ${TARGET_NAME} TARGET ${TARGET_NAME}
POST_BUILD 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_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 () endif ()

View file

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "DisplayPlugin.h" #include "DisplayPlugin.h"
#include <gl/Config.h>
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
@ -18,7 +19,6 @@
#include <GLMHelpers.h> #include <GLMHelpers.h>
#include <SimpleMovingAverage.h> #include <SimpleMovingAverage.h>
#include <gl/GLEscrow.h>
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
namespace gpu { namespace gpu {
@ -35,7 +35,6 @@ protected:
using Mutex = std::mutex; using Mutex = std::mutex;
using Lock = std::unique_lock<Mutex>; using Lock = std::unique_lock<Mutex>;
using Condition = std::condition_variable; using Condition = std::condition_variable;
using TextureEscrow = GLEscrow<gpu::TexturePointer>;
public: public:
// These must be final to ensure proper ordering of operations // These must be final to ensure proper ordering of operations
// between the main thread and the presentation thread // between the main thread and the presentation thread

View file

@ -58,9 +58,13 @@ void WebEntityAPIHelper::emitWebEvent(const QVariant& message) {
} else { } else {
// special case to handle raising and lowering the virtual keyboard // special case to handle raising and lowering the virtual keyboard
if (message.type() == QVariant::String && message.toString() == "_RAISE_KEYBOARD" && _renderableWebEntityItem) { 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) { } else if (message.type() == QVariant::String && message.toString() == "_LOWER_KEYBOARD" && _renderableWebEntityItem) {
_renderableWebEntityItem->setKeyboardRaised(false); if (_renderableWebEntityItem) {
_renderableWebEntityItem->setKeyboardRaised(false);
}
} else { } else {
emit webEventReceived(message); emit webEventReceived(message);
} }
@ -343,7 +347,7 @@ void RenderableWebEntityItem::destroyWebSurface() {
// The lifetime of the QML surface MUST be managed by the main thread // The lifetime of the QML surface MUST be managed by the main thread
// Additionally, we MUST use local variables copied by value, rather than // 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 // is no longer valid
auto webSurface = _webSurface; auto webSurface = _webSurface;
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] { AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
@ -388,35 +392,40 @@ static bool equals(const QByteArray& byteArray, const uint8_t* ptr) {
} }
void RenderableWebEntityItem::synthesizeKeyPress(QString key) { void RenderableWebEntityItem::synthesizeKeyPress(QString key) {
auto utf8Key = key.toUtf8(); auto eventHandler = getEventHandler();
if (eventHandler) {
auto utf8Key = key.toUtf8();
int scanCode = (int)utf8Key[0]; int scanCode = (int)utf8Key[0];
QString keyString = key; QString keyString = key;
if (equals(utf8Key, UPWARDS_WHITE_ARROW_FROM_BAR) || equals(utf8Key, ASTERISIM) || if (equals(utf8Key, UPWARDS_WHITE_ARROW_FROM_BAR) || equals(utf8Key, ASTERISIM) ||
equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) { equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) {
return; // ignore return; // ignore
} else if (equals(utf8Key, LEFT_ARROW)) { } else if (equals(utf8Key, LEFT_ARROW)) {
scanCode = Qt::Key_Backspace; scanCode = Qt::Key_Backspace;
keyString = "\x08"; keyString = "\x08";
} else if (equals(utf8Key, RETURN_SYMBOL)) { } else if (equals(utf8Key, RETURN_SYMBOL)) {
scanCode = Qt::Key_Return; scanCode = Qt::Key_Return;
keyString = "\x0d"; keyString = "\x0d";
} else if (equals(utf8Key, LEFTWARD_WHITE_ARROW)) { } else if (equals(utf8Key, LEFTWARD_WHITE_ARROW)) {
scanCode = Qt::Key_Left; scanCode = Qt::Key_Left;
keyString = ""; keyString = "";
} else if (equals(utf8Key, RIGHTWARD_WHITE_ARROW)) { } else if (equals(utf8Key, RIGHTWARD_WHITE_ARROW)) {
scanCode = Qt::Key_Right; scanCode = Qt::Key_Right;
keyString = ""; 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) { void RenderableWebEntityItem::emitScriptEvent(const QVariant& message) {
_webEntityAPIHelper->emitScriptEvent(message); if (_webEntityAPIHelper) {
_webEntityAPIHelper->emitScriptEvent(message);
}
} }
void RenderableWebEntityItem::setKeyboardRaised(bool raised) { 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. // raise the keyboard only while in HMD mode and it's being requested.
bool value = AbstractViewStateInterface::instance()->isHMDMode() && raised; 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));
}
}
} }

View file

@ -67,8 +67,8 @@ void GLWidget::createContext() {
_context = new gl::Context(); _context = new gl::Context();
_context->setWindow(windowHandle()); _context->setWindow(windowHandle());
_context->create(); _context->create();
_context->clear();
_context->makeCurrent(); _context->makeCurrent();
_context->clear();
} }
bool GLWidget::makeCurrent() { bool GLWidget::makeCurrent() {

View file

@ -6,7 +6,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "OffscreenQmlSurface.h" #include "OffscreenQmlSurface.h"
#include "OglplusHelpers.h" #include "Config.h"
#include <queue>
#include <set>
#include <map>
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
#include <QtQml/QtQml> #include <QtQml/QtQml>
@ -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 RESIZE = QEvent::Type(QEvent::User + 3);
static const QEvent::Type STOP = QEvent::Type(QEvent::User + 4); 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<GLuint, TexInfo>;
using Queue = std::queue<TexturePtr>;
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<Map::key_type> 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 { class OffscreenQmlRenderThread : public QThread {
public: public:
OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext); OffscreenQmlRenderThread(OffscreenQmlSurface* surface, QOpenGLContext* shareContext);
@ -165,9 +271,9 @@ private:
OffscreenQmlSurface* _surface{ nullptr }; OffscreenQmlSurface* _surface{ nullptr };
QQuickWindow* _quickWindow{ nullptr }; QQuickWindow* _quickWindow{ nullptr };
QMyQuickRenderControl* _renderControl{ nullptr }; QMyQuickRenderControl* _renderControl{ nullptr };
FramebufferPtr _fbo; GLuint _fbo { 0 };
RenderbufferPtr _depthStencil; GLuint _depthStencil { 0 };
TextureRecycler _textures { true }; RawTextureRecycler _textures { true };
GLTextureEscrow _escrow; GLTextureEscrow _escrow;
uint64_t _lastRenderTime{ 0 }; uint64_t _lastRenderTime{ 0 };
@ -253,24 +359,23 @@ bool OffscreenQmlRenderThread::event(QEvent *e) {
} }
void OffscreenQmlRenderThread::setupFbo() { void OffscreenQmlRenderThread::setupFbo() {
using namespace oglplus;
_textures.setSize(_size); _textures.setSize(_size);
if (_depthStencil) {
try { glDeleteRenderbuffers(1, &_depthStencil);
_depthStencil.reset(new Renderbuffer()); _depthStencil = 0;
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();
} }
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() { QJsonObject OffscreenQmlRenderThread::getGLContextData() {
@ -309,8 +414,15 @@ void OffscreenQmlRenderThread::init() {
void OffscreenQmlRenderThread::cleanup() { void OffscreenQmlRenderThread::cleanup() {
_renderControl->invalidate(); _renderControl->invalidate();
_fbo.reset(); if (_depthStencil) {
_depthStencil.reset(); glDeleteRenderbuffers(1, &_depthStencil);
_depthStencil = 0;
}
if (_fbo) {
glDeleteFramebuffers(1, &_fbo);
_fbo = 0;
}
_textures.clear(); _textures.clear();
_canvas.doneCurrent(); _canvas.doneCurrent();
@ -371,42 +483,22 @@ void OffscreenQmlRenderThread::render() {
releaseMainThread.trigger(); releaseMainThread.trigger();
} }
using namespace oglplus; _quickWindow->setRenderTarget(_fbo, QSize(_size.x, _size.y));
_quickWindow->setRenderTarget(GetName(*_fbo), QSize(_size.x, _size.y));
try { try {
PROFILE_RANGE("qml_render") GLuint texture = _textures.getNextTexture();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
TexturePtr texture = _textures.getNextTexture(); glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
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") PROFILE_RANGE("qml_render->rendercontrol")
_renderControl->render(); _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(); _quickWindow->resetOpenGLState();
_escrow.submit(GetName(*texture)); _escrow.submit(texture);
_lastRenderTime = usecTimestampNow(); _lastRenderTime = usecTimestampNow();
} catch (std::runtime_error& error) { } catch (std::runtime_error& error) {
qWarning() << "Failed to render QML: " << error.what(); qWarning() << "Failed to render QML: " << error.what();

View file

@ -18,7 +18,6 @@
std::unordered_map<TexturePointer, nvtxRangeId_t> _map; std::unordered_map<TexturePointer, nvtxRangeId_t> _map;
#endif #endif
//#define TEXTURE_TRANSFER_PBOS
#ifdef TEXTURE_TRANSFER_PBOS #ifdef TEXTURE_TRANSFER_PBOS
#define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024) #define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024)
@ -62,11 +61,16 @@ void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texture
void GLTextureTransferHelper::setup() { void GLTextureTransferHelper::setup() {
#ifdef THREADED_TEXTURE_TRANSFER #ifdef THREADED_TEXTURE_TRANSFER
_context.makeCurrent(); _context.makeCurrent();
#ifdef TEXTURE_TRANSFER_FORCE_DRAW
// FIXME don't use opengl 4.5 DSA functionality without verifying it's present
glCreateRenderbuffers(1, &_drawRenderbuffer); glCreateRenderbuffers(1, &_drawRenderbuffer);
glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128); glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128);
glCreateFramebuffers(1, &_drawFramebuffer); glCreateFramebuffers(1, &_drawFramebuffer);
glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer); glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer);
glCreateFramebuffers(1, &_readFramebuffer); glCreateFramebuffers(1, &_readFramebuffer);
#endif
#ifdef TEXTURE_TRANSFER_PBOS #ifdef TEXTURE_TRANSFER_PBOS
std::array<GLuint, TEXTURE_TRANSFER_PBO_COUNT> pbos; std::array<GLuint, TEXTURE_TRANSFER_PBO_COUNT> pbos;
glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]); glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]);
@ -84,7 +88,9 @@ void GLTextureTransferHelper::setup() {
void GLTextureTransferHelper::shutdown() { void GLTextureTransferHelper::shutdown() {
#ifdef THREADED_TEXTURE_TRANSFER #ifdef THREADED_TEXTURE_TRANSFER
_context.makeCurrent(); _context.makeCurrent();
#endif
#ifdef TEXTURE_TRANSFER_FORCE_DRAW
glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0); glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0);
glDeleteFramebuffers(1, &_drawFramebuffer); glDeleteFramebuffers(1, &_drawFramebuffer);
_drawFramebuffer = 0; _drawFramebuffer = 0;
@ -165,6 +171,11 @@ bool GLTextureTransferHelper::process() {
} }
gltexture->finishTransfer(); 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 #ifdef THREADED_TEXTURE_TRANSFER
clientWait(); clientWait();
#endif #endif

View file

@ -21,6 +21,14 @@
#define THREADED_TEXTURE_TRANSFER #define THREADED_TEXTURE_TRANSFER
#endif #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 { namespace gpu { namespace gl {
using TextureList = std::list<TexturePointer>; using TextureList = std::list<TexturePointer>;
@ -43,11 +51,15 @@ public:
private: private:
#ifdef THREADED_TEXTURE_TRANSFER #ifdef THREADED_TEXTURE_TRANSFER
::gl::OffscreenContext _context; ::gl::OffscreenContext _context;
#endif
#ifdef TEXTURE_TRANSFER_FORCE_DRAW
// Framebuffers / renderbuffers for forcing access to the texture on the transfer thread // Framebuffers / renderbuffers for forcing access to the texture on the transfer thread
GLuint _drawRenderbuffer { 0 }; GLuint _drawRenderbuffer { 0 };
GLuint _drawFramebuffer { 0 }; GLuint _drawFramebuffer { 0 };
GLuint _readFramebuffer { 0 }; GLuint _readFramebuffer { 0 };
#endif #endif
// A mutex for protecting items access on the render and transfer threads // A mutex for protecting items access on the render and transfer threads
Mutex _mutex; Mutex _mutex;
// Commands that have been submitted for execution on the texture transfer thread // Commands that have been submitted for execution on the texture transfer thread

View file

@ -377,8 +377,10 @@ void GeometryResource::deleter() {
} }
void GeometryResource::setTextures() { void GeometryResource::setTextures() {
for (const FBXMaterial& material : _fbxGeometry->materials) { if (_fbxGeometry) {
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl)); for (const FBXMaterial& material : _fbxGeometry->materials) {
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
}
} }
} }
@ -457,7 +459,9 @@ model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, c
_textures[channel] = Texture { fbxTexture.name, texture }; _textures[channel] = Texture { fbxTexture.name, texture };
auto map = std::make_shared<model::TextureMap>(); auto map = std::make_shared<model::TextureMap>();
map->setTextureSource(texture->_textureSource); if (texture) {
map->setTextureSource(texture->_textureSource);
}
map->setTextureTransform(fbxTexture.transform); map->setTextureTransform(fbxTexture.transform);
return map; return map;

View file

@ -44,8 +44,11 @@ Material::Material(const Material& material) :
} }
Material& Material::operator= (const Material& material) { Material& Material::operator= (const Material& material) {
QMutexLocker locker(&_textureMapsMutex);
_key = (material._key); _key = (material._key);
_textureMaps = (material._textureMaps); _textureMaps = (material._textureMaps);
_hasCalculatedTextureInfo = false;
// copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer // copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer
Schema schema; Schema schema;
@ -112,6 +115,8 @@ void Material::setScattering(float scattering) {
} }
void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) {
QMutexLocker locker(&_textureMapsMutex);
if (textureMap) { if (textureMap) {
_key.setMapChannel(channel, (true)); _key.setMapChannel(channel, (true));
_textureMaps[channel] = textureMap; _textureMaps[channel] = textureMap;
@ -119,6 +124,7 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur
_key.setMapChannel(channel, (false)); _key.setMapChannel(channel, (false));
_textureMaps.erase(channel); _textureMaps.erase(channel);
} }
_hasCalculatedTextureInfo = false;
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
@ -173,6 +179,8 @@ void Material::resetOpacityMap() const {
const TextureMapPointer Material::getTextureMap(MapChannel channel) const { const TextureMapPointer Material::getTextureMap(MapChannel channel) const {
QMutexLocker locker(&_textureMapsMutex);
auto result = _textureMaps.find(channel); auto result = _textureMaps.find(channel);
if (result != _textureMaps.end()) { if (result != _textureMaps.end()) {
return (result->second); return (result->second);
@ -180,3 +188,37 @@ const TextureMapPointer Material::getTextureMap(MapChannel channel) const {
return TextureMapPointer(); 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;
}

View file

@ -11,6 +11,8 @@
#ifndef hifi_model_Material_h #ifndef hifi_model_Material_h
#define hifi_model_Material_h #define hifi_model_Material_h
#include <QMutex>
#include <bitset> #include <bitset>
#include <map> #include <map>
@ -324,7 +326,7 @@ public:
// The texture map to channel association // The texture map to channel association
void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap); 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; const TextureMapPointer getTextureMap(MapChannel channel) const;
// Albedo maps cannot have opacity detected until they are loaded // Albedo maps cannot have opacity detected until they are loaded
@ -344,12 +346,25 @@ public:
}; };
const UniformBufferView& getTexMapArrayBuffer() const { return _texMapArrayBuffer; } 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: private:
mutable MaterialKey _key; mutable MaterialKey _key;
mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _schemaBuffer;
mutable UniformBufferView _texMapArrayBuffer; mutable UniformBufferView _texMapArrayBuffer;
TextureMaps _textureMaps; 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; typedef std::shared_ptr< Material > MaterialPointer;

View file

@ -71,39 +71,8 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor
void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) { void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
_drawMaterial = 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 MeshPartPayload::getKey() const {
ItemKey::Builder builder; ItemKey::Builder builder;
builder.withTypeShape(); builder.withTypeShape();
@ -378,7 +347,6 @@ void ModelMeshPartPayload::initCache() {
auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID); auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID);
if (networkMaterial) { if (networkMaterial) {
_drawMaterial = networkMaterial; _drawMaterial = networkMaterial;
calculateMaterialSize();
} }
} }
@ -429,7 +397,12 @@ ItemKey ModelMeshPartPayload::getKey() const {
} }
ShapeKey ModelMeshPartPayload::getShapeKey() 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 FBXGeometry& geometry = _model->getFBXGeometry();
const auto& networkMeshes = _model->getGeometry()->getMeshes(); const auto& networkMeshes = _model->getGeometry()->getMeshes();

View file

@ -66,13 +66,9 @@ public:
bool _hasColorAttrib = false; bool _hasColorAttrib = false;
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
size_t getMaterialTextureSize() { return _materialTextureSize; } size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; }
int getMaterialTextureCount() { return _materialTextureCount; } int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; }
bool calculateMaterialSize(); bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; }
protected:
size_t _materialTextureSize { 0 };
int _materialTextureCount { 0 };
}; };
namespace render { namespace render {

View file

@ -168,10 +168,9 @@ void Model::calculateTextureInfo() {
bool allTexturesLoaded = true; bool allTexturesLoaded = true;
foreach(auto renderItem, _modelMeshRenderItemsSet) { foreach(auto renderItem, _modelMeshRenderItemsSet) {
auto meshPart = renderItem.get(); auto meshPart = renderItem.get();
bool allTexturesForThisMesh = meshPart->calculateMaterialSize();
allTexturesLoaded = allTexturesLoaded & allTexturesForThisMesh;
textureSize += meshPart->getMaterialTextureSize(); textureSize += meshPart->getMaterialTextureSize();
textureCount += meshPart->getMaterialTextureCount(); textureCount += meshPart->getMaterialTextureCount();
allTexturesLoaded = allTexturesLoaded & meshPart->hasTextureInfo();
} }
_renderInfoTextureSize = textureSize; _renderInfoTextureSize = textureSize;
_renderInfoTextureCount = textureCount; _renderInfoTextureCount = textureCount;

View file

@ -1017,9 +1017,12 @@ void ScriptEngine::updateMemoryCost(const qint64& deltaSize) {
} }
void ScriptEngine::timerFired() { void ScriptEngine::timerFired() {
if (DependencyManager::get<ScriptEngines>()->isStopped()) { {
qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename(); auto engine = DependencyManager::get<ScriptEngines>();
return; // bail early if (!engine || engine->isStopped()) {
qCDebug(scriptengine) << "Script.timerFired() while shutting down is ignored... parent script:" << getFilename();
return; // bail early
}
} }
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender()); QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());

View file

@ -17,11 +17,9 @@
// keystroke: // keystroke:
// //
// CTRL/s for snapshot. // CTRL/s for snapshot.
// CTRL/m for mic mute and unmute.
// System generated notifications: // System generated notifications:
// If Screen is resized. // Connection refused.
// If mic is muted for any reason.
// //
// To add a new System notification type: // To add a new System notification type:
// //
@ -92,16 +90,12 @@ var lodTextID = false;
var NotificationType = { var NotificationType = {
UNKNOWN: 0, UNKNOWN: 0,
MUTE_TOGGLE: 1, SNAPSHOT: 1,
SNAPSHOT: 2, LOD_WARNING: 2,
WINDOW_RESIZE: 3, CONNECTION_REFUSED: 3,
LOD_WARNING: 4, EDIT_ERROR: 4,
CONNECTION_REFUSED: 5,
EDIT_ERROR: 6,
properties: [ properties: [
{ text: "Mute Toggle" },
{ text: "Snapshot" }, { text: "Snapshot" },
{ text: "Window Resize" },
{ text: "Level of Detail" }, { text: "Level of Detail" },
{ text: "Connection Refused" }, { text: "Connection Refused" },
{ text: "Edit error" } { text: "Edit error" }
@ -446,19 +440,6 @@ function wordWrap(str) {
return stringDivider(str, 43.0, "\n"); 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() { function update() {
var nextOverlay, var nextOverlay,
noticeOut, noticeOut,
@ -480,7 +461,6 @@ function update() {
frame += 1; frame += 1;
if ((frame % 60.0) === 0) { // only update once a second if ((frame % 60.0) === 0) { // only update once a second
checkSize(); // checks for size change to trigger windowResize notification
locationY = 20.0; locationY = 20.0;
for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade for (i = 0; i < arrays.length; i += 1) { //repositions overlays as others fade
nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY }); nextOverlay = Overlays.getOverlayAtPoint({ x: overlayLocationX, y: locationY });
@ -533,16 +513,6 @@ function isStartingUp() {
return startingUp; 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) { function onDomainConnectionRefused(reason) {
createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED);
} }
@ -653,7 +623,6 @@ LODManager.LODDecreased.connect(function() {
} }
}); });
AudioDevice.muteToggled.connect(onMuteStateChanged);
Controller.keyPressEvent.connect(keyPressEvent); Controller.keyPressEvent.connect(keyPressEvent);
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent);