From 49a91e3a0417f6a47aaaa18a40c95b5e6f3bca10 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 09:09:29 -0700 Subject: [PATCH 01/42] Update Oculus SDK --- cmake/externals/LibOVR/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index 5b8a689a9a..54a4a47929 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -20,8 +20,8 @@ if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.3.0_public.zip - URL_MD5 a2dcf695e0f03a70fdd1ed7480585e82 + URL https://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.8.0_public.zip + URL_MD5 bea17e04acc1dd8cf7cabefa1b28cc3c CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" @@ -29,8 +29,8 @@ if (WIN32) ) ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) - - set(LIBOVR_DIR ${SOURCE_DIR}/OculusSDK/LibOVR) + message("LIBOVR dir ${SOURCE_DIR}") + set(LIBOVR_DIR ${SOURCE_DIR}/LibOVR) if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") set(LIBOVR_LIB_DIR ${LIBOVR_DIR}/Lib/Windows/x64/Release/VS2013 CACHE TYPE INTERNAL) else() @@ -38,6 +38,7 @@ if (WIN32) endif() set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${LIBOVR_DIR}/Include CACHE TYPE INTERNAL) + message("LIBOVR include dir ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS}") set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${LIBOVR_LIB_DIR}/LibOVR.lib CACHE TYPE INTERNAL) elseif(APPLE) From a7f0ba24ed1b5944afb620f81d0d10c99b6eaf94 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sat, 10 Sep 2016 13:26:30 -0700 Subject: [PATCH 02/42] Dynamic texture memory management --- interface/src/ui/CachesSizeDialog.cpp | 5 +- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 1 + libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp | 241 +++++++++++++- libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h | 2 +- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 73 ++--- libraries/gpu-gl/src/gpu/gl/GLTexture.h | 70 ++-- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 6 +- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 2 - .../src/gpu/gl41/GL41BackendTexture.cpp | 59 +--- libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 5 + libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 71 +++-- .../src/gpu/gl45/GL45BackendTexture.cpp | 300 +++++++++++++++--- .../src/model-networking/TextureCache.cpp | 3 +- tests/render-perf/src/main.cpp | 14 +- tests/render-texture-load/src/main.cpp | 125 +++++++- 15 files changed, 733 insertions(+), 244 deletions(-) diff --git a/interface/src/ui/CachesSizeDialog.cpp b/interface/src/ui/CachesSizeDialog.cpp index dee9452c73..935a6d126e 100644 --- a/interface/src/ui/CachesSizeDialog.cpp +++ b/interface/src/ui/CachesSizeDialog.cpp @@ -58,7 +58,10 @@ void CachesSizeDialog::confirmClicked(bool checked) { DependencyManager::get()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES); DependencyManager::get()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES); DependencyManager::get()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES); + // Disabling the texture cache because it's a liability in cases where we're overcommiting GPU memory +#if 0 DependencyManager::get()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES); +#endif QDialog::close(); } @@ -78,4 +81,4 @@ void CachesSizeDialog::reject() { void CachesSizeDialog::closeEvent(QCloseEvent* event) { QDialog::closeEvent(event); emit closed(); -} \ No newline at end of file +} diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index bc348e3c3f..29e66da020 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -365,6 +365,7 @@ protected: typedef void (GLBackend::*CommandCall)(const Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; friend class GLState; + friend class GLTexture; }; } } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp index 4bff5c87bd..39c3bd2f67 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.cpp @@ -12,9 +12,244 @@ using namespace gpu; using namespace gpu::gl; -GLTexelFormat GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { - GLTexelFormat texel = { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }; - return texel; +GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { + GLenum result = GL_RGBA8; + switch (dstFormat.getDimension()) { + case gpu::SCALAR: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + case gpu::SRGB: + case gpu::SRGBA: + switch (dstFormat.getType()) { + case gpu::UINT32: + result = GL_R32UI; + break; + case gpu::INT32: + result = GL_R32I; + break; + case gpu::NUINT32: + result = GL_R8; + break; + case gpu::NINT32: + result = GL_R8_SNORM; + break; + case gpu::FLOAT: + result = GL_R32F; + break; + case gpu::UINT16: + result = GL_R16UI; + break; + case gpu::INT16: + result = GL_R16I; + break; + case gpu::NUINT16: + result = GL_R16; + break; + case gpu::NINT16: + result = GL_R16_SNORM; + break; + case gpu::HALF: + result = GL_R16F; + break; + case gpu::UINT8: + result = GL_R8UI; + break; + case gpu::INT8: + result = GL_R8I; + break; + case gpu::NUINT8: + if ((dstFormat.getSemantic() == gpu::SRGB || dstFormat.getSemantic() == gpu::SRGBA)) { + result = GL_SLUMINANCE8; + } else { + result = GL_R8; + } + break; + case gpu::NINT8: + result = GL_R8_SNORM; + break; + + default: + Q_UNREACHABLE(); + break; + } + break; + + case gpu::COMPRESSED_R: + result = GL_COMPRESSED_RED_RGTC1; + break; + + case gpu::R11G11B10: + // the type should be float + result = GL_R11F_G11F_B10F; + break; + + case gpu::DEPTH: + result = GL_DEPTH_COMPONENT32; + switch (dstFormat.getType()) { + case gpu::UINT32: + case gpu::INT32: + case gpu::NUINT32: + case gpu::NINT32: + result = GL_DEPTH_COMPONENT32; + break; + case gpu::FLOAT: + result = GL_DEPTH_COMPONENT32F; + break; + case gpu::UINT16: + case gpu::INT16: + case gpu::NUINT16: + case gpu::NINT16: + case gpu::HALF: + result = GL_DEPTH_COMPONENT16; + break; + case gpu::UINT8: + case gpu::INT8: + case gpu::NUINT8: + case gpu::NINT8: + result = GL_DEPTH_COMPONENT24; + break; + default: + Q_UNREACHABLE(); + break; + } + break; + + case gpu::DEPTH_STENCIL: + result = GL_DEPTH24_STENCIL8; + break; + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + case gpu::VEC2: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + result = GL_RG8; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC3: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + result = GL_RGB8; + break; + case gpu::SRGB: + case gpu::SRGBA: + result = GL_SRGB8; // standard 2.2 gamma correction color + break; + case gpu::COMPRESSED_RGB: + result = GL_COMPRESSED_RGB; + break; + case gpu::COMPRESSED_SRGB: + result = GL_COMPRESSED_SRGB; + break; + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + + break; + } + + case gpu::VEC4: { + switch (dstFormat.getSemantic()) { + case gpu::RGB: + result = GL_RGB8; + break; + case gpu::RGBA: + switch (dstFormat.getType()) { + case gpu::UINT32: + result = GL_RGBA32UI; + break; + case gpu::INT32: + result = GL_RGBA32I; + break; + case gpu::FLOAT: + result = GL_RGBA32F; + break; + case gpu::UINT16: + result = GL_RGBA16UI; + break; + case gpu::INT16: + result = GL_RGBA16I; + break; + case gpu::NUINT16: + result = GL_RGBA16; + break; + case gpu::NINT16: + result = GL_RGBA16_SNORM; + break; + case gpu::HALF: + result = GL_RGBA16F; + break; + case gpu::UINT8: + result = GL_RGBA8UI; + break; + case gpu::INT8: + result = GL_RGBA8I; + break; + case gpu::NUINT8: + result = GL_RGBA8; + break; + case gpu::NINT8: + result = GL_RGBA8_SNORM; + break; + case gpu::NUINT32: + case gpu::NINT32: + case gpu::NUM_TYPES: // quiet compiler + Q_UNREACHABLE(); + } + break; + case gpu::SRGB: + result = GL_SRGB8; + break; + case gpu::SRGBA: + result = GL_SRGB8_ALPHA8; // standard 2.2 gamma correction color + break; + case gpu::COMPRESSED_RGBA: + result = GL_COMPRESSED_RGBA; + break; + case gpu::COMPRESSED_SRGBA: + result = GL_COMPRESSED_SRGB_ALPHA; + break; + + // FIXME: WE will want to support this later + /* + case gpu::COMPRESSED_BC3_RGBA: + result = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case gpu::COMPRESSED_BC3_SRGBA: + result = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + break; + + case gpu::COMPRESSED_BC7_RGBA: + result = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + break; + case gpu::COMPRESSED_BC7_SRGBA: + result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + break; + */ + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + break; + } + + default: + qCDebug(gpugllogging) << "Unknown combination of texel format"; + } + return result; } GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h index bc3ec55066..94ded3dc23 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexelFormat.h @@ -21,7 +21,7 @@ public: static GLTexelFormat evalGLTexelFormat(const Element& dstFormat) { return evalGLTexelFormat(dstFormat, dstFormat); } - static GLTexelFormat evalGLTexelFormatInternal(const Element& dstFormat); + static GLenum evalGLTexelFormatInternal(const Element& dstFormat); static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat); }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 255258d762..d5a68bd99b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -118,34 +118,19 @@ float GLTexture::getMemoryPressure() { return (float)consumedGpuMemory / (float)availableTextureMemory; } -GLTexture::DownsampleSource::DownsampleSource(const std::weak_ptr& backend, GLTexture* oldTexture) : - _backend(backend), - _size(oldTexture ? oldTexture->_size : 0), - _texture(oldTexture ? oldTexture->takeOwnership() : 0), - _minMip(oldTexture ? oldTexture->_minMip : 0), - _maxMip(oldTexture ? oldTexture->_maxMip : 0) -{ -} -GLTexture::DownsampleSource::~DownsampleSource() { - if (_texture) { - auto backend = _backend.lock(); - if (backend) { - backend->releaseTexture(_texture, _size); - } - } -} - -GLTexture::GLTexture(const std::weak_ptr& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture, bool transferrable) : +// Create the texture and allocate storage +GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable) : GLObject(backend, texture, id), _storageStamp(texture.getStamp()), _target(getGLTextureType(texture)), _maxMip(texture.maxMip()), _minMip(texture.minMip()), _virtualSize(texture.evalTotalSize()), - _transferrable(transferrable), - _downsampleSource(backend, originalTexture) + _transferrable(transferrable) { + auto strongBackend = _backend.lock(); + strongBackend->recycle(); if (_transferrable) { uint16 mipCount = usedMipLevels(); _currentMaxMipCount = std::max(_currentMaxMipCount, mipCount); @@ -154,27 +139,9 @@ GLTexture::GLTexture(const std::weak_ptr& backend, const gpu::Texture } else { ++_textureCountByMips[mipCount]; } - } + } Backend::incrementTextureGPUCount(); Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize); -} - - -// Create the texture and allocate storage -GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable) : - GLTexture(backend, texture, id, nullptr, transferrable) -{ - // FIXME, do during allocation - //Backend::updateTextureGPUMemoryUsage(0, _size); - Backend::setGPUObject(texture, this); -} - -// Create the texture and copy from the original higher resolution version -GLTexture::GLTexture(const std::weak_ptr& backend, const gpu::Texture& texture, GLuint id, GLTexture* originalTexture) : - GLTexture(backend, texture, id, originalTexture, originalTexture->_transferrable) -{ - Q_ASSERT(_minMip >= originalTexture->_minMip); - // Set the GPU object last because that implicitly destroys the originalTexture object Backend::setGPUObject(texture, this); } @@ -196,6 +163,7 @@ GLTexture::~GLTexture() { auto backend = _backend.lock(); if (backend) { backend->releaseTexture(_id, _size); + backend->recycle(); } } Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); @@ -210,6 +178,28 @@ void GLTexture::createTexture() { }); } +void GLTexture::withPreservedTexture(std::function f) const { + GLint boundTex = -1; + switch (_target) { + case GL_TEXTURE_2D: + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + break; + + case GL_TEXTURE_CUBE_MAP: + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); + break; + + default: + qFatal("Unsupported texture type"); + } + (void)CHECK_GL_ERROR(); + + glBindTexture(_target, _texture); + f(); + glBindTexture(_target, boundTex); + (void)CHECK_GL_ERROR(); +} + void GLTexture::setSize(GLuint size) const { Backend::updateTextureGPUMemoryUsage(_size, size); const_cast(_size) = size; @@ -257,11 +247,6 @@ void GLTexture::postTransfer() { setSyncState(GLSyncState::Idle); ++_transferCount; - //// The public gltexture becaomes available - //_id = _privateTexture; - - _downsampleSource.reset(); - // At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory switch (_gpuObject.getType()) { case Texture::TEX_2D: diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index 742b223e36..e3bee4e103 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -73,14 +73,7 @@ public: return nullptr; } - // Do we need to reduce texture memory usage? - if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) { - // WARNING, this code path will essentially `delete this`, - // so no dereferencing of this instance should be done past this point - object = new GLTextureType(backend.shared_from_this(), texture, object); - _textureTransferHelper->transferTexture(texturePointer); - return nullptr; - } + ((GLTexture*)object)->updateMips(); return object; } @@ -96,30 +89,23 @@ public: } else { object = Backend::getGPUObject(*texture); } + if (!object) { return 0; } - GLuint result = object->_id; + if (!shouldSync) { + return object->_id; + } // Don't return textures that are in transfer state - if (shouldSync) { - if ((object->getSyncState() != GLSyncState::Idle) || - // Don't return transferrable textures that have never completed transfer - (!object->_transferrable || 0 != object->_transferCount)) { - // Will be either 0 or the original texture being downsampled. - result = object->_downsampleSource._texture; - } + if ((object->getSyncState() != GLSyncState::Idle) || + // Don't return transferrable textures that have never completed transfer + (!object->_transferrable || 0 != object->_transferCount)) { + return 0; } - return result; - } - - // Used by derived classes and helpers to ensure the actual GL object exceeds the lifetime of `this` - GLuint takeOwnership() { - GLuint result = _id; - const_cast(_id) = 0; - return result; + return object->_id; } ~GLTexture(); @@ -128,25 +114,11 @@ public: const Stamp _storageStamp; const GLenum _target; const uint16 _maxMip; - const uint16 _minMip; + uint16 _minMip; const GLuint _virtualSize; // theoretical size as expected Stamp _contentStamp { 0 }; const bool _transferrable; Size _transferCount { 0 }; - - struct DownsampleSource { - using Pointer = std::shared_ptr; - DownsampleSource(const std::weak_ptr& backend) : _backend(backend), _size(0), _texture(0), _minMip(0), _maxMip(0) {} - DownsampleSource(const std::weak_ptr& backend, GLTexture* originalTexture); - ~DownsampleSource(); - void reset() const { const_cast(_texture) = 0; } - const std::weak_ptr& _backend; - const GLuint _size { 0 }; - const GLuint _texture { 0 }; - const uint16 _minMip { 0 }; - const uint16 _maxMip { 0 }; - } _downsampleSource; - GLuint size() const { return _size; } GLSyncState getSyncState() const { return _syncState; } @@ -160,7 +132,7 @@ public: bool isReady() const; // Execute any post-move operations that must occur only on the main thread - void postTransfer(); + virtual void postTransfer(); bool isOverMaxMemory() const; @@ -170,33 +142,34 @@ public: 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); - - static GLenum getGLTextureType(const Texture& texture); // Return a floating point value indicating how much of the allowed // texture memory we are currently consuming. A value of 0 indicates // no texture memory usage, while a value of 1 indicates all available / allowed memory // is consumed. A value above 1 indicates that there is a problem. static float getMemoryPressure(); +protected: + + static const std::vector& getFaceTargets(GLenum textureType); + + static GLenum getGLTextureType(const Texture& texture); const GLuint _size { 0 }; // true size as reported by the gl api std::atomic _syncState { GLSyncState::Idle }; GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable); - GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, GLTexture* originalTexture); void setSyncState(GLSyncState syncState) { _syncState = syncState; } void createTexture(); - + + virtual void updateMips() {} virtual void allocateStorage() const = 0; virtual void updateSize() const = 0; virtual void syncSampler() const = 0; virtual void generateMips() const = 0; - virtual void withPreservedTexture(std::function f) const = 0; + virtual void withPreservedTexture(std::function f) const; protected: void setSize(GLuint size) const; @@ -207,9 +180,6 @@ protected: virtual void finishTransfer(); private: - - GLTexture(const std::weak_ptr& backend, const gpu::Texture& gpuTexture, GLuint id, GLTexture* originalTexture, bool transferrable); - friend class GLTextureTransferHelper; friend class GLBackend; }; diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index ae8739bb3b..c66ea39f56 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -144,9 +144,9 @@ 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); - clientWait(); + //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); + //clientWait(); gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); gltexture->updateSize(); gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index c89024b7e8..5d03997b44 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -43,7 +43,6 @@ public: GLuint allocate(); public: GL41Texture(const std::weak_ptr& backend, const Texture& buffer, bool transferrable); - GL41Texture(const std::weak_ptr& backend, const Texture& buffer, GL41Texture* original); protected: void transferMip(uint16_t mipLevel, uint8_t face) const; @@ -52,7 +51,6 @@ public: void updateSize() 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 3d55802ec2..3fb729711d 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -40,30 +40,6 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texture, bool transf GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(), transferrable) {} -GL41Texture::GL41Texture(const std::weak_ptr& backend, const Texture& texture, GL41Texture* original) : GLTexture(backend, texture, allocate(), original) {} - -void GL41Texture::withPreservedTexture(std::function f) const { - GLint boundTex = -1; - switch (_target) { - case GL_TEXTURE_2D: - glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); - break; - - case GL_TEXTURE_CUBE_MAP: - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex); - break; - - default: - qFatal("Unsupported texture type"); - } - (void)CHECK_GL_ERROR(); - - glBindTexture(_target, _texture); - f(); - glBindTexture(_target, boundTex); - (void)CHECK_GL_ERROR(); -} - void GL41Texture::generateMips() const { withPreservedTexture([&] { glGenerateMipmap(_target); @@ -147,35 +123,12 @@ void GL41Texture::startTransfer() { glBindTexture(_target, _id); (void)CHECK_GL_ERROR(); - if (_downsampleSource._texture) { - GLuint fbo { 0 }; - glGenFramebuffers(1, &fbo); - (void)CHECK_GL_ERROR(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); - (void)CHECK_GL_ERROR(); - // 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(); - glCopyTexSubImage2D(target, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y); - (void)CHECK_GL_ERROR(); - } - } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &fbo); - } else { - // 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); - } + // 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); } } } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index dad1f07ed3..bae6326e8f 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -147,3 +147,8 @@ void GL45Backend::do_multiDrawIndexedIndirect(const Batch& batch, size_t paramOf _stats._DSNumAPIDrawcalls++; (void)CHECK_GL_ERROR(); } + +void GL45Backend::recycle() const { + Parent::recycle(); + derezTextures(); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index db297e77fd..c78e9888ca 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -18,29 +18,6 @@ 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(std::vector& dest); - bool increment(); - TransferState(GLTexture& texture); -}; - class GL45Backend : public GLBackend { using Parent = GLBackend; // Context Backend static interface required @@ -55,12 +32,47 @@ public: 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(); + void postTransfer() override; + + struct SparseInfo { + GL45Texture& _texture; + uvec3 _pageDimensions; + GLuint _maxSparseLevel { 0 }; + uint32_t _maxPages { 0 }; + uint32_t _pageBytes { 0 }; + SparseInfo(GL45Texture& texture); + void update(); + uvec3 getPageCounts(const uvec3& dimensions) const; + uint32_t getPageCount(const uvec3& dimensions) const; + }; + + struct TransferState { + GL45Texture& _texture; + GLTexelFormat _texelFormat; + uint8_t _face { 0 }; + uint16_t _mipLevel { 0 }; + uint32_t _bytesPerLine { 0 }; + uint32_t _bytesPerPixel { 0 }; + uint32_t _bytesPerPage { 0 }; + + uvec3 _mipDimensions; + uvec3 _mipOffset; + const uint8_t* _srcPointer { nullptr }; + uvec3 currentPageSize() const; + void updateMip(); + void populatePage(std::vector& dest); + bool increment(); + TransferState(GL45Texture& texture); + }; + protected: + void updateMips() override; + void stripToMip(uint16_t newMinMip); void startTransfer() override; bool continueTransfer() override; + void finishTransfer() 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; @@ -69,12 +81,21 @@ public: void syncSampler() const override; void generateMips() const override; void withPreservedTexture(std::function f) const override; - + void derez(); + SparseInfo _sparseInfo; TransferState _transferState; + uint32_t _allocatedPages { 0 }; + uint32_t _lastMipAllocatedPages { 0 }; + bool _sparse { false }; + + friend class GL45Backend; }; protected: + void recycle() const override; + void derezTextures() const; + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index b511ed7811..a1c9129887 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -24,28 +24,66 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; +#ifdef THREADED_TEXTURE_TRANSFER #define SPARSE_TEXTURES 1 +#else +#define SPARSE_TEXTURES 0 +#endif // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) using GL45Texture = GL45Backend::GL45Texture; +static std::map> texturesByMipCounts; + GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { return GL45Texture::sync(*this, texture, transfer); } -TransferState::TransferState(GLTexture& texture) : _texture(texture) { +using SparseInfo = GL45Backend::GL45Texture::SparseInfo; + +SparseInfo::SparseInfo(GL45Texture& texture) + : _texture(texture) { } -void TransferState::updateSparse() { +void SparseInfo::update() { glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); - _internalFormat = gl::GLTexelFormat::evalGLTexelFormat(_texture._gpuObject.getTexelFormat(), _texture._gpuObject.getTexelFormat()).internalFormat; + GLenum 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); + 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); + _pageDimensions = uvec3(pageSize); + _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); + _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; + + for (uint16_t mipLevel = 0; mipLevel <= _maxSparseLevel; ++mipLevel) { + auto mipDimensions = _texture._gpuObject.evalMipDimensions(mipLevel); + auto mipPageCount = getPageCount(mipDimensions); + _maxPages += mipPageCount; + } + if (_texture._target == GL_TEXTURE_CUBE_MAP) { + _maxPages *= GLTexture::CUBE_NUM_FACES; + } +} + +uvec3 SparseInfo::getPageCounts(const uvec3& dimensions) const { + auto result = (dimensions / _pageDimensions) + + glm::clamp(dimensions % _pageDimensions, glm::uvec3(0), glm::uvec3(1)); + return result; + + +} + +uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { + auto pageCounts = getPageCounts(dimensions); + return pageCounts.x * pageCounts.y * pageCounts.z; +} + +using TransferState = GL45Backend::GL45Texture::TransferState; + +TransferState::TransferState(GL45Texture& texture) : _texture(texture) { } void TransferState::updateMip() { @@ -64,18 +102,19 @@ void TransferState::updateMip() { } bool TransferState::increment() { - if ((_mipOffset.x + _pageSize.x) < _mipDimensions.x) { - _mipOffset.x += _pageSize.x; + const SparseInfo& sparse = _texture._sparseInfo; + if ((_mipOffset.x + sparse._pageDimensions.x) < _mipDimensions.x) { + _mipOffset.x += sparse._pageDimensions.x; return true; } - if ((_mipOffset.y + _pageSize.y) < _mipDimensions.y) { + if ((_mipOffset.y + sparse._pageDimensions.y) < _mipDimensions.y) { _mipOffset.x = 0; - _mipOffset.y += _pageSize.y; + _mipOffset.y += sparse._pageDimensions.y; return true; } - if (_mipOffset.z + _pageSize.z < _mipDimensions.z) { + if (_mipOffset.z + sparse._pageDimensions.z < _mipDimensions.z) { _mipOffset.x = 0; _mipOffset.y = 0; ++_mipOffset.z; @@ -125,7 +164,7 @@ void TransferState::populatePage(std::vector& buffer) { } uvec3 TransferState::currentPageSize() const { - return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _pageSize); + return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _texture._sparseInfo._pageDimensions); } GLuint GL45Texture::allocate(const Texture& texture) { @@ -139,25 +178,44 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { } GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) - : GLTexture(backend, texture, allocate(texture), transferrable), _transferState(*this) { - + : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { #if SPARSE_TEXTURES - if (transferrable) { + _sparse = _transferrable; +#endif + if (_sparse) { glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); } -#endif } -GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLTexture* original) - : GLTexture(backend, texture, allocate(texture), original), _transferState(*this) { } - 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); - // } - //} + if (_sparse) { + auto mipLevels = usedMipLevels(); + if (texturesByMipCounts.count(mipLevels)) { + auto& textures = texturesByMipCounts[mipLevels]; + textures.erase(this); + if (textures.empty()) { + texturesByMipCounts.erase(mipLevels); + } + } + + auto originalAllocatedPages = _allocatedPages; + auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); + uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); + for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { + auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions); + for (uint8_t face = 0; face < maxFace; ++face) { + glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, mipDimensions.x, mipDimensions.y, mipDimensions.z, GL_FALSE); + assert(deallocatedPages <= _allocatedPages); + _allocatedPages -= deallocatedPages; + } + } + if (0 != _allocatedPages) { + auto maxSize = _gpuObject.evalMipDimensions(0); + qDebug() << "Allocated pages remaining " << _id << " " << _allocatedPages; + qDebug() << originalAllocatedPages; + } + } } void GL45Texture::withPreservedTexture(std::function f) const { @@ -183,19 +241,20 @@ void GL45Texture::allocateStorage() const { } void GL45Texture::updateSize() const { - setSize(_virtualSize); - if (!_id) { - return; - } - if (_gpuObject.getTexelFormat().isCompressed()) { qFatal("Compressed textures not yet supported"); } + + if (_transferrable) { + setSize(_allocatedPages * _sparseInfo._pageBytes); + } else { + setSize(_virtualSize); + } } void GL45Texture::startTransfer() { Parent::startTransfer(); - _transferState.updateSparse(); + _sparseInfo.update(); _transferState.updateMip(); } @@ -207,14 +266,20 @@ bool GL45Texture::continueTransfer() { uvec3 pageSize = _transferState.currentPageSize(); uvec3 offset = _transferState._mipOffset; -#if SPARSE_TEXTURES - if (_transferState._mipLevel <= _transferState._maxSparseLevel) { - glTexturePageCommitmentEXT(_id, _transferState._mipLevel, + // FIXME we should be using the DSA for all of this + if (_sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { + if (_allocatedPages > _sparseInfo._maxPages) { + qDebug() << "Exceeded max page allocation!"; + } + glBindTexture(_target, _id); + // FIXME we should be using glTexturePageCommitmentEXT, but for some reason it causes out of memory errors. + // Either I'm not understanding how it should work or there's a driver bug. + glTexPageCommitmentARB(_target, _transferState._mipLevel, offset.x, offset.y, _transferState._face, pageSize.x, pageSize.y, pageSize.z, GL_TRUE); + ++_allocatedPages; } -#endif if (_transferState._srcPointer) { // Transfer the mip data @@ -236,16 +301,31 @@ bool GL45Texture::continueTransfer() { } serverWait(); - return _transferState.increment(); + auto currentMip = _transferState._mipLevel; + auto result = _transferState.increment(); + if (_transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { + auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); + auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); + auto newPages = _allocatedPages - _lastMipAllocatedPages; + if (newPages != mipExpectedPages) { + qWarning() << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; + } + _lastMipAllocatedPages = _allocatedPages; + } + return result; } -void GL45Backend::GL45Texture::syncSampler() const { +void GL45Texture::finishTransfer() { + Parent::finishTransfer(); +} + +void GL45Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); const auto& fm = FILTER_MODES[sampler.getFilter()]; glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - + if (sampler.doComparison()) { glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); @@ -257,9 +337,149 @@ void GL45Backend::GL45Texture::syncSampler() const { glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); + auto baseMip = std::max(sampler.getMipOffset(), _minMip); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip); glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); } +void GL45Texture::postTransfer() { + Parent::postTransfer(); + if (_transferrable) { + auto mipLevels = usedMipLevels(); + if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + auto& textureMap = texturesByMipCounts; + texturesByMipCounts[mipLevels].insert(this); + } + } +} + +void GL45Texture::stripToMip(uint16_t newMinMip) { + if (!_sparse) { + return; + } + + if (newMinMip < _minMip) { + qWarning() << "Cannot decrease the min mip"; + return; + } + + if (newMinMip >= _sparseInfo._maxSparseLevel) { + qWarning() << "Cannot increase the min mip into the mip tail"; + return; + } + + auto mipLevels = usedMipLevels(); + assert(0 != texturesByMipCounts.count(mipLevels)); + assert(0 != texturesByMipCounts[mipLevels].count(this)); + texturesByMipCounts[mipLevels].erase(this); + if (texturesByMipCounts[mipLevels].empty()) { + texturesByMipCounts.erase(mipLevels); + } + + // FIXME this shouldn't be necessary should it? +#if 1 + glGenerateTextureMipmap(_id); +#else + static GLuint framebuffers[2] = { 0, 0 }; + static std::once_flag initFramebuffers; + std::call_once(initFramebuffers, [&] { + glCreateFramebuffers(2, framebuffers); + }); + auto readSize = _gpuObject.evalMipDimensions(_minMip); + auto drawSize = _gpuObject.evalMipDimensions(newMinMip); + glNamedFramebufferTexture(framebuffers[0], GL_COLOR_ATTACHMENT0, _id, _minMip); + glNamedFramebufferTexture(framebuffers[1], GL_COLOR_ATTACHMENT0, _id, newMinMip); + glBlitNamedFramebuffer(framebuffers[0], framebuffers[1], + 0, 0, readSize.x, readSize.y, + 0, 0, drawSize.x, drawSize.y, + GL_COLOR_BUFFER_BIT, GL_LINEAR); +#endif + + uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); + for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { + auto mipDimensions = _gpuObject.evalMipDimensions(mip); + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions); + for (uint8_t face = 0; face < maxFace; ++face) { + glTexturePageCommitmentEXT(_id, mip, + 0, 0, face, + mipDimensions.x, mipDimensions.y, mipDimensions.z, + GL_FALSE); + assert(deallocatedPages < _allocatedPages); + _allocatedPages -= deallocatedPages; + } + } + + _minMip = newMinMip; + // Re-sync the sampler to force access to the new mip level + syncSampler(); + size_t oldSize = _size; + updateSize(); + size_t newSize = _size; + if (newSize > oldSize) { + qDebug() << "WTF"; + qDebug() << "\told size " << oldSize; + qDebug() << "\tnew size " << newSize; + } + + // Re-insert into the texture-by-mips map if appropriate + mipLevels = usedMipLevels(); + if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + auto& textureMap = texturesByMipCounts; + texturesByMipCounts[mipLevels].insert(this); + } +} + +void GL45Texture::updateMips() { + if (!_sparse) { + return; + } + bool modified = false; + auto newMinMip = std::min(_gpuObject.minMip(), _sparseInfo._maxSparseLevel); + if (_minMip < newMinMip) { + stripToMip(newMinMip); + } +} + +void GL45Texture::derez() { + if (!_sparse) { + return; + } + assert(_minMip < _sparseInfo._maxSparseLevel); + assert(_minMip < _maxMip); + assert(_transferrable); + stripToMip(_minMip + 1); +} + +void GL45Backend::derezTextures() const { + if (GLTexture::getMemoryPressure() < 1.0f) { + return; + } + qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); + qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + + if (texturesByMipCounts.empty()) { + qDebug() << "No available textures to derez"; + return; + } + + auto mipLevel = texturesByMipCounts.rbegin()->first; + if (mipLevel <= 1) { + qDebug() << "Max mip levels " << mipLevel; + return; + } + + auto& textureMap = texturesByMipCounts; + auto newMipLevel = mipLevel - 1; + qDebug() << "Derez a texture"; + GL45Texture* targetTexture = nullptr; + { + auto& textures = texturesByMipCounts[mipLevel]; + assert(!textures.empty()); + targetTexture = *textures.begin(); + } + targetTexture->derez(); + + qDebug() << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); +} diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 32a6f4c323..5bb983c7f9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -35,8 +35,7 @@ #include "ModelNetworkingLogging.h" TextureCache::TextureCache() { - const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE; - setUnusedResourceCacheSize(TEXTURE_DEFAULT_UNUSED_MAX_SIZE); + setUnusedResourceCacheSize(0); setObjectName("TextureCache"); // Expose enum Type to JS/QML via properties diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 19bec7767d..267d192c7f 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -666,6 +666,14 @@ protected: toggleCulling(); return; + case Qt::Key_Home: + gpu::Texture::setAllowedGPUMemoryUsage(0); + return; + + case Qt::Key_End: + gpu::Texture::setAllowedGPUMemoryUsage(MB_TO_BYTES(256)); + return; + default: break; @@ -776,10 +784,11 @@ private: }; void updateText() { - QString title = QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4") + QString title = QString("FPS %1 Culling %2 TextureMemory GPU %3 CPU %4 Max GPU %5") .arg(_fps).arg(_cullingEnabled) .arg(toHumanSize(gpu::Context::getTextureGPUMemoryUsage(), 2)) - .arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2)); + .arg(toHumanSize(gpu::Texture::getTextureCPUMemoryUsage(), 2)) + .arg(toHumanSize(gpu::Texture::getAllowedGPUMemoryUsage(), 2)); setTitle(title); #if 0 { @@ -1111,7 +1120,6 @@ int main(int argc, char** argv) { QCoreApplication::setApplicationName("RenderPerf"); QCoreApplication::setOrganizationName("High Fidelity"); QCoreApplication::setOrganizationDomain("highfidelity.com"); - qInstallMessageHandler(messageHandler); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow::setup(); diff --git a/tests/render-texture-load/src/main.cpp b/tests/render-texture-load/src/main.cpp index a1c5f74777..ca0416baeb 100644 --- a/tests/render-texture-load/src/main.cpp +++ b/tests/render-texture-load/src/main.cpp @@ -297,8 +297,6 @@ public: }; QTestWindow() { - - _currentTexture = _textures.end(); { QStringList stringList; QFile textFile(DATA_DIR.path() + "/loads.txt"); @@ -318,12 +316,13 @@ public: QString timeStr = s.left(index); auto time = timeStr.toUInt(); QString path = DATA_DIR.path() + "/" + s.right(s.length() - index).trimmed(); - qDebug() << "Path " << path; if (!QFileInfo(path).exists()) { continue; } - _textureLoads.push({ time, path, s }); + qDebug() << "Path " << path; + _texturesFiles.push_back({ time, path, s }); } + _textures.resize(_texturesFiles.size()); } installEventFilter(this); @@ -383,6 +382,33 @@ protected: } void keyPressEvent(QKeyEvent* event) override { + switch (event->key()) { + case Qt::Key_Left: + prevTexture(); + break; + case Qt::Key_Right: + nextTexture(); + break; + case Qt::Key_Return: + reportMemory(); + break; + case Qt::Key_PageDown: + derezTexture(); + break; + case Qt::Key_Home: + unloadAll(); + break; + case Qt::Key_End: + loadAll(); + break; + case Qt::Key_Down: + loadTexture(); + break; + case Qt::Key_Up: + unloadTexture(); + break; + } + QWindow::keyPressEvent(event); } void keyReleaseEvent(QKeyEvent* event) override { @@ -395,10 +421,80 @@ protected: resizeWindow(ev->size()); } + void nextTexture() { + if (_textures.empty()) { + return; + } + auto textureCount = _textures.size(); + _currentTextureIndex = (_currentTextureIndex + 1) % textureCount; + loadTexture(); + } + + void prevTexture() { + if (_textures.empty()) { + return; + } + auto textureCount = _textures.size(); + _currentTextureIndex = (_currentTextureIndex + textureCount - 1) % textureCount; + loadTexture(); + } + + void reportMemory() { + static GLint lastMemory = 0; + GLint availableMem; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &availableMem); + qDebug() << "Memory available " << availableMem; + if (lastMemory != 0) { + qDebug() << "Delta " << availableMem - lastMemory; + } + lastMemory = availableMem; + } + + void derezTexture() { + if (!_textures[_currentTextureIndex]) { + return; + } + auto texture = _textures[_currentTextureIndex]; + texture->setMinMip(texture->minMip() + 1); + } + + void loadTexture() { + if (_textures[_currentTextureIndex]) { + return; + } + auto file = _texturesFiles[_currentTextureIndex].file; + qDebug() << "Loading texture " << file; + _textures[_currentTextureIndex] = DependencyManager::get()->getImageTexture(file); + } + + void unloadTexture() { + if (_textures.empty()) { + return; + } + _textures[_currentTextureIndex].reset(); + } + + void loadAll() { + for (auto i = 0; i < _texturesFiles.size(); ++i) { + if (_textures[i]) { + continue; + } + auto file = _texturesFiles[i].file; + qDebug() << "Loading texture " << file; + _textures[i] = DependencyManager::get()->getImageTexture(file); + } + } + + void unloadAll() { + for (auto& texture : _textures) { + texture.reset(); + } + } + private: - std::queue _textureLoads; - std::list _textures; - std::list::iterator _currentTexture; + size_t _currentTextureIndex { 0 }; + std::vector _texturesFiles; + std::vector _textures; uint16_t _fps; gpu::PipelinePointer _simplePipeline; @@ -438,7 +534,8 @@ private: auto now = usecTimestampNow(); static auto last = now; auto delta = (now - last) / USECS_PER_MSEC; - if (!_textureLoads.empty()) { +#if 0 + if (!_textures.empty()) { const auto& front = _textureLoads.front(); if (delta >= front.time) { QFileInfo fileInfo(front.file); @@ -456,6 +553,7 @@ private: } } } +#endif } void render() { @@ -474,14 +572,8 @@ private: auto vpsize = framebuffer->getSize(); auto vppos = ivec2(0); batch.setViewportTransform(ivec4(vppos, vpsize)); - if (_currentTexture != _textures.end()) { - ++_currentTexture; - } - if (_currentTexture == _textures.end()) { - _currentTexture = _textures.begin(); - } - if (_currentTexture != _textures.end()) { - batch.setResourceTexture(0, *_currentTexture); + if (!_textures.empty()) { + batch.setResourceTexture(0, _textures[_currentTextureIndex]); } batch.setPipeline(_simplePipeline); batch.draw(gpu::TRIANGLE_STRIP, 4); @@ -564,7 +656,6 @@ int main(int argc, char** argv) { }).waitForDownload(); } - QTestWindow::setup(); QTestWindow window; app.exec(); From 93b0364f73827c877ff1254efb322ba489c3baf5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 14 Sep 2016 10:17:20 -0700 Subject: [PATCH 03/42] Working on sparse stability --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 38 --------- libraries/gpu-gl/src/gpu/gl/GLTexture.h | 2 - .../src/gpu/gl45/GL45BackendTexture.cpp | 82 ++++++++----------- tests/render-perf/src/main.cpp | 34 -------- 4 files changed, 34 insertions(+), 122 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index d5a68bd99b..a04ae13b05 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -17,8 +17,6 @@ using namespace gpu; using namespace gpu::gl; std::shared_ptr GLTexture::_textureTransferHelper; -static std::map _textureCountByMips; -static uint16 _currentMaxMipCount { 0 }; // FIXME placeholder for texture memory over-use #define DEFAULT_MAX_MEMORY_MB 256 @@ -131,34 +129,12 @@ GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& tex { auto strongBackend = _backend.lock(); strongBackend->recycle(); - if (_transferrable) { - uint16 mipCount = usedMipLevels(); - _currentMaxMipCount = std::max(_currentMaxMipCount, mipCount); - if (!_textureCountByMips.count(mipCount)) { - _textureCountByMips[mipCount] = 1; - } else { - ++_textureCountByMips[mipCount]; - } - } Backend::incrementTextureGPUCount(); Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize); Backend::setGPUObject(texture, this); } GLTexture::~GLTexture() { - if (_transferrable) { - uint16 mipCount = usedMipLevels(); - Q_ASSERT(_textureCountByMips.count(mipCount)); - auto& numTexturesForMipCount = _textureCountByMips[mipCount]; - --numTexturesForMipCount; - if (0 == numTexturesForMipCount) { - _textureCountByMips.erase(mipCount); - if (mipCount == _currentMaxMipCount) { - _currentMaxMipCount = (_textureCountByMips.empty() ? 0 : _textureCountByMips.rbegin()->first); - } - } - } - if (_id) { auto backend = _backend.lock(); if (backend) { @@ -213,20 +189,6 @@ bool GLTexture::isOutdated() const { return GLSyncState::Idle == _syncState && _contentStamp < _gpuObject.getDataStamp(); } -bool GLTexture::isOverMaxMemory() const { - // FIXME switch to using the max mip count used from the previous frame - if (usedMipLevels() < _currentMaxMipCount) { - return false; - } - Q_ASSERT(usedMipLevels() == _currentMaxMipCount); - - if (getMemoryPressure() < 1.0f) { - return false; - } - - return true; -} - bool GLTexture::isReady() const { // If we have an invalid texture, we're never ready if (isInvalid()) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index e3bee4e103..a54e45989d 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -134,8 +134,6 @@ public: // Execute any post-move operations that must occur only on the main thread virtual void postTransfer(); - bool isOverMaxMemory() const; - uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } static const size_t CUBE_NUM_FACES = 6; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index a1c9129887..889229c1aa 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "../gl/GLTexelFormat.h" @@ -24,11 +25,8 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -#ifdef THREADED_TEXTURE_TRANSFER -#define SPARSE_TEXTURES 1 -#else -#define SPARSE_TEXTURES 0 -#endif +static const QString DEBUG_FLAG("HIFI_ENABLE_SPARSE_TEXTURES"); +static bool enableSparseTextures = true; // QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) @@ -36,6 +34,7 @@ using namespace gpu::gl45; using GL45Texture = GL45Backend::GL45Texture; static std::map> texturesByMipCounts; +static Mutex texturesByMipCountsMutex; GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { return GL45Texture::sync(*this, texture, transfer); @@ -179,9 +178,9 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { -#if SPARSE_TEXTURES - _sparse = _transferrable; -#endif + + _sparse = _transferrable && (_target != GL_TEXTURE_CUBE_MAP); + if (_sparse) { glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); } @@ -190,11 +189,15 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& GL45Texture::~GL45Texture() { if (_sparse) { auto mipLevels = usedMipLevels(); - if (texturesByMipCounts.count(mipLevels)) { - auto& textures = texturesByMipCounts[mipLevels]; - textures.erase(this); - if (textures.empty()) { - texturesByMipCounts.erase(mipLevels); + + { + Lock lock(texturesByMipCountsMutex); + if (texturesByMipCounts.count(mipLevels)) { + auto& textures = texturesByMipCounts[mipLevels]; + textures.erase(this); + if (textures.empty()) { + texturesByMipCounts.erase(mipLevels); + } } } @@ -271,10 +274,10 @@ bool GL45Texture::continueTransfer() { if (_allocatedPages > _sparseInfo._maxPages) { qDebug() << "Exceeded max page allocation!"; } - glBindTexture(_target, _id); + //glBindTexture(_target, _id); // FIXME we should be using glTexturePageCommitmentEXT, but for some reason it causes out of memory errors. // Either I'm not understanding how it should work or there's a driver bug. - glTexPageCommitmentARB(_target, _transferState._mipLevel, + glTexturePageCommitmentEXT(_id, _transferState._mipLevel, offset.x, offset.y, _transferState._face, pageSize.x, pageSize.y, pageSize.z, GL_TRUE); @@ -303,7 +306,7 @@ bool GL45Texture::continueTransfer() { serverWait(); auto currentMip = _transferState._mipLevel; auto result = _transferState.increment(); - if (_transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { + if (_sparse && _transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); auto newPages = _allocatedPages - _lastMipAllocatedPages; @@ -346,10 +349,10 @@ void GL45Texture::syncSampler() const { void GL45Texture::postTransfer() { Parent::postTransfer(); - if (_transferrable) { + if (_sparse) { auto mipLevels = usedMipLevels(); if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { - auto& textureMap = texturesByMipCounts; + Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } } @@ -371,32 +374,16 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { } auto mipLevels = usedMipLevels(); - assert(0 != texturesByMipCounts.count(mipLevels)); - assert(0 != texturesByMipCounts[mipLevels].count(this)); - texturesByMipCounts[mipLevels].erase(this); - if (texturesByMipCounts[mipLevels].empty()) { - texturesByMipCounts.erase(mipLevels); + { + Lock lock(texturesByMipCountsMutex); + assert(0 != texturesByMipCounts.count(mipLevels)); + assert(0 != texturesByMipCounts[mipLevels].count(this)); + texturesByMipCounts[mipLevels].erase(this); + if (texturesByMipCounts[mipLevels].empty()) { + texturesByMipCounts.erase(mipLevels); + } } - // FIXME this shouldn't be necessary should it? -#if 1 - glGenerateTextureMipmap(_id); -#else - static GLuint framebuffers[2] = { 0, 0 }; - static std::once_flag initFramebuffers; - std::call_once(initFramebuffers, [&] { - glCreateFramebuffers(2, framebuffers); - }); - auto readSize = _gpuObject.evalMipDimensions(_minMip); - auto drawSize = _gpuObject.evalMipDimensions(newMinMip); - glNamedFramebufferTexture(framebuffers[0], GL_COLOR_ATTACHMENT0, _id, _minMip); - glNamedFramebufferTexture(framebuffers[1], GL_COLOR_ATTACHMENT0, _id, newMinMip); - glBlitNamedFramebuffer(framebuffers[0], framebuffers[1], - 0, 0, readSize.x, readSize.y, - 0, 0, drawSize.x, drawSize.y, - GL_COLOR_BUFFER_BIT, GL_LINEAR); -#endif - uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { auto mipDimensions = _gpuObject.evalMipDimensions(mip); @@ -425,8 +412,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); - if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { - auto& textureMap = texturesByMipCounts; + if (_sparse && mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } } @@ -443,9 +430,7 @@ void GL45Texture::updateMips() { } void GL45Texture::derez() { - if (!_sparse) { - return; - } + assert(_sparse); assert(_minMip < _sparseInfo._maxSparseLevel); assert(_minMip < _maxMip); assert(_transferrable); @@ -459,6 +444,7 @@ void GL45Backend::derezTextures() const { qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + Lock lock(texturesByMipCountsMutex); if (texturesByMipCounts.empty()) { qDebug() << "No available textures to derez"; return; @@ -479,7 +465,7 @@ void GL45Backend::derezTextures() const { assert(!textures.empty()); targetTexture = *textures.begin(); } + lock.unlock(); targetTexture->derez(); - qDebug() << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); } diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 267d192c7f..bbe1c33bb1 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -286,10 +286,6 @@ public: } _context.makeCurrent(); - glewExperimental = true; - glewInit(); - glGetError(); - _frameTimes.resize(FRAME_TIME_BUFFER_SIZE, 0); { auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); @@ -552,36 +548,6 @@ public: _renderThread.initialize(this, _initContext); _initContext.makeCurrent(); -#if 0 - glfwInit(); - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - resizeWindow(QSize(800, 600)); - _window = glfwCreateWindow(_size.width(), _size.height(), "Window Title", NULL, NULL); - if (!_window) { - throw std::runtime_error("Could not create window"); - } - - glfwSetWindowUserPointer(_window, this); - glfwSetKeyCallback(_window, KeyboardHandler); - glfwSetMouseButtonCallback(_window, MouseHandler); - glfwSetCursorPosCallback(_window, MouseMoveHandler); - glfwSetWindowCloseCallback(_window, CloseHandler); - glfwSetFramebufferSizeCallback(_window, FramebufferSizeHandler); - glfwSetScrollCallback(_window, MouseScrollHandler); - - - glfwMakeContextCurrent(_window); - GLDebug::setupLogger(this); -#endif - -#ifdef Q_OS_WIN - //wglSwapIntervalEXT(0); -#endif - // FIXME use a wait condition QThread::msleep(1000); _renderThread.submitFrame(gpu::FramePointer()); From a55669b83e783057c793714e17f4d99e6bfd5b95 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 14 Sep 2016 11:57:25 -0700 Subject: [PATCH 04/42] Only enable sparse textures by env variable --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 889229c1aa..e198417db4 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -26,7 +26,7 @@ using namespace gpu::gl; using namespace gpu::gl45; static const QString DEBUG_FLAG("HIFI_ENABLE_SPARSE_TEXTURES"); -static bool enableSparseTextures = true; // QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +static bool enableSparseTextures = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) @@ -179,7 +179,7 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { - _sparse = _transferrable && (_target != GL_TEXTURE_CUBE_MAP); + _sparse = enableSparseTextures && _transferrable && (_target != GL_TEXTURE_CUBE_MAP); if (_sparse) { glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); From 151df325194353f4ae19c837b1785dd7779f34a4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 01:17:23 -0700 Subject: [PATCH 05/42] Check sparse texture support before enabling --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 1 + libraries/gpu-gl/src/gpu/gl/GLTexture.h | 1 + .../src/gpu/gl45/GL45BackendTexture.cpp | 20 ++++++++++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index a04ae13b05..a279bec11c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -122,6 +122,7 @@ GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& tex GLObject(backend, texture, id), _storageStamp(texture.getStamp()), _target(getGLTextureType(texture)), + _internalFormat(gl::GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat())), _maxMip(texture.maxMip()), _minMip(texture.minMip()), _virtualSize(texture.evalTotalSize()), diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index a54e45989d..fa893ae52a 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -113,6 +113,7 @@ public: const GLuint& _texture { _id }; const Stamp _storageStamp; const GLenum _target; + const GLenum _internalFormat; const uint16 _maxMip; uint16 _minMip; const GLuint _virtualSize; // theoretical size as expected diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index e198417db4..5dd356349d 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -179,10 +179,13 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { - _sparse = enableSparseTextures && _transferrable && (_target != GL_TEXTURE_CUBE_MAP); - - if (_sparse) { - glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); + if (enableSparseTextures && _transferrable && (_target != GL_TEXTURE_CUBE_MAP)) { + GLint pageSizesCount = 0; + glGetInternalformativ(_target, _internalFormat, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, 1, &pageSizesCount); + if (pageSizesCount > 0) { + _sparse = true; + glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); + } } } @@ -231,15 +234,14 @@ void GL45Texture::generateMips() 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); if (_gpuObject.getTexelFormat().isCompressed()) { qFatal("Compressed textures not yet supported"); } + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); // Get the dimensions, accounting for the downgrade level Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); - glTextureStorage2D(_id, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y); + glTextureStorage2D(_id, usedMipLevels(), _internalFormat, dimensions.x, dimensions.y); (void)CHECK_GL_ERROR(); } @@ -368,7 +370,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { return; } - if (newMinMip >= _sparseInfo._maxSparseLevel) { + if (newMinMip > _sparseInfo._maxSparseLevel) { qWarning() << "Cannot increase the min mip into the mip tail"; return; } From 2b5ed86a62d43cc91236ebe1c8bcfa9e88327aff Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 01:21:41 -0700 Subject: [PATCH 06/42] Fixing warnings --- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 14 +++++--------- tests/render-texture-load/src/main.cpp | 3 ++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 5dd356349d..9a9185cd7c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -204,7 +204,6 @@ GL45Texture::~GL45Texture() { } } - auto originalAllocatedPages = _allocatedPages; auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { @@ -216,10 +215,9 @@ GL45Texture::~GL45Texture() { _allocatedPages -= deallocatedPages; } } + if (0 != _allocatedPages) { - auto maxSize = _gpuObject.evalMipDimensions(0); - qDebug() << "Allocated pages remaining " << _id << " " << _allocatedPages; - qDebug() << originalAllocatedPages; + qWarning() << "Allocated pages remaining " << _id << " " << _allocatedPages; } } } @@ -424,7 +422,6 @@ void GL45Texture::updateMips() { if (!_sparse) { return; } - bool modified = false; auto newMinMip = std::min(_gpuObject.minMip(), _sparseInfo._maxSparseLevel); if (_minMip < newMinMip) { stripToMip(newMinMip); @@ -443,8 +440,6 @@ void GL45Backend::derezTextures() const { if (GLTexture::getMemoryPressure() < 1.0f) { return; } - qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); - qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); Lock lock(texturesByMipCountsMutex); if (texturesByMipCounts.empty()) { @@ -458,9 +453,10 @@ void GL45Backend::derezTextures() const { return; } + qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); + qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + auto& textureMap = texturesByMipCounts; - auto newMipLevel = mipLevel - 1; - qDebug() << "Derez a texture"; GL45Texture* targetTexture = nullptr; { auto& textures = texturesByMipCounts[mipLevel]; diff --git a/tests/render-texture-load/src/main.cpp b/tests/render-texture-load/src/main.cpp index ca0416baeb..fb0b16d16c 100644 --- a/tests/render-texture-load/src/main.cpp +++ b/tests/render-texture-load/src/main.cpp @@ -475,7 +475,7 @@ protected: } void loadAll() { - for (auto i = 0; i < _texturesFiles.size(); ++i) { + for (size_t i = 0; i < _texturesFiles.size(); ++i) { if (_textures[i]) { continue; } @@ -534,6 +534,7 @@ private: auto now = usecTimestampNow(); static auto last = now; auto delta = (now - last) / USECS_PER_MSEC; + Q_UNUSED(delta); #if 0 if (!_textures.empty()) { const auto& front = _textureLoads.front(); From 07ccbc6f82f940c68d9a28ab8ba8f0bb182eaf6c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 02:13:20 -0700 Subject: [PATCH 07/42] Fixing warnings --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 9a9185cd7c..ac1f4fddca 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -456,7 +456,6 @@ void GL45Backend::derezTextures() const { qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); - auto& textureMap = texturesByMipCounts; GL45Texture* targetTexture = nullptr; { auto& textures = texturesByMipCounts[mipLevel]; From f9857c7ac4d89898c43daa5f8ffdfcaf1920d72e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 14 Sep 2016 12:15:14 -0700 Subject: [PATCH 08/42] Disable threaded texture transfers --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 4 ++++ .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 18 ++++++++---------- .../gpu-gl/src/gpu/gl/GLTextureTransfer.h | 13 ++++++------- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index e3f391126b..1385a56f65 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -679,6 +679,10 @@ void GLBackend::recycle() const { glDeleteQueries((GLsizei)ids.size(), ids.data()); } } + +#ifndef THREADED_TEXTURE_TRANSFER + gl::GLTexture::_textureTransferHelper->process(); +#endif } void GLBackend::setCameraCorrection(const Mat4& correction) { diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index c66ea39f56..4cb8e4fad1 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -35,6 +35,8 @@ GLTextureTransferHelper::GLTextureTransferHelper() { initialize(true, QThread::LowPriority); // Clean shutdown on UNIX, otherwise _canvas is freed early connect(qApp, &QCoreApplication::aboutToQuit, [&] { terminate(); }); +#else + initialize(false, QThread::LowPriority); #endif } @@ -43,23 +45,18 @@ GLTextureTransferHelper::~GLTextureTransferHelper() { if (isStillRunning()) { terminate(); } +#else + terminate(); #endif } void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) { GLTexture* object = Backend::getGPUObject(*texturePointer); -#ifdef THREADED_TEXTURE_TRANSFER Backend::incrementTextureGPUTransferCount(); object->setSyncState(GLSyncState::Pending); Lock lock(_mutex); _pendingTextures.push_back(texturePointer); -#else - for (object->startTransfer(); object->continueTransfer(); ) { } - object->finishTransfer(); - object->_contentStamp = texturePointer->getDataStamp(); - object->setSyncState(GLSyncState::Transferred); -#endif } void GLTextureTransferHelper::setup() { @@ -101,7 +98,6 @@ void GLTextureTransferHelper::shutdown() { } bool GLTextureTransferHelper::process() { -#ifdef THREADED_TEXTURE_TRANSFER // Take any new textures off the queue TextureList newTransferTextures; { @@ -123,7 +119,9 @@ bool GLTextureTransferHelper::process() { // No transfers in progress, sleep if (_transferringTextures.empty()) { +#ifdef THREADED_TEXTURE_TRANSFER QThread::usleep(1); +#endif return true; } @@ -159,6 +157,7 @@ bool GLTextureTransferHelper::process() { _textureIterator = _transferringTextures.erase(_textureIterator); } +#ifdef THREADED_TEXTURE_TRANSFER if (!_transferringTextures.empty()) { // Don't saturate the GPU clientWait(); @@ -166,8 +165,7 @@ bool GLTextureTransferHelper::process() { // 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 d2207df7e6..a880f42394 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -18,7 +18,7 @@ #include "GLShared.h" #ifdef Q_OS_WIN -#define THREADED_TEXTURE_TRANSFER +//#define THREADED_TEXTURE_TRANSFER #endif namespace gpu { namespace gl { @@ -33,7 +33,6 @@ public: ~GLTextureTransferHelper(); void transferTexture(const gpu::TexturePointer& texturePointer); -protected: void setup() override; void shutdown() override; bool process() override; @@ -41,6 +40,11 @@ protected: private: #ifdef THREADED_TEXTURE_TRANSFER ::gl::OffscreenContext _context; + // Framebuffers / renderbuffers for forcing access to the texture on the transfer thread + GLuint _drawRenderbuffer { 0 }; + GLuint _drawFramebuffer { 0 }; + GLuint _readFramebuffer { 0 }; +#endif // A mutex for protecting items access on the render and transfer threads Mutex _mutex; // Textures that have been submitted for transfer @@ -50,11 +54,6 @@ private: 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/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index ac1f4fddca..852af02287 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -26,7 +26,7 @@ using namespace gpu::gl; using namespace gpu::gl45; static const QString DEBUG_FLAG("HIFI_ENABLE_SPARSE_TEXTURES"); -static bool enableSparseTextures = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +static bool enableSparseTextures = true; // QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) From 70ec9783fa6d48a519b0ecd8ef1f272d150c7068 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 11:07:15 -0700 Subject: [PATCH 09/42] Only use sparse allocation for supported sizes / formats --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 5 +- .../src/gpu/gl45/GL45BackendTexture.cpp | 103 ++++++++++++++---- 2 files changed, 83 insertions(+), 25 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index c78e9888ca..9589c0dc7e 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -42,7 +42,10 @@ public: GLuint _maxSparseLevel { 0 }; uint32_t _maxPages { 0 }; uint32_t _pageBytes { 0 }; + bool _sparse { false }; + GLint _pageDimensionsIndex { 0 }; SparseInfo(GL45Texture& texture); + void maybeMakeSparse(); void update(); uvec3 getPageCounts(const uvec3& dimensions) const; uint32_t getPageCount(const uvec3& dimensions) const; @@ -86,8 +89,6 @@ public: TransferState _transferState; uint32_t _allocatedPages { 0 }; uint32_t _lastMipAllocatedPages { 0 }; - bool _sparse { false }; - friend class GL45Backend; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 852af02287..383e3b7c38 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -25,8 +25,8 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -static const QString DEBUG_FLAG("HIFI_ENABLE_SPARSE_TEXTURES"); -static bool enableSparseTextures = true; // QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +static const QString DEBUG_FLAG("HIFI_DISABLE_SPARSE_TEXTURES"); +static bool enableSparseTextures = !QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) @@ -35,6 +35,51 @@ using GL45Texture = GL45Backend::GL45Texture; static std::map> texturesByMipCounts; static Mutex texturesByMipCountsMutex; +using TextureTypeFormat = std::pair; +std::map> sparsePageDimensionsByFormat; +Mutex sparsePageDimensionsByFormatMutex; + + +static std::vector getPageDimensionsForFormat(const TextureTypeFormat& typeFormat) { + { + Lock lock(sparsePageDimensionsByFormatMutex); + if (sparsePageDimensionsByFormat.count(typeFormat)) { + return sparsePageDimensionsByFormat[typeFormat]; + } + } + GLint count = 0; + glGetInternalformativ(typeFormat.first, typeFormat.second, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, 1, &count); + + std::vector result; + if (count > 0) { + std::vector x, y, z; + x.resize(count); + glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_X_ARB, 1, &x[0]); + y.resize(count); + glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_Y_ARB, 1, &y[0]); + z.resize(count); + glGetInternalformativ(typeFormat.first, typeFormat.second, GL_VIRTUAL_PAGE_SIZE_Z_ARB, 1, &z[0]); + + result.resize(count); + for (GLint i = 0; i < count; ++i) { + result[i] = uvec3(x[i], y[i], z[i]); + } + qDebug() << "Got " << count << " page sizes"; + } + + { + Lock lock(sparsePageDimensionsByFormatMutex); + if (0 == sparsePageDimensionsByFormat.count(typeFormat)) { + sparsePageDimensionsByFormat[typeFormat] = result; + } + } + + return result; +} + +static std::vector getPageDimensionsForFormat(GLenum target, GLenum format) { + return getPageDimensionsForFormat({ target, format }); +} GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { return GL45Texture::sync(*this, texture, transfer); @@ -46,14 +91,31 @@ SparseInfo::SparseInfo(GL45Texture& texture) : _texture(texture) { } +void SparseInfo::maybeMakeSparse() { + const uvec3 dimensions = _texture._gpuObject.getDimensions(); + auto allowedPageDimensions = getPageDimensionsForFormat(_texture._target, _texture._internalFormat); + // In order to enable sparse the texture size must be an integer multiple of the page size + for (size_t i = 0; i < allowedPageDimensions.size(); ++i) { + _pageDimensionsIndex = (uint32_t) i; + _pageDimensions = allowedPageDimensions[i]; + // Is this texture an integer multiple of page dimensions? + if (uvec3(0) == (dimensions % _pageDimensions)) { + _sparse = true; + break; + } + } + + if (_sparse) { + glTextureParameteri(_texture._id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); + glTextureParameteri(_texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, _pageDimensionsIndex); + } else { + qDebug() << "Texture size " << dimensions.x << " x " << dimensions.y << " is not supported by any sparse page size"; + } +} + +// This can only be called after we've established our storage size void SparseInfo::update() { glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); - GLenum 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); - _pageDimensions = uvec3(pageSize); _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; @@ -179,18 +241,13 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { - if (enableSparseTextures && _transferrable && (_target != GL_TEXTURE_CUBE_MAP)) { - GLint pageSizesCount = 0; - glGetInternalformativ(_target, _internalFormat, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, 1, &pageSizesCount); - if (pageSizesCount > 0) { - _sparse = true; - glTextureParameteri(_id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); - } + if (enableSparseTextures && _transferrable) { + _sparseInfo.maybeMakeSparse(); } } GL45Texture::~GL45Texture() { - if (_sparse) { + if (_sparseInfo._sparse) { auto mipLevels = usedMipLevels(); { @@ -270,7 +327,7 @@ bool GL45Texture::continueTransfer() { uvec3 offset = _transferState._mipOffset; // FIXME we should be using the DSA for all of this - if (_sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { + if (_sparseInfo._sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { if (_allocatedPages > _sparseInfo._maxPages) { qDebug() << "Exceeded max page allocation!"; } @@ -306,7 +363,7 @@ bool GL45Texture::continueTransfer() { serverWait(); auto currentMip = _transferState._mipLevel; auto result = _transferState.increment(); - if (_sparse && _transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { + if (_sparseInfo._sparse && _transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); auto newPages = _allocatedPages - _lastMipAllocatedPages; @@ -349,7 +406,7 @@ void GL45Texture::syncSampler() const { void GL45Texture::postTransfer() { Parent::postTransfer(); - if (_sparse) { + if (_sparseInfo._sparse) { auto mipLevels = usedMipLevels(); if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { Lock lock(texturesByMipCountsMutex); @@ -359,7 +416,7 @@ void GL45Texture::postTransfer() { } void GL45Texture::stripToMip(uint16_t newMinMip) { - if (!_sparse) { + if (!_sparseInfo._sparse) { return; } @@ -412,14 +469,14 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); - if (_sparse && mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + if (_sparseInfo._sparse && mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } } void GL45Texture::updateMips() { - if (!_sparse) { + if (!_sparseInfo._sparse) { return; } auto newMinMip = std::min(_gpuObject.minMip(), _sparseInfo._maxSparseLevel); @@ -429,7 +486,7 @@ void GL45Texture::updateMips() { } void GL45Texture::derez() { - assert(_sparse); + assert(_sparseInfo._sparse); assert(_minMip < _sparseInfo._maxSparseLevel); assert(_minMip < _maxMip); assert(_transferrable); From 26a06b29145689d619b55b84d765f80fc439e486 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 12:40:32 -0700 Subject: [PATCH 10/42] Removing invalid comments --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 383e3b7c38..b6eae6e611 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -133,8 +133,6 @@ uvec3 SparseInfo::getPageCounts(const uvec3& dimensions) const { auto result = (dimensions / _pageDimensions) + glm::clamp(dimensions % _pageDimensions, glm::uvec3(0), glm::uvec3(1)); return result; - - } uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { @@ -323,17 +321,13 @@ bool GL45Texture::continueTransfer() { if (buffer.empty()) { buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); } - uvec3 pageSize = _transferState.currentPageSize(); - uvec3 offset = _transferState._mipOffset; + const uvec3 pageSize = _transferState.currentPageSize(); + const uvec3& offset = _transferState._mipOffset; - // FIXME we should be using the DSA for all of this if (_sparseInfo._sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { if (_allocatedPages > _sparseInfo._maxPages) { - qDebug() << "Exceeded max page allocation!"; + qWarning() << "Exceeded max page allocation!"; } - //glBindTexture(_target, _id); - // FIXME we should be using glTexturePageCommitmentEXT, but for some reason it causes out of memory errors. - // Either I'm not understanding how it should work or there's a driver bug. glTexturePageCommitmentEXT(_id, _transferState._mipLevel, offset.x, offset.y, _transferState._face, pageSize.x, pageSize.y, pageSize.z, From 12de36a534f60158759ec0e024c978727084f8ed Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 14:07:27 -0700 Subject: [PATCH 11/42] Check the total GPU memory usage from the card as well as our computed memory usage --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 4 ++++ libraries/gpu-gl/src/gpu/gl/GLShared.cpp | 26 +++++++++++++++++++++++ libraries/gpu-gl/src/gpu/gl/GLShared.h | 1 + libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 14 ++++++++++-- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 1385a56f65..8753db8081 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -39,6 +39,10 @@ static GLBackend* INSTANCE{ nullptr }; static const char* GL_BACKEND_PROPERTY_NAME = "com.highfidelity.gl.backend"; BackendPointer GLBackend::createBackend() { + // The ATI memory info extension only exposes 'free memory' so we want to force it to + // cache the value as early as possible + getDedicatedMemory(); + // FIXME provide a mechanism to override the backend for testing // Where the gpuContext is initialized and where the TRUE Backend is created and assigned auto version = QOpenGLContextWrapper::currentContextVersion(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp index d59be0d9de..af03da1931 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp @@ -60,6 +60,32 @@ bool checkGLErrorDebug(const char* name) { #endif } +gpu::Size getFreeDedicatedMemory() { + Size result { 0 }; + static bool nvidiaMemorySupported { true }; + static bool atiMemorySupported { true }; + if (nvidiaMemorySupported) { + + GLint nvGpuMemory { 0 }; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &nvGpuMemory); + if (GL_NO_ERROR == glGetError()) { + result = KB_TO_BYTES(nvGpuMemory); + } else { + nvidiaMemorySupported = false; + } + } else if (atiMemorySupported) { + GLint atiGpuMemory[4]; + // not really total memory, but close enough if called early enough in the application lifecycle + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory); + if (GL_NO_ERROR == glGetError()) { + result = KB_TO_BYTES(atiGpuMemory[0]); + } else { + atiMemorySupported = false; + } + } + return result; +} + gpu::Size getDedicatedMemory() { static Size dedicatedMemory { 0 }; static std::once_flag once; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h index 7ec6deeb9d..b5dece7cf4 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShared.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h @@ -25,6 +25,7 @@ void serverWait(); void clientWait(); gpu::Size getDedicatedMemory(); +gpu::Size getFreeDedicatedMemory(); ComparisonFunction comparisonFuncFromGL(GLenum func); State::StencilOp stencilOpFromGL(GLenum stencilOp); State::BlendOp blendOpFromGL(GLenum blendOp); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index a279bec11c..fc50c69538 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -92,6 +92,7 @@ const std::vector& GLTexture::getFaceTargets(GLenum target) { return faceTargets; } +#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f float GLTexture::getMemoryPressure() { // Check for an explicit memory limit auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage(); @@ -100,10 +101,19 @@ float GLTexture::getMemoryPressure() { if (!availableTextureMemory) { auto totalGpuMemory = getDedicatedMemory(); - // If no limit has been explicitly set, and the dedicated memory can't be determined, - // just use a fallback fixed value of 256 MB if (!totalGpuMemory) { + // If we can't query the dedicated memory just use a fallback fixed value of 256 MB totalGpuMemory = MB_TO_BYTES(DEFAULT_MAX_MEMORY_MB); + } else { + // Check the global free GPU memory + auto freeGpuMemory = getFreeDedicatedMemory(); + if (freeGpuMemory) { + auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory; + if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) { + qDebug() << "Exceeded max GPU memory"; + return 2.0; + } + } } // Allow 75% of all available GPU memory to be consumed by textures From 50233f6ffb4ef0ba4cf5ffdd7bc75103bc93dd8a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 14:29:02 -0700 Subject: [PATCH 12/42] Don't re-report texture memory usage until the returned value changes --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index fc50c69538..3a45f55646 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -93,6 +93,7 @@ const std::vector& GLTexture::getFaceTargets(GLenum target) { } #define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f + float GLTexture::getMemoryPressure() { // Check for an explicit memory limit auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage(); @@ -107,8 +108,10 @@ float GLTexture::getMemoryPressure() { } else { // Check the global free GPU memory auto freeGpuMemory = getFreeDedicatedMemory(); - if (freeGpuMemory) { - auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory; + static gpu::Size lastFreeGpuMemory = 0; + auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory; + if (freeGpuMemory != lastFreeGpuMemory) { + lastFreeGpuMemory = freeGpuMemory; if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) { qDebug() << "Exceeded max GPU memory"; return 2.0; From 74481b3c1fefe940da669ce56d66651d400263a5 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 15 Sep 2016 15:45:47 -0700 Subject: [PATCH 13/42] Re-enable threaded texture transfer --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 16 +++++++++------- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 3a45f55646..4796d0497e 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -108,13 +108,15 @@ float GLTexture::getMemoryPressure() { } else { // Check the global free GPU memory auto freeGpuMemory = getFreeDedicatedMemory(); - static gpu::Size lastFreeGpuMemory = 0; - auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory; - if (freeGpuMemory != lastFreeGpuMemory) { - lastFreeGpuMemory = freeGpuMemory; - if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) { - qDebug() << "Exceeded max GPU memory"; - return 2.0; + if (freeGpuMemory) { + static gpu::Size lastFreeGpuMemory = 0; + auto freePercentage = (float)freeGpuMemory / (float)totalGpuMemory; + if (freeGpuMemory != lastFreeGpuMemory) { + lastFreeGpuMemory = freeGpuMemory; + if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) { + qDebug() << "Exceeded max GPU memory"; + return 2.0; + } } } } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h index a880f42394..fe7414e370 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -18,7 +18,7 @@ #include "GLShared.h" #ifdef Q_OS_WIN -//#define THREADED_TEXTURE_TRANSFER +#define THREADED_TEXTURE_TRANSFER #endif namespace gpu { namespace gl { From 1ff91219a8d7b726289f880af62c4212512156ed Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 16 Sep 2016 14:36:24 -0700 Subject: [PATCH 14/42] Fix strange artifacts in skybox --- .../src/gpu/gl45/GL45BackendTexture.cpp | 20 ++++++++++++++++++- libraries/gpu/src/gpu/Texture.h | 4 ++++ libraries/model/src/model/TextureMap.cpp | 18 +++++++++++------ libraries/model/src/model/TextureMap.h | 2 +- .../render-utils/src/SubsurfaceScattering.cpp | 3 +++ 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index b6eae6e611..d967a1a7a2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -92,6 +92,11 @@ SparseInfo::SparseInfo(GL45Texture& texture) } void SparseInfo::maybeMakeSparse() { + // Don't enable sparse for objects with explicitly managed mip levels + if (!_texture._gpuObject.isAutogenerateMips()) { + qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << _texture._gpuObject.source().c_str(); + return; + } const uvec3 dimensions = _texture._gpuObject.getDimensions(); auto allowedPageDimensions = getPageDimensionsForFormat(_texture._target, _texture._internalFormat); // In order to enable sparse the texture size must be an integer multiple of the page size @@ -100,6 +105,7 @@ void SparseInfo::maybeMakeSparse() { _pageDimensions = allowedPageDimensions[i]; // Is this texture an integer multiple of page dimensions? if (uvec3(0) == (dimensions % _pageDimensions)) { + qCDebug(gpugl45logging) << "Enabling sparse for texture " << _texture._gpuObject.source().c_str(); _sparse = true; break; } @@ -109,12 +115,16 @@ void SparseInfo::maybeMakeSparse() { glTextureParameteri(_texture._id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); glTextureParameteri(_texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, _pageDimensionsIndex); } else { - qDebug() << "Texture size " << dimensions.x << " x " << dimensions.y << " is not supported by any sparse page size"; + qCDebug(gpugl45logging) << "Size " << dimensions.x << " x " << dimensions.y << + " is not supported by any sparse page size for texture" << _texture._gpuObject.source().c_str(); } } // This can only be called after we've established our storage size void SparseInfo::update() { + if (!_sparse) { + return; + } glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; @@ -282,6 +292,7 @@ void GL45Texture::withPreservedTexture(std::function f) const { } void GL45Texture::generateMips() const { + qDebug() << "Generating mipmaps for " << _gpuObject.source().c_str(); glGenerateTextureMipmap(_id); (void)CHECK_GL_ERROR(); } @@ -435,6 +446,13 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { } } + // If we weren't generating mips before, we need to now that we're stripping down mip levels. + if (!_gpuObject.isAutogenerateMips()) { + qDebug() << "Force mip generation for texture"; + glGenerateTextureMipmap(_id); + } + + uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { auto mipDimensions = _gpuObject.evalMipDimensions(mip); diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index a7ac472922..ae1afcafcb 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -389,6 +389,8 @@ public: uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; } + const std::string& source() const { return _source; } + void setSource(const std::string& source) { _source = source; } bool setMinMip(uint16 newMinMip); bool incremementMinMip(uint16 count = 1); @@ -450,6 +452,8 @@ public: const GPUObjectPointer gpuObject {}; protected: + // Not strictly necessary, but incredibly useful for debugging + std::string _source; std::unique_ptr< Storage > _storage; Stamp _stamp = 0; diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 9345124d54..30f176b5a6 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -176,7 +176,7 @@ void generateFaceMips(gpu::Texture* texture, QImage& image, gpu::Element formatM #endif } -gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips) { +gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips) { bool validAlpha = false; bool alphaAsMask = true; QImage image = process2DImageColor(srcImage, validAlpha, alphaAsMask); @@ -189,7 +189,7 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag defineColorTexelFormats(formatGPU, formatMip, image, isLinear, doCompress); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); - + theTexture->setSource(srcImageName); auto usage = gpu::Texture::Usage::Builder().withColor(); if (validAlpha) { usage.withAlpha(); @@ -210,20 +210,20 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag } gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, false, false, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false, false, true); } gpu::Texture* TextureUsage::createAlbedoTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, false, true, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true); } gpu::Texture* TextureUsage::createEmissiveTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, false, true, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true); } gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) { - return process2DTextureColorFromImage(srcImage, false, true, true); + return process2DTextureColorFromImage(srcImage, srcImageName, false, true, true); } @@ -241,6 +241,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip); } @@ -324,6 +325,7 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip); } @@ -355,6 +357,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip); @@ -392,6 +395,7 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip); @@ -426,6 +430,7 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag gpu::Element formatMip = gpu::Element(gpu::SCALAR, gpu::NUINT8, gpu::RGB); theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR))); + theTexture->setSource(srcImageName); theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); generateMips(theTexture, image, formatMip); @@ -737,6 +742,7 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm // If the 6 faces have been created go on and define the true Texture if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) { theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP)); + theTexture->setSource(srcImageName); int f = 0; for (auto& face : faces) { theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f); diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index ac35db2f03..220ee57a97 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -47,7 +47,7 @@ public: static const QImage process2DImageColor(const QImage& srcImage, bool& validAlpha, bool& alphaAsMask); static void defineColorTexelFormats(gpu::Element& formatGPU, gpu::Element& formatMip, const QImage& srcImage, bool isLinear, bool doCompress); - static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, bool isLinear, bool doCompress, bool generateMips); + static gpu::Texture* process2DTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips); static gpu::Texture* processCubeTextureColorFromImage(const QImage& srcImage, const std::string& srcImageName, bool isLinear, bool doCompress, bool generateMips, bool generateIrradiance); }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index f1aec66433..3e4ec50dee 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -415,6 +415,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringProfile(Rend // const auto pixelFormat = gpu::Element::COLOR_SRGBA_32; const auto pixelFormat = gpu::Element::COLOR_R11G11B10; auto profileMap = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, PROFILE_RESOLUTION, 1, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); + profileMap->setSource("Generated Scattering Profile"); diffuseProfileGPU(profileMap, args); return profileMap; } @@ -426,6 +427,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin const auto pixelFormat = gpu::Element::COLOR_R11G11B10; auto scatteringLUT = gpu::TexturePointer(gpu::Texture::create2D(pixelFormat, TABLE_RESOLUTION, TABLE_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); //diffuseScatter(scatteringLUT); + scatteringLUT->setSource("Generated pre-integrated scattering"); diffuseScatterGPU(profile, scatteringLUT, args); return scatteringLUT; } @@ -433,6 +435,7 @@ gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScatterin gpu::TexturePointer SubsurfaceScatteringResource::generateScatteringSpecularBeckmann(RenderArgs* args) { const int SPECULAR_RESOLUTION = 256; auto beckmannMap = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32 /*gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RGB)*/, SPECULAR_RESOLUTION, SPECULAR_RESOLUTION, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP))); + beckmannMap->setSource("Generated beckmannMap"); computeSpecularBeckmannGPU(beckmannMap, args); return beckmannMap; } From 64cb45240d387874a304a137e3fca5df18cdf43d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 10:20:51 -0700 Subject: [PATCH 15/42] Fix invalid page size for non-sparse textures --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 9589c0dc7e..0f61cd1ab9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -30,6 +30,7 @@ public: class GL45Texture : public GLTexture { using Parent = GLTexture; static GLuint allocate(const Texture& texture); + static const uint32_t DEFAULT_PAGE_DIMENSION = 128; public: GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable); ~GL45Texture(); @@ -38,7 +39,7 @@ public: struct SparseInfo { GL45Texture& _texture; - uvec3 _pageDimensions; + uvec3 _pageDimensions { DEFAULT_PAGE_DIMENSION }; GLuint _maxSparseLevel { 0 }; uint32_t _maxPages { 0 }; uint32_t _pageBytes { 0 }; From 5734332150886a2c4701e4062a807b2867807d0c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 11:29:27 -0700 Subject: [PATCH 16/42] Fix sparse texture deallocation --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 16 ++++ libraries/gpu-gl/src/gpu/gl/GLBackend.h | 2 + libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 1 - .../src/gpu/gl45/GL45BackendTexture.cpp | 79 ++++++++++--------- 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 8753db8081..72a953c5f3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -593,7 +593,23 @@ void GLBackend::releaseQuery(GLuint id) const { _queriesTrash.push_back(id); } +void GLBackend::releaseLambda(const std::function lambda) const { + Lock lock(_trashMutex); + _lambdasTrash.push_back(lambda); +} + void GLBackend::recycle() const { + { + std::list> lamdbasTrash; + { + Lock lock(_trashMutex); + std::swap(_lambdasTrash, lamdbasTrash); + } + for (auto lambda : lamdbasTrash) { + lambda(); + } + } + { std::vector ids; std::list> buffersTrash; diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 29e66da020..545ae6cbdc 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -175,6 +175,7 @@ public: virtual void releaseShader(GLuint id) const; virtual void releaseProgram(GLuint id) const; virtual void releaseQuery(GLuint id) const; + virtual void releaseLambda(const std::function lambda) const; protected: @@ -197,6 +198,7 @@ protected: mutable std::list _shadersTrash; mutable std::list _programsTrash; mutable std::list _queriesTrash; + mutable std::list> _lambdasTrash; void renderPassTransfer(const Batch& batch); void renderPassDraw(const Batch& batch); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 4796d0497e..c2d6b3eb54 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -155,7 +155,6 @@ GLTexture::~GLTexture() { auto backend = _backend.lock(); if (backend) { backend->releaseTexture(_id, _size); - backend->recycle(); } } Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index d967a1a7a2..b369d6d819 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -30,6 +30,7 @@ static bool enableSparseTextures = !QProcessEnvironment::systemEnvironment().con // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) +#define DEFAULT_GL_PIXEL_ALIGNMENT 4 using GL45Texture = GL45Backend::GL45Texture; @@ -39,7 +40,6 @@ using TextureTypeFormat = std::pair; std::map> sparsePageDimensionsByFormat; Mutex sparsePageDimensionsByFormatMutex; - static std::vector getPageDimensionsForFormat(const TextureTypeFormat& typeFormat) { { Lock lock(sparsePageDimensionsByFormatMutex); @@ -64,7 +64,7 @@ static std::vector getPageDimensionsForFormat(const TextureTypeFormat& ty for (GLint i = 0; i < count; ++i) { result[i] = uvec3(x[i], y[i], z[i]); } - qDebug() << "Got " << count << " page sizes"; + qCDebug(gpugl45logging) << "Got " << count << " page sizes"; } { @@ -212,7 +212,6 @@ bool TransferState::increment() { return false; } -#define DEFAULT_GL_PIXEL_ALIGNMENT 4 void TransferState::populatePage(std::vector& buffer) { uvec3 pageSize = currentPageSize(); auto bytesPerPageLine = _bytesPerPixel * pageSize.x; @@ -254,35 +253,41 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& } } +// Destructors get called on the main thread, potentially without a context active. We need to queue the +// deallocation of the sparse pages for this content. GL45Texture::~GL45Texture() { - if (_sparseInfo._sparse) { - auto mipLevels = usedMipLevels(); - { - Lock lock(texturesByMipCountsMutex); - if (texturesByMipCounts.count(mipLevels)) { - auto& textures = texturesByMipCounts[mipLevels]; - textures.erase(this); - if (textures.empty()) { - texturesByMipCounts.erase(mipLevels); + if (_sparseInfo._sparse) { + auto backend = _backend.lock(); + if (backend) { + auto id = _id; + auto mipLevels = usedMipLevels(); + { + Lock lock(texturesByMipCountsMutex); + if (texturesByMipCounts.count(mipLevels)) { + auto& textures = texturesByMipCounts[mipLevels]; + textures.erase(this); + if (textures.empty()) { + texturesByMipCounts.erase(mipLevels); + } } } - } - auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); - uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { - auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); - auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions); - for (uint8_t face = 0; face < maxFace; ++face) { - glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, mipDimensions.x, mipDimensions.y, mipDimensions.z, GL_FALSE); + auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); + uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); + for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { + auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); + backend->releaseLambda([=] { + glTexturePageCommitmentEXT(id, mipLevel, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); + }); + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; assert(deallocatedPages <= _allocatedPages); _allocatedPages -= deallocatedPages; } - } - if (0 != _allocatedPages) { - qWarning() << "Allocated pages remaining " << _id << " " << _allocatedPages; + if (0 != _allocatedPages) { + qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; + } } } } @@ -292,7 +297,7 @@ void GL45Texture::withPreservedTexture(std::function f) const { } void GL45Texture::generateMips() const { - qDebug() << "Generating mipmaps for " << _gpuObject.source().c_str(); + qCDebug(gpugl45logging) << "Generating mipmaps for " << _gpuObject.source().c_str(); glGenerateTextureMipmap(_id); (void)CHECK_GL_ERROR(); } @@ -337,7 +342,7 @@ bool GL45Texture::continueTransfer() { if (_sparseInfo._sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { if (_allocatedPages > _sparseInfo._maxPages) { - qWarning() << "Exceeded max page allocation!"; + qCWarning(gpugl45logging) << "Exceeded max page allocation!"; } glTexturePageCommitmentEXT(_id, _transferState._mipLevel, offset.x, offset.y, _transferState._face, @@ -373,7 +378,7 @@ bool GL45Texture::continueTransfer() { auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); auto newPages = _allocatedPages - _lastMipAllocatedPages; if (newPages != mipExpectedPages) { - qWarning() << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; + qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages; } _lastMipAllocatedPages = _allocatedPages; } @@ -426,12 +431,12 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { } if (newMinMip < _minMip) { - qWarning() << "Cannot decrease the min mip"; + qCWarning(gpugl45logging) << "Cannot decrease the min mip"; return; } if (newMinMip > _sparseInfo._maxSparseLevel) { - qWarning() << "Cannot increase the min mip into the mip tail"; + qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail"; return; } @@ -448,7 +453,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { // If we weren't generating mips before, we need to now that we're stripping down mip levels. if (!_gpuObject.isAutogenerateMips()) { - qDebug() << "Force mip generation for texture"; + qCDebug(gpugl45logging) << "Force mip generation for texture"; glGenerateTextureMipmap(_id); } @@ -474,9 +479,9 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { updateSize(); size_t newSize = _size; if (newSize > oldSize) { - qDebug() << "WTF"; - qDebug() << "\told size " << oldSize; - qDebug() << "\tnew size " << newSize; + qCDebug(gpugl45logging) << "WTF"; + qCDebug(gpugl45logging) << "\told size " << oldSize; + qCDebug(gpugl45logging) << "\tnew size " << newSize; } // Re-insert into the texture-by-mips map if appropriate @@ -512,18 +517,18 @@ void GL45Backend::derezTextures() const { Lock lock(texturesByMipCountsMutex); if (texturesByMipCounts.empty()) { - qDebug() << "No available textures to derez"; + qCDebug(gpugl45logging) << "No available textures to derez"; return; } auto mipLevel = texturesByMipCounts.rbegin()->first; if (mipLevel <= 1) { - qDebug() << "Max mip levels " << mipLevel; + qCDebug(gpugl45logging) << "Max mip levels " << mipLevel; return; } - qDebug() << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); - qDebug() << "Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "Allowed texture memory " << Texture::getAllowedGPUMemoryUsage(); + qCDebug(gpugl45logging) << "Used texture memory " << Context::getTextureGPUMemoryUsage(); GL45Texture* targetTexture = nullptr; { @@ -533,5 +538,5 @@ void GL45Backend::derezTextures() const { } lock.unlock(); targetTexture->derez(); - qDebug() << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); + qCDebug(gpugl45logging) << "New Used texture memory " << Context::getTextureGPUMemoryUsage(); } From 88bbb2faa8e074d2e9e90b13409ce79b341b978d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 11:52:19 -0700 Subject: [PATCH 17/42] Fix cubemap mips by overcommiting --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index b369d6d819..f6d8110b3c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -126,6 +126,11 @@ void SparseInfo::update() { return; } glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); + // For some reason the long mip tail isn't working properly with cubemaps unless + // I extend one more level + if (GL_TEXTURE_CUBE_MAP == _texture._target) { + ++_maxSparseLevel; + } _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; @@ -253,10 +258,7 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& } } -// Destructors get called on the main thread, potentially without a context active. We need to queue the -// deallocation of the sparse pages for this content. GL45Texture::~GL45Texture() { - if (_sparseInfo._sparse) { auto backend = _backend.lock(); if (backend) { @@ -277,6 +279,8 @@ GL45Texture::~GL45Texture() { uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); + // Destructors get called on the main thread, potentially without a context active. + // We need to queue the deallocation of the sparse pages for this content. backend->releaseLambda([=] { glTexturePageCommitmentEXT(id, mipLevel, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); }); From ffbddd2d0f94d3cc74d63226fce5623a28018102 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 13:57:15 -0700 Subject: [PATCH 18/42] Disable sparse textures on cubemaps --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index f6d8110b3c..79f4615317 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -97,6 +97,12 @@ void SparseInfo::maybeMakeSparse() { qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << _texture._gpuObject.source().c_str(); return; } + + if (GL_TEXTURE_CUBE_MAP == _texture._target) { + qCDebug(gpugl45logging) << "Don't enable sparse texture for cubemaps " << _texture._gpuObject.source().c_str(); + return; + } + const uvec3 dimensions = _texture._gpuObject.getDimensions(); auto allowedPageDimensions = getPageDimensionsForFormat(_texture._target, _texture._internalFormat); // In order to enable sparse the texture size must be an integer multiple of the page size From fa23fa7b2de407aced32e3f304ed03e820ab41d3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 14:36:37 -0700 Subject: [PATCH 19/42] Working on cubemap mip bug --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 3 ++- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 10 ---------- libraries/model/src/model/skybox.slf | 2 +- tests/render-perf/src/Camera.hpp | 18 ++++++++++++++---- tests/render-perf/src/main.cpp | 7 ++++--- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 0f61cd1ab9..b684a9b8d2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -31,6 +31,7 @@ public: using Parent = GLTexture; static GLuint allocate(const Texture& texture); static const uint32_t DEFAULT_PAGE_DIMENSION = 128; + static const uint32_t DEFAULT_MAX_SPARSE_LEVEL = 0xFFFF; public: GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable); ~GL45Texture(); @@ -40,7 +41,7 @@ public: struct SparseInfo { GL45Texture& _texture; uvec3 _pageDimensions { DEFAULT_PAGE_DIMENSION }; - GLuint _maxSparseLevel { 0 }; + GLuint _maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; uint32_t _maxPages { 0 }; uint32_t _pageBytes { 0 }; bool _sparse { false }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 79f4615317..09c6003ced 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -98,11 +98,6 @@ void SparseInfo::maybeMakeSparse() { return; } - if (GL_TEXTURE_CUBE_MAP == _texture._target) { - qCDebug(gpugl45logging) << "Don't enable sparse texture for cubemaps " << _texture._gpuObject.source().c_str(); - return; - } - const uvec3 dimensions = _texture._gpuObject.getDimensions(); auto allowedPageDimensions = getPageDimensionsForFormat(_texture._target, _texture._internalFormat); // In order to enable sparse the texture size must be an integer multiple of the page size @@ -132,11 +127,6 @@ void SparseInfo::update() { return; } glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); - // For some reason the long mip tail isn't working properly with cubemaps unless - // I extend one more level - if (GL_TEXTURE_CUBE_MAP == _texture._target) { - ++_maxSparseLevel; - } _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; diff --git a/libraries/model/src/model/skybox.slf b/libraries/model/src/model/skybox.slf index 7b25e36af7..c0770525f7 100755 --- a/libraries/model/src/model/skybox.slf +++ b/libraries/model/src/model/skybox.slf @@ -48,7 +48,7 @@ void main(void) { // blend is only set if there is a cubemap if (skybox.color.a > 0.0) { - color = texture(cubeMap, coord).rgb; + color = textureLod(cubeMap, coord, 0).rgb; if (skybox.color.a < 1.0) { color *= skybox.color.rgb; } diff --git a/tests/render-perf/src/Camera.hpp b/tests/render-perf/src/Camera.hpp index ebfcfb9e32..6e1d95bfe1 100644 --- a/tests/render-perf/src/Camera.hpp +++ b/tests/render-perf/src/Camera.hpp @@ -14,9 +14,10 @@ protected: public: glm::quat getOrientation() const { - return glm::angleAxis(yaw, Vectors::UP); + return glm::angleAxis(yawPitch.x, Vectors::UP) * glm::angleAxis(yawPitch.y, Vectors::RIGHT); } - float yaw { 0 }; + + vec2 yawPitch { 0 }; glm::vec3 position; float rotationSpeed { 1.0f }; float movementSpeed { 1.0f }; @@ -76,7 +77,12 @@ public: }; void rotate(const float delta) { - yaw += delta; + yawPitch.x += delta; + updateViewMatrix(); + } + + void rotate(const glm::vec2& delta) { + yawPitch += delta; updateViewMatrix(); } @@ -84,7 +90,11 @@ public: glm::vec3 f = rotation * Vectors::UNIT_NEG_Z; f.y = 0; f = glm::normalize(f); - yaw = angleBetween(Vectors::UNIT_NEG_Z, f); + yawPitch.x = angleBetween(Vectors::UNIT_NEG_Z, f); + f = rotation * Vectors::UNIT_NEG_Z; + f.x = 0; + f = glm::normalize(f); + yawPitch.y = angleBetween(Vectors::UNIT_NEG_Z, f); updateViewMatrix(); } diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index bbe1c33bb1..605ccf3787 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -188,7 +188,8 @@ public: if (buttons & Qt::RightButton) { dolly(delta.y * 0.01f); } else if (buttons & Qt::LeftButton) { - rotate(delta.x * -0.01f); + //rotate(delta.x * -0.01f); + rotate(delta * -0.01f); } else if (buttons & Qt::MiddleButton) { delta.y *= -1.0f; translate(delta * -0.01f); @@ -367,7 +368,7 @@ public: sortedHighFrames.sort(); for (const auto& t : sortedHighFrames) { - qDebug() << "Long frame " << t; + //qDebug() << "Long frame " << t; } } @@ -990,7 +991,7 @@ private: } void resetPosition() { - _camera.yaw = 0; + _camera.yawPitch = vec3(0); _camera.setPosition(vec3()); } From 0953027ef349c19245bbe8cac68cc5a380172457 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 15:42:26 -0700 Subject: [PATCH 20/42] Identify pre-generated textures --- libraries/gpu/src/gpu/Framebuffer.cpp | 6 ++++-- .../model-networking/src/model-networking/TextureCache.cpp | 4 ++++ libraries/render-utils/src/AntialiasingEffect.cpp | 1 + libraries/render-utils/src/DeferredFramebuffer.cpp | 6 +++++- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 ++ libraries/render-utils/src/SurfaceGeometryPass.cpp | 6 ++++++ tests/render-perf/src/main.cpp | 2 +- 7 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index beb0334208..20e55b9ef9 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -32,6 +32,7 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, uint16 width, auto framebuffer = Framebuffer::create(); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); + colorTexture->setSource("Framebuffer::colorTexture"); framebuffer->setRenderBuffer(0, colorTexture); @@ -42,8 +43,9 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& auto framebuffer = Framebuffer::create(); auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); + colorTexture->setSource("Framebuffer::colorTexture"); auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height, Sampler(Sampler::FILTER_MIN_MAG_POINT))); - + depthTexture->setSource("Framebuffer::depthTexture"); framebuffer->setRenderBuffer(0, colorTexture); framebuffer->setDepthStencilBuffer(depthTexture, depthStencilBufferFormat); @@ -55,7 +57,7 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) { auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width)); - + depthTexture->setSource("Framebuffer::shadowMap"); Sampler::Desc samplerDesc; samplerDesc._borderColor = glm::vec4(1.0f); samplerDesc._wrapModeU = Sampler::WRAP_BORDER; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 5bb983c7f9..b4803a7bcd 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -117,6 +117,7 @@ const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF }; const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (!_whiteTexture) { _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); + _whiteTexture->setSource("TextureCache::_whiteTexture"); _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE); } return _whiteTexture; @@ -125,6 +126,7 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() { const gpu::TexturePointer& TextureCache::getGrayTexture() { if (!_grayTexture) { _grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); + _grayTexture->setSource("TextureCache::_grayTexture"); _grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY); } return _grayTexture; @@ -133,6 +135,7 @@ const gpu::TexturePointer& TextureCache::getGrayTexture() { const gpu::TexturePointer& TextureCache::getBlueTexture() { if (!_blueTexture) { _blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); + _blueTexture->setSource("TextureCache::_blueTexture"); _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE); } return _blueTexture; @@ -141,6 +144,7 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() { const gpu::TexturePointer& TextureCache::getBlackTexture() { if (!_blackTexture) { _blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1)); + _blackTexture->setSource("TextureCache::_blackTexture"); _blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK); } return _blackTexture; diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index b7995c1b47..df9280c187 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -56,6 +56,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get()->getLightingTexture()->getTexelFormat(); auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + _antialiasingTexture->setSource("Antialiasing::_antialiasingTexture"); _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); // Good to go add the brand new pipeline diff --git a/libraries/render-utils/src/DeferredFramebuffer.cpp b/libraries/render-utils/src/DeferredFramebuffer.cpp index 32f91f83d8..067687f9ef 100644 --- a/libraries/render-utils/src/DeferredFramebuffer.cpp +++ b/libraries/render-utils/src/DeferredFramebuffer.cpp @@ -54,9 +54,11 @@ void DeferredFramebuffer::allocate() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); - + _deferredColorTexture->setSource("DeferredFramebuffer::_deferredColorTexture"); _deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(linearFormat, width, height, defaultSampler)); + _deferredNormalTexture->setSource("DeferredFramebuffer::_deferredNormalTexture"); _deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _deferredSpecularTexture->setSource("DeferredFramebuffer::_deferredSpecularTexture"); _deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture); _deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture); @@ -67,6 +69,7 @@ void DeferredFramebuffer::allocate() { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format if (!_primaryDepthTexture) { _primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); + _primaryDepthTexture->setSource("DeferredFramebuffer::_primaryDepthTexture"); } _deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); @@ -77,6 +80,7 @@ void DeferredFramebuffer::allocate() { auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); _lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, defaultSampler)); + _lightingTexture->setSource("DeferredFramebuffer::_lightingTexture"); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lightingFramebuffer->setRenderBuffer(0, _lightingTexture); _lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8e83f737ea..ae1c3dafb8 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -345,6 +345,7 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); auto primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, frameSize.x, frameSize.y, defaultSampler)); + primaryColorTexture->setSource("PreparePrimaryFramebuffer::primaryColorTexture"); _primaryFramebuffer->setRenderBuffer(0, primaryColorTexture); @@ -352,6 +353,7 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format auto primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, frameSize.x, frameSize.y, defaultSampler)); + primaryDepthTexture->setSource("PreparePrimaryFramebuffer::primaryDepthTexture"); _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); diff --git a/libraries/render-utils/src/SurfaceGeometryPass.cpp b/libraries/render-utils/src/SurfaceGeometryPass.cpp index 1957f8456a..e43afd94a9 100644 --- a/libraries/render-utils/src/SurfaceGeometryPass.cpp +++ b/libraries/render-utils/src/SurfaceGeometryPass.cpp @@ -74,6 +74,7 @@ void LinearDepthFramebuffer::allocate() { // For Linear Depth: _linearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _linearDepthTexture->setSource("LinearDepthFramebuffer::_linearDepthTexture"); _linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture); _linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat()); @@ -81,10 +82,12 @@ void LinearDepthFramebuffer::allocate() { // For Downsampling: _halfLinearDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _halfLinearDepthTexture->setSource("LinearDepthFramebuffer::_halfLinearDepthTexture"); _halfLinearDepthTexture->autoGenerateMips(5); _halfNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), _halfFrameSize.x, _halfFrameSize.y, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _halfNormalTexture->setSource("LinearDepthFramebuffer::_halfNormalTexture"); _downsampleFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _downsampleFramebuffer->setRenderBuffer(0, _halfLinearDepthTexture); @@ -301,14 +304,17 @@ void SurfaceGeometryFramebuffer::allocate() { auto height = _frameSize.y; _curvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _curvatureTexture->setSource("SurfaceGeometryFramebuffer::_curvatureTexture"); _curvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _curvatureFramebuffer->setRenderBuffer(0, _curvatureTexture); _lowCurvatureTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _lowCurvatureTexture->setSource("SurfaceGeometryFramebuffer::_lowCurvatureTexture"); _lowCurvatureFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _lowCurvatureFramebuffer->setRenderBuffer(0, _lowCurvatureTexture); _blurringTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT))); + _blurringTexture->setSource("SurfaceGeometryFramebuffer::_blurringTexture"); _blurringFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); _blurringFramebuffer->setRenderBuffer(0, _blurringTexture); } diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 605ccf3787..238972dc00 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -368,7 +368,7 @@ public: sortedHighFrames.sort(); for (const auto& t : sortedHighFrames) { - //qDebug() << "Long frame " << t; + qDebug() << "Long frame " << t; } } From 82db3d5d55b32e00e406a58e52db5df503a0f4a7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 19 Sep 2016 16:47:30 -0700 Subject: [PATCH 21/42] Disable support for framebuffer resizing --- libraries/gpu/src/gpu/Framebuffer.cpp | 12 ++++---- libraries/gpu/src/gpu/Framebuffer.h | 2 +- .../render-utils/src/AntialiasingEffect.cpp | 28 ++++++++++--------- .../src/DeferredLightingEffect.cpp | 10 +++++-- libraries/render/src/render/BlurTask.cpp | 24 ++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 20e55b9ef9..8a97c0d748 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -115,29 +115,31 @@ void Framebuffer::updateSize(const TexturePointer& texture) { } } +#if 0 void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) { if (width && height && numSamples && !isEmpty() && !isSwapchain()) { if ((width != _width) || (height != _height) || (numSamples != _numSamples)) { + _numSamples = numSamples; for (uint32 i = 0; i < _renderBuffers.size(); ++i) { if (_renderBuffers[i]) { - _renderBuffers[i]._texture->resize2D(width, height, numSamples); - _numSamples = _renderBuffers[i]._texture->getNumSamples(); + _renderBuffers[i]._texture->resize2D(width, height, _numSamples); + assert(_renderBuffers[i]._texture->getNumSamples() == _numSamples); ++_colorStamps[i]; } } if (_depthStencilBuffer) { - _depthStencilBuffer._texture->resize2D(width, height, numSamples); - _numSamples = _depthStencilBuffer._texture->getNumSamples(); + _depthStencilBuffer._texture->resize2D(width, height, _numSamples); + assert(_depthStencilBuffer._texture->getNumSamples() == _numSamples); ++_depthStamp; } _width = width; _height = height; - // _numSamples = numSamples; } } } +#endif uint16 Framebuffer::getWidth() const { if (isSwapchain()) { diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index 6fa6367c7d..f357cfc3f8 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -131,7 +131,7 @@ public: float getAspectRatio() const { return getWidth() / (float) getHeight() ; } // If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call - void resize( uint16 width, uint16 height, uint16 samples = 1 ); + //void resize( uint16 width, uint16 height, uint16 samples = 1 ); static const uint32 MAX_NUM_RENDER_BUFFERS = 8; static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index df9280c187..8147b06846 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -34,7 +34,21 @@ Antialiasing::Antialiasing() { const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { int width = DependencyManager::get()->getFrameBufferSize().width(); int height = DependencyManager::get()->getFrameBufferSize().height(); - + + if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) { + _antialiasingBuffer.reset(); + } + + if (!_antialiasingBuffer) { + // Link the antialiasing FBO to texture + _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get()->getLightingTexture()->getTexelFormat(); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); + _antialiasingTexture->setSource("Antialiasing::_antialiasingTexture"); + _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); + } + if (!_antialiasingPipeline) { auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); auto ps = gpu::Shader::createPixel(std::string(fxaa_frag)); @@ -51,22 +65,10 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { state->setDepthTest(false, false, gpu::LESS_EQUAL); - // Link the antialiasing FBO to texture - _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); - auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get()->getLightingTexture()->getTexelFormat(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); - _antialiasingTexture->setSource("Antialiasing::_antialiasingTexture"); - _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); - // Good to go add the brand new pipeline _antialiasingPipeline = gpu::Pipeline::create(program, state); } - if (width != _antialiasingBuffer->getWidth() || height != _antialiasingBuffer->getHeight()) { - _antialiasingBuffer->resize(width, height); - } - return _antialiasingPipeline; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index ae1c3dafb8..808d765dd7 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -337,7 +337,13 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con auto framebufferCache = DependencyManager::get(); auto framebufferSize = framebufferCache->getFrameBufferSize(); - glm::ivec2 frameSize(framebufferSize.width(), framebufferSize.height()); + glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height()); + + // Resizing framebuffers instead of re-building them seems to cause issues with threaded + // rendering + if (_primaryFramebuffer && _primaryFramebuffer->getSize() != frameSize) { + _primaryFramebuffer.reset(); + } if (!_primaryFramebuffer) { _primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); @@ -356,9 +362,7 @@ void PreparePrimaryFramebuffer::run(const SceneContextPointer& sceneContext, con primaryDepthTexture->setSource("PreparePrimaryFramebuffer::primaryDepthTexture"); _primaryFramebuffer->setDepthStencilBuffer(primaryDepthTexture, depthFormat); - } - _primaryFramebuffer->resize(frameSize.x, frameSize.y); primaryFramebuffer = _primaryFramebuffer; } diff --git a/libraries/render/src/render/BlurTask.cpp b/libraries/render/src/render/BlurTask.cpp index 3849adf588..144e1e0058 100644 --- a/libraries/render/src/render/BlurTask.cpp +++ b/libraries/render/src/render/BlurTask.cpp @@ -96,6 +96,9 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra if (!sourceFramebuffer) { return false; } + if (_blurredFramebuffer && _blurredFramebuffer->getSize() != sourceFramebuffer->getSize()) { + _blurredFramebuffer.reset(); + } if (!_blurredFramebuffer) { _blurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); @@ -107,21 +110,17 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler)); _blurredFramebuffer->setRenderBuffer(0, blurringTarget); - } else { - // it would be easier to just call resize on the bluredFramebuffer and let it work if needed but the source might loose it's depth buffer when doing so - if ((_blurredFramebuffer->getWidth() != sourceFramebuffer->getWidth()) || (_blurredFramebuffer->getHeight() != sourceFramebuffer->getHeight())) { - _blurredFramebuffer->resize(sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), sourceFramebuffer->getNumSamples()); - //if (sourceFramebuffer->hasDepthStencil()) { - // _blurredFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); - //} - } - } + } blurringResources.sourceTexture = sourceFramebuffer->getRenderBuffer(0); blurringResources.blurringFramebuffer = _blurredFramebuffer; blurringResources.blurringTexture = _blurredFramebuffer->getRenderBuffer(0); if (_generateOutputFramebuffer) { + if (_outputFramebuffer && _outputFramebuffer->getSize() != sourceFramebuffer->getSize()) { + _outputFramebuffer.reset(); + } + // The job output the blur result in a new Framebuffer spawning here. // Let s make sure it s ready for this if (!_outputFramebuffer) { @@ -134,13 +133,6 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra auto blurringSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); auto blurringTarget = gpu::TexturePointer(gpu::Texture::create2D(sourceFramebuffer->getRenderBuffer(0)->getTexelFormat(), sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), blurringSampler)); _outputFramebuffer->setRenderBuffer(0, blurringTarget); - } else { - if ((_outputFramebuffer->getWidth() != sourceFramebuffer->getWidth()) || (_outputFramebuffer->getHeight() != sourceFramebuffer->getHeight())) { - _outputFramebuffer->resize(sourceFramebuffer->getWidth(), sourceFramebuffer->getHeight(), sourceFramebuffer->getNumSamples()); - /* if (sourceFramebuffer->hasDepthStencil()) { - _outputFramebuffer->setDepthStencilBuffer(sourceFramebuffer->getDepthStencilBuffer(), sourceFramebuffer->getDepthStencilBufferFormat()); - }*/ - } } // Should be good to use the output Framebuffer as final From f33d3a3b36169c671330c43434e28134bd30467d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 13:24:03 -0700 Subject: [PATCH 22/42] Migrate logging functionality to shared library --- interface/src/Application.h | 2 +- interface/src/ui/LogDialog.h | 2 +- interface/src/ui/Snapshot.cpp | 2 +- libraries/networking/src/HifiSockAddr.cpp | 30 ------------- libraries/networking/src/HifiSockAddr.h | 3 -- libraries/networking/src/LimitedNodeList.cpp | 1 + .../src/shared}/AbstractLoggerInterface.h | 0 .../shared/src/shared}/FileLogger.cpp | 9 ++-- .../shared/src/shared}/FileLogger.h | 2 +- .../shared/src/shared}/FileUtils.cpp | 0 .../shared/src/shared}/FileUtils.h | 0 libraries/shared/src/shared/NetworkUtils.cpp | 42 +++++++++++++++++++ libraries/shared/src/shared/NetworkUtils.h | 17 ++++++++ tests/render-perf/src/main.cpp | 22 ++++++---- 14 files changed, 83 insertions(+), 49 deletions(-) rename {interface/src => libraries/shared/src/shared}/AbstractLoggerInterface.h (100%) rename {interface/src => libraries/shared/src/shared}/FileLogger.cpp (97%) rename {interface/src => libraries/shared/src/shared}/FileLogger.h (97%) rename {interface/src => libraries/shared/src/shared}/FileUtils.cpp (100%) rename {interface/src => libraries/shared/src/shared}/FileUtils.h (100%) create mode 100644 libraries/shared/src/shared/NetworkUtils.cpp create mode 100644 libraries/shared/src/shared/NetworkUtils.h diff --git a/interface/src/Application.h b/interface/src/Application.h index 4c52ff8526..2dc60c2438 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -44,12 +44,12 @@ #include #include #include +#include #include "avatar/MyAvatar.h" #include "Bookmarks.h" #include "Camera.h" #include "ConnectionMonitor.h" -#include "FileLogger.h" #include "gpu/Context.h" #include "Menu.h" #include "octree/OctreePacketProcessor.h" diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index c38cf84f00..1493a43f01 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -20,7 +20,7 @@ #include #include -#include "AbstractLoggerInterface.h" +#include class KeywordHighlighter : public QSyntaxHighlighter { Q_OBJECT diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index c2fcafb2f3..a0ee260bcc 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index bde0aca7b7..d6981f420d 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -124,36 +124,6 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) { return dataStream; } -QHostAddress getGuessedLocalAddress() { - - QHostAddress localAddress; - - foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { - if (networkInterface.flags() & QNetworkInterface::IsUp - && networkInterface.flags() & QNetworkInterface::IsRunning - && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { - // we've decided that this is the active NIC - // enumerate it's addresses to grab the IPv4 address - foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { - // make sure it's an IPv4 address that isn't the loopback - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { - - // set our localAddress and break out - localAddress = entry.ip(); - break; - } - } - } - - if (!localAddress.isNull()) { - break; - } - } - - // return the looked up local address - return localAddress; -} - uint qHash(const HifiSockAddr& key, uint seed) { // use the existing QHostAddress and quint16 hash functions to get our hash return qHash(key.getAddress(), seed) ^ qHash(key.getPort(), seed); diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 063a41a202..c4ff8cb246 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -91,9 +91,6 @@ namespace std { }; } - -QHostAddress getGuessedLocalAddress(); - Q_DECLARE_METATYPE(HifiSockAddr); #endif // hifi_HifiSockAddr_h diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index ec4b2c3573..ce555315e8 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/interface/src/AbstractLoggerInterface.h b/libraries/shared/src/shared/AbstractLoggerInterface.h similarity index 100% rename from interface/src/AbstractLoggerInterface.h rename to libraries/shared/src/shared/AbstractLoggerInterface.h diff --git a/interface/src/FileLogger.cpp b/libraries/shared/src/shared/FileLogger.cpp similarity index 97% rename from interface/src/FileLogger.cpp rename to libraries/shared/src/shared/FileLogger.cpp index 754fa7f474..ef3436a8d7 100644 --- a/interface/src/FileLogger.cpp +++ b/libraries/shared/src/shared/FileLogger.cpp @@ -15,11 +15,12 @@ #include #include -#include -#include -#include +#include "FileUtils.h" +#include "NetworkUtils.h" + +#include "../NumericalConstants.h" +#include "../SharedUtil.h" -#include "HifiSockAddr.h" static const QString FILENAME_FORMAT = "hifi-log_%1_%2.txt"; static const QString DATETIME_FORMAT = "yyyy-MM-dd_hh.mm.ss"; diff --git a/interface/src/FileLogger.h b/libraries/shared/src/shared/FileLogger.h similarity index 97% rename from interface/src/FileLogger.h rename to libraries/shared/src/shared/FileLogger.h index 950590e789..697b96c6d8 100644 --- a/interface/src/FileLogger.h +++ b/libraries/shared/src/shared/FileLogger.h @@ -13,7 +13,7 @@ #define hifi_FileLogger_h #include "AbstractLoggerInterface.h" -#include +#include "../GenericQueueThread.h" #include diff --git a/interface/src/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp similarity index 100% rename from interface/src/FileUtils.cpp rename to libraries/shared/src/shared/FileUtils.cpp diff --git a/interface/src/FileUtils.h b/libraries/shared/src/shared/FileUtils.h similarity index 100% rename from interface/src/FileUtils.h rename to libraries/shared/src/shared/FileUtils.h diff --git a/libraries/shared/src/shared/NetworkUtils.cpp b/libraries/shared/src/shared/NetworkUtils.cpp new file mode 100644 index 0000000000..50356d30fc --- /dev/null +++ b/libraries/shared/src/shared/NetworkUtils.cpp @@ -0,0 +1,42 @@ +// +// Created by Bradley Austin Davis on 2016/09/20 +// 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 "NetworkUtils.h" +#include + +QHostAddress getGuessedLocalAddress() { + + QHostAddress localAddress; + + foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { + if (networkInterface.flags() & QNetworkInterface::IsUp + && networkInterface.flags() & QNetworkInterface::IsRunning + && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { + // we've decided that this is the active NIC + // enumerate it's addresses to grab the IPv4 address + foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { + // make sure it's an IPv4 address that isn't the loopback + if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { + + // set our localAddress and break out + localAddress = entry.ip(); + break; + } + } + } + + if (!localAddress.isNull()) { + break; + } + } + + // return the looked up local address + return localAddress; +} + + diff --git a/libraries/shared/src/shared/NetworkUtils.h b/libraries/shared/src/shared/NetworkUtils.h new file mode 100644 index 0000000000..b881441004 --- /dev/null +++ b/libraries/shared/src/shared/NetworkUtils.h @@ -0,0 +1,17 @@ +// +// Created by Bradley Austin Davis on 2016/09/20 +// 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 hifi_shared_NetworkUtils_h +#define hifi_shared_NetworkUtils_h + +#include + +QHostAddress getGuessedLocalAddress(); + +#endif // hifi_shared_NetworkUtils_h diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 238972dc00..4745529f19 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -32,12 +32,11 @@ #include +#include +#include +#include #include -//#include -//#include -//#include - #include #include #include @@ -149,6 +148,7 @@ public: }; #else + class QWindowCamera : public Camera { Key forKey(int key) { switch (key) { @@ -417,6 +417,7 @@ public: }; render::ItemID BackgroundRenderData::_item = 0; +QSharedPointer logger; namespace render { template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { @@ -1069,12 +1070,14 @@ private: bool QTestWindow::_cullingEnabled = true; void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { - if (!message.isEmpty()) { + QString logMessage = LogHandler::getInstance().printMessage((LogMsgType)type, context, message); + + if (!logMessage.isEmpty()) { #ifdef Q_OS_WIN - OutputDebugStringA(message.toLocal8Bit().constData()); + OutputDebugStringA(logMessage.toLocal8Bit().constData()); OutputDebugStringA("\n"); #endif - std::cout << message.toLocal8Bit().constData() << std::endl; + logger->addMessage(qPrintable(logMessage + "\n")); } } @@ -1082,11 +1085,14 @@ const char * LOG_FILTER_RULES = R"V0G0N( hifi.gpu=true )V0G0N"; + int main(int argc, char** argv) { - QApplication app(argc, argv); + QGuiApplication app(argc, argv); QCoreApplication::setApplicationName("RenderPerf"); QCoreApplication::setOrganizationName("High Fidelity"); QCoreApplication::setOrganizationDomain("highfidelity.com"); + logger.reset(new FileLogger()); + qInstallMessageHandler(messageHandler); QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow::setup(); From 2a058fa4196352a19a00d57274c29e307a6e2727 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 15:44:55 -0700 Subject: [PATCH 23/42] Add file logging to perf tool --- libraries/shared/src/shared/FileUtils.cpp | 25 +++- libraries/shared/src/shared/FileUtils.h | 3 +- tests/render-perf/src/main.cpp | 144 +++++++++++++--------- 3 files changed, 110 insertions(+), 62 deletions(-) diff --git a/libraries/shared/src/shared/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp index a89a873bea..8c962dfd6d 100644 --- a/libraries/shared/src/shared/FileUtils.cpp +++ b/libraries/shared/src/shared/FileUtils.cpp @@ -9,14 +9,29 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include -#include -#include #include "FileUtils.h" +#include +#include +#include +#include +#include +#include +#include + + +QString FileUtils::readFile(const QString& filename) { + QFile file(filename); + file.open(QFile::Text | QFile::ReadOnly); + QString result; + result.append(QTextStream(&file).readAll()); + return result; +} + +QStringList FileUtils::readLines(const QString& filename, QString::SplitBehavior splitBehavior) { + return readFile(filename).split(QRegularExpression("[\\r\\n]"), QString::SkipEmptyParts); +} void FileUtils::locateFile(QString filePath) { diff --git a/libraries/shared/src/shared/FileUtils.h b/libraries/shared/src/shared/FileUtils.h index d2b30595a7..4f2c1b7af5 100644 --- a/libraries/shared/src/shared/FileUtils.h +++ b/libraries/shared/src/shared/FileUtils.h @@ -19,7 +19,8 @@ class FileUtils { public: static void locateFile(QString fileName); static QString standardPath(QString subfolder); - + static QString readFile(const QString& filename); + static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts); }; #endif // hifi_FileUtils_h diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 4745529f19..bf1ec283cf 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -98,57 +100,6 @@ public: } }; -#if 0 -class GlfwCamera : public Camera { - Key forKey(int key) { - switch (key) { - case GLFW_KEY_W: return FORWARD; - case GLFW_KEY_S: return BACK; - case GLFW_KEY_A: return LEFT; - case GLFW_KEY_D: return RIGHT; - case GLFW_KEY_E: return UP; - case GLFW_KEY_C: return DOWN; - case GLFW_MOUSE_BUTTON_LEFT: return MLEFT; - case GLFW_MOUSE_BUTTON_RIGHT: return MRIGHT; - case GLFW_MOUSE_BUTTON_MIDDLE: return MMIDDLE; - default: break; - } - return INVALID; - } - - vec2 _lastMouse; -public: - void keyHandler(int key, int scancode, int action, int mods) { - Key k = forKey(key); - if (k == INVALID) { - return; - } - if (action == GLFW_PRESS) { - keys.set(k); - } else if (action == GLFW_RELEASE) { - keys.reset(k); - } - } - - //static void MouseMoveHandler(GLFWwindow* window, double posx, double posy); - //static void MouseScrollHandler(GLFWwindow* window, double xoffset, double yoffset); - void onMouseMove(double posx, double posy) { - vec2 mouse = vec2(posx, posy); - vec2 delta = mouse - _lastMouse; - if (keys.at(Key::MRIGHT)) { - dolly(delta.y * 0.01f); - } else if (keys.at(Key::MLEFT)) { - rotate(delta.x * -0.01f); - } else if (keys.at(Key::MMIDDLE)) { - delta.y *= -1.0f; - translate(delta * -0.01f); - } - _lastMouse = mouse; - } - -}; -#else - class QWindowCamera : public Camera { Key forKey(int key) { switch (key) { @@ -198,7 +149,6 @@ public: _lastMouse = mouse; } }; -#endif static QString toHumanSize(size_t size, size_t maxUnit = std::numeric_limits::max()) { static const std::vector SUFFIXES{ { "B", "KB", "MB", "GB", "TB", "PB" } }; @@ -241,7 +191,7 @@ public: std::mutex _mutex; std::shared_ptr _backend; std::vector _frameTimes; - size_t _frameIndex; + size_t _frameIndex { 0 }; std::mutex _frameLock; std::queue _pendingFrames; gpu::FramePointer _activeFrame; @@ -253,7 +203,6 @@ public: _pendingFrames.push(frame); } - void initialize(QWindow* window, gl::Context& initContext) { setObjectName("RenderThread"); _context.setWindow(window); @@ -372,7 +321,6 @@ public: } } - bool process() override { std::queue pendingFrames; { @@ -590,6 +538,16 @@ public: DependencyManager::destroy(); } + void loadCommands(const QString& filename) { + QFileInfo fileInfo(filename); + if (!fileInfo.exists()) { + return; + } + _commandPath = fileInfo.absolutePath(); + _commands = FileUtils::readLines(filename); + _commandIndex = 0; + } + protected: bool eventFilter(QObject *obj, QEvent *event) override { @@ -780,10 +738,76 @@ private: #endif } + void runCommand(const QString& command) { + QStringList commandParams = command.split(QRegularExpression(QString("\\s"))); + QString verb = commandParams[0].toLower(); + if (verb == "loop") { + if (commandParams.length() > 1) { + int maxLoops = commandParams[1].toInt(); + if (maxLoops > ++_commandLoops) { + qDebug() << "Exceeded loop count"; + return; + } + } + _commandIndex = 0; + } else if (verb == "wait") { + if (commandParams.length() < 2) { + qDebug() << "No wait time specified"; + return; + } + int seconds = commandParams[1].toInt(); + _nextCommandTime = usecTimestampNow() + seconds * USECS_PER_SECOND; + } else if (verb == "load") { + if (commandParams.length() < 2) { + qDebug() << "No load file specified"; + return; + } + QString file = commandParams[1]; + if (QFileInfo(file).isRelative()) { + file = _commandPath + "/" + file; + } + if (!QFileInfo(file).exists()) { + qDebug() << "Cannot find scene file " + file; + return; + } + + importScene(file); + } else if (verb == "go") { + if (commandParams.length() < 2) { + qDebug() << "No destination specified for go command"; + return; + } + parsePath(commandParams[1]); + } else { + qDebug() << "Unknown command " << command; + } + } + + void runNextCommand(quint64 now) { + if (_commands.empty()) { + return; + } + + if (_commandIndex >= _commands.size()) { + _commands.clear(); + return; + } + + if (now < _nextCommandTime) { + return; + } + + _nextCommandTime = 0; + QString command = _commands[_commandIndex++]; + runCommand(command); + } + void update() { auto now = usecTimestampNow(); static auto last = now; + runNextCommand(now); + float delta = now - last; // Update the camera _camera.update(delta / USECS_PER_SECOND); @@ -936,7 +960,6 @@ private: QString atpUrl = QUrl::fromLocalFile(atpPath).toString(); ResourceManager::setUrlPrefixOverride("atp:/", atpUrl + "/"); } - _settings.setValue(LAST_SCENE_KEY, fileName); _octree->clear(); _octree->getTree()->readFromURL(fileName); } @@ -955,6 +978,7 @@ private: if (fileName.isNull()) { return; } + _settings.setValue(LAST_SCENE_KEY, fileName); importScene(fileName); } @@ -1054,6 +1078,13 @@ private: model::SunSkyStage _sunSkyStage; model::LightPointer _globalLight { std::make_shared() }; bool _ready { false }; + + QStringList _commands; + QString _commandPath; + int _commandLoops { 0 }; + int _commandIndex { -1 }; + uint64_t _nextCommandTime { 0 }; + //TextOverlay* _textOverlay; static bool _cullingEnabled; @@ -1097,6 +1128,7 @@ int main(int argc, char** argv) { QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow::setup(); QTestWindow window; + window.loadCommands("C:/Users/bdavis/Git/dreaming/exports/commands.txt"); app.exec(); return 0; } From d382305174b1d4d2d30042b1a68c94c1f61eb8c7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 15:46:04 -0700 Subject: [PATCH 24/42] Add fence tracking and max values tracking to gpu::Context --- libraries/gpu/src/gpu/Context.cpp | 46 +++++++++++++++++++++++++------ libraries/gpu/src/gpu/Context.h | 7 ++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/libraries/gpu/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp index 68a6be1fe5..af3552911c 100644 --- a/libraries/gpu/src/gpu/Context.cpp +++ b/libraries/gpu/src/gpu/Context.cpp @@ -10,6 +10,7 @@ // #include "Context.h" #include "Frame.h" +#include "GPULogging.h" using namespace gpu; Context::CreateBackend Context::_createBackendCallback = nullptr; @@ -161,8 +162,9 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S } // Counters for Buffer and Texture usage in GPU/Context -std::atomic Context::_bufferGPUCount{ 0 }; -std::atomic Context::_bufferGPUMemoryUsage{ 0 }; +std::atomic Context::_fenceCount { 0 }; +std::atomic Context::_bufferGPUCount { 0 }; +std::atomic Context::_bufferGPUMemoryUsage { 0 }; std::atomic Context::_textureGPUCount{ 0 }; std::atomic Context::_textureGPUMemoryUsage{ 0 }; @@ -170,10 +172,15 @@ std::atomic Context::_textureGPUVirtualMemoryUsage{ 0 }; std::atomic Context::_textureGPUTransferCount{ 0 }; void Context::incrementBufferGPUCount() { - _bufferGPUCount++; + static std::atomic max { 0 }; + auto total = ++_bufferGPUCount; + if (total > max.load()) { + max = total; + qCDebug(gpulogging) << "New max GPU buffers " << total; + } } void Context::decrementBufferGPUCount() { - _bufferGPUCount--; + --_bufferGPUCount; } void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { @@ -186,12 +193,30 @@ void Context::updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize } } +void Context::incrementFenceCount() { + static std::atomic max { 0 }; + auto total = ++_fenceCount; + if (total > max.load()) { + max = total; + qCDebug(gpulogging) << "New max Fences " << total; + } +} +void Context::decrementFenceCount() { + --_fenceCount; +} + void Context::incrementTextureGPUCount() { - _textureGPUCount++; + static std::atomic max { 0 }; + auto total = ++_textureGPUCount; + if (total > max.load()) { + max = total; + qCDebug(gpulogging) << "New max GPU textures " << total; + } } void Context::decrementTextureGPUCount() { - _textureGPUCount--; + --_textureGPUCount; } + void Context::updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { return; @@ -215,10 +240,15 @@ void Context::updateTextureGPUVirtualMemoryUsage(Size prevObjectSize, Size newOb } void Context::incrementTextureGPUTransferCount() { - _textureGPUTransferCount++; + static std::atomic max { 0 }; + auto total = ++_textureGPUTransferCount; + if (total > max.load()) { + max = total; + qCDebug(gpulogging) << "New max GPU textures transfers" << total; + } } void Context::decrementTextureGPUTransferCount() { - _textureGPUTransferCount--; + --_textureGPUTransferCount; } uint32_t Context::getBufferGPUCount() { diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 42b81606db..4c701e170d 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -230,6 +230,9 @@ protected: static void decrementBufferGPUCount(); static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); + static void incrementFenceCount(); + static void decrementFenceCount(); + static void incrementTextureGPUCount(); static void decrementTextureGPUCount(); static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize); @@ -237,7 +240,9 @@ protected: static void incrementTextureGPUTransferCount(); static void decrementTextureGPUTransferCount(); - // Buffer and Texture Counters + // Buffer, Texture and Fence Counters + static std::atomic _fenceCount; + static std::atomic _bufferGPUCount; static std::atomic _bufferGPUMemoryUsage; From ee476a604866369fbcb20b3db1610638c6f61b2b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 19:45:50 -0700 Subject: [PATCH 25/42] GLTextures store the source for easier debugging --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 1 + libraries/gpu-gl/src/gpu/gl/GLTexture.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index c2d6b3eb54..16ee81592a 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -135,6 +135,7 @@ float GLTexture::getMemoryPressure() { // Create the texture and allocate storage GLTexture::GLTexture(const std::weak_ptr& backend, const Texture& texture, GLuint id, bool transferrable) : GLObject(backend, texture, id), + _source(texture.source()), _storageStamp(texture.getStamp()), _target(getGLTextureType(texture)), _internalFormat(gl::GLTexelFormat::evalGLTexelFormatInternal(texture.getTexelFormat())), diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index fa893ae52a..4375d0644f 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -111,6 +111,7 @@ public: ~GLTexture(); const GLuint& _texture { _id }; + const std::string _source; const Stamp _storageStamp; const GLenum _target; const GLenum _internalFormat; From 255e9e6435ca8b1d90c4479b98069d44eb191a0d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 19:46:26 -0700 Subject: [PATCH 26/42] Add support for executing arbitrary commands on the texture transfer thread --- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 15 +++++++++++++-- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 4cb8e4fad1..7a709dfce3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -97,12 +97,23 @@ void GLTextureTransferHelper::shutdown() { #endif } +void GLTextureTransferHelper::queueExecution(VoidLambda lambda) { + Lock lock(_mutex); + _pendingCommands.push_back(lambda); +} + bool GLTextureTransferHelper::process() { - // Take any new textures off the queue + // Take any new textures or commands off the queue + VoidLambdaList pendingCommands; TextureList newTransferTextures; { Lock lock(_mutex); newTransferTextures.swap(_pendingTextures); + pendingCommands.swap(_pendingCommands); + } + + for (auto command : pendingCommands) { + command(); } if (!newTransferTextures.empty()) { @@ -144,7 +155,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); - //clientWait(); + clientWait(); gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); gltexture->updateSize(); gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h index fe7414e370..289aec40bb 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.h @@ -28,10 +28,13 @@ using TextureListIterator = TextureList::iterator; class GLTextureTransferHelper : public GenericThread { public: + using VoidLambda = std::function; + using VoidLambdaList = std::list; using Pointer = std::shared_ptr; GLTextureTransferHelper(); ~GLTextureTransferHelper(); void transferTexture(const gpu::TexturePointer& texturePointer); + void queueExecution(VoidLambda lambda); void setup() override; void shutdown() override; @@ -47,6 +50,8 @@ private: #endif // A mutex for protecting items access on the render and transfer threads Mutex _mutex; + // Commands that have been submitted for execution on the texture transfer thread + VoidLambdaList _pendingCommands; // Textures that have been submitted for transfer TextureList _pendingTextures; // Textures currently in the transfer process From 28bb82c8a34112add8e40fe5c75335d587a80a0b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 19:47:31 -0700 Subject: [PATCH 27/42] Force all sparse allocation and deallocation onto one thread / context --- .../src/gpu/gl45/GL45BackendTexture.cpp | 82 +++++++++++-------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 09c6003ced..886c7b8145 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -94,7 +94,7 @@ SparseInfo::SparseInfo(GL45Texture& texture) void SparseInfo::maybeMakeSparse() { // Don't enable sparse for objects with explicitly managed mip levels if (!_texture._gpuObject.isAutogenerateMips()) { - qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << _texture._gpuObject.source().c_str(); + qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << _texture._source.c_str(); return; } @@ -106,7 +106,7 @@ void SparseInfo::maybeMakeSparse() { _pageDimensions = allowedPageDimensions[i]; // Is this texture an integer multiple of page dimensions? if (uvec3(0) == (dimensions % _pageDimensions)) { - qCDebug(gpugl45logging) << "Enabling sparse for texture " << _texture._gpuObject.source().c_str(); + qCDebug(gpugl45logging) << "Enabling sparse for texture " << _texture._source.c_str(); _sparse = true; break; } @@ -117,7 +117,7 @@ void SparseInfo::maybeMakeSparse() { glTextureParameteri(_texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, _pageDimensionsIndex); } else { qCDebug(gpugl45logging) << "Size " << dimensions.x << " x " << dimensions.y << - " is not supported by any sparse page size for texture" << _texture._gpuObject.source().c_str(); + " is not supported by any sparse page size for texture" << _texture._source.c_str(); } } @@ -255,40 +255,56 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& } GL45Texture::~GL45Texture() { + qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str(); if (_sparseInfo._sparse) { - auto backend = _backend.lock(); - if (backend) { - auto id = _id; + // Remove this texture from the candidate list of derezzable textures + { auto mipLevels = usedMipLevels(); - { - Lock lock(texturesByMipCountsMutex); - if (texturesByMipCounts.count(mipLevels)) { - auto& textures = texturesByMipCounts[mipLevels]; - textures.erase(this); - if (textures.empty()) { - texturesByMipCounts.erase(mipLevels); - } + Lock lock(texturesByMipCountsMutex); + if (texturesByMipCounts.count(mipLevels)) { + auto& textures = texturesByMipCounts[mipLevels]; + textures.erase(this); + if (textures.empty()) { + texturesByMipCounts.erase(mipLevels); } } - - auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); - uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { - auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); - // Destructors get called on the main thread, potentially without a context active. - // We need to queue the deallocation of the sparse pages for this content. - backend->releaseLambda([=] { - glTexturePageCommitmentEXT(id, mipLevel, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); - }); - auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; - assert(deallocatedPages <= _allocatedPages); - _allocatedPages -= deallocatedPages; - } - - if (0 != _allocatedPages) { - qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; - } } + + // Experimenation suggests that allocating sparse textures on one context/thread and deallocating + // them on another is buggy. So for sparse textures we need to queue a lambda with the deallocation + // callls to the transfer thread + auto id = _id; + // Set the class _id to 0 so we don't try to double delete + const_cast(_id) = 0; + std::list> destructionFunctions; + + auto minMip = _minMip; + uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); + auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); + for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { + auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); + destructionFunctions.push_back([id, maxFace, mipLevel, mipDimensions] { + glTexturePageCommitmentEXT(id, mipLevel, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); + }); + + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; + assert(deallocatedPages <= _allocatedPages); + _allocatedPages -= deallocatedPages; + } + + if (0 != _allocatedPages) { + qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages; + } + + auto size = _size; + _textureTransferHelper->queueExecution([id, size, destructionFunctions] { + for (auto function : destructionFunctions) { + function(); + } + glDeleteTextures(1, &id); + Backend::decrementTextureGPUCount(); + Backend::updateTextureGPUMemoryUsage(size, 0); + }); } } @@ -297,7 +313,7 @@ void GL45Texture::withPreservedTexture(std::function f) const { } void GL45Texture::generateMips() const { - qCDebug(gpugl45logging) << "Generating mipmaps for " << _gpuObject.source().c_str(); + qCDebug(gpugl45logging) << "Generating mipmaps for " << _source.c_str(); glGenerateTextureMipmap(_id); (void)CHECK_GL_ERROR(); } From 5dbaa671ca2c93df8393c63533fbee1cb63051af Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 19:48:19 -0700 Subject: [PATCH 28/42] Add some more debugging in render perf test --- tests/render-perf/src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index bf1ec283cf..1bc042d319 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -739,6 +739,7 @@ private: } void runCommand(const QString& command) { + qDebug() << "Running command: " << command; QStringList commandParams = command.split(QRegularExpression(QString("\\s"))); QString verb = commandParams[0].toLower(); if (verb == "loop") { From 6711b9c41792f436214af9dae8fb9fbb419b0fdf Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 19:48:49 -0700 Subject: [PATCH 29/42] Restore proper mip handling to skybox --- libraries/model/src/model/skybox.slf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model/src/model/skybox.slf b/libraries/model/src/model/skybox.slf index c0770525f7..7b25e36af7 100755 --- a/libraries/model/src/model/skybox.slf +++ b/libraries/model/src/model/skybox.slf @@ -48,7 +48,7 @@ void main(void) { // blend is only set if there is a cubemap if (skybox.color.a > 0.0) { - color = textureLod(cubeMap, coord, 0).rgb; + color = texture(cubeMap, coord).rgb; if (skybox.color.a < 1.0) { color *= skybox.color.rgb; } From 09a218b9fd0da9eb64659b802ea8473387521b14 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 20 Sep 2016 22:51:48 -0700 Subject: [PATCH 30/42] Fix build after moving network function --- assignment-client/src/octree/OctreeServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 48ffc2fdbc..3e36250a82 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include From cfa5376effded42351975103a5d187e4946a2392 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 07:25:44 -0700 Subject: [PATCH 31/42] Straight up bug --- libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index 906144e013..f18962976c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -165,7 +165,7 @@ void GLBackend::do_setUniformBuffer(const Batch& batch, size_t paramOffset) { _uniform._buffers[slot] = uniformBuffer; (void) CHECK_GL_ERROR(); } else { - releaseResourceTexture(slot); + releaseUniformBuffer(slot); return; } } From c52de6c685ec9186748c7b850acc1eeac46f667a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 07:34:22 -0700 Subject: [PATCH 32/42] Fixing mip deallocation --- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 886c7b8145..de61952a93 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -476,16 +476,15 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); for (uint16_t mip = _minMip; mip < newMinMip; ++mip) { + auto id = _id; auto mipDimensions = _gpuObject.evalMipDimensions(mip); - auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions); - for (uint8_t face = 0; face < maxFace; ++face) { - glTexturePageCommitmentEXT(_id, mip, - 0, 0, face, - mipDimensions.x, mipDimensions.y, mipDimensions.z, - GL_FALSE); - assert(deallocatedPages < _allocatedPages); - _allocatedPages -= deallocatedPages; - } + _textureTransferHelper->queueExecution([id, mip, mipDimensions, maxFace] { + glTexturePageCommitmentEXT(id, mip, 0, 0, 0, mipDimensions.x, mipDimensions.y, maxFace, GL_FALSE); + }); + + auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace; + assert(deallocatedPages < _allocatedPages); + _allocatedPages -= deallocatedPages; } _minMip = newMinMip; From 2de7f62b9563839a8786776228fdb111c31b93da Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 07:36:58 -0700 Subject: [PATCH 33/42] Fixing loop logic --- tests/render-perf/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 1bc042d319..660ffd6994 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -745,7 +745,7 @@ private: if (verb == "loop") { if (commandParams.length() > 1) { int maxLoops = commandParams[1].toInt(); - if (maxLoops > ++_commandLoops) { + if (maxLoops < ++_commandLoops) { qDebug() << "Exceeded loop count"; return; } From bca9da48fc4acb5cb3534b0c6b3ca4a84831bee7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 07:43:12 -0700 Subject: [PATCH 34/42] Fix warnings --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index de61952a93..43aa257028 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -278,7 +278,6 @@ GL45Texture::~GL45Texture() { const_cast(_id) = 0; std::list> destructionFunctions; - auto minMip = _minMip; uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { From 2886c51a29a327cc11dffab70988ce2c8dc91771 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 11:01:51 -0700 Subject: [PATCH 35/42] Fixing use of widgets in test app --- tests/render-perf/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 660ffd6994..5ac82bdf29 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -1119,7 +1119,7 @@ hifi.gpu=true int main(int argc, char** argv) { - QGuiApplication app(argc, argv); + QApplication app(argc, argv); QCoreApplication::setApplicationName("RenderPerf"); QCoreApplication::setOrganizationName("High Fidelity"); QCoreApplication::setOrganizationDomain("highfidelity.com"); From 44a549317ece2086bb6d59faafe79462e748786e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 11:45:18 -0700 Subject: [PATCH 36/42] Reduce number of texture transfers per clientWait, process smaller textures first --- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 7a709dfce3..84bf278939 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -102,6 +102,8 @@ void GLTextureTransferHelper::queueExecution(VoidLambda lambda) { _pendingCommands.push_back(lambda); } +#define MAX_TRANSFERS_PER_PASS 2 + bool GLTextureTransferHelper::process() { // Take any new textures or commands off the queue VoidLambdaList pendingCommands; @@ -126,6 +128,9 @@ bool GLTextureTransferHelper::process() { _transferringTextures.push_back(texturePointer); _textureIterator = _transferringTextures.begin(); } + _transferringTextures.sort([](const gpu::TexturePointer& a, const gpu::TexturePointer& b)->bool { + return a->getSize() < b->getSize(); + }); } // No transfers in progress, sleep @@ -144,7 +149,11 @@ bool GLTextureTransferHelper::process() { qDebug() << "Texture list " << _transferringTextures.size(); } - for (auto _textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) { + size_t transferCount = 0; + for (_textureIterator = _transferringTextures.begin(); _textureIterator != _transferringTextures.end();) { + if (++transferCount > MAX_TRANSFERS_PER_PASS) { + break; + } auto texture = *_textureIterator; GLTexture* gltexture = Backend::getGPUObject(*texture); if (gltexture->continueTransfer()) { From 74a3d7fcb9f52b1d00de519d69c4ffdde192d167 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 21 Sep 2016 15:02:02 -0700 Subject: [PATCH 37/42] Flush executed commands on the transfer thread --- libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index 84bf278939..dbe022df2c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -114,8 +114,11 @@ bool GLTextureTransferHelper::process() { pendingCommands.swap(_pendingCommands); } - for (auto command : pendingCommands) { - command(); + if (!pendingCommands.empty()) { + for (auto command : pendingCommands) { + command(); + } + glFlush(); } if (!newTransferTextures.empty()) { From ab8a67e84daec061ad52d3197205c137107f83ce Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Sep 2016 10:17:23 -0700 Subject: [PATCH 38/42] Code review comments --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 6 +- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 4 +- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 9 +- .../gpu-gl/src/gpu/gl/GLTextureTransfer.cpp | 4 +- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 41 ++--- .../src/gpu/gl45/GL45BackendTexture.cpp | 167 +++++++++--------- libraries/gpu/src/gpu/Framebuffer.cpp | 26 --- libraries/gpu/src/gpu/Framebuffer.h | 3 - 8 files changed, 114 insertions(+), 146 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 72a953c5f3..f070dfe637 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -593,9 +593,9 @@ void GLBackend::releaseQuery(GLuint id) const { _queriesTrash.push_back(id); } -void GLBackend::releaseLambda(const std::function lambda) const { +void GLBackend::queueLambda(const std::function lambda) const { Lock lock(_trashMutex); - _lambdasTrash.push_back(lambda); + _lambdaQueue.push_back(lambda); } void GLBackend::recycle() const { @@ -603,7 +603,7 @@ void GLBackend::recycle() const { std::list> lamdbasTrash; { Lock lock(_trashMutex); - std::swap(_lambdasTrash, lamdbasTrash); + std::swap(_lambdaQueue, lamdbasTrash); } for (auto lambda : lamdbasTrash) { lambda(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 545ae6cbdc..af4851a1b0 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -175,7 +175,7 @@ public: virtual void releaseShader(GLuint id) const; virtual void releaseProgram(GLuint id) const; virtual void releaseQuery(GLuint id) const; - virtual void releaseLambda(const std::function lambda) const; + virtual void queueLambda(const std::function lambda) const; protected: @@ -198,7 +198,7 @@ protected: mutable std::list _shadersTrash; mutable std::list _programsTrash; mutable std::list _queriesTrash; - mutable std::list> _lambdasTrash; + mutable std::list> _lambdaQueue; void renderPassTransfer(const Batch& batch); void renderPassDraw(const Batch& batch); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 16ee81592a..94d645378b 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -20,6 +20,8 @@ std::shared_ptr GLTexture::_textureTransferHelper; // FIXME placeholder for texture memory over-use #define DEFAULT_MAX_MEMORY_MB 256 +#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f +#define OVER_MEMORY_PRESSURE 2.0f const GLenum GLTexture::CUBE_FACE_LAYOUT[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -92,7 +94,6 @@ const std::vector& GLTexture::getFaceTargets(GLenum target) { return faceTargets; } -#define MIN_FREE_GPU_MEMORY_PERCENTAGE 0.25f float GLTexture::getMemoryPressure() { // Check for an explicit memory limit @@ -115,15 +116,15 @@ float GLTexture::getMemoryPressure() { lastFreeGpuMemory = freeGpuMemory; if (freePercentage < MIN_FREE_GPU_MEMORY_PERCENTAGE) { qDebug() << "Exceeded max GPU memory"; - return 2.0; + return OVER_MEMORY_PRESSURE; } } } } - // Allow 75% of all available GPU memory to be consumed by textures + // Allow 50% of all available GPU memory to be consumed by textures // FIXME overly conservative? - availableTextureMemory = (totalGpuMemory >> 2) * 3; + availableTextureMemory = (totalGpuMemory > 2); } // Return the consumed texture memory divided by the available texture memory. diff --git a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp index dbe022df2c..75af08d9a3 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTextureTransfer.cpp @@ -165,9 +165,9 @@ 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); +#ifdef THREADED_TEXTURE_TRANSFER clientWait(); +#endif gltexture->_contentStamp = gltexture->_gpuObject.getDataStamp(); gltexture->updateSize(); gltexture->setSyncState(gpu::gl::GLSyncState::Transferred); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index b684a9b8d2..f1c30b9382 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -39,39 +39,39 @@ public: void postTransfer() override; struct SparseInfo { - GL45Texture& _texture; - uvec3 _pageDimensions { DEFAULT_PAGE_DIMENSION }; - GLuint _maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; - uint32_t _maxPages { 0 }; - uint32_t _pageBytes { 0 }; - bool _sparse { false }; - GLint _pageDimensionsIndex { 0 }; SparseInfo(GL45Texture& texture); void maybeMakeSparse(); void update(); uvec3 getPageCounts(const uvec3& dimensions) const; uint32_t getPageCount(const uvec3& dimensions) const; + + GL45Texture& texture; + bool sparse { false }; + uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION }; + GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL }; + uint32_t maxPages { 0 }; + uint32_t pageBytes { 0 }; + GLint pageDimensionsIndex { 0 }; }; struct TransferState { - GL45Texture& _texture; - GLTexelFormat _texelFormat; - uint8_t _face { 0 }; - uint16_t _mipLevel { 0 }; - uint32_t _bytesPerLine { 0 }; - uint32_t _bytesPerPixel { 0 }; - uint32_t _bytesPerPage { 0 }; - - uvec3 _mipDimensions; - uvec3 _mipOffset; - const uint8_t* _srcPointer { nullptr }; + TransferState(GL45Texture& texture); uvec3 currentPageSize() const; void updateMip(); void populatePage(std::vector& dest); bool increment(); - TransferState(GL45Texture& texture); - }; + GL45Texture& texture; + GLTexelFormat texelFormat; + uint8_t face { 0 }; + uint16_t mipLevel { 0 }; + uint32_t bytesPerLine { 0 }; + uint32_t bytesPerPixel { 0 }; + uint32_t bytesPerPage { 0 }; + uvec3 mipDimensions; + uvec3 mipOffset; + const uint8_t* srcPointer { nullptr }; + }; protected: void updateMips() override; void stripToMip(uint16_t newMinMip); @@ -87,6 +87,7 @@ public: void generateMips() const override; void withPreservedTexture(std::function f) const override; void derez(); + SparseInfo _sparseInfo; TransferState _transferState; uint32_t _allocatedPages { 0 }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 43aa257028..1b5013beb2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -88,61 +88,61 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transf using SparseInfo = GL45Backend::GL45Texture::SparseInfo; SparseInfo::SparseInfo(GL45Texture& texture) - : _texture(texture) { + : texture(texture) { } void SparseInfo::maybeMakeSparse() { // Don't enable sparse for objects with explicitly managed mip levels - if (!_texture._gpuObject.isAutogenerateMips()) { - qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << _texture._source.c_str(); + if (!texture._gpuObject.isAutogenerateMips()) { + qCDebug(gpugl45logging) << "Don't enable sparse texture for explicitly generated mipmaps on texture " << texture._source.c_str(); return; } - const uvec3 dimensions = _texture._gpuObject.getDimensions(); - auto allowedPageDimensions = getPageDimensionsForFormat(_texture._target, _texture._internalFormat); + const uvec3 dimensions = texture._gpuObject.getDimensions(); + auto allowedPageDimensions = getPageDimensionsForFormat(texture._target, texture._internalFormat); // In order to enable sparse the texture size must be an integer multiple of the page size for (size_t i = 0; i < allowedPageDimensions.size(); ++i) { - _pageDimensionsIndex = (uint32_t) i; - _pageDimensions = allowedPageDimensions[i]; + pageDimensionsIndex = (uint32_t) i; + pageDimensions = allowedPageDimensions[i]; // Is this texture an integer multiple of page dimensions? - if (uvec3(0) == (dimensions % _pageDimensions)) { - qCDebug(gpugl45logging) << "Enabling sparse for texture " << _texture._source.c_str(); - _sparse = true; + if (uvec3(0) == (dimensions % pageDimensions)) { + qCDebug(gpugl45logging) << "Enabling sparse for texture " << texture._source.c_str(); + sparse = true; break; } } - if (_sparse) { - glTextureParameteri(_texture._id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); - glTextureParameteri(_texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, _pageDimensionsIndex); + if (sparse) { + glTextureParameteri(texture._id, GL_TEXTURE_SPARSE_ARB, GL_TRUE); + glTextureParameteri(texture._id, GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, pageDimensionsIndex); } else { qCDebug(gpugl45logging) << "Size " << dimensions.x << " x " << dimensions.y << - " is not supported by any sparse page size for texture" << _texture._source.c_str(); + " is not supported by any sparse page size for texture" << texture._source.c_str(); } } // This can only be called after we've established our storage size void SparseInfo::update() { - if (!_sparse) { + if (!sparse) { return; } - glGetTextureParameterIuiv(_texture._id, GL_NUM_SPARSE_LEVELS_ARB, &_maxSparseLevel); - _pageBytes = _texture._gpuObject.getTexelFormat().getSize(); - _pageBytes *= _pageDimensions.x * _pageDimensions.y * _pageDimensions.z; + glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel); + pageBytes = texture._gpuObject.getTexelFormat().getSize(); + pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z; - for (uint16_t mipLevel = 0; mipLevel <= _maxSparseLevel; ++mipLevel) { - auto mipDimensions = _texture._gpuObject.evalMipDimensions(mipLevel); + for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) { + auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel); auto mipPageCount = getPageCount(mipDimensions); - _maxPages += mipPageCount; + maxPages += mipPageCount; } - if (_texture._target == GL_TEXTURE_CUBE_MAP) { - _maxPages *= GLTexture::CUBE_NUM_FACES; + if (texture._target == GL_TEXTURE_CUBE_MAP) { + maxPages *= GLTexture::CUBE_NUM_FACES; } } uvec3 SparseInfo::getPageCounts(const uvec3& dimensions) const { - auto result = (dimensions / _pageDimensions) + - glm::clamp(dimensions % _pageDimensions, glm::uvec3(0), glm::uvec3(1)); + auto result = (dimensions / pageDimensions) + + glm::clamp(dimensions % pageDimensions, glm::uvec3(0), glm::uvec3(1)); return result; } @@ -153,59 +153,59 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const { using TransferState = GL45Backend::GL45Texture::TransferState; -TransferState::TransferState(GL45Texture& texture) : _texture(texture) { +TransferState::TransferState(GL45Texture& texture) : texture(texture) { } void TransferState::updateMip() { - _mipDimensions = _texture._gpuObject.evalMipDimensions(_mipLevel); - _mipOffset = uvec3(); - if (!_texture._gpuObject.isStoredMipFaceAvailable(_mipLevel, _face)) { - _srcPointer = nullptr; + 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; + 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() { - const SparseInfo& sparse = _texture._sparseInfo; - if ((_mipOffset.x + sparse._pageDimensions.x) < _mipDimensions.x) { - _mipOffset.x += sparse._pageDimensions.x; + const SparseInfo& sparse = texture._sparseInfo; + if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) { + mipOffset.x += sparse.pageDimensions.x; return true; } - if ((_mipOffset.y + sparse._pageDimensions.y) < _mipDimensions.y) { - _mipOffset.x = 0; - _mipOffset.y += sparse._pageDimensions.y; + if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) { + mipOffset.x = 0; + mipOffset.y += sparse.pageDimensions.y; return true; } - if (_mipOffset.z + sparse._pageDimensions.z < _mipDimensions.z) { - _mipOffset.x = 0; - _mipOffset.y = 0; - ++_mipOffset.z; + if (mipOffset.z + sparse.pageDimensions.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; + if (mipLevel + 1 < texture.usedMipLevels()) { + mipOffset = uvec3(0); + ++mipLevel; updateMip(); return true; } - uint8_t maxFace = (uint8_t)((_texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - uint8_t nextFace = _face + 1; + 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 (nextFace < maxFace) { - ++_face; - _mipOffset = uvec3(0); - _mipLevel = 0; + ++face; + mipOffset = uvec3(0); + mipLevel = 0; updateMip(); return true; } @@ -215,7 +215,7 @@ bool TransferState::increment() { void TransferState::populatePage(std::vector& buffer) { uvec3 pageSize = currentPageSize(); - auto bytesPerPageLine = _bytesPerPixel * pageSize.x; + 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)); @@ -226,14 +226,14 @@ void TransferState::populatePage(std::vector& buffer) { } 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 srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x); uint32_t dstOffset = bytesPerPageLine * y; - memcpy(dst + dstOffset, _srcPointer + srcOffset, pageSize.x * _bytesPerPixel); + memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel); } } uvec3 TransferState::currentPageSize() const { - return glm::clamp(_mipDimensions - _mipOffset, uvec3(1), _texture._sparseInfo._pageDimensions); + return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions); } GLuint GL45Texture::allocate(const Texture& texture) { @@ -256,7 +256,7 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& GL45Texture::~GL45Texture() { qCDebug(gpugl45logging) << "Destroying texture " << _id << " from source " << _source.c_str(); - if (_sparseInfo._sparse) { + if (_sparseInfo.sparse) { // Remove this texture from the candidate list of derezzable textures { auto mipLevels = usedMipLevels(); @@ -279,7 +279,7 @@ GL45Texture::~GL45Texture() { std::list> destructionFunctions; uint8_t maxFace = (uint8_t)((_target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1); - auto maxSparseMip = std::min(_maxMip, _sparseInfo._maxSparseLevel); + auto maxSparseMip = std::min(_maxMip, _sparseInfo.maxSparseLevel); for (uint16_t mipLevel = _minMip; mipLevel <= maxSparseMip; ++mipLevel) { auto mipDimensions = _gpuObject.evalMipDimensions(mipLevel); destructionFunctions.push_back([id, maxFace, mipLevel, mipDimensions] { @@ -335,7 +335,7 @@ void GL45Texture::updateSize() const { } if (_transferrable) { - setSize(_allocatedPages * _sparseInfo._pageBytes); + setSize(_allocatedPages * _sparseInfo.pageBytes); } else { setSize(_virtualSize); } @@ -353,42 +353,42 @@ bool GL45Texture::continueTransfer() { buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); } const uvec3 pageSize = _transferState.currentPageSize(); - const uvec3& offset = _transferState._mipOffset; + const uvec3& offset = _transferState.mipOffset; - if (_sparseInfo._sparse && _transferState._mipLevel <= _sparseInfo._maxSparseLevel) { - if (_allocatedPages > _sparseInfo._maxPages) { + if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) { + if (_allocatedPages > _sparseInfo.maxPages) { qCWarning(gpugl45logging) << "Exceeded max page allocation!"; } - glTexturePageCommitmentEXT(_id, _transferState._mipLevel, - offset.x, offset.y, _transferState._face, + glTexturePageCommitmentEXT(_id, _transferState.mipLevel, + offset.x, offset.y, _transferState.face, pageSize.x, pageSize.y, pageSize.z, GL_TRUE); ++_allocatedPages; } - if (_transferState._srcPointer) { + if (_transferState.srcPointer) { // Transfer the mip data _transferState.populatePage(buffer); if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, _transferState._mipLevel, + glTextureSubImage2D(_id, _transferState.mipLevel, offset.x, offset.y, pageSize.x, pageSize.y, - _transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); + _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); } else if (GL_TEXTURE_CUBE_MAP == _target) { - auto target = CUBE_FACE_LAYOUT[_transferState._face]; + 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, + glTextureSubImage2DEXT(_id, target, _transferState.mipLevel, offset.x, offset.y, pageSize.x, pageSize.y, - _transferState._texelFormat.format, _transferState._texelFormat.type, &buffer[0]); + _transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]); } } serverWait(); - auto currentMip = _transferState._mipLevel; + auto currentMip = _transferState.mipLevel; auto result = _transferState.increment(); - if (_sparseInfo._sparse && _transferState._mipLevel != currentMip && currentMip <= _sparseInfo._maxSparseLevel) { + if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) { auto mipDimensions = _gpuObject.evalMipDimensions(currentMip); auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions); auto newPages = _allocatedPages - _lastMipAllocatedPages; @@ -431,9 +431,9 @@ void GL45Texture::syncSampler() const { void GL45Texture::postTransfer() { Parent::postTransfer(); - if (_sparseInfo._sparse) { + if (_sparseInfo.sparse) { auto mipLevels = usedMipLevels(); - if (mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + if (mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } @@ -441,7 +441,7 @@ void GL45Texture::postTransfer() { } void GL45Texture::stripToMip(uint16_t newMinMip) { - if (!_sparseInfo._sparse) { + if (!_sparseInfo.sparse) { return; } @@ -450,7 +450,7 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { return; } - if (newMinMip > _sparseInfo._maxSparseLevel) { + if (newMinMip > _sparseInfo.maxSparseLevel) { qCWarning(gpugl45logging) << "Cannot increase the min mip into the mip tail"; return; } @@ -491,26 +491,21 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { syncSampler(); size_t oldSize = _size; updateSize(); - size_t newSize = _size; - if (newSize > oldSize) { - qCDebug(gpugl45logging) << "WTF"; - qCDebug(gpugl45logging) << "\told size " << oldSize; - qCDebug(gpugl45logging) << "\tnew size " << newSize; - } + assert(_size > oldSize); // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); - if (_sparseInfo._sparse && mipLevels > 1 && _minMip < _sparseInfo._maxSparseLevel) { + if (_sparseInfo.sparse && mipLevels > 1 && _minMip < _sparseInfo.maxSparseLevel) { Lock lock(texturesByMipCountsMutex); texturesByMipCounts[mipLevels].insert(this); } } void GL45Texture::updateMips() { - if (!_sparseInfo._sparse) { + if (!_sparseInfo.sparse) { return; } - auto newMinMip = std::min(_gpuObject.minMip(), _sparseInfo._maxSparseLevel); + auto newMinMip = std::min(_gpuObject.minMip(), _sparseInfo.maxSparseLevel); if (_minMip < newMinMip) { stripToMip(newMinMip); } diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp index 8a97c0d748..2cd39d49ae 100755 --- a/libraries/gpu/src/gpu/Framebuffer.cpp +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -115,32 +115,6 @@ void Framebuffer::updateSize(const TexturePointer& texture) { } } -#if 0 -void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) { - if (width && height && numSamples && !isEmpty() && !isSwapchain()) { - if ((width != _width) || (height != _height) || (numSamples != _numSamples)) { - _numSamples = numSamples; - for (uint32 i = 0; i < _renderBuffers.size(); ++i) { - if (_renderBuffers[i]) { - _renderBuffers[i]._texture->resize2D(width, height, _numSamples); - assert(_renderBuffers[i]._texture->getNumSamples() == _numSamples); - ++_colorStamps[i]; - } - } - - if (_depthStencilBuffer) { - _depthStencilBuffer._texture->resize2D(width, height, _numSamples); - assert(_depthStencilBuffer._texture->getNumSamples() == _numSamples); - ++_depthStamp; - } - - _width = width; - _height = height; - } - } -} -#endif - uint16 Framebuffer::getWidth() const { if (isSwapchain()) { return getSwapchain()->getWidth(); diff --git a/libraries/gpu/src/gpu/Framebuffer.h b/libraries/gpu/src/gpu/Framebuffer.h index f357cfc3f8..8c26037ada 100755 --- a/libraries/gpu/src/gpu/Framebuffer.h +++ b/libraries/gpu/src/gpu/Framebuffer.h @@ -130,9 +130,6 @@ public: float getAspectRatio() const { return getWidth() / (float) getHeight() ; } - // If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call - //void resize( uint16 width, uint16 height, uint16 samples = 1 ); - static const uint32 MAX_NUM_RENDER_BUFFERS = 8; static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } From ba3abc7b510fe0a5f671958ddba99f6bcc00f86f Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Sep 2016 10:41:17 -0700 Subject: [PATCH 39/42] Fix warnings --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 1b5013beb2..7a86e4f3a2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -491,7 +491,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) { syncSampler(); size_t oldSize = _size; updateSize(); - assert(_size > oldSize); + Q_ASSERT(_size > oldSize); + // Re-insert into the texture-by-mips map if appropriate mipLevels = usedMipLevels(); From e6f23d6ffd3b9eb8f0a84f3833c9ae25fc1b12db Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Sep 2016 10:43:56 -0700 Subject: [PATCH 40/42] Disable sparse textures on non-Windows systems --- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 7a86e4f3a2..2489f79c0b 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -25,8 +25,12 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; +#ifdef Q_OS_WIN static const QString DEBUG_FLAG("HIFI_DISABLE_SPARSE_TEXTURES"); static bool enableSparseTextures = !QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); +#else +static bool enableSparseTextures = false; +#endif // Allocate 1 MB of buffer space for paged transfers #define DEFAULT_PAGE_BUFFER_SIZE (1024*1024) From 5a91116c069047162c63b596869e1ccff8d479d0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Sep 2016 11:16:31 -0700 Subject: [PATCH 41/42] Fix debug build, fix typo in available texture memory calculation --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 2 +- libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 94d645378b..56ff4166ea 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -124,7 +124,7 @@ float GLTexture::getMemoryPressure() { // Allow 50% of all available GPU memory to be consumed by textures // FIXME overly conservative? - availableTextureMemory = (totalGpuMemory > 2); + availableTextureMemory = (totalGpuMemory >> 1); } // Return the consumed texture memory divided by the available texture memory. diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 2489f79c0b..6733475c01 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -517,8 +517,8 @@ void GL45Texture::updateMips() { } void GL45Texture::derez() { - assert(_sparseInfo._sparse); - assert(_minMip < _sparseInfo._maxSparseLevel); + assert(_sparseInfo.sparse); + assert(_minMip < _sparseInfo.maxSparseLevel); assert(_minMip < _maxMip); assert(_transferrable); stripToMip(_minMip + 1); From 2dd93e0586dce438113e73baa4c9f75d3717b751 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 23 Sep 2016 12:04:35 -0700 Subject: [PATCH 42/42] Disable debug command list --- tests/render-perf/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index 5ac82bdf29..987fbe33d5 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -1129,7 +1129,7 @@ int main(int argc, char** argv) { QLoggingCategory::setFilterRules(LOG_FILTER_RULES); QTestWindow::setup(); QTestWindow window; - window.loadCommands("C:/Users/bdavis/Git/dreaming/exports/commands.txt"); + //window.loadCommands("C:/Users/bdavis/Git/dreaming/exports/commands.txt"); app.exec(); return 0; }