From 7b8f61609935486944e4f69deb5c0d0795a9563c Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 8 Sep 2016 17:20:40 -0700 Subject: [PATCH 01/10] add audiostream (jitter) logging --- libraries/audio/src/AudioLogging.cpp | 6 ++++++ libraries/audio/src/AudioLogging.h | 1 + libraries/audio/src/InboundAudioStream.cpp | 11 +++++++++++ 3 files changed, 18 insertions(+) diff --git a/libraries/audio/src/AudioLogging.cpp b/libraries/audio/src/AudioLogging.cpp index f01b8ce846..9bb44f5be6 100644 --- a/libraries/audio/src/AudioLogging.cpp +++ b/libraries/audio/src/AudioLogging.cpp @@ -12,3 +12,9 @@ #include "AudioLogging.h" Q_LOGGING_CATEGORY(audio, "hifi.audio") + +#if DEV_BUILD || PR_BUILD +Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream", QtDebugMsg) +#else +Q_LOGGING_CATEGORY(audiostream, "hifi.audio-stream", QtInfoMsg) +#endif diff --git a/libraries/audio/src/AudioLogging.h b/libraries/audio/src/AudioLogging.h index c15e53be41..71e22e952c 100644 --- a/libraries/audio/src/AudioLogging.h +++ b/libraries/audio/src/AudioLogging.h @@ -15,5 +15,6 @@ #include Q_DECLARE_LOGGING_CATEGORY(audio) +Q_DECLARE_LOGGING_CATEGORY(audiostream) #endif // hifi_AudioLogging_h diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 6b79879bb7..7acefd30b8 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -16,6 +16,7 @@ #include #include "InboundAudioStream.h" +#include "AudioLogging.h" const int STARVE_HISTORY_CAPACITY = 50; @@ -174,6 +175,9 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { _currentJitterBufferFrames = 0; _oldFramesDropped += framesToDrop; + + qCDebug(audiostream, "Dropped %d frames", framesToDrop); + qCDebug(audiostream, "Resetted current jitter frames"); } framesAvailableChanged(); @@ -228,6 +232,9 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) { _currentJitterBufferFrames -= numSilentFramesToDrop; _silentFramesDropped += numSilentFramesToDrop; + qCDebug(audiostream, "Dropped %d silent frames", numSilentFramesToDrop); + qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames); + _framesAvailableStat.reset(); } @@ -308,6 +315,8 @@ void InboundAudioStream::framesAvailableChanged() { if (_framesAvailableStat.getElapsedUsecs() >= FRAMES_AVAILABLE_STAT_WINDOW_USECS) { _currentJitterBufferFrames = (int)ceil(_framesAvailableStat.getAverage()); + qCDebug(audiostream, "Set current jitter frames to %d", _currentJitterBufferFrames); + _framesAvailableStat.reset(); } } @@ -355,6 +364,7 @@ void InboundAudioStream::setToStarved() { // make sure _desiredJitterBufferFrames does not become lower here if (calculatedJitterBufferFrames >= _desiredJitterBufferFrames) { _desiredJitterBufferFrames = calculatedJitterBufferFrames; + qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames); } } } @@ -444,6 +454,7 @@ void InboundAudioStream::packetReceivedUpdateTimingStats() { / (float)AudioConstants::NETWORK_FRAME_USECS); if (calculatedJitterBufferFrames < _desiredJitterBufferFrames) { _desiredJitterBufferFrames = calculatedJitterBufferFrames; + qCDebug(audiostream, "Set desired jitter frames to %d", _desiredJitterBufferFrames); } _timeGapStatsForDesiredReduction.clearNewStatsAvailableFlag(); } From e785c0cdf801bffd2a007e53ca1e716921749eee Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 8 Sep 2016 17:23:30 -0700 Subject: [PATCH 02/10] add test for audio jitter --- interface/src/ui/PreferencesDialog.cpp | 11 ++++++ libraries/audio-client/src/AudioClient.cpp | 41 ++++++++++++++++++++++ libraries/audio-client/src/AudioClient.h | 25 +++++++++++++ 3 files changed, 77 insertions(+) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 7fdafc9bda..c2f15a2ba1 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -277,6 +277,17 @@ void setupPreferences() { preference->setStep(1); preferences->addPreference(preference); } +#if DEV_BUILD || PR_BUILD + { + auto getter = []()->float { return DependencyManager::get()->getGateThreshold(); }; + auto setter = [](float value) { return DependencyManager::get()->setGateThreshold(value); }; + auto preference = new SpinnerPreference(AUDIO, "Debug gate threshold", getter, setter); + preference->setMin(1); + preference->setMax((float)100); + preference->setStep(1); + preferences->addPreference(preference); + } +#endif { auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); }; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 7fdda5a118..f567e50a9f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -55,6 +55,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; static const auto DEFAULT_POSITION_GETTER = []{ return Vectors::ZERO; }; static const auto DEFAULT_ORIENTATION_GETTER = [] { return Quaternions::IDENTITY; }; +static const int DEFAULT_AUDIO_OUTPUT_GATE_THRESHOLD = 1; + Setting::Handle dynamicJitterBuffers("dynamicJitterBuffers", DEFAULT_DYNAMIC_JITTER_BUFFERS); Setting::Handle maxFramesOverDesired("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED); Setting::Handle staticDesiredJitterBufferFrames("staticDesiredJitterBufferFrames", @@ -99,6 +101,8 @@ private: AudioClient::AudioClient() : AbstractAudioInterface(), + _gateThreshold("audioOutputGateThreshold", DEFAULT_AUDIO_OUTPUT_GATE_THRESHOLD), + _gate(this, _gateThreshold.get()), _audioInput(NULL), _desiredInputFormat(), _inputFormat(), @@ -540,11 +544,48 @@ void AudioClient::handleAudioDataPacket(QSharedPointer message) emit receivedFirstPacket(); } +#if DEV_BUILD || PR_BUILD + _gate.insert(message); +#else // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(*message); +#endif } } +AudioClient::Gate::Gate(AudioClient* audioClient, int threshold) : + _audioClient(audioClient), + _threshold(threshold) {} + +void AudioClient::Gate::setThreshold(int threshold) { + flush(); + _threshold = std::max(threshold, 1); +} + +void AudioClient::Gate::insert(QSharedPointer message) { + // Short-circuit for normal behavior + if (_threshold == 1) { + _audioClient->_receivedAudioStream.parseData(*message); + return; + } + + _queue.push(message); + _index++; + + if (_index % _threshold == 0) { + flush(); + } +} + +void AudioClient::Gate::flush() { + while (!_queue.empty()) { + _audioClient->_receivedAudioStream.parseData(*_queue.front()); + _queue.pop(); + } + _index = 0; +} + + void AudioClient::handleNoisyMutePacket(QSharedPointer message) { if (!_muted) { toggleMute(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index b9e662bf85..ba6b98e1bd 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,9 @@ public: int getOutputStarveDetectionThreshold() { return _outputStarveDetectionThreshold.get(); } void setOutputStarveDetectionThreshold(int threshold) { _outputStarveDetectionThreshold.set(threshold); } + int getGateThreshold() { return _gate.getThreshold(); } + void setGateThreshold(int threshold) { _gate.setThreshold(threshold); } + void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; } void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; } @@ -227,6 +231,27 @@ private: float azimuthForSource(const glm::vec3& relativePosition); float gainForSource(float distance, float volume); + class Gate { + public: + Gate(AudioClient* audioClient, int threshold); + + int getThreshold() { return _threshold; } + void setThreshold(int threshold); + + void insert(QSharedPointer message); + + private: + void flush(); + + AudioClient* _audioClient; + std::queue> _queue; + int _index{ 0 }; + int _threshold; + }; + + Setting::Handle _gateThreshold; + Gate _gate; + Mutex _injectorsMutex; QByteArray firstInputFrame; QAudioInput* _audioInput; From f18b8f80fe4327b2bc9bcb7c02947233df23834e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 2 Sep 2016 12:17:35 -0700 Subject: [PATCH 03/10] Sparse texture transfers Conflicts: libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp --- libraries/gpu-gl/CMakeLists.txt | 1 + libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 1 - libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 11 + libraries/gpu-gl/src/gpu/gl/GLTexture.h | 13 +- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 170 ++++++++---- .../gpu-gl/src/gpu/gl/GLTextureTransfer.h | 43 ++- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 4 +- .../src/gpu/gl41/GL41BackendTexture.cpp | 54 +--- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 34 ++- .../src/gpu/gl45/GL45BackendTexture.cpp | 251 ++++++++++++------ 10 files changed, 388 insertions(+), 194 deletions(-) diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index 320f9b3c71..65df5ed9dc 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -4,6 +4,7 @@ link_hifi_libraries(shared gl gpu) GroupSources("src") target_opengl() +target_nsight() if (NOT ANDROID) target_glew() diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 7c369f4124..98a073e283 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -315,7 +315,6 @@ void GLBackend::render(const Batch& batch) { void GLBackend::syncCache() { - recycle(); syncTransformStateCache(); syncPipelineStateCache(); syncInputStateCache(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index d90ca3bbd6..255258d762 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -292,3 +292,14 @@ void GLTexture::postTransfer() { void GLTexture::initTextureTransferHelper() { _textureTransferHelper = std::make_shared(); } + +void GLTexture::startTransfer() { + createTexture(); +} + +void GLTexture::finishTransfer() { + if (_gpuObject.isAutogenerateMips()) { + generateMips(); + } +} + diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index 4f67039aa8..742b223e36 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -11,6 +11,7 @@ #include "GLShared.h" #include "GLTextureTransfer.h" #include "GLBackend.h" +#include "GLTexelFormat.h" namespace gpu { namespace gl { @@ -19,6 +20,7 @@ struct GLFilterMode { GLint magFilter; }; + class GLTexture : public GLObject { public: static const uint16_t INVALID_MIP { (uint16_t)-1 }; @@ -162,11 +164,13 @@ public: bool isOverMaxMemory() const; -protected: + uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } + static const size_t CUBE_NUM_FACES = 6; static const GLenum CUBE_FACE_LAYOUT[6]; static const GLFilterMode FILTER_MODES[Sampler::NUM_FILTERS]; static const GLenum WRAP_MODES[Sampler::NUM_WRAP_MODES]; +protected: static const std::vector& getFaceTargets(GLenum textureType); @@ -185,13 +189,11 @@ protected: GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, GLTexture* originalTexture); void setSyncState(GLSyncState syncState) { _syncState = syncState; } - uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } void createTexture(); virtual void allocateStorage() const = 0; virtual void updateSize() const = 0; - virtual void transfer() const = 0; virtual void syncSampler() const = 0; virtual void generateMips() const = 0; virtual void withPreservedTexture(std::function f) const = 0; @@ -199,6 +201,11 @@ protected: protected: void setSize(GLuint size) const; + virtual void startTransfer(); + // Returns true if this is the last block required to complete transfer + virtual bool continueTransfer() { return false; } + virtual void finishTransfer(); + private: GLTexture(const std::weak_ptr& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 1d22ae7a52..0f64ea1182 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -13,6 +13,18 @@ #include "GLShared.h" #include "GLTexture.h" +#ifdef HAVE_NSIGHT +#include "nvToolsExt.h" +std::unordered_map _map; +#endif + +//#define TEXTURE_TRANSFER_PBOS + +#ifdef TEXTURE_TRANSFER_PBOS +#define TEXTURE_TRANSFER_BLOCK_SIZE (64 * 1024) +#define TEXTURE_TRANSFER_PBO_COUNT 128 +#endif + using namespace gpu; using namespace gpu::gl; @@ -36,82 +48,126 @@ GLTextureTransferHelper::~GLTextureTransferHelper() { void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { GLTexture* object = Backend::getGPUObject(*texturePointer); - Backend::incrementTextureGPUTransferCount(); -#ifdef THREADED_TEXTURE_TRANSFER - GLsync fence { 0 }; - //fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - //glFlush(); - TextureTransferPackage package { texturePointer, fence }; +#ifdef THREADED_TEXTURE_TRANSFER + Backend::incrementTextureGPUTransferCount(); object->setSyncState(GLSyncState::Pending); - queueItem(package); + Lock lock(_mutex); + _pendingTextures.push_back(texturePointer); #else - object->withPreservedTexture([&] { - do_transfer(*object); - }); + for (object->startTransfer(); object->continueTransfer(); ) { } + object->finishTransfer(); object->_contentStamp = texturePointer->getDataStamp(); object->setSyncState(GLSyncState::Transferred); #endif } void GLTextureTransferHelper::setup() { +#ifdef THREADED_TEXTURE_TRANSFER + _context.makeCurrent(); + glCreateRenderbuffers(1, &_drawRenderbuffer); + glNamedRenderbufferStorage(_drawRenderbuffer, GL_RGBA8, 128, 128); + glCreateFramebuffers(1, &_drawFramebuffer); + glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _drawRenderbuffer); + glCreateFramebuffers(1, &_readFramebuffer); +#ifdef TEXTURE_TRANSFER_PBOS + std::array pbos; + glCreateBuffers(TEXTURE_TRANSFER_PBO_COUNT, &pbos[0]); + for (uint32_t i = 0; i < TEXTURE_TRANSFER_PBO_COUNT; ++i) { + TextureTransferBlock newBlock; + newBlock._pbo = pbos[i]; + glNamedBufferStorage(newBlock._pbo, TEXTURE_TRANSFER_BLOCK_SIZE, 0, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + newBlock._mapped = glMapNamedBufferRange(newBlock._pbo, 0, TEXTURE_TRANSFER_BLOCK_SIZE, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + _readyQueue.push(newBlock); + } +#endif +#endif } void GLTextureTransferHelper::shutdown() { -} - -void GLTextureTransferHelper::do_transfer(GLTexture& texture) { - texture.createTexture(); - texture.transfer(); - texture.updateSize(); - Backend::decrementTextureGPUTransferCount(); -} - -bool GLTextureTransferHelper::processQueueItems(const Queue& messages) { #ifdef THREADED_TEXTURE_TRANSFER _context.makeCurrent(); + + glNamedFramebufferRenderbuffer(_drawFramebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0); + glDeleteFramebuffers(1, &_drawFramebuffer); + _drawFramebuffer = 0; + glDeleteFramebuffers(1, &_readFramebuffer); + _readFramebuffer = 0; + + glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0); + glDeleteRenderbuffers(1, &_drawRenderbuffer); + _drawRenderbuffer = 0; #endif - for (auto package : messages) { - TexturePointer texturePointer = package.texture.lock(); - // Texture no longer exists, move on to the next - if (!texturePointer) { +} + +bool GLTextureTransferHelper::process() { +#ifdef THREADED_TEXTURE_TRANSFER + // Take any new textures off the queue + TextureList newTransferTextures; + { + Lock lock(_mutex); + newTransferTextures.swap(_pendingTextures); + } + + if (!newTransferTextures.empty()) { + for (auto& texturePointer : newTransferTextures) { +#ifdef HAVE_NSIGHT + _map[texturePointer] = nvtxRangeStart("TextureTansfer"); +#endif + GLTexture* object = Backend::getGPUObject(*texturePointer); + object->startTransfer(); + _transferringTextures.push_back(texturePointer); + _textureIterator = _transferringTextures.begin(); + } + } + + // No transfers in progress, sleep + if (_transferringTextures.empty()) { + QThread::usleep(1); + return true; + } + + static auto lastReport = usecTimestampNow(); + auto now = usecTimestampNow(); + auto lastReportInterval = now - lastReport; + if (lastReportInterval > USECS_PER_SECOND * 4) { + lastReport = now; + qDebug() << "Texture list " << _transferringTextures.size(); + } + + for (auto _textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) { + auto texture = *_textureIterator; + GLTexture* gltexture = Backend::getGPUObject(*texture); + if (gltexture->continueTransfer()) { + ++_textureIterator; continue; } - if (package.fence) { - auto result = glClientWaitSync(package.fence, 0, 0); - while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { - // Minimum sleep - QThread::usleep(1); - result = glClientWaitSync(package.fence, 0, 0); - } - assert(GL_CONDITION_SATISFIED == result || GL_ALREADY_SIGNALED == result); - glDeleteSync(package.fence); - package.fence = 0; - } - - GLTexture* object = Backend::getGPUObject(*texturePointer); - - do_transfer(*object); - glBindTexture(object->_target, 0); - - { - auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - assert(fence); - auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0); - while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { - // Minimum sleep - QThread::usleep(1); - result = glClientWaitSync(fence, 0, 0); - } - glDeleteSync(fence); - } - - object->_contentStamp = texturePointer->getDataStamp(); - object->setSyncState(GLSyncState::Transferred); + gltexture->finishTransfer(); + glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, gltexture->_id, 0); + glBlitNamedFramebuffer(_readFramebuffer, _drawFramebuffer, 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glFinish(); + gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); + gltexture->updateSize(); + gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); + Backend::decrementTextureGPUTransferCount(); +#ifdef HAVE_NSIGHT + // Mark the texture as transferred + nvtxRangeEnd(_map[texture]); + _map.erase(texture); +#endif + _textureIterator = _transferringTextures.erase(_textureIterator); } -#ifdef THREADED_TEXTURE_TRANSFER - _context.doneCurrent(); + + if (!_transferringTextures.empty()) { + // Don't saturate the GPU + glFinish(); + } else { + // Don't saturate the CPU + QThread::msleep(1); + } +#else + QThread::msleep(1); #endif return true; } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h index e64e204af3..f88dddc5ff 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -23,27 +23,62 @@ namespace gpu { namespace gl { +using VoidLambda = std::function; + +#if 0 struct TextureTransferPackage { std::weak_ptr texture; GLsync fence; }; -class GLTextureTransferHelper : public GenericQueueThread { +struct TextureTransferBlock { + GLuint _pbo { 0 }; + void* _mapped { nullptr }; + GLsync _fence; + std::function _transferCallback; + bool isSignaled(); + void transfer(); +}; + +using CommandQueue = std::list; +struct FencedLambda { + GLsync _fence { 0 }; + VoidLambda _callback; +}; +#endif + +using TextureList = std::list; +using TextureListIterator = TextureList::iterator; + +class GLTextureTransferHelper : public GenericThread { public: using Pointer = std::shared_ptr; GLTextureTransferHelper(); ~GLTextureTransferHelper(); void transferTexture(const gpu::TexturePointer& texturePointer); - void postTransfer(const gpu::TexturePointer& texturePointer); protected: void setup() override; void shutdown() override; - bool processQueueItems(const Queue& messages) override; - void do_transfer(GLTexture& texturePointer); + bool process() override; private: +#ifdef THREADED_TEXTURE_TRANSFER ::gl::OffscreenContext _context; + // A mutex for protecting items access on the render and transfer threads + Mutex _mutex; + // Textures that have been submitted for transfer + TextureList _pendingTextures; + // Textures currently in the transfer process + // Only used on the transfer thread + TextureList _transferringTextures; + TextureListIterator _textureIterator; + + // Framebuffers / renderbuffers for forcing access to the texture on the transfer thread + GLuint _drawRenderbuffer { 0 }; + GLuint _drawFramebuffer { 0 }; + GLuint _readFramebuffer { 0 }; +#endif }; } } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 6e15542310..c89024b7e8 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -46,10 +46,10 @@ public: GL41Texture(const std::weak_ptr& backend, const Texture& buffer, GL41Texture* original); protected: - void transferMip(uint16_t mipLevel, uint8_t face = 0) const; + void transferMip(uint16_t mipLevel, uint8_t face) const; + void startTransfer() override; void allocateStorage() const override; void updateSize() const override; - void transfer() const override; void syncSampler() const override; void generateMips() const override; void withPreservedTexture(std::function f) const override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index ff1a790ba5..3d55802ec2 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -42,7 +42,7 @@ GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {} -void GL41Backend::GL41Texture::withPreservedTexture(std::function f) const { +void GL41Texture::withPreservedTexture(std::function f) const { GLint boundTex = -1; switch (_target) { case GL_TEXTURE_2D: @@ -64,14 +64,14 @@ void GL41Backend::GL41Texture::withPreservedTexture(std::function f) con (void)CHECK_GL_ERROR(); } -void GL41Backend::GL41Texture::generateMips() const { +void GL41Texture::generateMips() const { withPreservedTexture([&] { glGenerateMipmap(_target); }); (void)CHECK_GL_ERROR(); } -void GL41Backend::GL41Texture::allocateStorage() const { +void GL41Texture::allocateStorage() const { GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0); (void)CHECK_GL_ERROR(); @@ -94,7 +94,7 @@ void GL41Backend::GL41Texture::allocateStorage() const { } } -void GL41Backend::GL41Texture::updateSize() const { +void GL41Texture::updateSize() const { setSize(_virtualSize); if (!_id) { return; @@ -130,7 +130,7 @@ void GL41Backend::GL41Texture::updateSize() const { } // Move content bits from the CPU to the GPU for a given mip / face -void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const { +void GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) const { auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); //GLenum target = getFaceTargets()[face]; @@ -140,15 +140,9 @@ void GL41Backend::GL41Texture::transferMip(uint16_t mipLevel, uint8_t face) cons (void)CHECK_GL_ERROR(); } -// This should never happen on the main thread -// Move content bits from the CPU to the GPU -void GL41Backend::GL41Texture::transfer() const { +void GL41Texture::startTransfer() { PROFILE_RANGE(__FUNCTION__); - //qDebug() << "Transferring texture: " << _privateTexture; - // Need to update the content of the GPU object from the source sysmem of the texture - if (_contentStamp >= _gpuObject.getDataStamp()) { - return; - } + Parent::startTransfer(); glBindTexture(_target, _id); (void)CHECK_GL_ERROR(); @@ -175,38 +169,16 @@ void GL41Backend::GL41Texture::transfer() const { glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); } else { - // GO through the process of allocating the correct storage and/or update the content - switch (_gpuObject.getType()) { - case Texture::TEX_2D: - { - for (uint16_t i = _minMip; i <= _maxMip; ++i) { - if (_gpuObject.isStoredMipFaceAvailable(i)) { - transferMip(i); - } + // transfer pixels from each faces + uint8_t numFaces = (Texture::TEX_CUBE == _gpuObject.getType()) ? CUBE_NUM_FACES : 1; + for (uint8_t f = 0; f < numFaces; f++) { + for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i, f)) { + transferMip(i, f); } } - break; - - case Texture::TEX_CUBE: - // transfer pixels from each faces - for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { - for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { - if (_gpuObject.isStoredMipFaceAvailable(i, f)) { - transferMip(i, f); - } - } - } - break; - - default: - qCWarning(gpugl41logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; - break; } } - if (_gpuObject.isAutogenerateMips()) { - glGenerateMipmap(_target); - (void)CHECK_GL_ERROR(); - } } void GL41Backend::GL41Texture::syncSampler() const { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 0d737ef3ba..22e1a87719 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -18,6 +18,29 @@ namespace gpu { namespace gl45 { using namespace gpu::gl; +struct TransferState { + GLTexture& _texture; + GLenum _internalFormat { GL_RGBA8 }; + GLTexelFormat _texelFormat; + uint8_t _face { 0 }; + uint16_t _mipLevel { 0 }; + uint32_t _bytesPerLine { 0 }; + uint32_t _bytesPerPixel { 0 }; + uint32_t _bytesPerPage { 0 }; + GLuint _maxSparseLevel { 0 }; + + uvec3 _mipDimensions; + uvec3 _mipOffset; + uvec3 _pageSize; + const uint8_t* _srcPointer { nullptr }; + uvec3 currentPageSize() const; + void updateSparse(); + void updateMip(); + void populatePage(uint8_t* dest); + bool increment(); + TransferState(GLTexture& texture); +}; + class GL45Backend : public GLBackend { using Parent = GLBackend; // Context Backend static interface required @@ -29,19 +52,26 @@ public: class GL45Texture : public GLTexture { using Parent = GLTexture; - GLuint allocate(const Texture& texture); + static GLuint allocate(const Texture& texture); public: GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable); GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLTexture* original); + ~GL45Texture(); protected: + void startTransfer() override; + bool continueTransfer() override; + void incrementalTransfer(const uvec3& size, const gpu::Texture::PixelsPointer& mip, std::function f) const; void transferMip(uint16_t mipLevel, uint8_t face = 0) const; + void allocateMip(uint16_t mipLevel, uint8_t face = 0) const; void allocateStorage() const override; void updateSize() const override; - void transfer() const override; +// void transfer() const override; void syncSampler() const override; void generateMips() const override; void withPreservedTexture(std::function f) const override; + + TransferState _transferState; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index d3222b9acf..3b512b3278 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -10,8 +10,11 @@ // #include "GL45Backend.h" +#include +#include #include #include +#include #include @@ -21,10 +24,114 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; +#define SPARSE_TEXTURES 1 + using GL45Texture = GL45Backend::GL45Texture; +GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { + return GL45Texture::sync(*this, texture, transfer); +} + +void serverWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(fence); +} + +void clientWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0); + while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { + // Minimum sleep + QThread::usleep(1); + result = glClientWaitSync(fence, 0, 0); + } + glDeleteSync(fence); +} + +TransferState::TransferState(GLTexture& texture) : _texture(texture) { +} + +void TransferState::updateSparse() { + glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); + _internalFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), _texture._gpuObject.getTexelFormat()).internalFormat; + ivec3 pageSize; + glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_X_ARB, 1, &pageSize.x); + glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_Y_ARB, 1, &pageSize.y); + glGetInternalformativ(_texture._target, _internalFormat, GL_VIRTUAL_PAGE_SIZE_Z_ARB, 1, &pageSize.z); + _pageSize = uvec3(pageSize); +} + +void TransferState::updateMip() { + _mipDimensions = _texture._gpuObject.evalMipDimensions(_mipLevel); + _mipOffset = uvec3(); + if (!_texture._gpuObject.isStoredMipFaceAvailable(_mipLevel, _face)) { + _srcPointer = nullptr; + return; + } + + auto mip = _texture._gpuObject.accessStoredMipFace(_mipLevel, _face); + _texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), mip->getFormat()); + _srcPointer = mip->readData(); + _bytesPerLine = (uint32_t)mip->getSize() / _mipDimensions.y; + _bytesPerPixel = _bytesPerLine / _mipDimensions.x; +} + +bool TransferState::increment() { + if ((_mipOffset.x + _pageSize.x) < _mipDimensions.x) { + _mipOffset.x += _pageSize.x; + return true; + } + + if ((_mipOffset.y + _pageSize.y) < _mipDimensions.y) { + _mipOffset.x = 0; + _mipOffset.y += _pageSize.y; + return true; + } + + if (_mipOffset.z + _pageSize.z < _mipDimensions.z) { + _mipOffset.x = 0; + _mipOffset.y = 0; + ++_mipOffset.z; + return true; + } + + // Done with this mip?, move on to the next mip + if (_mipLevel + 1 < _texture.usedMipLevels()) { + _mipOffset = uvec3(0); + ++_mipLevel; + updateMip(); + return true; + } + + // Done with this face? Move on to the next + if (_face + 1 < ((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1)) { + ++_face; + _mipOffset = uvec3(0); + _mipLevel = 0; + updateMip(); + return true; + } + + return false; +} + +void TransferState::populatePage(uint8_t* dst) { + uvec3 pageSize = currentPageSize(); + for (uint32_t y = 0; y < pageSize.y; ++y) { + uint32_t srcOffset = (_bytesPerLine * (_mipOffset.y + y)) + (_bytesPerPixel * _mipOffset.x); + uint32_t dstOffset = (_bytesPerPixel * pageSize.x) * y; + memcpy(dst + dstOffset, _srcPointer + srcOffset, pageSize.x * _bytesPerPixel); + } +} + +uvec3 TransferState::currentPageSize() const { + return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _pageSize); +} + GLuint GL45Texture::allocate(const Texture& texture) { - Backend::incrementTextureGPUCount(); GLuint result; glCreateTextures(getGLTextureType(texture), 1, &result); return result; @@ -34,26 +141,38 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { return GL45Texture::getId(*this, texture, transfer); } -GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { - return GL45Texture::sync(*this, texture, transfer); +GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) + : GLTexture(backend, texture, allocate(texture), transferrable), _transferState(*this) { + +#if SPARSE_TEXTURES + if (transferrable) { + glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); + } +#endif } -GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) - : GLTexture(backend, texture, allocate(texture), transferrable) {} +GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLTexture* original) + : GLTexture(backend, texture, allocate(texture), original), _transferState(*this) { } -GL45Backend::GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLTexture* original) - : GLTexture(backend, texture, allocate(texture), original) {} +GL45Texture::~GL45Texture() { + // FIXME do we need to explicitly deallocate the virtual memory here? + //if (_transferrable) { + // for (uint16_t mipLevel = 0; mipLevel < usedMipLevels(); ++i) { + // glTexturePageCommitmentEXT(_id, mipLevel, offset.x, offset.y, offset.z, size.x, size.y, size.z, GL_TRUE); + // } + //} +} -void GL45Backend::GL45Texture::withPreservedTexture(std::function f) const { +void GL45Texture::withPreservedTexture(std::function f) const { f(); } -void GL45Backend::GL45Texture::generateMips() const { +void GL45Texture::generateMips() const { glGenerateTextureMipmap(_id); (void)CHECK_GL_ERROR(); } -void GL45Backend::GL45Texture::allocateStorage() const { +void GL45Texture::allocateStorage() const { GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); @@ -66,7 +185,7 @@ void GL45Backend::GL45Texture::allocateStorage() const { (void)CHECK_GL_ERROR(); } -void GL45Backend::GL45Texture::updateSize() const { +void GL45Texture::updateSize() const { setSize(_virtualSize); if (!_id) { return; @@ -77,86 +196,50 @@ void GL45Backend::GL45Texture::updateSize() const { } } -// Move content bits from the CPU to the GPU for a given mip / face -void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const { - auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); - auto size = _gpuObject.evalMipDimensions(mipLevel); - if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); - } else if (GL_TEXTURE_CUBE_MAP == _target) { - // DSA ARB does not work on AMD, so use EXT - // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); - auto target = CUBE_FACE_LAYOUT[face]; - glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); - } else { - Q_ASSERT(false); - } - (void)CHECK_GL_ERROR(); +void GL45Texture::startTransfer() { + Parent::startTransfer(); + _transferState.updateSparse(); + _transferState.updateMip(); } -// This should never happen on the main thread -// Move content bits from the CPU to the GPU -void GL45Backend::GL45Texture::transfer() const { - PROFILE_RANGE(__FUNCTION__); - //qDebug() << "Transferring texture: " << _privateTexture; - // Need to update the content of the GPU object from the source sysmem of the texture - if (_contentStamp >= _gpuObject.getDataStamp()) { - return; +bool GL45Texture::continueTransfer() { + static std::vector buffer; + if (buffer.empty()) { + buffer.resize(1024 * 1024); } + uvec3 pageSize = _transferState.currentPageSize(); + uvec3 offset = _transferState._mipOffset; - if (_downsampleSource._texture) { - GLuint fbo { 0 }; - glCreateFramebuffers(1, &fbo); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - // Find the distance between the old min mip and the new one - uint16 mipOffset = _minMip - _downsampleSource._minMip; - for (uint16 i = _minMip; i <= _maxMip; ++i) { - uint16 targetMip = i - _minMip; - uint16 sourceMip = targetMip + mipOffset; - Vec3u dimensions = _gpuObject.evalMipDimensions(i); - for (GLenum target : getFaceTargets(_target)) { - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, _downsampleSource._texture, sourceMip); - (void)CHECK_GL_ERROR(); - glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y); - (void)CHECK_GL_ERROR(); - } - } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &fbo); - } else { - // GO through the process of allocating the correct storage and/or update the content - switch (_gpuObject.getType()) { - case Texture::TEX_2D: - { - for (uint16_t i = _minMip; i <= _maxMip; ++i) { - if (_gpuObject.isStoredMipFaceAvailable(i)) { - transferMip(i); - } - } - } - break; +#if SPARSE_TEXTURES + if (_transferState._mipLevel <= _transferState._maxSparseLevel) { + glTexturePageCommitmentEXT(_id, _transferState._mipLevel, + offset.x, offset.y, _transferState._face, + pageSize.x, pageSize.y, pageSize.z, + GL_TRUE); + } +#endif - case Texture::TEX_CUBE: - // transfer pixels from each faces - for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { - for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { - if (_gpuObject.isStoredMipFaceAvailable(i, f)) { - transferMip(i, f); - } - } - } - break; - - default: - qCWarning(gpugl45logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; - break; + if (_transferState._srcPointer) { + // Transfer the mip data + _transferState.populatePage(&buffer[0]); + if (GL_TEXTURE_2D == _target) { + glTextureSubImage2D(_id, _transferState._mipLevel, + offset.x, offset.y, + pageSize.x, pageSize.y, + _transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); + } else if (GL_TEXTURE_CUBE_MAP == _target) { + auto target = CUBE_FACE_LAYOUT[_transferState._face]; + // DSA ARB does not work on AMD, so use EXT + // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); + glTextureSubImage2DEXT(_id, target, _transferState._mipLevel, + offset.x, offset.y, + pageSize.x, pageSize.y, + _transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); } } - if (_gpuObject.isAutogenerateMips()) { - glGenerateTextureMipmap(_id); - (void)CHECK_GL_ERROR(); - } + + serverWait(); + return _transferState.increment(); } void GL45Backend::GL45Texture::syncSampler() const { From a9ba92f16c3ca325de870892615747ea48aa490a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Sep 2016 13:22:27 -0700 Subject: [PATCH 04/10] Fix alignment of small pages --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 3b512b3278..ce359ad6c2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -118,11 +118,17 @@ bool TransferState::increment() { return false; } +#define DEFAULT_GL_PIXEL_ALIGNMENT 4 void TransferState::populatePage(uint8_t* dst) { uvec3 pageSize = currentPageSize(); + auto bytesPerPageLine = _bytesPerPixel * pageSize.x; + if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { + bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); + assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); + } for (uint32_t y = 0; y < pageSize.y; ++y) { uint32_t srcOffset = (_bytesPerLine * (_mipOffset.y + y)) + (_bytesPerPixel * _mipOffset.x); - uint32_t dstOffset = (_bytesPerPixel * pageSize.x) * y; + uint32_t dstOffset = bytesPerPageLine * y; memcpy(dst + dstOffset, _srcPointer + srcOffset, pageSize.x * _bytesPerPixel); } } From e03b0b5825ed8d0309c8b9aacfe00d97adeb44d2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 7 Sep 2016 12:45:44 -0700 Subject: [PATCH 05/10] Cleanup dead code --- .../gpu-gl/src/gpu/gl/GLTextureTransfer.h | 24 ------------------- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 1 - 2 files changed, 25 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h index f88dddc5ff..d2207df7e6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -23,30 +23,6 @@ namespace gpu { namespace gl { -using VoidLambda = std::function; - -#if 0 -struct TextureTransferPackage { - std::weak_ptr texture; - GLsync fence; -}; - -struct TextureTransferBlock { - GLuint _pbo { 0 }; - void* _mapped { nullptr }; - GLsync _fence; - std::function _transferCallback; - bool isSignaled(); - void transfer(); -}; - -using CommandQueue = std::list; -struct FencedLambda { - GLsync _fence { 0 }; - VoidLambda _callback; -}; -#endif - using TextureList = std::list; using TextureListIterator = TextureList::iterator; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 22e1a87719..eab1aa07d8 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -66,7 +66,6 @@ public: void allocateMip(uint16_t mipLevel, uint8_t face = 0) const; void allocateStorage() const override; void updateSize() const override; -// void transfer() const override; void syncSampler() const override; void generateMips() const override; void withPreservedTexture(std::function f) const override; From bc6b43b7bea23c9581175f4eca00794b5ff25e7e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Sep 2016 11:20:37 -0700 Subject: [PATCH 06/10] Add debug option to lower texture resolution --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 10 ++++++++++ libraries/model/src/model/TextureMap.cpp | 23 +++++++++++++++-------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 904a6c5b65..f475bf18e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2006,7 +2006,7 @@ void Application::resizeGL() { static qreal lastDevicePixelRatio = 0; qreal devicePixelRatio = _window->devicePixelRatio(); if (offscreenUi->size() != fromGlm(uiSize) || devicePixelRatio != lastDevicePixelRatio) { - qDebug() << "Device pixel ratio changed, triggering resize"; + qDebug() << "Device pixel ratio changed, triggering resize to " << uiSize; offscreenUi->resize(fromGlm(uiSize), true); _offscreenContext->makeCurrent(); lastDevicePixelRatio = devicePixelRatio; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d3caa4a092..08abbf63d2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -47,6 +47,8 @@ #include "Menu.h" +extern bool DEV_DECIMATE_TEXTURES; + Menu* Menu::getInstance() { return dynamic_cast(qApp->getWindow()->menuBar()); } @@ -390,6 +392,14 @@ Menu::Menu() { // Developer > Render > LOD Tools addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools())); + // HACK enable texture decimation + { + auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, "Decimate Textures"); + connect(action, &QAction::triggered, [&](bool checked) { + DEV_DECIMATE_TEXTURES = checked; + }); + } + // Developer > Assets >>> MenuWrapper* assetDeveloperMenu = developerMenu->addMenu("Assets"); auto& atpMigrator = ATPAssetMigrator::getInstance(); diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 754862aa4a..9345124d54 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -22,6 +22,13 @@ using namespace gpu; // FIXME: Declare this to enable compression //#define COMPRESS_TEXTURES +bool DEV_DECIMATE_TEXTURES = false; +QImage processSourceImage(const QImage& srcImage) { + if (DEV_DECIMATE_TEXTURES) { + return srcImage.scaled(srcImage.size() * 0.5f); + } + return srcImage; +} void TextureMap::setTextureSource(TextureSourcePointer& textureSource) { _textureSource = textureSource; @@ -53,7 +60,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) { } const QImage TextureUsage::process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); validAlpha = false; alphaAsMask = true; const uint8 OPAQUE_ALPHA = 255; @@ -221,7 +228,7 @@ gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImag gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); @@ -254,8 +261,8 @@ double mapComponent(double sobelValue) { } gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; - + QImage image = processSourceImage(srcImage); + if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); } @@ -325,7 +332,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm } gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); if (!image.hasAlphaChannel()) { if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); @@ -358,7 +365,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma } gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); if (!image.hasAlphaChannel()) { if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); @@ -395,7 +402,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s } gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); if (!image.hasAlphaChannel()) { if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); @@ -687,7 +694,7 @@ const int CubeLayout::NUM_CUBEMAP_LAYOUTS = sizeof(CubeLayout::CUBEMAP_LAYOUTS) gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance) { gpu::Texture* theTexture = nullptr; if ((srcImage.width() > 0) && (srcImage.height() > 0)) { - QImage image = srcImage; + QImage image = processSourceImage(srcImage); if (image.format() != QImage::Format_RGB888) { image = image.convertToFormat(QImage::Format_RGB888); } From a13450b36f6a5dfe3121ad344aab4ff598c0c4ab Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Sep 2016 22:25:04 -0700 Subject: [PATCH 07/10] Fix ubuntu warning --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index ce359ad6c2..db8186221c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -106,8 +106,10 @@ bool TransferState::increment() { return true; } + uint8_t maxFace = (uint8_t)((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); + uint8_t nextFace = _face + 1; // Done with this face? Move on to the next - if (_face + 1 < ((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1)) { + if (nextFace < maxFace) { ++_face; _mipOffset = uvec3(0); _mipLevel = 0; From 27ddd39a22058b28cf057ed5aae9433278670b81 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 9 Sep 2016 09:30:38 -0700 Subject: [PATCH 08/10] PR comments --- libraries/gpu-gl/src/gpu/gl/GLShared.cpp | 21 +++++++++++++++++++ libraries/gpu-gl/src/gpu/gl/GLShared.h | 6 ++++++ .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 4 ++-- .../src/gpu/gl45/GL45BackendTexture.cpp | 19 ----------------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp index fd6857c4c0..d59be0d9de 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include #include @@ -933,9 +935,28 @@ void makeProgramBindings(ShaderObject& shaderObject) { (void)CHECK_GL_ERROR(); } +void serverWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(fence); +} + +void clientWait() { + auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + assert(fence); + auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0); + while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { + // Minimum sleep + QThread::usleep(1); + result = glClientWaitSync(fence, 0, 0); + } + glDeleteSync(fence); +} } } + using namespace gpu; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h index 676d3910ff..7ec6deeb9d 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h @@ -18,6 +18,12 @@ Q_DECLARE_LOGGING_CATEGORY(gpugllogging) namespace gpu { namespace gl { +// Create a fence and inject a GPU wait on the fence +void serverWait(); + +// Create a fence and synchronously wait on the fence +void clientWait(); + gpu::Size getDedicatedMemory(); ComparisonFunction comparisonFuncFromGL(GLenum func); State::StencilOp stencilOpFromGL(GLenum stencilOp); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 0f64ea1182..ae8739bb3b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -146,7 +146,7 @@ bool GLTextureTransferHelper::process() { gltexture->finishTransfer(); glNamedFramebufferTexture(_readFramebuffer, GL_COLOR_ATTACHMENT0, gltexture->_id, 0); glBlitNamedFramebuffer(_readFramebuffer, _drawFramebuffer, 0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glFinish(); + clientWait(); gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); gltexture->updateSize(); gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); @@ -161,7 +161,7 @@ bool GLTextureTransferHelper::process() { if (!_transferringTextures.empty()) { // Don't saturate the GPU - glFinish(); + clientWait(); } else { // Don't saturate the CPU QThread::msleep(1); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index db8186221c..871a2c8a03 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -32,25 +32,6 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transf return GL45Texture::sync(*this, texture, transfer); } -void serverWait() { - auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - assert(fence); - glWaitSync(fence, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(fence); -} - -void clientWait() { - auto fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - assert(fence); - auto result = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 0); - while (GL_TIMEOUT_EXPIRED == result || GL_WAIT_FAILED == result) { - // Minimum sleep - QThread::usleep(1); - result = glClientWaitSync(fence, 0, 0); - } - glDeleteSync(fence); -} - TransferState::TransferState(GLTexture& texture) : _texture(texture) { } From 017181f0203b24b5bdc6ef4307f240daaf6bcfb9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 9 Sep 2016 09:46:54 -0700 Subject: [PATCH 09/10] Remove magic numbers, ensure proper buffer size for page transfers --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 2 +- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index eab1aa07d8..db297e77fd 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -36,7 +36,7 @@ struct TransferState { uvec3 currentPageSize() const; void updateSparse(); void updateMip(); - void populatePage(uint8_t* dest); + void populatePage(std::vector& dest); bool increment(); TransferState(GLTexture& texture); }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 871a2c8a03..b511ed7811 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -26,6 +26,9 @@ using namespace gpu::gl45; #define SPARSE_TEXTURES 1 +// Allocate 1 MB of buffer space for paged transfers +#define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) + using GL45Texture = GL45Backend::GL45Texture; GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { @@ -102,13 +105,18 @@ bool TransferState::increment() { } #define DEFAULT_GL_PIXEL_ALIGNMENT 4 -void TransferState::populatePage(uint8_t* dst) { +void TransferState::populatePage(std::vector& buffer) { uvec3 pageSize = currentPageSize(); auto bytesPerPageLine = _bytesPerPixel * pageSize.x; if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) { bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT); assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)); } + auto totalPageSize = bytesPerPageLine * pageSize.y; + if (totalPageSize > buffer.size()) { + buffer.resize(totalPageSize); + } + uint8_t* dst = &buffer[0]; for (uint32_t y = 0; y < pageSize.y; ++y) { uint32_t srcOffset = (_bytesPerLine * (_mipOffset.y + y)) + (_bytesPerPixel * _mipOffset.x); uint32_t dstOffset = bytesPerPageLine * y; @@ -194,7 +202,7 @@ void GL45Texture::startTransfer() { bool GL45Texture::continueTransfer() { static std::vector buffer; if (buffer.empty()) { - buffer.resize(1024 * 1024); + buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); } uvec3 pageSize = _transferState.currentPageSize(); uvec3 offset = _transferState._mipOffset; @@ -210,7 +218,7 @@ bool GL45Texture::continueTransfer() { if (_transferState._srcPointer) { // Transfer the mip data - _transferState.populatePage(&buffer[0]); + _transferState.populatePage(buffer); if (GL_TEXTURE_2D == _target) { glTextureSubImage2D(_id, _transferState._mipLevel, offset.x, offset.y, From ecfe56085db9314c3b7f65d7ddd8f414e8b88b9d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 3 Sep 2016 15:02:49 -0700 Subject: [PATCH 10/10] GLM update and GLI integration --- CMakeLists.txt | 7 ++ cmake/externals/gli/CMakeLists.txt | 21 ++++++ cmake/externals/glm/CMakeLists.txt | 4 +- cmake/macros/TargetGli.cmake | 12 ++++ cmake/modules/FindGLI.cmake | 26 +++++++ interface/src/Application.cpp | 2 +- interface/src/avatar/SoftAttachmentModel.cpp | 2 +- libraries/animation/src/Rig.cpp | 4 +- libraries/audio/src/AudioInjector.cpp | 2 +- .../src/RenderableLightEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- libraries/entities/src/EntityItemProperties.h | 3 +- libraries/entities/src/LightEntityItem.cpp | 4 +- .../src/model-networking/TextureCache.cpp | 21 ++++++ libraries/physics/src/BulletUtil.h | 2 +- libraries/shared/CMakeLists.txt | 2 +- libraries/shared/src/AACube.cpp | 8 +-- libraries/shared/src/Extents.h | 4 +- libraries/shared/src/GLMHelpers.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 4 +- tests/render-texture-load/CMakeLists.txt | 3 + tests/render-texture-load/src/GLIHelpers.cpp | 70 ++++++++++++++++++ tests/render-texture-load/src/GLIHelpers.h | 47 ++++++++++++ tests/render-texture-load/src/main.cpp | 71 ++++++++----------- 25 files changed, 262 insertions(+), 69 deletions(-) create mode 100644 cmake/externals/gli/CMakeLists.txt create mode 100644 cmake/macros/TargetGli.cmake create mode 100644 cmake/modules/FindGLI.cmake create mode 100644 tests/render-texture-load/src/GLIHelpers.cpp create mode 100644 tests/render-texture-load/src/GLIHelpers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ad411229..1ab7e55343 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,13 @@ else () endif () endif(WIN32) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.3") + # GLM 0.9.8 on Ubuntu 14 (gcc 4.4) has issues with the simd declarations + add_definitions(-DGLM_FORCE_PURE) + endif() +endif() + if (NOT ANDROID) if ((NOT MSVC12) AND (NOT MSVC14)) include(CheckCXXCompilerFlag) diff --git a/cmake/externals/gli/CMakeLists.txt b/cmake/externals/gli/CMakeLists.txt new file mode 100644 index 0000000000..2ef4d2b3af --- /dev/null +++ b/cmake/externals/gli/CMakeLists.txt @@ -0,0 +1,21 @@ +set(EXTERNAL_NAME gli) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://hifi-public.s3.amazonaws.com/dependencies/gli-0.8.1.0.zip + URL_MD5 00c990f59c12bbf367956ef399d6f798 + BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "List of gli include directories") \ No newline at end of file diff --git a/cmake/externals/glm/CMakeLists.txt b/cmake/externals/glm/CMakeLists.txt index 74e98ad19e..79a44fa48e 100644 --- a/cmake/externals/glm/CMakeLists.txt +++ b/cmake/externals/glm/CMakeLists.txt @@ -3,8 +3,8 @@ set(EXTERNAL_NAME glm) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.5.4.zip - URL_MD5 fab76fc982b256b46208e5c750ed456a + URL https://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.8.zip + URL_MD5 579ac77a3110befa3244d68c0ceb7281 BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= LOG_DOWNLOAD 1 diff --git a/cmake/macros/TargetGli.cmake b/cmake/macros/TargetGli.cmake new file mode 100644 index 0000000000..664fcc00c5 --- /dev/null +++ b/cmake/macros/TargetGli.cmake @@ -0,0 +1,12 @@ +# +# Copyright 2015 High Fidelity, Inc. +# Created by Bradley Austin Davis on 2015/10/10 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_GLI) + add_dependency_external_projects(gli) + find_package(GLI REQUIRED) + target_include_directories(${TARGET_NAME} PUBLIC ${GLI_INCLUDE_DIRS}) +endmacro() \ No newline at end of file diff --git a/cmake/modules/FindGLI.cmake b/cmake/modules/FindGLI.cmake new file mode 100644 index 0000000000..0f42a9b052 --- /dev/null +++ b/cmake/modules/FindGLI.cmake @@ -0,0 +1,26 @@ +# +# FindGLI.cmake +# +# Try to find GLI include path. +# Once done this will define +# +# GLI_INCLUDE_DIRS +# +# Created on 2016/09/03 by Bradley Austin Davis +# Copyright 2013-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 +# + +# setup hints for GLI search +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("gli") + +# locate header +find_path(GLI_INCLUDE_DIRS "gli/gli.hpp" HINTS ${GLI_SEARCH_DIRS}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLI DEFAULT_MSG GLI_INCLUDE_DIRS) + +mark_as_advanced(GLI_INCLUDE_DIRS GLI_SEARCH_DIRS) \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 904a6c5b65..7b07df414f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3288,7 +3288,7 @@ void Application::init() { getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) { auto dims = item.getDimensions(); - auto maxSize = glm::max(dims.x, dims.y, dims.z); + auto maxSize = glm::compMax(dims); if (maxSize <= 0.0f) { return 0.0f; diff --git a/interface/src/avatar/SoftAttachmentModel.cpp b/interface/src/avatar/SoftAttachmentModel.cpp index b90fd9470c..c2e8dab2a1 100644 --- a/interface/src/avatar/SoftAttachmentModel.cpp +++ b/interface/src/avatar/SoftAttachmentModel.cpp @@ -55,7 +55,7 @@ void SoftAttachmentModel::updateClusterMatrices(glm::vec3 modelPosition, glm::qu // TODO: cache these look ups as an optimization int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); - glm::mat4 jointMatrix(glm::mat4::_null); + glm::mat4 jointMatrix; if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride->getJointStateCount()) { jointMatrix = _rigOverride->getJointTransform(jointIndexOverride); } else { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index d6ec0487f0..877c6c3e91 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1093,7 +1093,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { // prevent the hand IK targets from intersecting the body capsule glm::vec3 handPosition = params.leftPosition; - glm::vec3 displacement(glm::vec3::_null); + glm::vec3 displacement; if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) { handPosition -= displacement; } @@ -1111,7 +1111,7 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { // prevent the hand IK targets from intersecting the body capsule glm::vec3 handPosition = params.rightPosition; - glm::vec3 displacement(glm::vec3::_null); + glm::vec3 displacement; if (findSphereCapsulePenetration(handPosition, HAND_RADIUS, bodyCapsuleStart, bodyCapsuleEnd, bodyCapsuleRadius, displacement)) { handPosition -= displacement; } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index c6368259c0..5fc07adb8d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -26,7 +26,7 @@ #include "SoundCache.h" #include "AudioSRC.h" -int audioInjectorPtrMetaTypeId = qRegisterMetaType(); +//int audioInjectorPtrMetaTypeId = qRegisterMetaType(); AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index b7f32cca65..3ed26456b4 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -33,7 +33,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { glm::vec3 position = getPosition(); glm::vec3 dimensions = getDimensions(); glm::quat rotation = getRotation(); - float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); + float largestDiameter = glm::compMax(dimensions); glm::vec3 color = toGlm(getXColor()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index abc4e1c767..f2e938ece3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -299,7 +299,7 @@ bool RenderableModelEntityItem::getAnimationFrame() { if (index < translations.size()) { translationMat = glm::translate(translations[index]); } - glm::mat4 rotationMat(glm::mat4::_null); + glm::mat4 rotationMat; if (index < rotations.size()) { rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation); } else { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index eb6db2874f..a2ca2a7cfe 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -447,7 +447,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // set ray cast length to long enough to cover all of the voxel space float distanceToEntity = glm::distance(origin, getPosition()); glm::vec3 dimensions = getDimensions(); - float largestDimension = glm::max(dimensions.x, dimensions.y, dimensions.z) * 2.0f; + float largestDimension = glm::compMax(dimensions) * 2.0f; glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 473966dd60..3468b7dcde 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -221,7 +220,7 @@ public: public: - float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } + float getMaxDimension() const { return glm::compMax(_dimensions); } float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); } diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 1be133463c..9a143beb8d 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -49,7 +49,7 @@ void LightEntityItem::setDimensions(const glm::vec3& value) { const float width = length * glm::sin(glm::radians(_cutoff)); EntityItem::setDimensions(glm::vec3(width, width, length)); } else { - float maxDimension = glm::max(value.x, value.y, value.z); + float maxDimension = glm::compMax(value); EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); } } @@ -82,7 +82,7 @@ void LightEntityItem::setIsSpotlight(bool value) { const float width = length * glm::sin(glm::radians(_cutoff)); setDimensions(glm::vec3(width, width, length)); } else { - float maxDimension = glm::max(dimensions.x, dimensions.y, dimensions.z); + float maxDimension = glm::compMax(dimensions); setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1cc00bb850..32a6f4c323 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -18,12 +18,15 @@ #include #include #include +#include +#include #include #include #include +#include #include #include @@ -307,6 +310,24 @@ ImageReader::ImageReader(const QWeakPointer& resource, const QByteArra _url(url), _content(data) { +#if DEBUG_DUMP_TEXTURE_LOADS + static auto start = usecTimestampNow() / USECS_PER_MSEC; + auto now = usecTimestampNow() / USECS_PER_MSEC - start; + QString urlStr = _url.toString(); + auto dot = urlStr.lastIndexOf("."); + QString outFileName = QString(QCryptographicHash::hash(urlStr.toLocal8Bit(), QCryptographicHash::Md5).toHex()) + urlStr.right(urlStr.length() - dot); + QFile loadRecord("h:/textures/loads.txt"); + loadRecord.open(QFile::Text | QFile::Append | QFile::ReadWrite); + loadRecord.write(QString("%1 %2\n").arg(now).arg(outFileName).toLocal8Bit()); + outFileName = "h:/textures/" + outFileName; + QFileInfo outInfo(outFileName); + if (!outInfo.exists()) { + QFile outFile(outFileName); + outFile.open(QFile::WriteOnly | QFile::Truncate); + outFile.write(data); + outFile.close(); + } +#endif } void ImageReader::listSupportedImageFormats() { diff --git a/libraries/physics/src/BulletUtil.h b/libraries/physics/src/BulletUtil.h index 0122e86288..b6fac74617 100644 --- a/libraries/physics/src/BulletUtil.h +++ b/libraries/physics/src/BulletUtil.h @@ -46,7 +46,7 @@ inline btTransform glmToBullet(const glm::mat4& m) { } inline glm::mat4 bulletToGLM(const btTransform& t) { - glm::mat4 m(glm::mat4::_null); + glm::mat4 m; const btMatrix3x3& basis = t.getBasis(); // copy over 3x3 part diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index da345d1970..f9b835df5c 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -8,4 +8,4 @@ if (WIN32) endif() target_zlib() -target_nsight() +target_nsight() \ No newline at end of file diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index f8122ea4dc..8cff3255b3 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include - #include "AABox.h" #include "AACube.h" #include "Extents.h" @@ -25,7 +23,7 @@ AACube::AACube(const Extents& other) : _corner(other.minimum) { glm::vec3 dimensions = other.maximum - other.minimum; - _scale = glm::max(dimensions.x, dimensions.y, dimensions.z); + _scale = glm::compMax(dimensions); } AACube::AACube(const glm::vec3& corner, float size) : @@ -479,8 +477,8 @@ AACube& AACube::operator += (const glm::vec3& point) { glm::vec3 scaleOld = oldMaximumPoint - _corner; glm::vec3 scalePoint = point - _corner; - _scale = glm::max(_scale, scalePoint.x, scalePoint.y, scalePoint.z); - _scale = glm::max(_scale, scaleOld.x, scaleOld.y, scaleOld.z); + _scale = std::max(_scale, glm::compMax(scalePoint)); + _scale = std::max(_scale, glm::compMax(scaleOld)); return (*this); } diff --git a/libraries/shared/src/Extents.h b/libraries/shared/src/Extents.h index 07fad60a04..850735dd5d 100644 --- a/libraries/shared/src/Extents.h +++ b/libraries/shared/src/Extents.h @@ -14,7 +14,7 @@ #define hifi_Extents_h #include -#include +#include #include #include "StreamUtils.h" @@ -67,7 +67,7 @@ public: void transform(const Transform& transform); glm::vec3 size() const { return maximum - minimum; } - float largestDimension() const {glm::vec3 s = size(); return glm::max(s[0], s[1], s[2]); } + float largestDimension() const { return glm::compMax(size()); } /// \return new Extents which is original rotated around orign by rotation Extents getRotated(const glm::quat& rotation) const { diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index ef3bfeb674..898dfa873d 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -203,19 +203,19 @@ inline float lerp(float x, float y, float a) { // vec2 lerp - linear interpolate template -glm::detail::tvec2 lerp(const glm::detail::tvec2& x, const glm::detail::tvec2& y, T a) { +glm::tvec2 lerp(const glm::tvec2& x, const glm::tvec2& y, T a) { return x * (T(1) - a) + (y * a); } // vec3 lerp - linear interpolate template -glm::detail::tvec3 lerp(const glm::detail::tvec3& x, const glm::detail::tvec3& y, T a) { +glm::tvec3 lerp(const glm::tvec3& x, const glm::tvec3& y, T a) { return x * (T(1) - a) + (y * a); } // vec4 lerp - linear interpolate template -glm::detail::tvec4 lerp(const glm::detail::tvec4& x, const glm::detail::tvec4& y, T a) { +glm::tvec4 lerp(const glm::tvec4& x, const glm::tvec4& y, T a) { return x * (T(1) - a) + (y * a); } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 453035de0f..b37fcd3699 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -797,7 +797,7 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { } glm::vec3 SpatiallyNestable::getLocalVelocity() const { - glm::vec3 result(glm::vec3::_null); + glm::vec3 result; _velocityLock.withReadLock([&] { result = _velocity; }); @@ -811,7 +811,7 @@ void SpatiallyNestable::setLocalVelocity(const glm::vec3& velocity) { } glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const { - glm::vec3 result(glm::vec3::_null); + glm::vec3 result; _angularVelocityLock.withReadLock([&] { result = _angularVelocity; }); diff --git a/tests/render-texture-load/CMakeLists.txt b/tests/render-texture-load/CMakeLists.txt index ecf910f434..0e5f32f46a 100644 --- a/tests/render-texture-load/CMakeLists.txt +++ b/tests/render-texture-load/CMakeLists.txt @@ -14,6 +14,9 @@ link_hifi_libraries(shared octree gl gpu gpu-gl render model model-networking ne package_libraries_for_deployment() +target_gli() +target_glm() + target_zlib() add_dependency_external_projects(quazip) find_package(QuaZip REQUIRED) diff --git a/tests/render-texture-load/src/GLIHelpers.cpp b/tests/render-texture-load/src/GLIHelpers.cpp new file mode 100644 index 0000000000..8067993b49 --- /dev/null +++ b/tests/render-texture-load/src/GLIHelpers.cpp @@ -0,0 +1,70 @@ +// +// Created by Bradley Austin Davis on 2016/09/03 +// Copyright 2013-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 "GLIHelpers.h" + +#include +#include + +#include +#include +#include +#include + +gli::format fromQImageFormat(QImage::Format format) { + switch (format) { + case QImage::Format_RGB32: + return gli::format::FORMAT_BGRA8_UNORM_PACK8; + + case QImage::Format_ARGB32: + return gli::format::FORMAT_BGRA8_UNORM_PACK8; + + case QImage::Format_Grayscale8: + return gli::format::FORMAT_L8_UNORM_PACK8; + + default: + return gli::format::FORMAT_UNDEFINED; + } +} + +QString getKtxFileName(const QString& sourceFileName) { + QFileInfo fileInfo(sourceFileName); + QString name = fileInfo.completeBaseName(); + QString ext = fileInfo.suffix(); + QString path = fileInfo.absolutePath(); + return path + "/" + name + ".ktx"; +} + +QString convertTexture(const QString& sourceFile) { + if (sourceFile.endsWith(".ktx") || sourceFile.endsWith(".dds")) { + return sourceFile; + } + QImage sourceImage(sourceFile); + gli::texture2d workTexture( + fromQImageFormat(sourceImage.format()), + gli::extent2d(sourceImage.width(), sourceImage.height())); + auto sourceSize = sourceImage.byteCount(); + assert(sourceSize == workTexture[workTexture.base_level()].size()); + memcpy(workTexture[workTexture.base_level()].data(), sourceImage.constBits(), sourceSize); + + QString resultFile = getKtxFileName(sourceFile) ; + gli::texture2d TextureMipmaped = gli::generate_mipmaps(workTexture, gli::FILTER_LINEAR); + gli::save(TextureMipmaped, resultFile.toLocal8Bit().data()); + gli::texture loaded = gli::load(resultFile.toLocal8Bit().data()); + return sourceFile; +} + + +gpu::TexturePointer processTexture(const QString& sourceFile) { + auto ktxFile = convertTexture(sourceFile); + gli::texture texture = gli::load(ktxFile.toLocal8Bit().data()); + if (texture.empty()) { + return gpu::TexturePointer(); + } + // FIXME load the actual KTX texture + return gpu::TexturePointer(); +} diff --git a/tests/render-texture-load/src/GLIHelpers.h b/tests/render-texture-load/src/GLIHelpers.h new file mode 100644 index 0000000000..c2841311a9 --- /dev/null +++ b/tests/render-texture-load/src/GLIHelpers.h @@ -0,0 +1,47 @@ +// +// Created by Bradley Austin Davis on 2016/09/03 +// Copyright 2013-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 +// +#pragma once +#ifndef _GLIHelpers_H_ +#define _GLIHelpers_H_ + +#include +#include + +// Work around for a bug in the MSVC compiler that chokes when you use GLI and Qt headers together. +#define gli glm + +#ifdef Q_OS_MAC +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wempty-body" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-result" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + +#include + +#ifdef Q_OS_MAC +#pragma clang diagnostic pop +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#include + +gpu::TexturePointer processTexture(const QString& file); + +#endif diff --git a/tests/render-texture-load/src/main.cpp b/tests/render-texture-load/src/main.cpp index 04bce72757..a1c5f74777 100644 --- a/tests/render-texture-load/src/main.cpp +++ b/tests/render-texture-load/src/main.cpp @@ -11,9 +11,6 @@ #include #include -#include -#include - #include #include #include @@ -41,6 +38,7 @@ #include +#include "GLIHelpers.h" #include #include #include @@ -55,15 +53,15 @@ #include #include #include -#include -#include -#include + +#include +#include extern QThread* RENDER_THREAD; static const QString DATA_SET = "https://hifi-content.s3.amazonaws.com/austin/textures.zip"; -static const QTemporaryDir DATA_DIR; - +static QDir DATA_DIR = QDir(QString("h:/textures")); +static QTemporaryDir* DOWNLOAD_DIR = nullptr; class FileDownloader : public QObject { Q_OBJECT @@ -81,7 +79,7 @@ public: } } -private slots: + private slots: void fileDownloaded(QNetworkReply* pReply) { _handler(pReply->readAll()); pReply->deleteLater(); @@ -132,8 +130,6 @@ public: _gpuContext = std::make_shared(); _backend = _gpuContext->getBackend(); _context.makeCurrent(); - DependencyManager::get()->init(); - _context.makeCurrent(); initContext.create(); _context.doneCurrent(); std::unique_lock lock(_mutex); @@ -191,7 +187,7 @@ public: _gpuContext->executeFrame(frame); { - + auto geometryCache = DependencyManager::get(); gpu::Batch presentBatch; presentBatch.setViewportTransform({ 0, 0, _size.width(), _size.height() }); @@ -277,16 +273,6 @@ public: } }; -QString fileForPath(const QString& name) { - QCryptographicHash hash(QCryptographicHash::Md5); - hash.addData(name.toLocal8Bit().data(), name.length()); - QString hashStr = QString(hash.result().toHex()); - auto dot = name.lastIndexOf('.'); - QString extension = name.right(name.length() - dot); - QString result = DATA_DIR.path() + "/" + hashStr + extension; - return result; -} - // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { public: @@ -296,7 +282,6 @@ public: //DependencyManager::registerInheritance(); DependencyManager::set(); DependencyManager::set(NodeType::Agent); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -316,7 +301,7 @@ public: _currentTexture = _textures.end(); { QStringList stringList; - QFile textFile("h:/textures/loads.txt"); + QFile textFile(DATA_DIR.path() + "/loads.txt"); textFile.open(QFile::ReadOnly); //... (open the file for reading, etc.) QTextStream textStream(&textFile); @@ -332,8 +317,7 @@ public: auto index = s.indexOf(" "); QString timeStr = s.left(index); auto time = timeStr.toUInt(); - QString path = s.right(s.length() - index).trimmed(); - path = fileForPath(path); + QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed(); qDebug() << "Path " << path; if (!QFileInfo(path).exists()) { continue; @@ -341,7 +325,7 @@ public: _textureLoads.push({ time, path, s }); } } - + installEventFilter(this); QThreadPool::globalInstance()->setMaxThreadCount(2); QThread::currentThread()->setPriority(QThread::HighestPriority); @@ -436,7 +420,7 @@ private: QSize windowSize = _size; auto framebufferCache = DependencyManager::get(); framebufferCache->setFrameBufferSize(windowSize); - + // Final framebuffer that will be handled to the display-plugin render(); @@ -462,8 +446,9 @@ private: qDebug() << "Missing file " << front.file; } else { qDebug() << "Loading " << front.src; + auto file = front.file.toLocal8Bit().toStdString(); + processTexture(file.c_str()); _textures.push_back(DependencyManager::get()->getImageTexture(front.file)); - _currentTexture = _textures.begin(); } _textureLoads.pop(); if (_textureLoads.empty()) { @@ -481,7 +466,7 @@ private: }); PROFILE_RANGE(__FUNCTION__); auto framebuffer = DependencyManager::get()->getFramebuffer(); - + gpu::doInBatch(gpuContext, [&](gpu::Batch& batch) { batch.enableStereo(false); batch.setFramebuffer(framebuffer); @@ -494,8 +479,7 @@ private: } if (_currentTexture == _textures.end()) { _currentTexture = _textures.begin(); - } - + } if (_currentTexture != _textures.end()) { batch.setResourceTexture(0, *_currentTexture); } @@ -505,7 +489,7 @@ private: auto frame = gpuContext->endFrame(); frame->framebuffer = framebuffer; - frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){ + frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) { DependencyManager::get()->releaseFramebuffer(framebuffer); }; _renderThread.submitFrame(frame); @@ -546,20 +530,23 @@ hifi.gpu=true )V0G0N"; void unzipTestData(const QByteArray& zipData) { + DOWNLOAD_DIR = new QTemporaryDir(); + QTemporaryDir& tempDir = *DOWNLOAD_DIR; QTemporaryFile zipFile; + if (zipFile.open()) { zipFile.write(zipData); zipFile.close(); } qDebug() << zipFile.fileName(); - if (!DATA_DIR.isValid()) { + if (!tempDir.isValid()) { qFatal("Unable to create temp dir"); } - + DATA_DIR = QDir(tempDir.path()); + //auto files = JlCompress::getFileList(zipData); auto files = JlCompress::extractDir(zipFile.fileName(), DATA_DIR.path()); qDebug() << DATA_DIR.path(); - } int main(int argc, char** argv) { @@ -570,12 +557,14 @@ int main(int argc, char** argv) { qInstallMessageHandler(messageHandler); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); + if (!DATA_DIR.exists()) { + FileDownloader(DATA_SET, [&](const QByteArray& data) { + qDebug() << "Fetched size " << data.size(); + unzipTestData(data); + }).waitForDownload(); + } + - FileDownloader(DATA_SET, [&](const QByteArray& data) { - qDebug() << "Fetched size " << data.size(); - unzipTestData(data); - }).waitForDownload(); - QTestWindow::setup(); QTestWindow window; app.exec();